diff --git a/OpenMetaverse/ObjectManager.cs b/OpenMetaverse/ObjectManager.cs index 6b6eb925..508a6830 100644 --- a/OpenMetaverse/ObjectManager.cs +++ b/OpenMetaverse/ObjectManager.cs @@ -36,14 +36,18 @@ namespace OpenMetaverse /// /// /// - public enum ObjectPropertiesRequestType + public enum ReportType : uint { - /// + /// No report None = 0, - /// - BugReportRequest = 1, - /// - ComplaintReportRequest = 2 + /// Unknown report type + Unknown = 1, + /// Bug report + Bug = 2, + /// Complaint report + Complaint = 3, + /// Customer service report + CustomerServiceRequest = 4 } /// @@ -83,15 +87,16 @@ namespace OpenMetaverse { /// None None = 0x00, - /// Change Position of prims + /// Change position of prims Position = 0x01, - /// Change Rotation of prims + /// Change rotation of prims Rotation = 0x02, - /// Change Size of Prims + /// Change size of prims Scale = 0x04, /// Perform operation on link set Linked = 0x08, - /// Scale prims uniformly, same as selecing ctrl+shift in viewer + /// Scale prims uniformly, same as selecing ctrl+shift in the + /// viewer. Used in conjunction with Scale Uniform = 0x10 } @@ -170,7 +175,7 @@ namespace OpenMetaverse /// /// public delegate void ObjectPropertiesFamilyCallback(Simulator simulator, Primitive.ObjectProperties props, - ObjectPropertiesRequestType type); + ReportType type); /// /// /// @@ -2190,7 +2195,7 @@ namespace OpenMetaverse ObjectPropertiesFamilyPacket op = (ObjectPropertiesFamilyPacket)p; Primitive.ObjectProperties props = new Primitive.ObjectProperties(); - ObjectPropertiesRequestType requestType = (ObjectPropertiesRequestType)op.ObjectData.RequestFlags; + ReportType requestType = (ReportType)op.ObjectData.RequestFlags; props.ObjectID = op.ObjectData.ObjectID; props.Category = (ObjectCategory)op.ObjectData.Category; @@ -2294,7 +2299,7 @@ namespace OpenMetaverse } protected void FireOnObjectPropertiesFamily(Simulator sim, Primitive.ObjectProperties props, - ObjectPropertiesRequestType type) + ReportType type) { if (OnObjectPropertiesFamily != null) { diff --git a/Programs/Simian/Extensions/AvatarManager.cs b/Programs/Simian/Extensions/AvatarManager.cs index 382772c0..3af54e07 100644 --- a/Programs/Simian/Extensions/AvatarManager.cs +++ b/Programs/Simian/Extensions/AvatarManager.cs @@ -25,6 +25,7 @@ namespace Simian.Extensions Server.UDPServer.RegisterPacketCallback(PacketType.AgentSetAppearance, new UDPServer.PacketCallback(AgentSetAppearanceHandler)); Server.UDPServer.RegisterPacketCallback(PacketType.AgentAnimation, new UDPServer.PacketCallback(AgentAnimationHandler)); Server.UDPServer.RegisterPacketCallback(PacketType.ViewerEffect, new UDPServer.PacketCallback(ViewerEffectHandler)); + Server.UDPServer.RegisterPacketCallback(PacketType.UUIDNameRequest, new UDPServer.PacketCallback(UUIDNameRequestHandler)); } public void Stop() @@ -232,6 +233,45 @@ namespace Simian.Extensions } } + void UUIDNameRequestHandler(Packet packet, Agent agent) + { + UUIDNameRequestPacket request = (UUIDNameRequestPacket)packet; + Dictionary replies = new Dictionary(request.UUIDNameBlock.Length); + + // FIXME: This is messy/slow until we get a proper ISceneProvider + for (int i = 0; i < request.UUIDNameBlock.Length; i++) + { + lock (Server.Agents) + { + foreach (Agent curAgent in Server.Agents.Values) + { + if (curAgent.AgentID == request.UUIDNameBlock[i].ID) + { + replies[curAgent.AgentID] = curAgent; + break; + } + } + } + } + + if (replies.Count > 0) + { + UUIDNameReplyPacket reply = new UUIDNameReplyPacket(); + reply.UUIDNameBlock = new UUIDNameReplyPacket.UUIDNameBlockBlock[replies.Count]; + + int i = 0; + foreach (KeyValuePair kvp in replies) + { + reply.UUIDNameBlock[i] = new UUIDNameReplyPacket.UUIDNameBlockBlock(); + reply.UUIDNameBlock[i].ID = kvp.Key; + reply.UUIDNameBlock[i].FirstName = Utils.StringToBytes(kvp.Value.FirstName); + reply.UUIDNameBlock[i].LastName = Utils.StringToBytes(kvp.Value.LastName); + } + + agent.SendPacket(reply); + } + } + public static AvatarAppearancePacket BuildAppearancePacket(Agent agent) { AvatarAppearancePacket appearance = new AvatarAppearancePacket(); diff --git a/Programs/Simian/Extensions/ObjectManager.cs b/Programs/Simian/Extensions/ObjectManager.cs index 8e59eb37..64d69faf 100644 --- a/Programs/Simian/Extensions/ObjectManager.cs +++ b/Programs/Simian/Extensions/ObjectManager.cs @@ -23,7 +23,10 @@ namespace Simian.Extensions { Server.UDPServer.RegisterPacketCallback(PacketType.ObjectAdd, new UDPServer.PacketCallback(ObjectAddHandler)); Server.UDPServer.RegisterPacketCallback(PacketType.ObjectSelect, new UDPServer.PacketCallback(ObjectSelectHandler)); + Server.UDPServer.RegisterPacketCallback(PacketType.ObjectDeselect, new UDPServer.PacketCallback(ObjectDeselectHandler)); Server.UDPServer.RegisterPacketCallback(PacketType.DeRezObject, new UDPServer.PacketCallback(DeRezObjectHandler)); + Server.UDPServer.RegisterPacketCallback(PacketType.MultipleObjectUpdate, new UDPServer.PacketCallback(MultipleObjectUpdateHandler)); + Server.UDPServer.RegisterPacketCallback(PacketType.RequestObjectPropertiesFamily, new UDPServer.PacketCallback(RequestObjectPropertiesFamilyHandler)); } public void Stop() @@ -67,7 +70,11 @@ namespace Simian.Extensions } } - position.Z += scale.Z * 0.5f; + // Position lies on the face of another surface, either terrain of an object. + // Back up along the ray so we are not colliding with the mesh. + // HACK: This is really cheesy and should be done by a collision system + Vector3 rayDir = Vector3.Normalize(add.ObjectData.RayEnd - add.ObjectData.RayStart); + position -= rayDir * scale; #endregion Position Calculation @@ -218,6 +225,13 @@ namespace Simian.Extensions agent.SendPacket(properties); } + void ObjectDeselectHandler(Packet packet, Agent agent) + { + ObjectDeselectPacket deselect = (ObjectDeselectPacket)packet; + + // TODO: Do we need this at all? + } + void DeRezObjectHandler(Packet packet, Agent agent) { DeRezObjectPacket derez = (DeRezObjectPacket)packet; @@ -264,6 +278,7 @@ namespace Simian.Extensions InventoryObject invObj; if (agent.Inventory.TryGetValue(derez.AgentBlock.DestinationID, out invObj) && invObj is InventoryFolder) { + // FIXME: Handle children InventoryFolder trash = (InventoryFolder)invObj; Server.Inventory.CreateItem(agent, obj.Prim.Properties.Name, obj.Prim.Properties.Description, InventoryType.Object, AssetType.Object, obj.Prim.ID, trash.ID, PermissionMask.All, PermissionMask.All, agent.AgentID, @@ -300,6 +315,105 @@ namespace Simian.Extensions } } + void MultipleObjectUpdateHandler(Packet packet, Agent agent) + { + MultipleObjectUpdatePacket update = (MultipleObjectUpdatePacket)packet; + + for (int i = 0; i < update.ObjectData.Length; i++) + { + MultipleObjectUpdatePacket.ObjectDataBlock block = update.ObjectData[i]; + + SimulationObject obj; + if (SceneObjects.Dictionary.TryGetValue(block.ObjectLocalID, out obj)) + { + UpdateType type = (UpdateType)block.Type; + bool linked = ((type & UpdateType.Linked) != 0); + int pos = 0; + + // FIXME: Handle linksets + + if ((type & UpdateType.Position) != 0) + { + Vector3 newpos = new Vector3(block.Data, pos); + pos += 12; + + obj.Prim.Position = newpos; + } + if ((type & UpdateType.Rotation) != 0) + { + Quaternion newrot = new Quaternion(block.Data, pos, true); + pos += 12; + + obj.Prim.Rotation = newrot; + } + if ((type & UpdateType.Scale) != 0) + { + Vector3 newscale = new Vector3(block.Data, pos); + pos += 12; + + // TODO: Use this + bool uniform = ((type & UpdateType.Uniform) != 0); + + obj.Prim.Scale = newscale; + } + + // Send the update out to everyone + ObjectUpdatePacket editedobj = Movement.BuildFullUpdate(obj.Prim, String.Empty, obj.Prim.RegionHandle, 0, + obj.Prim.Flags); + lock (Server.Agents) + { + foreach (Agent recipient in Server.Agents.Values) + recipient.SendPacket(editedobj); + } + } + else + { + // Ghosted prim, send a kill message to this agent + // FIXME: Handle children + KillObjectPacket kill = new KillObjectPacket(); + kill.ObjectData = new KillObjectPacket.ObjectDataBlock[1]; + kill.ObjectData[0] = new KillObjectPacket.ObjectDataBlock(); + kill.ObjectData[0].ID = block.ObjectLocalID; + agent.SendPacket(kill); + } + } + } + + void RequestObjectPropertiesFamilyHandler(Packet packet, Agent agent) + { + RequestObjectPropertiesFamilyPacket request = (RequestObjectPropertiesFamilyPacket)packet; + ReportType type = (ReportType)request.ObjectData.RequestFlags; + + SimulationObject obj; + if (SceneObjectsByID.TryGetValue(request.ObjectData.ObjectID, out obj)) + { + ObjectPropertiesFamilyPacket props = new ObjectPropertiesFamilyPacket(); + props.ObjectData.BaseMask = (uint)obj.Prim.Properties.Permissions.BaseMask; + props.ObjectData.Category = (uint)obj.Prim.Properties.Category; + props.ObjectData.Description = Utils.StringToBytes(obj.Prim.Properties.Description); + props.ObjectData.EveryoneMask = (uint)obj.Prim.Properties.Permissions.EveryoneMask; + props.ObjectData.GroupID = obj.Prim.Properties.GroupID; + props.ObjectData.GroupMask = (uint)obj.Prim.Properties.Permissions.GroupMask; + props.ObjectData.LastOwnerID = obj.Prim.Properties.LastOwnerID; + props.ObjectData.Name = Utils.StringToBytes(obj.Prim.Properties.Name); + props.ObjectData.NextOwnerMask = (uint)obj.Prim.Properties.Permissions.NextOwnerMask; + props.ObjectData.ObjectID = obj.Prim.ID; + props.ObjectData.OwnerID = obj.Prim.Properties.OwnerID; + props.ObjectData.OwnerMask = (uint)obj.Prim.Properties.Permissions.OwnerMask; + props.ObjectData.OwnershipCost = obj.Prim.Properties.OwnershipCost; + props.ObjectData.RequestFlags = (uint)type; + props.ObjectData.SalePrice = obj.Prim.Properties.SalePrice; + props.ObjectData.SaleType = (byte)obj.Prim.Properties.SaleType; + + agent.SendPacket(props); + } + else + { + Logger.Log("RequestObjectPropertiesFamily sent for unknown object " + + request.ObjectData.ObjectID.ToString(), Helpers.LogLevel.Warning); + } + } + void KillObject(SimulationObject obj) { lock (SceneObjects) @@ -334,7 +448,7 @@ namespace Simian.Extensions if (rayStart == rayEnd) { - Logger.DebugLog("RayStart is equal to RayEnd, rezzing from given location"); + Logger.DebugLog("RayStart is equal to RayEnd, returning given location"); return closestPoint; } @@ -343,10 +457,10 @@ namespace Simian.Extensions // Get the mesh that has been transformed into world-space SimpleMesh mesh = null; - if (obj.Prim.LocalID != 0) + if (obj.Prim.ParentID != 0) { SimulationObject parent; - if (SceneObjects.TryGetValue(obj.Prim.LocalID, out parent)) + if (SceneObjects.TryGetValue(obj.Prim.ParentID, out parent)) mesh = obj.GetWorldMesh(DetailLevel.Low, parent); } else @@ -362,12 +476,15 @@ namespace Simian.Extensions float closestDistance = Single.MaxValue; for (int i = 0; i < mesh.Indices.Count; i += 3) { - if (RayTriangleIntersection(rayStart, direction, mesh.Vertices[i].Position, - mesh.Vertices[i + 1].Position, mesh.Vertices[i + 2].Position)) + Vector3 point0 = mesh.Vertices[mesh.Indices[i + 0]].Position; + Vector3 point1 = mesh.Vertices[mesh.Indices[i + 1]].Position; + Vector3 point2 = mesh.Vertices[mesh.Indices[i + 2]].Position; + + if (RayTriangleIntersection(rayStart, direction, point0, point1, point2)) { - // Find the barycenter of this triangle - Vector3 center = - (mesh.Vertices[i].Position + mesh.Vertices[i + 1].Position + mesh.Vertices[i + 2].Position) * OO_THREE; + // HACK: Find the barycenter of this triangle. Would be better to have + // RayTriangleIntersection return the exact collision point + Vector3 center = (point0 + point1 + point2) * OO_THREE; Logger.DebugLog("Collision hit with triangle at " + center); diff --git a/Programs/examples/TestClient/Commands/Prims/ExportCommand.cs b/Programs/examples/TestClient/Commands/Prims/ExportCommand.cs index 5b47000f..58edb884 100644 --- a/Programs/examples/TestClient/Commands/Prims/ExportCommand.cs +++ b/Programs/examples/TestClient/Commands/Prims/ExportCommand.cs @@ -217,7 +217,7 @@ namespace OpenMetaverse.TestClient } void Objects_OnObjectPropertiesFamily(Simulator simulator, Primitive.ObjectProperties properties, - ObjectPropertiesRequestType type) + ReportType type) { Properties.SetFamilyProperties(properties); GotPermissions = true;