diff --git a/OpenMetaverse/ObjectManager.cs b/OpenMetaverse/ObjectManager.cs
index 40f280b1..b164575e 100644
--- a/OpenMetaverse/ObjectManager.cs
+++ b/OpenMetaverse/ObjectManager.cs
@@ -57,9 +57,9 @@ namespace OpenMetaverse
[Flags]
public enum CompressedFlags : uint
{
- /// Hasn't been spotted in the wild yet
+ /// Unknown
ScratchPad = 0x01,
- /// This may be incorrect
+ /// Whether the object has a TreeSpecies
Tree = 0x02,
/// Whether the object has floating text ala llSetText
HasText = 0x04,
diff --git a/OpenMetaverse/Types/Color4.cs b/OpenMetaverse/Types/Color4.cs
index e754aee6..f93671fb 100644
--- a/OpenMetaverse/Types/Color4.cs
+++ b/OpenMetaverse/Types/Color4.cs
@@ -239,7 +239,7 @@ namespace OpenMetaverse
}
///
- /// Writes the raw bytes for this color to a byte array
+ /// Serializes this color into four bytes in a byte array
///
/// Destination byte array
/// Position in the destination array to start
diff --git a/Programs/Simian/Extensions/PhysicsSimple.cs b/Programs/Simian/Extensions/PhysicsSimple.cs
index d49489d9..f0485f44 100644
--- a/Programs/Simian/Extensions/PhysicsSimple.cs
+++ b/Programs/Simian/Extensions/PhysicsSimple.cs
@@ -9,6 +9,11 @@ namespace Simian.Extensions
{
Simian server;
+ public float TimeDilation
+ {
+ get { return 1.0f; }
+ }
+
public PhysicsSimple()
{
}
diff --git a/Programs/Simian/Extensions/SceneManager.cs b/Programs/Simian/Extensions/SceneManager.cs
index ca73b88f..22007cfc 100644
--- a/Programs/Simian/Extensions/SceneManager.cs
+++ b/Programs/Simian/Extensions/SceneManager.cs
@@ -98,6 +98,8 @@ namespace Simian.Extensions
}
}
+ #region Object Interfaces
+
public void ObjectAddOrUpdate(object sender, SimulationObject obj, UUID ownerID, int scriptStartParam, PrimFlags creatorFlags, UpdateFlags updateFlags)
{
if (OnObjectAddOrUpdate != null)
@@ -212,196 +214,6 @@ namespace Simian.Extensions
SendObjectPacket(obj, canUseCompressed, canUseImproved, creatorFlags, updateFlags);
}
- void SendObjectPacket(SimulationObject obj, bool canUseCompressed, bool canUseImproved, PrimFlags creatorFlags, UpdateFlags updateFlags)
- {
- if (!canUseImproved && !canUseCompressed)
- {
- #region ObjectUpdate
-
- Logger.DebugLog("Sending ObjectUpdate");
-
- if (sceneAgents.ContainsKey(obj.Prim.OwnerID))
- {
- // Send an update out to the creator
- ObjectUpdatePacket updateToOwner = SimulationObject.BuildFullUpdate(obj.Prim, regionHandle,
- obj.Prim.Flags | creatorFlags | PrimFlags.ObjectYouOwner, obj.CRC);
- server.UDP.SendPacket(obj.Prim.OwnerID, updateToOwner, PacketCategory.State);
- }
-
- // Send an update out to everyone else
- ObjectUpdatePacket updateToOthers = SimulationObject.BuildFullUpdate(obj.Prim, regionHandle,
- obj.Prim.Flags, obj.CRC);
- server.Scene.ForEachAgent(
- delegate(Agent recipient)
- {
- if (recipient.ID != obj.Prim.OwnerID)
- server.UDP.SendPacket(recipient.ID, updateToOthers, PacketCategory.State);
- }
- );
-
- #endregion ObjectUpdate
- }
- else if (!canUseImproved)
- {
- #region ObjectUpdateCompressed
-
- ObjectUpdateCompressedPacket update = new ObjectUpdateCompressedPacket();
- update.RegionData.RegionHandle = RegionHandle;
- update.RegionData.TimeDilation = (ushort)(1f * (float)UInt16.MaxValue); // TODO: Implement this
- update.ObjectData = new ObjectUpdateCompressedPacket.ObjectDataBlock[1];
- update.ObjectData[0] = new ObjectUpdateCompressedPacket.ObjectDataBlock();
-
- CompressedFlags flags = 0;
- int size = 0;
- byte[] textBytes;
- byte[] mediaURLBytes;
-
- if ((updateFlags & UpdateFlags.AngularVelocity) != 0)
- {
- flags |= CompressedFlags.HasAngularVelocity;
- size += 12;
- }
- if ((updateFlags & UpdateFlags.ParentID) != 0)
- {
- flags |= CompressedFlags.HasParent;
- size += 4;
- }
- if ((updateFlags & UpdateFlags.ScratchPad) != 0)
- {
- switch (obj.Prim.PrimData.PCode)
- {
- case PCode.Grass:
- case PCode.Tree:
- case PCode.NewTree:
- flags |= CompressedFlags.Tree;
- size += 2;
- break;
- default:
- flags |= CompressedFlags.ScratchPad;
- size += 1 + obj.Prim.ScratchPad.Length;
- break;
- }
- }
- if ((updateFlags & UpdateFlags.Text) != 0)
- {
- flags |= CompressedFlags.HasText;
- textBytes = Utils.StringToBytes(obj.Prim.Text);
- size += textBytes.Length;
- }
- if ((updateFlags & UpdateFlags.MediaURL) != 0)
- {
- flags |= CompressedFlags.MediaURL;
- mediaURLBytes = Utils.StringToBytes(obj.Prim.MediaURL);
- size += mediaURLBytes.Length;
- }
- if ((updateFlags & UpdateFlags.Particles) != 0)
- {
- flags |= CompressedFlags.HasParticles;
- // size +=
- }
- // Extra Params
- if ((updateFlags & UpdateFlags.Sound) != 0)
- {
- flags |= CompressedFlags.HasSound;
- }
- if ((updateFlags & UpdateFlags.NameValue) != 0)
- {
- flags |= CompressedFlags.HasNameValues;
- //size +=
- }
- // PrimData
- // Texture Length
- // Texture Entry
- if ((updateFlags & UpdateFlags.TextureAnim) != 0)
- {
- flags |= CompressedFlags.TextureAnimation;
- // size += 4 +
- }
-
- Logger.DebugLog("Sending ObjectUpdateCompressed with " + flags.ToString());
-
- update.ObjectData[0].UpdateFlags = (uint)flags;
- //update.ObjectData[0].Data = data;
- //server.UDP.BroadcastPacket(update, PacketCategory.State);
-
- #endregion ObjectUpdateCompressed
- }
- else
- {
- #region ImprovedTerseObjectUpdate
-
- Logger.DebugLog("Sending ImprovedTerseObjectUpdate");
-
- int pos = 0;
- byte[] data = new byte[(obj.Prim is Avatar ? 60 : 44)];
-
- // LocalID
- Utils.UIntToBytes(obj.Prim.LocalID, data, pos);
- pos += 4;
- // Avatar/CollisionPlane
- data[pos++] = obj.Prim.PrimData.State;
- if (obj.Prim is Avatar)
- {
- data[pos++] = 1;
- obj.Prim.CollisionPlane.ToBytes(data, pos);
- pos += 16;
- }
- else
- {
- ++pos;
- }
- // Position
- obj.Prim.Position.ToBytes(data, pos);
- pos += 12;
-
- // Velocity
- Utils.UInt16ToBytes(Utils.FloatToUInt16(obj.Prim.Velocity.X, -128.0f, 128.0f), data, pos); pos += 2;
- Utils.UInt16ToBytes(Utils.FloatToUInt16(obj.Prim.Velocity.Y, -128.0f, 128.0f), data, pos); pos += 2;
- Utils.UInt16ToBytes(Utils.FloatToUInt16(obj.Prim.Velocity.Z, -128.0f, 128.0f), data, pos); pos += 2;
- // Acceleration
- Utils.UInt16ToBytes(Utils.FloatToUInt16(obj.Prim.Acceleration.X, -64.0f, 64.0f), data, pos); pos += 2;
- Utils.UInt16ToBytes(Utils.FloatToUInt16(obj.Prim.Acceleration.Y, -64.0f, 64.0f), data, pos); pos += 2;
- Utils.UInt16ToBytes(Utils.FloatToUInt16(obj.Prim.Acceleration.Z, -64.0f, 64.0f), data, pos); pos += 2;
- // Rotation
- Utils.UInt16ToBytes(Utils.FloatToUInt16(obj.Prim.Rotation.X, -1.0f, 1.0f), data, pos); pos += 2;
- Utils.UInt16ToBytes(Utils.FloatToUInt16(obj.Prim.Rotation.Y, -1.0f, 1.0f), data, pos); pos += 2;
- Utils.UInt16ToBytes(Utils.FloatToUInt16(obj.Prim.Rotation.Z, -1.0f, 1.0f), data, pos); pos += 2;
- Utils.UInt16ToBytes(Utils.FloatToUInt16(obj.Prim.Rotation.W, -1.0f, 1.0f), data, pos); pos += 2;
- // Angular Velocity
- Utils.UInt16ToBytes(Utils.FloatToUInt16(obj.Prim.AngularVelocity.X, -64.0f, 64.0f), data, pos); pos += 2;
- Utils.UInt16ToBytes(Utils.FloatToUInt16(obj.Prim.AngularVelocity.Y, -64.0f, 64.0f), data, pos); pos += 2;
- Utils.UInt16ToBytes(Utils.FloatToUInt16(obj.Prim.AngularVelocity.Z, -64.0f, 64.0f), data, pos); pos += 2;
-
- ImprovedTerseObjectUpdatePacket update = new ImprovedTerseObjectUpdatePacket();
- update.RegionData.RegionHandle = RegionHandle;
- update.RegionData.TimeDilation = (ushort)(1f * (float)UInt16.MaxValue); // TODO: Implement this
- update.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[1];
- update.ObjectData[0] = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock();
- update.ObjectData[0].Data = data;
-
- if ((updateFlags & UpdateFlags.Textures) != 0)
- {
- byte[] textureBytes = obj.Prim.Textures.GetBytes();
- byte[] textureEntry = new byte[textureBytes.Length + 4];
-
- // Texture Length
- Utils.IntToBytes(textureBytes.Length, textureEntry, 0);
- // Texture
- Buffer.BlockCopy(textureBytes, 0, textureEntry, 4, textureBytes.Length);
-
- update.ObjectData[0].TextureEntry = textureEntry;
- }
- else
- {
- update.ObjectData[0].TextureEntry = Utils.EmptyBytes;
- }
-
- server.UDP.BroadcastPacket(update, PacketCategory.State);
-
- #endregion ImprovedTerseObjectUpdate
- }
- }
-
public bool ObjectRemove(object sender, uint localID)
{
SimulationObject obj;
@@ -456,36 +268,6 @@ namespace Simian.Extensions
return false;
}
- void AgentRemove(object sender, Agent agent)
- {
- if (OnAgentRemove != null)
- OnAgentRemove(sender, agent);
-
- Logger.Log("Removing agent " + agent.FullName + " from the scene", Helpers.LogLevel.Info);
-
- lock (sceneAgents) sceneAgents.Remove(agent.ID);
-
- KillObjectPacket kill = new KillObjectPacket();
- kill.ObjectData = new KillObjectPacket.ObjectDataBlock[1];
- kill.ObjectData[0] = new KillObjectPacket.ObjectDataBlock();
- kill.ObjectData[0].ID = agent.Avatar.Prim.LocalID;
-
- server.UDP.BroadcastPacket(kill, PacketCategory.State);
-
- // Kill the EventQueue
- RemoveEventQueue(agent.ID);
-
- // Remove the UDP client
- server.UDP.RemoveClient(agent);
-
- // Notify everyone in the scene that this agent has gone offline
- OfflineNotificationPacket offline = new OfflineNotificationPacket();
- offline.AgentBlock = new OfflineNotificationPacket.AgentBlockBlock[1];
- offline.AgentBlock[0] = new OfflineNotificationPacket.AgentBlockBlock();
- offline.AgentBlock[0].AgentID = agent.ID;
- server.UDP.BroadcastPacket(offline, PacketCategory.State);
- }
-
public void ObjectSetRotationAxis(object sender, SimulationObject obj, Vector3 rotationAxis)
{
if (OnObjectSetRotationAxis != null)
@@ -626,6 +408,41 @@ namespace Simian.Extensions
}
}
+ public bool ContainsObject(uint localID)
+ {
+ return sceneObjects.ContainsKey(localID);
+ }
+
+ public bool ContainsObject(UUID id)
+ {
+ return sceneObjects.ContainsKey(id);
+ }
+
+ public int ObjectCount()
+ {
+ return sceneObjects.Count;
+ }
+
+ public bool TryGetObject(uint localID, out SimulationObject obj)
+ {
+ return sceneObjects.TryGetValue(localID, out obj);
+ }
+
+ public bool TryGetObject(UUID id, out SimulationObject obj)
+ {
+ return sceneObjects.TryGetValue(id, out obj);
+ }
+
+ public void ForEachObject(Action action)
+ {
+ sceneObjects.ForEach(action);
+ }
+
+ public SimulationObject FindObject(Predicate predicate)
+ {
+ return sceneObjects.FindValue(predicate);
+ }
+
public void TriggerSound(object sender, UUID objectID, UUID parentID, UUID ownerID, UUID soundID, Vector3 position, float gain)
{
if (OnTriggerSound != null)
@@ -676,30 +493,9 @@ namespace Simian.Extensions
server.UDP.BroadcastPacket(effect, PacketCategory.State);
}
- public bool ContainsObject(uint localID)
- {
- return sceneObjects.ContainsKey(localID);
- }
+ #endregion Object Interfaces
- public bool ContainsObject(UUID id)
- {
- return sceneObjects.ContainsKey(id);
- }
-
- public int ObjectCount()
- {
- return sceneObjects.Count;
- }
-
- public bool TryGetObject(uint localID, out SimulationObject obj)
- {
- return sceneObjects.TryGetValue(localID, out obj);
- }
-
- public bool TryGetObject(UUID id, out SimulationObject obj)
- {
- return sceneObjects.TryGetValue(id, out obj);
- }
+ #region Agent Interfaces
public bool AgentAdd(object sender, Agent agent, PrimFlags creatorFlags)
{
@@ -756,6 +552,36 @@ namespace Simian.Extensions
return true;
}
+ void AgentRemove(object sender, Agent agent)
+ {
+ if (OnAgentRemove != null)
+ OnAgentRemove(sender, agent);
+
+ Logger.Log("Removing agent " + agent.FullName + " from the scene", Helpers.LogLevel.Info);
+
+ lock (sceneAgents) sceneAgents.Remove(agent.ID);
+
+ KillObjectPacket kill = new KillObjectPacket();
+ kill.ObjectData = new KillObjectPacket.ObjectDataBlock[1];
+ kill.ObjectData[0] = new KillObjectPacket.ObjectDataBlock();
+ kill.ObjectData[0].ID = agent.Avatar.Prim.LocalID;
+
+ server.UDP.BroadcastPacket(kill, PacketCategory.State);
+
+ // Kill the EventQueue
+ RemoveEventQueue(agent.ID);
+
+ // Remove the UDP client
+ server.UDP.RemoveClient(agent);
+
+ // Notify everyone in the scene that this agent has gone offline
+ OfflineNotificationPacket offline = new OfflineNotificationPacket();
+ offline.AgentBlock = new OfflineNotificationPacket.AgentBlockBlock[1];
+ offline.AgentBlock[0] = new OfflineNotificationPacket.AgentBlockBlock();
+ offline.AgentBlock[0].AgentID = agent.ID;
+ server.UDP.BroadcastPacket(offline, PacketCategory.State);
+ }
+
public void AgentAppearance(object sender, Agent agent, Primitive.TextureEntry textures, byte[] visualParams)
{
if (OnAgentAppearance != null)
@@ -788,16 +614,6 @@ namespace Simian.Extensions
}
}
- public void ForEachObject(Action action)
- {
- sceneObjects.ForEach(action);
- }
-
- public SimulationObject FindObject(Predicate predicate)
- {
- return sceneObjects.FindValue(predicate);
- }
-
public bool TryGetAgent(UUID id, out Agent agent)
{
return sceneAgents.TryGetValue(id, out agent);
@@ -831,6 +647,8 @@ namespace Simian.Extensions
return null;
}
+ #endregion Agent Interfaces
+
#region Terrain and Wind
public float GetTerrainHeightAt(float fx, float fy)
@@ -946,6 +764,8 @@ namespace Simian.Extensions
#endregion Terrain and Wind
+ #region Capabilities Interfaces
+
public Uri CreateEventQueue(UUID agentID)
{
EventQueueServer eqServer = new EventQueueServer(server.HttpServer);
@@ -1039,6 +859,10 @@ namespace Simian.Extensions
return true;
}
+ #endregion Capabilities Interfaces
+
+ #region Callback Handlers
+
bool EventQueueHandler(IHttpClientContext context, IHttpRequest request, IHttpResponse response, object state)
{
EventQueueServer eqServer = (EventQueueServer)state;
@@ -1073,6 +897,8 @@ namespace Simian.Extensions
server.UDP.BroadcastPacket(online, PacketCategory.State);
}
+ #endregion Callback Handlers
+
// HACK: The reduction provider will deprecate this at some point
void SynchronizeStateTo(Agent agent)
{
@@ -1082,8 +908,12 @@ namespace Simian.Extensions
// Send object updates for objects and avatars
sceneObjects.ForEach(delegate(SimulationObject obj)
{
- ObjectUpdatePacket update = SimulationObject.BuildFullUpdate(obj.Prim,
- obj.Prim.RegionHandle, obj.Prim.Flags, obj.CRC);
+ ObjectUpdatePacket update = new ObjectUpdatePacket();
+ update.RegionData.RegionHandle = regionHandle;
+ update.RegionData.TimeDilation = (ushort)(server.Physics.TimeDilation * (float)UInt16.MaxValue);
+ update.ObjectData = new ObjectUpdatePacket.ObjectDataBlock[1];
+ update.ObjectData[0] = SimulationObject.BuildUpdateBlock(obj.Prim, obj.Prim.Flags, obj.CRC);
+
server.UDP.SendPacket(agent.ID, update, PacketCategory.State);
});
@@ -1184,6 +1014,388 @@ namespace Simian.Extensions
}
}
+ void SendObjectPacket(SimulationObject obj, bool canUseCompressed, bool canUseImproved, PrimFlags creatorFlags, UpdateFlags updateFlags)
+ {
+ if (!canUseImproved && !canUseCompressed)
+ {
+ #region ObjectUpdate
+
+ Logger.DebugLog("Sending ObjectUpdate");
+
+ if (sceneAgents.ContainsKey(obj.Prim.OwnerID))
+ {
+ // Send an update out to the creator
+ ObjectUpdatePacket updateToOwner = new ObjectUpdatePacket();
+ updateToOwner.RegionData.RegionHandle = regionHandle;
+ updateToOwner.RegionData.TimeDilation = (ushort)(server.Physics.TimeDilation * (float)UInt16.MaxValue);
+ updateToOwner.ObjectData = new ObjectUpdatePacket.ObjectDataBlock[1];
+ updateToOwner.ObjectData[0] = SimulationObject.BuildUpdateBlock(obj.Prim,
+ obj.Prim.Flags | creatorFlags | PrimFlags.ObjectYouOwner, obj.CRC);
+
+ server.UDP.SendPacket(obj.Prim.OwnerID, updateToOwner, PacketCategory.State);
+ }
+
+ // Send an update out to everyone else
+ ObjectUpdatePacket updateToOthers = new ObjectUpdatePacket();
+ updateToOthers.RegionData.RegionHandle = regionHandle;
+ updateToOthers.RegionData.TimeDilation = UInt16.MaxValue;
+ updateToOthers.ObjectData = new ObjectUpdatePacket.ObjectDataBlock[1];
+ updateToOthers.ObjectData[0] = SimulationObject.BuildUpdateBlock(obj.Prim,
+ obj.Prim.Flags, obj.CRC);
+
+ server.Scene.ForEachAgent(
+ delegate(Agent recipient)
+ {
+ if (recipient.ID != obj.Prim.OwnerID)
+ server.UDP.SendPacket(recipient.ID, updateToOthers, PacketCategory.State);
+ }
+ );
+
+ #endregion ObjectUpdate
+ }
+ else if (!canUseImproved)
+ {
+ #region ObjectUpdateCompressed
+
+ #region Size calculation and field serialization
+
+ CompressedFlags flags = 0;
+ int size = 84;
+ byte[] textBytes = null;
+ byte[] mediaURLBytes = null;
+ byte[] particleBytes = null;
+ byte[] extraParamBytes = null;
+ byte[] nameValueBytes = null;
+ byte[] textureBytes = null;
+ byte[] textureAnimBytes = null;
+
+ if ((updateFlags & UpdateFlags.AngularVelocity) != 0)
+ {
+ flags |= CompressedFlags.HasAngularVelocity;
+ size += 12;
+ }
+ if ((updateFlags & UpdateFlags.ParentID) != 0)
+ {
+ flags |= CompressedFlags.HasParent;
+ size += 4;
+ }
+ if ((updateFlags & UpdateFlags.ScratchPad) != 0)
+ {
+ switch (obj.Prim.PrimData.PCode)
+ {
+ case PCode.Grass:
+ case PCode.Tree:
+ case PCode.NewTree:
+ flags |= CompressedFlags.Tree;
+ size += 2; // Size byte plus one byte
+ break;
+ default:
+ flags |= CompressedFlags.ScratchPad;
+ size += 1 + obj.Prim.ScratchPad.Length; // Size byte plus bytes
+ break;
+ }
+ }
+ if ((updateFlags & UpdateFlags.Text) != 0)
+ {
+ flags |= CompressedFlags.HasText;
+ textBytes = Utils.StringToBytes(obj.Prim.Text);
+ size += textBytes.Length; // Null-terminated, no size byte
+ size += 4; // Text color
+ }
+ if ((updateFlags & UpdateFlags.MediaURL) != 0)
+ {
+ flags |= CompressedFlags.MediaURL;
+ mediaURLBytes = Utils.StringToBytes(obj.Prim.MediaURL);
+ size += mediaURLBytes.Length; // Null-terminated, no size byte
+ }
+ if ((updateFlags & UpdateFlags.Particles) != 0)
+ {
+ flags |= CompressedFlags.HasParticles;
+ particleBytes = obj.Prim.ParticleSys.GetBytes();
+ size += particleBytes.Length; // Should be exactly 86 bytes
+ }
+
+ // Extra Params
+ extraParamBytes = obj.Prim.GetExtraParamsBytes();
+ size += extraParamBytes.Length;
+
+ if ((updateFlags & UpdateFlags.Sound) != 0)
+ {
+ flags |= CompressedFlags.HasSound;
+ size += 25; // SoundID, SoundGain, SoundFlags, SoundRadius
+ }
+ if ((updateFlags & UpdateFlags.NameValue) != 0)
+ {
+ flags |= CompressedFlags.HasNameValues;
+ nameValueBytes = Utils.StringToBytes(NameValue.NameValuesToString(obj.Prim.NameValues));
+ size += nameValueBytes.Length; // Null-terminated, no size byte
+ }
+
+ size += 23; // PrimData
+ size += 4; // Texture Length
+ textureBytes = obj.Prim.Textures.GetBytes();
+ size += textureBytes.Length; // Texture Entry
+
+ if ((updateFlags & UpdateFlags.TextureAnim) != 0)
+ {
+ flags |= CompressedFlags.TextureAnimation;
+ size += 4; // TextureAnim Length
+ textureAnimBytes = obj.Prim.TextureAnim.GetBytes();
+ size += textureAnimBytes.Length; // TextureAnim
+ }
+
+ #endregion Size calculation and field serialization
+
+ #region Packet serialization
+
+ int pos = 0;
+ byte[] data = new byte[size];
+
+ // UUID
+ obj.Prim.ID.ToBytes(data, 0);
+ pos += 16;
+ // LocalID
+ Utils.UIntToBytes(obj.Prim.LocalID, data, pos);
+ pos += 4;
+ // PCode
+ data[pos++] = (byte)obj.Prim.PrimData.PCode;
+ // State
+ data[pos++] = obj.Prim.PrimData.State;
+ // CRC
+ Utils.UIntToBytes(obj.CRC, data, pos);
+ pos += 4;
+ // Material
+ data[pos++] = (byte)obj.Prim.PrimData.Material;
+ // ClickAction
+ data[pos++] = (byte)obj.Prim.ClickAction;
+ // Scale
+ obj.Prim.Scale.ToBytes(data, pos);
+ pos += 12;
+ // Position
+ obj.Prim.Position.ToBytes(data, pos);
+ pos += 12;
+ // Rotation
+ obj.Prim.Rotation.ToBytes(data, pos);
+ pos += 12;
+ // Compressed Flags
+ Utils.UIntToBytes((uint)flags, data, pos);
+ pos += 4;
+ // OwnerID
+ obj.Prim.OwnerID.ToBytes(data, pos);
+ pos += 16;
+
+ if ((flags & CompressedFlags.HasAngularVelocity) != 0)
+ {
+ obj.Prim.AngularVelocity.ToBytes(data, pos);
+ pos += 12;
+ }
+ if ((flags & CompressedFlags.HasParent) != 0)
+ {
+ Utils.UIntToBytes(obj.Prim.ParentID, data, pos);
+ pos += 4;
+ }
+ if ((flags & CompressedFlags.ScratchPad) != 0)
+ {
+ data[pos++] = (byte)obj.Prim.ScratchPad.Length;
+ Buffer.BlockCopy(obj.Prim.ScratchPad, 0, data, pos, obj.Prim.ScratchPad.Length);
+ pos += obj.Prim.ScratchPad.Length;
+ }
+ else if ((flags & CompressedFlags.Tree) != 0)
+ {
+ data[pos++] = 1;
+ data[pos++] = (byte)obj.Prim.TreeSpecies;
+ }
+ if ((flags & CompressedFlags.HasText) != 0)
+ {
+ Buffer.BlockCopy(textBytes, 0, data, pos, textBytes.Length);
+ pos += textBytes.Length;
+ obj.Prim.TextColor.ToBytes(data, pos, false);
+ pos += 4;
+ }
+ if ((flags & CompressedFlags.MediaURL) != 0)
+ {
+ Buffer.BlockCopy(mediaURLBytes, 0, data, pos, mediaURLBytes.Length);
+ pos += mediaURLBytes.Length;
+ }
+ if ((flags & CompressedFlags.HasParticles) != 0)
+ {
+ Buffer.BlockCopy(particleBytes, 0, data, pos, particleBytes.Length);
+ pos += particleBytes.Length;
+ }
+
+ // Extra Params
+ Buffer.BlockCopy(extraParamBytes, 0, data, pos, extraParamBytes.Length);
+ pos += extraParamBytes.Length;
+
+ if ((flags & CompressedFlags.HasSound) != 0)
+ {
+ obj.Prim.Sound.ToBytes(data, pos);
+ pos += 16;
+ Utils.FloatToBytes(obj.Prim.SoundGain, data, pos);
+ pos += 4;
+ data[pos++] = (byte)obj.Prim.SoundFlags;
+ Utils.FloatToBytes(obj.Prim.SoundRadius, data, pos);
+ pos += 4;
+ }
+ if ((flags & CompressedFlags.HasNameValues) != 0)
+ {
+ Buffer.BlockCopy(nameValueBytes, 0, data, pos, nameValueBytes.Length);
+ pos += nameValueBytes.Length;
+ }
+
+ // Path PrimData
+ data[pos++] = (byte)obj.Prim.PrimData.PathCurve;
+ Utils.UInt16ToBytes(Primitive.PackBeginCut(obj.Prim.PrimData.PathBegin), data, pos); pos += 2;
+ Utils.UInt16ToBytes(Primitive.PackEndCut(obj.Prim.PrimData.PathEnd), data, pos); pos += 2;
+ data[pos++] = Primitive.PackPathScale(obj.Prim.PrimData.PathScaleX);
+ data[pos++] = Primitive.PackPathScale(obj.Prim.PrimData.PathScaleY);
+ data[pos++] = (byte)Primitive.PackPathShear(obj.Prim.PrimData.PathShearX);
+ data[pos++] = (byte)Primitive.PackPathShear(obj.Prim.PrimData.PathShearY);
+ data[pos++] = (byte)Primitive.PackPathTwist(obj.Prim.PrimData.PathTwist);
+ data[pos++] = (byte)Primitive.PackPathTwist(obj.Prim.PrimData.PathTwistBegin);
+ data[pos++] = (byte)Primitive.PackPathTwist(obj.Prim.PrimData.PathRadiusOffset);
+ data[pos++] = (byte)Primitive.PackPathTaper(obj.Prim.PrimData.PathTaperX);
+ data[pos++] = (byte)Primitive.PackPathTaper(obj.Prim.PrimData.PathTaperY);
+ data[pos++] = Primitive.PackPathRevolutions(obj.Prim.PrimData.PathRevolutions);
+ data[pos++] = (byte)Primitive.PackPathTwist(obj.Prim.PrimData.PathSkew);
+ // Profile PrimData
+ data[pos++] = obj.Prim.PrimData.profileCurve;
+ Utils.UInt16ToBytes(Primitive.PackBeginCut(obj.Prim.PrimData.ProfileBegin), data, pos); pos += 2;
+ Utils.UInt16ToBytes(Primitive.PackEndCut(obj.Prim.PrimData.ProfileEnd), data, pos); pos += 2;
+ Utils.UInt16ToBytes(Primitive.PackProfileHollow(obj.Prim.PrimData.ProfileHollow), data, pos); pos += 2;
+
+ // Texture Length
+ Utils.UIntToBytes((uint)textureBytes.Length, data, pos);
+ pos += 4;
+ // Texture Entry
+ Buffer.BlockCopy(textureBytes, 0, data, pos, textureBytes.Length);
+ pos += textureBytes.Length;
+
+ if ((flags & CompressedFlags.TextureAnimation) != 0)
+ {
+ Utils.UIntToBytes((uint)textureAnimBytes.Length, data, pos);
+ pos += 4;
+ Buffer.BlockCopy(textureAnimBytes, 0, data, pos, textureAnimBytes.Length);
+ pos += textureAnimBytes.Length;
+ }
+
+ #endregion Packet serialization
+
+ #region Packet sending
+
+ //Logger.DebugLog("Sending ObjectUpdateCompressed with " + flags.ToString());
+
+ if (sceneAgents.ContainsKey(obj.Prim.OwnerID))
+ {
+ // Send an update out to the creator
+ ObjectUpdateCompressedPacket updateToOwner = new ObjectUpdateCompressedPacket();
+ updateToOwner.RegionData.RegionHandle = regionHandle;
+ updateToOwner.RegionData.TimeDilation = (ushort)(server.Physics.TimeDilation * (float)UInt16.MaxValue);
+ updateToOwner.ObjectData = new ObjectUpdateCompressedPacket.ObjectDataBlock[1];
+ updateToOwner.ObjectData[0] = new ObjectUpdateCompressedPacket.ObjectDataBlock();
+ updateToOwner.ObjectData[0].UpdateFlags = (uint)(obj.Prim.Flags | creatorFlags | PrimFlags.ObjectYouOwner);
+ updateToOwner.ObjectData[0].Data = data;
+
+ server.UDP.SendPacket(obj.Prim.OwnerID, updateToOwner, PacketCategory.State);
+ }
+
+ // Send an update out to everyone else
+ ObjectUpdateCompressedPacket updateToOthers = new ObjectUpdateCompressedPacket();
+ updateToOthers.RegionData.RegionHandle = regionHandle;
+ updateToOthers.RegionData.TimeDilation = UInt16.MaxValue;
+ updateToOthers.ObjectData = new ObjectUpdateCompressedPacket.ObjectDataBlock[1];
+ updateToOthers.ObjectData[0] = new ObjectUpdateCompressedPacket.ObjectDataBlock();
+ updateToOthers.ObjectData[0].UpdateFlags = (uint)obj.Prim.Flags;
+ updateToOthers.ObjectData[0].Data = data;
+
+ server.Scene.ForEachAgent(
+ delegate(Agent recipient)
+ {
+ if (recipient.ID != obj.Prim.OwnerID)
+ server.UDP.SendPacket(recipient.ID, updateToOthers, PacketCategory.State);
+ }
+ );
+
+ #endregion Packet sending
+
+ #endregion ObjectUpdateCompressed
+ }
+ else
+ {
+ #region ImprovedTerseObjectUpdate
+
+ Logger.DebugLog("Sending ImprovedTerseObjectUpdate");
+
+ int pos = 0;
+ byte[] data = new byte[(obj.Prim is Avatar ? 60 : 44)];
+
+ // LocalID
+ Utils.UIntToBytes(obj.Prim.LocalID, data, pos);
+ pos += 4;
+ // Avatar/CollisionPlane
+ data[pos++] = obj.Prim.PrimData.State;
+ if (obj.Prim is Avatar)
+ {
+ data[pos++] = 1;
+ obj.Prim.CollisionPlane.ToBytes(data, pos);
+ pos += 16;
+ }
+ else
+ {
+ ++pos;
+ }
+ // Position
+ obj.Prim.Position.ToBytes(data, pos);
+ pos += 12;
+
+ // Velocity
+ Utils.UInt16ToBytes(Utils.FloatToUInt16(obj.Prim.Velocity.X, -128.0f, 128.0f), data, pos); pos += 2;
+ Utils.UInt16ToBytes(Utils.FloatToUInt16(obj.Prim.Velocity.Y, -128.0f, 128.0f), data, pos); pos += 2;
+ Utils.UInt16ToBytes(Utils.FloatToUInt16(obj.Prim.Velocity.Z, -128.0f, 128.0f), data, pos); pos += 2;
+ // Acceleration
+ Utils.UInt16ToBytes(Utils.FloatToUInt16(obj.Prim.Acceleration.X, -64.0f, 64.0f), data, pos); pos += 2;
+ Utils.UInt16ToBytes(Utils.FloatToUInt16(obj.Prim.Acceleration.Y, -64.0f, 64.0f), data, pos); pos += 2;
+ Utils.UInt16ToBytes(Utils.FloatToUInt16(obj.Prim.Acceleration.Z, -64.0f, 64.0f), data, pos); pos += 2;
+ // Rotation
+ Utils.UInt16ToBytes(Utils.FloatToUInt16(obj.Prim.Rotation.X, -1.0f, 1.0f), data, pos); pos += 2;
+ Utils.UInt16ToBytes(Utils.FloatToUInt16(obj.Prim.Rotation.Y, -1.0f, 1.0f), data, pos); pos += 2;
+ Utils.UInt16ToBytes(Utils.FloatToUInt16(obj.Prim.Rotation.Z, -1.0f, 1.0f), data, pos); pos += 2;
+ Utils.UInt16ToBytes(Utils.FloatToUInt16(obj.Prim.Rotation.W, -1.0f, 1.0f), data, pos); pos += 2;
+ // Angular Velocity
+ Utils.UInt16ToBytes(Utils.FloatToUInt16(obj.Prim.AngularVelocity.X, -64.0f, 64.0f), data, pos); pos += 2;
+ Utils.UInt16ToBytes(Utils.FloatToUInt16(obj.Prim.AngularVelocity.Y, -64.0f, 64.0f), data, pos); pos += 2;
+ Utils.UInt16ToBytes(Utils.FloatToUInt16(obj.Prim.AngularVelocity.Z, -64.0f, 64.0f), data, pos); pos += 2;
+
+ ImprovedTerseObjectUpdatePacket update = new ImprovedTerseObjectUpdatePacket();
+ update.RegionData.RegionHandle = RegionHandle;
+ update.RegionData.TimeDilation = (ushort)(server.Physics.TimeDilation * (float)UInt16.MaxValue);
+ update.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[1];
+ update.ObjectData[0] = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock();
+ update.ObjectData[0].Data = data;
+
+ if ((updateFlags & UpdateFlags.Textures) != 0)
+ {
+ byte[] textureBytes = obj.Prim.Textures.GetBytes();
+ byte[] textureEntry = new byte[textureBytes.Length + 4];
+
+ // Texture Length
+ Utils.IntToBytes(textureBytes.Length, textureEntry, 0);
+ // Texture
+ Buffer.BlockCopy(textureBytes, 0, textureEntry, 4, textureBytes.Length);
+
+ update.ObjectData[0].TextureEntry = textureEntry;
+ }
+ else
+ {
+ update.ObjectData[0].TextureEntry = Utils.EmptyBytes;
+ }
+
+ server.UDP.BroadcastPacket(update, PacketCategory.State);
+
+ #endregion ImprovedTerseObjectUpdate
+ }
+ }
+
static AvatarAppearancePacket BuildAppearancePacket(Agent agent)
{
AvatarAppearancePacket appearance = new AvatarAppearancePacket();
diff --git a/Programs/Simian/Extensions/UDPManager.cs b/Programs/Simian/Extensions/UDPManager.cs
index 0f46c155..91d6e44f 100644
--- a/Programs/Simian/Extensions/UDPManager.cs
+++ b/Programs/Simian/Extensions/UDPManager.cs
@@ -477,6 +477,7 @@ namespace Simian
clients.Remove(agent.ID);
}
+ Logger.DebugLog(String.Format("Adding client {0} from {1}", agent.FullName, address));
AddClient(agent, address);
if (clients.TryGetValue(agent.ID, out client))
{
diff --git a/Programs/Simian/Interfaces/IPhysicsProvider.cs b/Programs/Simian/Interfaces/IPhysicsProvider.cs
index 175e2fd7..804d701d 100644
--- a/Programs/Simian/Interfaces/IPhysicsProvider.cs
+++ b/Programs/Simian/Interfaces/IPhysicsProvider.cs
@@ -5,6 +5,8 @@ namespace Simian
{
public interface IPhysicsProvider
{
+ float TimeDilation { get; }
+
Vector3 ObjectCollisionTest(Vector3 rayStart, Vector3 rayEnd, SimulationObject obj);
bool TryGetObjectMass(UUID objectID, out float mass);
}
diff --git a/Programs/Simian/SimulationObject.cs b/Programs/Simian/SimulationObject.cs
index fc530693..801359a3 100644
--- a/Programs/Simian/SimulationObject.cs
+++ b/Programs/Simian/SimulationObject.cs
@@ -246,17 +246,6 @@ namespace Simian
}
}
- public static ObjectUpdatePacket BuildFullUpdate(Primitive obj, ulong regionHandle, PrimFlags flags, uint crc)
- {
- ObjectUpdatePacket update = new ObjectUpdatePacket();
- update.RegionData.RegionHandle = regionHandle;
- update.RegionData.TimeDilation = UInt16.MaxValue;
- update.ObjectData = new ObjectUpdatePacket.ObjectDataBlock[1];
- update.ObjectData[0] = BuildUpdateBlock(obj, flags, crc);
-
- return update;
- }
-
public static ObjectUpdatePacket.ObjectDataBlock BuildUpdateBlock(Primitive prim, PrimFlags flags, uint crc)
{
byte[] objectData = new byte[60];