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;