diff --git a/Programs/Simian/Agent.cs b/Programs/Simian/Agent.cs index 46d5a14d..4c1227b3 100644 --- a/Programs/Simian/Agent.cs +++ b/Programs/Simian/Agent.cs @@ -19,6 +19,14 @@ namespace Simian public int Balance; public bool Running; public AgentManager.ControlFlags ControlFlags = AgentManager.ControlFlags.NONE; + public Dictionary Inventory = new Dictionary(); + public Dictionary Library = new Dictionary(); + public Dictionary Wearables = new Dictionary(); + // TODO: Replace byte with enum + public byte State; + public LLObject.ObjectFlags Flags; + public UUID InventoryRoot; + public UUID InventoryLibRoot; /// Sequence numbers of packets we've received (for duplicate checking) internal Queue packetArchive = new Queue(); diff --git a/Programs/Simian/Extensions/ConnectionManagement.cs b/Programs/Simian/Extensions/ConnectionManagement.cs index 8f99bf1e..32621611 100644 --- a/Programs/Simian/Extensions/ConnectionManagement.cs +++ b/Programs/Simian/Extensions/ConnectionManagement.cs @@ -2,7 +2,7 @@ using System; using OpenMetaverse; using OpenMetaverse.Packets; -namespace Simian +namespace Simian.Extensions { public class ConnectionManagement : ISimianExtension { diff --git a/Programs/Simian/Extensions/ImageDelivery.cs b/Programs/Simian/Extensions/ImageDelivery.cs index 5f056928..9781e928 100644 --- a/Programs/Simian/Extensions/ImageDelivery.cs +++ b/Programs/Simian/Extensions/ImageDelivery.cs @@ -1,17 +1,17 @@ -using OpenMetaverse; -using OpenMetaverse.Imaging; -using OpenMetaverse.Packets; using System; using System.Collections.Generic; using System.Drawing; -using System.Text; +using OpenMetaverse; +using OpenMetaverse.Imaging; +using OpenMetaverse.Packets; namespace Simian.Extensions { public class ImageDelivery : ISimianExtension { Simian Server; - Bitmap DefaultImage; + byte[] DefaultJP2; + byte[] DefaultBakedJP2; public ImageDelivery(Simian server) { @@ -22,12 +22,22 @@ namespace Simian.Extensions { Server.UDPServer.RegisterPacketCallback(PacketType.RequestImage, new UDPServer.PacketCallback(RequestImageHandler)); - if (DefaultImage != null) DefaultImage = null; - DefaultImage = new Bitmap(32, 32); - Graphics gfx = Graphics.FromImage(DefaultImage); + Bitmap defaultImage = new Bitmap(32, 32); + Graphics gfx = Graphics.FromImage(defaultImage); gfx.Clear(Color.White); gfx.FillRectangles(Brushes.LightGray, new Rectangle[] { new Rectangle(16, 16, 16, 16), new Rectangle(0, 0, 16, 16) }); - gfx.DrawImage(DefaultImage, 0, 0, 32, 32); + gfx.DrawImage(defaultImage, 0, 0, 32, 32); + + ManagedImage defaultManaged = new ManagedImage(defaultImage); + + ManagedImage defaultBaked = new ManagedImage(defaultImage); + defaultBaked.Channels = ManagedImage.ImageChannels.Color | ManagedImage.ImageChannels.Alpha | + ManagedImage.ImageChannels.Bump; + defaultBaked.Alpha = defaultBaked.Red; + defaultBaked.Bump = defaultBaked.Red; + + DefaultJP2 = OpenJPEG.Encode(defaultManaged, true); + DefaultBakedJP2 = OpenJPEG.Encode(defaultBaked, true); } public void Stop() @@ -38,22 +48,29 @@ namespace Simian.Extensions { RequestImagePacket request = (RequestImagePacket)packet; - foreach (RequestImagePacket.RequestImageBlock block in request.RequestImage) + for (int i = 0; i < request.RequestImage.Length; i++) { - //ImageNotInDatabasePacket missing = new ImageNotInDatabasePacket(); - //missing.ImageID.ID = block.Image; - //agent.SendPacket(missing); + RequestImagePacket.RequestImageBlock block = request.RequestImage[i]; + bool bake = ((ImageType)block.Type == ImageType.Baked); ImageDataPacket imageData = new ImageDataPacket(); - imageData.ImageData.Data = OpenJPEG.EncodeFromImage(DefaultImage, true); imageData.ImageID.ID = block.Image; imageData.ImageID.Codec = 1; imageData.ImageID.Packets = 1; + if (bake) + { + Logger.DebugLog("Sending default bake texture"); + imageData.ImageData.Data = DefaultBakedJP2; + } + else + { + Logger.DebugLog("Sending default texture"); + imageData.ImageData.Data = DefaultJP2; + } imageData.ImageID.Size = (uint)imageData.ImageData.Data.Length; agent.SendPacket(imageData); } } - } } diff --git a/Programs/Simian/Extensions/Movement.cs b/Programs/Simian/Extensions/Movement.cs index f9ed3a41..0c80099e 100644 --- a/Programs/Simian/Extensions/Movement.cs +++ b/Programs/Simian/Extensions/Movement.cs @@ -24,15 +24,17 @@ namespace Simian.Extensions public void Start() { Server.UDPServer.RegisterPacketCallback(PacketType.AgentUpdate, new UDPServer.PacketCallback(AgentUpdateHandler)); + Server.UDPServer.RegisterPacketCallback(PacketType.AgentHeightWidth, new UDPServer.PacketCallback(AgentHeightWidthHandler)); Server.UDPServer.RegisterPacketCallback(PacketType.SetAlwaysRun, new UDPServer.PacketCallback(SetAlwaysRunHandler)); - if (UpdateTimer != null) UpdateTimer = null; + Server.UDPServer.RegisterPacketCallback(PacketType.ViewerEffect, new UDPServer.PacketCallback(ViewerEffectHandler)); + UpdateTimer = new Timer(new TimerCallback(UpdateTimer_Elapsed)); UpdateTimer.Change(100, 100); } public void Stop() { - UpdateTimer = null; + UpdateTimer.Dispose(); } void UpdateTimer_Elapsed(object sender) @@ -92,7 +94,6 @@ namespace Simian.Extensions else if (agent.Avatar.Position.Y > 255) agent.Avatar.Position.Y = 255f; if (agent.Avatar.Position.Z < lowerLimit) agent.Avatar.Position.Z = lowerLimit; - } } } @@ -105,11 +106,17 @@ namespace Simian.Extensions { agent.Avatar.Rotation = update.AgentData.BodyRotation; agent.ControlFlags = (AgentManager.ControlFlags)update.AgentData.ControlFlags; + agent.State = update.AgentData.State; + //agent.Flags = (LLObject.ObjectFlags)update.AgentData.Flags; - ObjectUpdatePacket fullUpdate = BuildFullUpdate(agent, agent.Avatar, update.AgentData.State, update.AgentData.Flags); + ObjectUpdatePacket fullUpdate = BuildFullUpdate(agent, agent.Avatar, Server.RegionHandle, + agent.State, agent.Flags); - foreach (Agent recipient in Server.Agents.Values) - recipient.SendPacket(fullUpdate); + lock (Server.Agents) + { + foreach (Agent recipient in Server.Agents.Values) + recipient.SendPacket(fullUpdate); + } } } @@ -149,7 +156,22 @@ namespace Simian.Extensions return ((lerpX + lerpY) / 2); } - ObjectUpdatePacket BuildFullUpdate(Agent agent, LLObject obj, byte state, uint flags) + void AgentHeightWidthHandler(Packet packet, Agent agent) + { + AgentHeightWidthPacket heightWidth = (AgentHeightWidthPacket)packet; + + Logger.Log(String.Format("Agent wants to set height={0}, width={1}", + heightWidth.HeightWidthBlock.Height, heightWidth.HeightWidthBlock.Width), Helpers.LogLevel.Info); + } + + void ViewerEffectHandler(Packet packet, Agent agent) + { + ViewerEffectPacket effect = (ViewerEffectPacket)packet; + + // TODO: Do something with these + } + + public static ObjectUpdatePacket BuildFullUpdate(Agent agent, LLObject obj, ulong regionHandle, byte state, LLObject.ObjectFlags flags) { byte[] objectData = new byte[60]; int pos = 0; @@ -164,7 +186,7 @@ namespace Simian.Extensions agent.Avatar.AngularVelocity.GetBytes().CopyTo(objectData, pos); ObjectUpdatePacket update = new ObjectUpdatePacket(); - update.RegionData.RegionHandle = Server.RegionHandle; + update.RegionData.RegionHandle = regionHandle; update.RegionData.TimeDilation = Helpers.FloatToByte(1f, 0f, 1f); update.ObjectData = new ObjectUpdatePacket.ObjectDataBlock[1]; update.ObjectData[0] = new ObjectUpdatePacket.ObjectDataBlock(); @@ -178,19 +200,19 @@ namespace Simian.Extensions update.ObjectData[0].JointAxisOrAnchor = Vector3.Zero; update.ObjectData[0].JointPivot = Vector3.Zero; update.ObjectData[0].JointType = (byte)0; - update.ObjectData[0].Material = (byte)3; + update.ObjectData[0].Material = (byte)LLObject.MaterialType.Flesh; update.ObjectData[0].MediaURL = new byte[0]; update.ObjectData[0].NameValue = Utils.StringToBytes(NameValue.NameValuesToString(agent.Avatar.NameValues)); update.ObjectData[0].ObjectData = objectData; update.ObjectData[0].OwnerID = UUID.Zero; update.ObjectData[0].ParentID = 0; update.ObjectData[0].PathBegin = 0; - update.ObjectData[0].PathCurve = (byte)32; + update.ObjectData[0].PathCurve = (byte)16; update.ObjectData[0].PathEnd = 0; update.ObjectData[0].PathRadiusOffset = (sbyte)0; update.ObjectData[0].PathRevolutions = (byte)0; update.ObjectData[0].PathScaleX = (byte)100; - update.ObjectData[0].PathScaleY = (byte)150; + update.ObjectData[0].PathScaleY = (byte)100; update.ObjectData[0].PathShearX = (byte)0; update.ObjectData[0].PathShearY = (byte)0; update.ObjectData[0].PathSkew = (sbyte)0; @@ -200,23 +222,22 @@ namespace Simian.Extensions update.ObjectData[0].PathTwistBegin = (sbyte)0; update.ObjectData[0].PCode = (byte)PCode.Avatar; update.ObjectData[0].ProfileBegin = 0; - update.ObjectData[0].ProfileCurve = (byte)0; + update.ObjectData[0].ProfileCurve = (byte)1; update.ObjectData[0].ProfileEnd = 0; update.ObjectData[0].ProfileHollow = 0; update.ObjectData[0].PSBlock = new byte[0]; update.ObjectData[0].TextColor = Vector3.Zero.GetBytes(); update.ObjectData[0].TextureAnim = new byte[0]; - update.ObjectData[0].TextureEntry = new byte[63]; + update.ObjectData[0].TextureEntry = obj.Textures.ToBytes(); update.ObjectData[0].Radius = 0f; update.ObjectData[0].Scale = obj.Scale; update.ObjectData[0].Sound = UUID.Zero; update.ObjectData[0].State = state; update.ObjectData[0].Text = new byte[0]; - update.ObjectData[0].UpdateFlags = flags; + update.ObjectData[0].UpdateFlags = (uint)flags; update.ObjectData[0].Data = new byte[0]; return update; } - } } diff --git a/Programs/Simian/Extensions/SceneManager.cs b/Programs/Simian/Extensions/SceneManager.cs index 62eeeb91..901619b5 100644 --- a/Programs/Simian/Extensions/SceneManager.cs +++ b/Programs/Simian/Extensions/SceneManager.cs @@ -9,13 +9,12 @@ using OpenMetaverse; using OpenMetaverse.Imaging; using OpenMetaverse.Packets; -namespace Simian +namespace Simian.Extensions { public class SceneManager : ISimianExtension { Simian server; int currentLocalID = 0; - int currentWearablesSerialNum = 0; public SceneManager(Simian server) { @@ -25,8 +24,6 @@ namespace Simian public void Start() { server.UDPServer.RegisterPacketCallback(PacketType.CompleteAgentMovement, new UDPServer.PacketCallback(CompleteAgentMovementHandler)); - server.UDPServer.RegisterPacketCallback(PacketType.AgentWearablesRequest, new UDPServer.PacketCallback(AgentWearablesRequestHandler)); - LoadTerrain("Maps/default.tga"); } @@ -44,7 +41,11 @@ namespace Simian avatar.LocalID = (uint)Interlocked.Increment(ref currentLocalID); avatar.Position = new Vector3(128f, 128f, 25f); avatar.Rotation = Quaternion.Identity; - avatar.Scale = new Vector3(1f, 1f, 3f); + avatar.Scale = new Vector3(0.45f, 0.6f, 1.9f); + + // Create a default outfit for the avatar + LLObject.TextureEntry te = new LLObject.TextureEntry(new UUID("c228d1cf-4b5d-4ba8-84f4-899a0796aa97")); + avatar.Textures = te; // Set the avatar name NameValue[] name = new NameValue[2]; @@ -74,26 +75,6 @@ namespace Simian SendLayerData(agent); } - void AgentWearablesRequestHandler(Packet packet, Agent agent) - { - AgentWearablesUpdatePacket update = new AgentWearablesUpdatePacket(); - update.AgentData.AgentID = agent.AgentID; - update.AgentData.SessionID = agent.SessionID; - // Technically this should be per-agent, but if the only requirement is that it - // increments this is easier - update.AgentData.SerialNum = (uint)Interlocked.Increment(ref currentWearablesSerialNum); - update.WearableData = new AgentWearablesUpdatePacket.WearableDataBlock[4]; - for (int i = 0; i < 4; i++) - { - update.WearableData[i] = new AgentWearablesUpdatePacket.WearableDataBlock(); - update.WearableData[i].AssetID = UUID.Zero; - update.WearableData[i].ItemID = UUID.Zero; - update.WearableData[i].WearableType = 42; // HACK - } - - agent.SendPacket(update); - } - void LoadTerrain(string mapFile) { if (File.Exists(mapFile)) diff --git a/Programs/Simian/Simian.cs b/Programs/Simian/Simian.cs index d3bb57e7..ef6a3616 100644 --- a/Programs/Simian/Simian.cs +++ b/Programs/Simian/Simian.cs @@ -18,6 +18,7 @@ namespace Simian public Dictionary SceneObjects = new Dictionary(); public ulong RegionHandle; public float[] Heightmap = new float[65536]; + public Dictionary AssetStore = new Dictionary(); /// All of the agents currently connected to this UDP server public Dictionary Agents = new Dictionary(); @@ -254,6 +255,29 @@ namespace Simian agent.SessionID = UUID.Random(); agent.SecureSessionID = UUID.Random(); agent.CircuitCode = CreateAgentCircuit(agent); + agent.InventoryRoot = UUID.Random(); + agent.InventoryLibRoot = UUID.Random(); + agent.Flags = LLObject.ObjectFlags.Physics | LLObject.ObjectFlags.ObjectModify | LLObject.ObjectFlags.ObjectCopy | + LLObject.ObjectFlags.ObjectAnyOwner | LLObject.ObjectFlags.ObjectMove | LLObject.ObjectFlags.InventoryEmpty | + LLObject.ObjectFlags.ObjectTransfer | LLObject.ObjectFlags.ObjectOwnerModify | LLObject.ObjectFlags.ObjectYouOwner; + + // Setup the agent inventory + InventoryFolder rootFolder = new InventoryFolder(); + rootFolder.ID = agent.InventoryRoot; + rootFolder.Name = "Inventory"; + rootFolder.OwnerID = agent.AgentID; + rootFolder.PreferredType = AssetType.RootFolder; + rootFolder.Version = 1; + agent.Inventory[rootFolder.ID] = rootFolder; + + // Setup the default library + InventoryFolder libRootFolder = new InventoryFolder(); + libRootFolder.ID = agent.InventoryLibRoot; + libRootFolder.Name = "Library"; + libRootFolder.OwnerID = agent.AgentID; + libRootFolder.PreferredType = AssetType.RootFolder; + libRootFolder.Version = 1; + agent.Library[libRootFolder.ID] = libRootFolder; IPHostEntry addresses = Dns.GetHostByName(Dns.GetHostName()); IPAddress simIP = addresses.AddressList.Length > 0 ? addresses.AddressList[0] : IPAddress.Loopback; @@ -271,12 +295,12 @@ namespace Simian response.HomeLookAt = Vector3.UnitX; response.HomePosition = new Vector3(128f, 128f, 25f); response.HomeRegion = Helpers.UIntsToLong(regionX, regionY); - response.InventorySkeleton = null; - response.InventoryRoot = UUID.Random(); + response.InventoryRoot = agent.InventoryRoot; + response.InventoryFolders = null; response.LastName = agent.LastName; - response.LibrarySkeleton = null; response.LibraryOwner = response.AgentID; - response.LibraryRoot = UUID.Random(); + response.LibraryRoot = agent.InventoryLibRoot; + response.LibraryFolders = null; response.LookAt = Vector3.UnitX; response.Message = "Welcome to Simian"; response.Reason = String.Empty;