diff --git a/OpenMetaverse.Rendering.Meshmerizer/MeshmerizerTypes.cs b/OpenMetaverse.Rendering.Meshmerizer/MeshmerizerTypes.cs
index 9b21963c..e008af8d 100644
--- a/OpenMetaverse.Rendering.Meshmerizer/MeshmerizerTypes.cs
+++ b/OpenMetaverse.Rendering.Meshmerizer/MeshmerizerTypes.cs
@@ -1119,7 +1119,7 @@ namespace OpenMetaverse.Rendering
return new Primitive.TextureEntry(m_textureEntry, 0, m_textureEntry.Length);
}
- set { m_textureEntry = value.ToBytes(); }
+ set { m_textureEntry = value.GetBytes(); }
}
public byte[] TextureEntry
diff --git a/OpenMetaverse.Tests/PrimObjectTests.cs b/OpenMetaverse.Tests/PrimObjectTests.cs
index b3611d6c..54d93a24 100644
--- a/OpenMetaverse.Tests/PrimObjectTests.cs
+++ b/OpenMetaverse.Tests/PrimObjectTests.cs
@@ -147,11 +147,11 @@ namespace OpenMetaverse.Tests
face.TexMapType = MappingType.Planar;
face.TextureID = UUID.Random();
- byte[] teBytes = te.ToBytes();
+ byte[] teBytes = te.GetBytes();
Primitive.TextureEntry te2 = new Primitive.TextureEntry(teBytes, 0, teBytes.Length);
- byte[] teBytes2 = te2.ToBytes();
+ byte[] teBytes2 = te2.GetBytes();
Assert.IsTrue(teBytes.Length == teBytes2.Length);
diff --git a/OpenMetaverse/AppearanceManager.cs b/OpenMetaverse/AppearanceManager.cs
index e3c8e03a..c0d11ca9 100644
--- a/OpenMetaverse/AppearanceManager.cs
+++ b/OpenMetaverse/AppearanceManager.cs
@@ -970,7 +970,7 @@ namespace OpenMetaverse
}
// Set the packet TextureEntry
- set.ObjectData.TextureEntry = te.ToBytes();
+ set.ObjectData.TextureEntry = te.GetBytes();
}
// FIXME: Our hackish algorithm is making squished avatars. See
diff --git a/OpenMetaverse/ObjectManager.cs b/OpenMetaverse/ObjectManager.cs
index 8c1d6655..40f280b1 100644
--- a/OpenMetaverse/ObjectManager.cs
+++ b/OpenMetaverse/ObjectManager.cs
@@ -755,7 +755,7 @@ namespace OpenMetaverse
image.ObjectData = new ObjectImagePacket.ObjectDataBlock[1];
image.ObjectData[0] = new ObjectImagePacket.ObjectDataBlock();
image.ObjectData[0].ObjectLocalID = localID;
- image.ObjectData[0].TextureEntry = textures.ToBytes();
+ image.ObjectData[0].TextureEntry = textures.GetBytes();
image.ObjectData[0].MediaURL = Utils.StringToBytes(mediaUrl);
Client.Network.SendPacket(image, simulator);
@@ -1537,7 +1537,7 @@ namespace OpenMetaverse
// Sound information
prim.Sound = block.Sound;
- prim.SoundFlags = block.Flags;
+ prim.SoundFlags = (SoundFlags)block.Flags;
prim.SoundGain = block.Gain;
prim.SoundRadius = block.Radius;
@@ -1558,8 +1558,24 @@ namespace OpenMetaverse
prim.SetExtraParamsFromBytes(block.ExtraParams, 0);
// PCode-specific data
- prim.GenericData = block.Data;
-
+ switch (pcode)
+ {
+ case PCode.Grass:
+ case PCode.Tree:
+ case PCode.NewTree:
+ if (block.Data.Length == 1)
+ prim.TreeSpecies = (Tree)block.Data[0];
+ else
+ Logger.Log("Got a foliage update with an invalid TreeSpecies field", Helpers.LogLevel.Warning);
+ prim.ScratchPad = Utils.EmptyBytes;
+ break;
+ default:
+ prim.ScratchPad = new byte[block.Data.Length];
+ if (block.Data.Length > 0)
+ Buffer.BlockCopy(block.Data, 0, prim.ScratchPad, 0, prim.ScratchPad.Length);
+ break;
+ }
+
// Packed parameters
prim.CollisionPlane = collisionPlane;
prim.Position = position;
@@ -1614,7 +1630,7 @@ namespace OpenMetaverse
avatar.AngularVelocity = angularVelocity;
avatar.NameValues = nameValues;
avatar.PrimData = data;
- avatar.GenericData = block.Data;
+ if (block.Data.Length > 0) Logger.Log("Unexpected Data field for an avatar update, length " + block.Data.Length, Helpers.LogLevel.Warning);
avatar.ParentID = block.ParentID;
avatar.RegionHandle = update.RegionData.RegionHandle;
@@ -1747,7 +1763,7 @@ namespace OpenMetaverse
Utils.UInt16ToFloat(block.Data, pos + 4, -1.0f, 1.0f),
Utils.UInt16ToFloat(block.Data, pos + 6, -1.0f, 1.0f));
pos += 8;
- // Angular velocity
+ // Angular velocity (omega)
update.AngularVelocity = new Vector3(
Utils.UInt16ToFloat(block.Data, pos, -64.0f, 64.0f),
Utils.UInt16ToFloat(block.Data, pos + 2, -64.0f, 64.0f),
@@ -1892,15 +1908,17 @@ namespace OpenMetaverse
// Tree data
if ((flags & CompressedFlags.Tree) != 0)
{
- prim.GenericData = new byte[1];
- prim.GenericData[0] = block.Data[i++];
+ prim.TreeSpecies = (Tree)block.Data[i++];
+ prim.ScratchPad = Utils.EmptyBytes;
}
// Scratch pad
else if ((flags & CompressedFlags.ScratchPad) != 0)
{
+ prim.TreeSpecies = (Tree)0;
+
int size = block.Data[i++];
- prim.GenericData = new byte[size];
- Buffer.BlockCopy(block.Data, i, prim.GenericData, 0, size);
+ prim.ScratchPad = new byte[size];
+ Buffer.BlockCopy(block.Data, i, prim.ScratchPad, 0, size);
i += size;
}
@@ -1920,7 +1938,6 @@ namespace OpenMetaverse
// Text color
prim.TextColor = new Color4(block.Data, i, false);
- // FIXME: Is alpha inversed here as well?
i += 4;
}
else
@@ -1960,7 +1977,7 @@ namespace OpenMetaverse
prim.SoundGain = Utils.BytesToFloat(block.Data, i);
i += 4;
- prim.SoundFlags = block.Data[i++];
+ prim.SoundFlags = (SoundFlags)block.Data[i++];
prim.SoundRadius = Utils.BytesToFloat(block.Data, i);
i += 4;
}
diff --git a/OpenMetaverse/Primitives/Primitive.cs b/OpenMetaverse/Primitives/Primitive.cs
index 562108b6..e8e26f30 100644
--- a/OpenMetaverse/Primitives/Primitive.cs
+++ b/OpenMetaverse/Primitives/Primitive.cs
@@ -139,6 +139,28 @@ namespace OpenMetaverse
ZlibCompressed = 0x80000000
}
+ ///
+ /// Sound flags for sounds attached to primitives
+ ///
+ [Flags]
+ public enum SoundFlags : byte
+ {
+ ///
+ None = 0,
+ ///
+ Loop = 0x01,
+ ///
+ SyncMaster = 0x02,
+ ///
+ SyncSlave = 0x04,
+ ///
+ SyncPending = 0x08,
+ ///
+ Queue = 0x10,
+ ///
+ Stop = 0x20
+ }
+
public enum ProfileCurve : byte
{
Circle = 0x00,
@@ -1004,8 +1026,11 @@ namespace OpenMetaverse
public ulong RegionHandle;
///
public PrimFlags Flags;
+ /// Foliage type for this primitive. Only applicable if this
+ /// primitive is foliage
+ public Tree TreeSpecies;
/// Unknown
- public byte[] GenericData;
+ public byte[] ScratchPad;
///
public Vector3 Position;
///
@@ -1034,7 +1059,7 @@ namespace OpenMetaverse
/// active
public UUID OwnerID;
///
- public byte SoundFlags;
+ public SoundFlags SoundFlags;
///
public float SoundGain;
///
@@ -1150,14 +1175,14 @@ namespace OpenMetaverse
ParentID = prim.ParentID;
RegionHandle = prim.RegionHandle;
Flags = prim.Flags;
- if (prim.GenericData != null)
+ TreeSpecies = prim.TreeSpecies;
+ if (prim.ScratchPad != null)
{
- if (GenericData == null || GenericData.Length != prim.GenericData.Length)
- GenericData = new byte[prim.GenericData.Length];
- Buffer.BlockCopy(prim.GenericData, 0, GenericData, 0, prim.GenericData.Length);
+ ScratchPad = new byte[prim.ScratchPad.Length];
+ Buffer.BlockCopy(prim.ScratchPad, 0, ScratchPad, 0, ScratchPad.Length);
}
else
- GenericData = null;
+ ScratchPad = null;
Position = prim.Position;
Scale = prim.Scale;
Rotation = prim.Rotation;
@@ -1193,7 +1218,7 @@ namespace OpenMetaverse
// FIXME: Get a real copy constructor for TextureEntry instead of serializing to bytes and back
if (prim.Textures != null)
{
- byte[] textureBytes = prim.Textures.ToBytes();
+ byte[] textureBytes = prim.Textures.GetBytes();
Textures = new TextureEntry(textureBytes, 0, textureBytes.Length);
}
else
diff --git a/OpenMetaverse/Primitives/TextureEntry.cs b/OpenMetaverse/Primitives/TextureEntry.cs
index 7a1cbac2..47a38b1b 100644
--- a/OpenMetaverse/Primitives/TextureEntry.cs
+++ b/OpenMetaverse/Primitives/TextureEntry.cs
@@ -842,7 +842,7 @@ namespace OpenMetaverse
///
///
///
- public byte[] ToBytes()
+ public byte[] GetBytes()
{
if (DefaultTexture == null)
return Utils.EmptyBytes;
diff --git a/OpenMetaverse/Types/UtilsConversions.cs b/OpenMetaverse/Types/UtilsConversions.cs
index 7ed83806..81f64773 100644
--- a/OpenMetaverse/Types/UtilsConversions.cs
+++ b/OpenMetaverse/Types/UtilsConversions.cs
@@ -409,6 +409,14 @@ namespace OpenMetaverse
return UTF8Encoding.UTF8.GetString(bytes, 0, bytes.Length);
}
+ public static string BytesToString(byte[] bytes, int index, int count)
+ {
+ if (bytes.Length > index + count && bytes[index + count - 1] == 0x00)
+ return UTF8Encoding.UTF8.GetString(bytes, index, count - 1);
+ else
+ return UTF8Encoding.UTF8.GetString(bytes, index, count);
+ }
+
///
/// Converts a byte array to a string containing hexadecimal characters
///
@@ -638,6 +646,16 @@ namespace OpenMetaverse
return fval;
}
+ public static ushort FloatToUInt16(float value, float lower, float upper)
+ {
+ float delta = upper - lower;
+ value -= lower;
+ value /= delta;
+ value *= (float)UInt16.MaxValue;
+
+ return (ushort)value;
+ }
+
#endregion Packed Values
#region TryParse
diff --git a/Programs/SimExport/OarFile.cs b/Programs/SimExport/OarFile.cs
index aafe4d1f..967b3fd3 100644
--- a/Programs/SimExport/OarFile.cs
+++ b/Programs/SimExport/OarFile.cs
@@ -202,7 +202,7 @@ namespace SimExport
byte[] te;
if (prim.Textures != null)
- te = prim.Textures.ToBytes();
+ te = prim.Textures.GetBytes();
else
te = Utils.EmptyBytes;
diff --git a/Programs/Simian/Extensions/Movement.cs b/Programs/Simian/Extensions/Movement.cs
index 0cad8853..e998a6f4 100644
--- a/Programs/Simian/Extensions/Movement.cs
+++ b/Programs/Simian/Extensions/Movement.cs
@@ -4,6 +4,7 @@ using System.Threading;
using ExtensionLoader;
using OpenMetaverse;
using OpenMetaverse.Packets;
+using OpenMetaverse.Rendering;
namespace Simian.Extensions
{
@@ -46,6 +47,8 @@ namespace Simian.Extensions
{
this.server = server;
+ server.Scene.OnObjectAddOrUpdate += Scene_OnObjectAddOrUpdate;
+
server.UDP.RegisterPacketCallback(PacketType.AgentRequestSit, AgentRequestSitHandler);
server.UDP.RegisterPacketCallback(PacketType.AgentSit, AgentSitHandler);
server.UDP.RegisterPacketCallback(PacketType.AgentUpdate, AgentUpdateHandler);
@@ -65,6 +68,27 @@ namespace Simian.Extensions
}
}
+ void Scene_OnObjectAddOrUpdate(object sender, SimulationObject obj, UUID ownerID, int scriptStartParam, PrimFlags creatorFlags, UpdateFlags update)
+ {
+ bool forceMeshing = false;
+ bool forceTransform = false;
+
+ if ((update & UpdateFlags.Scale) != 0 ||
+ (update & UpdateFlags.Position) != 0 ||
+ (update & UpdateFlags.Rotation) != 0)
+ {
+ forceTransform = true;
+ }
+
+ if ((update & UpdateFlags.PrimData) != 0)
+ {
+ forceMeshing = true;
+ }
+
+ // TODO: This doesn't update children prims when their parents move
+ obj.GetWorldMesh(DetailLevel.Low, forceMeshing, forceTransform);
+ }
+
void UpdateTimer_Elapsed(object sender)
{
int tick = Environment.TickCount;
@@ -427,12 +451,13 @@ namespace Simian.Extensions
{
agent.Avatar.Prim.Flags &= ~PrimFlags.Physics;
agent.Avatar.Prim.ParentID = obj.Prim.LocalID;
- agent.Avatar.Prim.Position = Vector3.Zero;
- agent.Avatar.Prim.Position.X = obj.Prim.Scale.X * 0.5f;
- agent.Avatar.Prim.Position.Z = obj.Prim.Scale.Z * 0.5f;
- agent.Avatar.Prim.Position.Z += agent.Avatar.Prim.Scale.Z * 0.33f;
+ agent.Avatar.Prim.Position = new Vector3(
+ obj.Prim.Scale.X * 0.5f,
+ obj.Prim.Scale.Z * 0.5f,
+ agent.Avatar.Prim.Scale.Z * 0.33f);
- server.Scene.ObjectAddOrUpdate(this, avObj, avObj.Prim.OwnerID, 0, PrimFlags.None);
+ server.Scene.ObjectAddOrUpdate(this, avObj, avObj.Prim.OwnerID, 0, PrimFlags.None,
+ UpdateFlags.PrimFlags | UpdateFlags.ParentID | UpdateFlags.Position);
server.Avatars.SetDefaultAnimation(agent, Animations.SIT);
server.Avatars.SendAnimations(agent);
}
@@ -450,40 +475,36 @@ namespace Simian.Extensions
{
AgentUpdatePacket update = (AgentUpdatePacket)packet;
- if (agent.Avatar.Prim.ParentID == 0)
- agent.Avatar.Prim.Rotation = update.AgentData.BodyRotation;
-
- agent.ControlFlags = (AgentManager.ControlFlags)update.AgentData.ControlFlags;
- agent.State = (AgentState)update.AgentData.State;
- agent.HideTitle = update.AgentData.Flags != 0;
-
- if (agent.Avatar.Prim.ParentID > 0 && (agent.ControlFlags & AgentManager.ControlFlags.AGENT_CONTROL_STAND_UP) == AgentManager.ControlFlags.AGENT_CONTROL_STAND_UP)
+ SimulationObject obj;
+ if (server.Scene.TryGetObject(agent.ID, out obj))
{
- SimulationObject obj;
- if (server.Scene.TryGetObject(agent.Avatar.Prim.ParentID, out obj))
+ if (agent.Avatar.Prim.ParentID == 0)
+ agent.Avatar.Prim.Rotation = update.AgentData.BodyRotation;
+
+ agent.ControlFlags = (AgentManager.ControlFlags)update.AgentData.ControlFlags;
+ agent.State = (AgentState)update.AgentData.State;
+ agent.HideTitle = update.AgentData.Flags != 0;
+
+ // Check for standing up
+ SimulationObject parent;
+ if (server.Scene.TryGetObject(agent.Avatar.Prim.ParentID, out parent) &&
+ agent.Avatar.Prim.ParentID > 0 &&
+ (agent.ControlFlags & AgentManager.ControlFlags.AGENT_CONTROL_STAND_UP) == AgentManager.ControlFlags.AGENT_CONTROL_STAND_UP)
{
- agent.Avatar.Prim.Position = obj.Prim.Position
- + Vector3.Transform(obj.SitPosition, Matrix4.CreateFromQuaternion(obj.SitRotation))
+ agent.Avatar.Prim.Position = parent.Prim.Position
+ + Vector3.Transform(parent.SitPosition, Matrix4.CreateFromQuaternion(parent.SitRotation))
+ Vector3.UnitZ;
- }
- else
- {
- //TODO: get position from course locations?
- agent.Avatar.Prim.Position = Vector3.Zero;
+
+ agent.Avatar.Prim.ParentID = 0;
+
+ server.Avatars.SetDefaultAnimation(agent, Animations.STAND);
+ server.Avatars.SendAnimations(agent);
+
+ agent.Avatar.Prim.Flags |= PrimFlags.Physics;
}
- agent.Avatar.Prim.ParentID = 0;
-
- server.Avatars.SetDefaultAnimation(agent, Animations.STAND);
- server.Avatars.SendAnimations(agent);
-
- agent.Avatar.Prim.Flags |= PrimFlags.Physics;
+ server.Scene.ObjectAddOrUpdate(this, obj, obj.Prim.OwnerID, 0, PrimFlags.None, UpdateFlags.Position | UpdateFlags.Rotation);
}
-
- ObjectUpdatePacket fullUpdate = SimulationObject.BuildFullUpdate(agent.Avatar.Prim,
- server.Scene.RegionHandle, agent.Avatar.Prim.Flags, 0);
-
- server.UDP.BroadcastPacket(fullUpdate, PacketCategory.State);
}
void SetAlwaysRunHandler(Packet packet, Agent agent)
diff --git a/Programs/Simian/Extensions/ObjectManager.cs b/Programs/Simian/Extensions/ObjectManager.cs
index 1569f17d..98380594 100644
--- a/Programs/Simian/Extensions/ObjectManager.cs
+++ b/Programs/Simian/Extensions/ObjectManager.cs
@@ -164,7 +164,7 @@ namespace Simian.Extensions
// Add this prim to the object database
SimulationObject simObj = new SimulationObject(prim, server);
- server.Scene.ObjectAddOrUpdate(this, simObj, agent.ID, 0, flags);
+ server.Scene.ObjectAddOrUpdate(this, simObj, agent.ID, 0, flags, UpdateFlags.FullUpdate);
}
void ObjectAttachHandler(Packet packet, Agent agent)
@@ -174,18 +174,21 @@ namespace Simian.Extensions
for (int i = 0; i < attach.ObjectData.Length; i++)
{
SimulationObject obj;
- if (!server.Scene.TryGetObject(attach.ObjectData[i].ObjectLocalID, out obj))
- continue;
+ if (server.Scene.TryGetObject(attach.ObjectData[i].ObjectLocalID, out obj))
+ {
+ obj.BeforeAttachmentRotation = attach.ObjectData[i].Rotation;
- obj.Prim.ParentID = agent.Avatar.Prim.LocalID;
- obj.Prim.Position = Vector3.Zero; //TODO: simulationObject.AttachmentPoint
- obj.Prim.Rotation = attach.ObjectData[i].Rotation; //TODO: simulationObject.AttachmentRot ?
+ obj.Prim.ParentID = agent.Avatar.Prim.LocalID;
+ obj.Prim.Position = obj.AttachmentPosition;
+ obj.Prim.Rotation = obj.AttachmentRotation;
- AttachmentPoint point = (AttachmentPoint)attach.AgentData.AttachmentPoint;
- obj.Prim.PrimData.AttachmentPoint = point == AttachmentPoint.Default ? obj.LastAttachmentPoint : point;
+ AttachmentPoint point = (AttachmentPoint)attach.AgentData.AttachmentPoint;
+ obj.Prim.PrimData.AttachmentPoint = (point == AttachmentPoint.Default ? obj.LastAttachmentPoint : point);
- // Send an update out to everyone
- server.Scene.ObjectAddOrUpdate(this, obj, agent.ID, 0, obj.Prim.Flags);
+ // Send an update out to everyone
+ server.Scene.ObjectAddOrUpdate(this, obj, agent.ID, 0, obj.Prim.Flags,
+ UpdateFlags.ParentID | UpdateFlags.Position | UpdateFlags.Rotation | UpdateFlags.AttachmentPoint);
+ }
}
}
@@ -209,7 +212,7 @@ namespace Simian.Extensions
newObj.Prim.LocalID = 0;
newObj.Prim.Properties.CreationDate = DateTime.Now;
- server.Scene.ObjectAddOrUpdate(this, newObj, agent.ID, 0, flags);
+ server.Scene.ObjectAddOrUpdate(this, newObj, agent.ID, 0, flags, UpdateFlags.FullUpdate);
}
else
{
@@ -310,12 +313,12 @@ namespace Simian.Extensions
SimulationObject obj;
if (!server.Scene.TryGetObject(link.ObjectData[i].ObjectLocalID, out obj))
{
- //TODO: send an error message
+ //TODO: Send an error message
return;
}
else if (obj.Prim.OwnerID != agent.ID)
{
- //TODO: send an error message
+ //TODO: Do a full permissions check
return;
}
else
@@ -330,32 +333,35 @@ namespace Simian.Extensions
if (linkSet[i].Prim.ParentID > 0)
{
- //previously linked children
+ // Previously linked children
SimulationObject parent;
if (server.Scene.TryGetObject(linkSet[i].Prim.ParentID, out parent))
{
- //re-add old root orientation
- linkSet[i].Prim.Position = parent.Prim.Position + Vector3.Transform(linkSet[i].Prim.Position, Matrix4.CreateFromQuaternion(parent.Prim.Rotation));
+ // Re-add old root orientation
+ linkSet[i].Prim.Position = parent.Prim.Position + Vector3.Transform(linkSet[i].Prim.Position,
+ Matrix4.CreateFromQuaternion(parent.Prim.Rotation));
linkSet[i].Prim.Rotation *= parent.Prim.Rotation;
}
}
if (i > 0)
{
- //subtract root prim orientation
- linkSet[i].Prim.Position = Vector3.Transform(linkSet[i].Prim.Position - linkSet[0].Prim.Position, Matrix4.CreateFromQuaternion(Quaternion.Identity / linkSet[0].Prim.Rotation));
+ // Subtract root prim orientation
+ linkSet[i].Prim.Position = Vector3.Transform(linkSet[i].Prim.Position - linkSet[0].Prim.Position,
+ Matrix4.CreateFromQuaternion(Quaternion.Identity / linkSet[0].Prim.Rotation));
linkSet[i].Prim.Rotation /= linkSet[0].Prim.Rotation;
- //set parent ID
+ // Set parent ID
linkSet[i].Prim.ParentID = linkSet[0].Prim.LocalID;
}
else
{
- //root prim
+ // Root prim
linkSet[i].Prim.ParentID = 0;
}
- server.Scene.ObjectAddOrUpdate(this, linkSet[i], agent.ID, 0, linkSet[i].Prim.Flags);
+ server.Scene.ObjectAddOrUpdate(this, linkSet[i], agent.ID, 0, linkSet[i].Prim.Flags,
+ UpdateFlags.Position | UpdateFlags.Rotation | UpdateFlags.ParentID);
}
}
@@ -369,12 +375,12 @@ namespace Simian.Extensions
SimulationObject obj;
if (!server.Scene.TryGetObject(delink.ObjectData[i].ObjectLocalID, out obj))
{
- //TODO: send an error message
+ //TODO: Send an error message
return;
}
else if (obj.Prim.OwnerID != agent.ID)
{
- //TODO: send an error message
+ //TODO: Do a full permissions check
return;
}
else
@@ -388,14 +394,16 @@ namespace Simian.Extensions
linkSet[i].Prim.ParentID = 0;
linkSet[i].LinkNumber = 0;
- //add root prim orientation to child prims
+ // Add root prim orientation to child prims
if (i > 0)
{
- linkSet[i].Prim.Position = linkSet[0].Prim.Position + Vector3.Transform(linkSet[i].Prim.Position, Matrix4.CreateFromQuaternion(linkSet[0].Prim.Rotation));
+ linkSet[i].Prim.Position = linkSet[0].Prim.Position + Vector3.Transform(linkSet[i].Prim.Position,
+ Matrix4.CreateFromQuaternion(linkSet[0].Prim.Rotation));
linkSet[i].Prim.Rotation *= linkSet[0].Prim.Rotation;
}
- server.Scene.ObjectAddOrUpdate(this, linkSet[i], agent.ID, 0, linkSet[i].Prim.Flags);
+ server.Scene.ObjectAddOrUpdate(this, linkSet[i], agent.ID, 0, linkSet[i].Prim.Flags,
+ UpdateFlags.Position | UpdateFlags.Rotation | UpdateFlags.ParentID);
}
}
@@ -431,7 +439,8 @@ namespace Simian.Extensions
data.ProfileEnd = Primitive.UnpackEndCut(block.ProfileEnd);
data.ProfileHollow = Primitive.UnpackProfileHollow(block.ProfileHollow);
- server.Scene.ObjectModify(this, obj, data);
+ obj.Prim.PrimData = data;
+ server.Scene.ObjectAddOrUpdate(this, obj, obj.Prim.OwnerID, 0, PrimFlags.None, UpdateFlags.PrimData);
}
else
{
@@ -470,7 +479,8 @@ namespace Simian.Extensions
else
flags &= ~PrimFlags.Physics;
- server.Scene.ObjectFlags(this, obj, flags);
+ obj.Prim.Flags = flags;
+ server.Scene.ObjectAddOrUpdate(this, obj, obj.Prim.OwnerID, 0, PrimFlags.None, UpdateFlags.PrimFlags);
}
else
{
@@ -523,7 +533,7 @@ namespace Simian.Extensions
}
}
- server.Scene.ObjectAddOrUpdate(this, obj, obj.Prim.OwnerID, 0, PrimFlags.None);
+ server.Scene.ObjectAddOrUpdate(this, obj, obj.Prim.OwnerID, 0, PrimFlags.None, UpdateFlags.ExtraData);
}
}
}
@@ -536,9 +546,11 @@ namespace Simian.Extensions
{
SimulationObject obj;
if (server.Scene.TryGetObject(image.ObjectData[i].ObjectLocalID, out obj))
- server.Scene.ObjectModifyTextures(this, obj,
- Utils.BytesToString(image.ObjectData[i].MediaURL),
- new Primitive.TextureEntry(image.ObjectData[i].TextureEntry, 0, image.ObjectData[i].TextureEntry.Length));
+ {
+ obj.Prim.MediaURL = Utils.BytesToString(image.ObjectData[i].MediaURL);
+ obj.Prim.Textures = new Primitive.TextureEntry(image.ObjectData[i].TextureEntry, 0, image.ObjectData[i].TextureEntry.Length);
+ server.Scene.ObjectAddOrUpdate(this, obj, obj.Prim.OwnerID, 0, PrimFlags.None, UpdateFlags.MediaURL | UpdateFlags.Textures);
+ }
}
}
@@ -665,18 +677,23 @@ namespace Simian.Extensions
Quaternion rotation = obj.Prim.Rotation;
Vector3 scale = obj.Prim.Scale;
+ UpdateFlags updateFlags = UpdateFlags.None;
+
if ((type & UpdateType.Position) != 0)
{
+ updateFlags |= UpdateFlags.Position;
position = new Vector3(block.Data, pos);
pos += 12;
}
if ((type & UpdateType.Rotation) != 0)
{
+ updateFlags |= UpdateFlags.Rotation;
rotation = new Quaternion(block.Data, pos, true);
pos += 12;
}
if ((type & UpdateType.Scale) != 0)
{
+ updateFlags |= UpdateFlags.Scale;
scaled = true;
scale = new Vector3(block.Data, pos);
pos += 12;
@@ -685,19 +702,11 @@ namespace Simian.Extensions
//bool uniform = ((type & UpdateType.Uniform) != 0);
}
- if (scaled)
- {
- obj.Prim.Position = position;
- obj.Prim.Rotation = rotation;
- obj.Prim.Scale = scale;
+ obj.Prim.Position = position;
+ obj.Prim.Rotation = rotation;
+ if (scaled) obj.Prim.Scale = scale;
- server.Scene.ObjectAddOrUpdate(this, obj, agent.ID, 0, PrimFlags.None);
- }
- else
- {
- server.Scene.ObjectTransform(this, obj, position, rotation,
- obj.Prim.Velocity, obj.Prim.Acceleration, obj.Prim.AngularVelocity);
- }
+ server.Scene.ObjectAddOrUpdate(this, obj, agent.ID, 0, PrimFlags.None, updateFlags);
}
else
{
diff --git a/Programs/Simian/Extensions/Periscope.cs b/Programs/Simian/Extensions/Periscope.cs
index 4ee02acf..78a55ff8 100644
--- a/Programs/Simian/Extensions/Periscope.cs
+++ b/Programs/Simian/Extensions/Periscope.cs
@@ -72,13 +72,13 @@ namespace Simian.Extensions
SimulationObject simObj = new SimulationObject(prim, server);
if (MasterAgent != null)
simObj.Prim.OwnerID = MasterAgent.ID;
- server.Scene.ObjectAddOrUpdate(this, simObj, MasterAgent.ID, 0, PrimFlags.None);
+ server.Scene.ObjectAddOrUpdate(this, simObj, MasterAgent.ID, 0, PrimFlags.None, UpdateFlags.FullUpdate);
}
void Objects_OnNewAttachment(Simulator simulator, Primitive prim, ulong regionHandle, ushort timeDilation)
{
SimulationObject simObj = new SimulationObject(prim, server);
- server.Scene.ObjectAddOrUpdate(this, simObj, MasterAgent.ID, 0, PrimFlags.None);
+ server.Scene.ObjectAddOrUpdate(this, simObj, MasterAgent.ID, 0, PrimFlags.None, UpdateFlags.FullUpdate);
}
void Objects_OnNewAvatar(Simulator simulator, Avatar avatar, ulong regionHandle, ushort timeDilation)
@@ -101,8 +101,9 @@ namespace Simian.Extensions
SimulationObject obj;
if (server.Scene.TryGetObject(update.LocalID, out obj))
{
- server.Scene.ObjectTransform(this, obj, update.Position, update.Rotation, update.Velocity,
- update.Acceleration, update.AngularVelocity);
+ server.Scene.ObjectAddOrUpdate(this, obj, obj.Prim.OwnerID, 0, PrimFlags.None,
+ UpdateFlags.Acceleration | UpdateFlags.AngularVelocity | UpdateFlags.CollisionPlane |
+ UpdateFlags.Position | UpdateFlags.Rotation | UpdateFlags.Velocity);
}
if (update.LocalID == client.Self.LocalID)
diff --git a/Programs/Simian/Extensions/PeriscopeMovement.cs b/Programs/Simian/Extensions/PeriscopeMovement.cs
index ebca8f4d..6a3253b4 100644
--- a/Programs/Simian/Extensions/PeriscopeMovement.cs
+++ b/Programs/Simian/Extensions/PeriscopeMovement.cs
@@ -331,14 +331,9 @@ namespace Simian.Extensions
SimulationObject obj;
if (server.Scene.TryGetObject(update.AgentData.AgentID, out obj))
{
- server.Scene.ObjectTransform(this, obj, obj.Prim.Position, update.AgentData.BodyRotation, obj.Prim.Velocity,
- obj.Prim.Acceleration, obj.Prim.AngularVelocity);
+ obj.Prim.Rotation = update.AgentData.BodyRotation;
+ server.Scene.ObjectAddOrUpdate(this, obj, obj.Prim.OwnerID, 0, PrimFlags.None, UpdateFlags.Rotation);
}
-
- /*ObjectUpdatePacket fullUpdate = SimulationObject.BuildFullUpdate(agent.Avatar,
- server.Scene.RegionHandle, agent.Flags);
-
- server.UDP.BroadcastPacket(fullUpdate, PacketCategory.State);*/
}
void SetAlwaysRunHandler(Packet packet, Agent agent)
diff --git a/Programs/Simian/Extensions/PhysicsSimple.cs b/Programs/Simian/Extensions/PhysicsSimple.cs
index 2be7607b..d49489d9 100644
--- a/Programs/Simian/Extensions/PhysicsSimple.cs
+++ b/Programs/Simian/Extensions/PhysicsSimple.cs
@@ -16,10 +16,6 @@ namespace Simian.Extensions
public void Start(Simian server)
{
this.server = server;
-
- server.Scene.OnObjectAdd += Scene_OnObjectAdd;
- server.Scene.OnObjectModify += Scene_OnObjectModify;
- server.Scene.OnObjectTransform += Scene_OnObjectTransform;
}
public void Stop()
@@ -404,30 +400,5 @@ namespace Simian.Extensions
return returnMass;
}
-
- #region Callbacks
-
- void Scene_OnObjectAdd(object sender, SimulationObject obj, UUID ownerID, int scriptStartParam, PrimFlags creatorFlags)
- {
- // TODO: This doesn't update children prims when their parents move. "World meshes" are a bad approach in general,
- // the transforms should probably be applied to the mesh in the collision test
- obj.GetWorldMesh(DetailLevel.Low, true, true);
- }
-
- void Scene_OnObjectModify(object sender, SimulationObject obj, Primitive.ConstructionData data)
- {
- obj.GetWorldMesh(DetailLevel.Low, true, false);
- }
-
- void Scene_OnObjectTransform(object sender, SimulationObject obj, Vector3 position, Quaternion rotation, Vector3 velocity,
- Vector3 acceleration, Vector3 angularVelocity)
- {
- // TODO: This doesn't update children prims when their parents move. "World meshes" are a bad approach in general,
- // the transforms should probably be applied to the mesh in the collision test
- if (position != obj.Prim.Position || rotation != obj.Prim.Rotation)
- obj.GetWorldMesh(DetailLevel.Low, false, true);
- }
-
- #endregion Callbacks
}
}
diff --git a/Programs/Simian/Extensions/SceneManager.cs b/Programs/Simian/Extensions/SceneManager.cs
index cb3cfdbf..ca73b88f 100644
--- a/Programs/Simian/Extensions/SceneManager.cs
+++ b/Programs/Simian/Extensions/SceneManager.cs
@@ -43,12 +43,8 @@ namespace Simian.Extensions
TerrainPatch[,] heightmap = new TerrainPatch[16, 16];
Vector2[,] windSpeeds = new Vector2[16, 16];
- public event ObjectAddCallback OnObjectAdd;
+ public event ObjectAddOrUpdateCallback OnObjectAddOrUpdate;
public event ObjectRemoveCallback OnObjectRemove;
- public event ObjectTransformCallback OnObjectTransform;
- public event ObjectFlagsCallback OnObjectFlags;
- public event ObjectModifyCallback OnObjectModify;
- public event ObjectModifyTexturesCallback OnObjectModifyTextures;
public event ObjectSetRotationAxisCallback OnObjectSetRotationAxis;
public event ObjectApplyImpulseCallback OnObjectApplyImpulse;
public event ObjectApplyRotationalImpulseCallback OnObjectApplyRotationalImpulse;
@@ -94,9 +90,749 @@ namespace Simian.Extensions
public void Stop()
{
- ForEachAgent(delegate(Agent agent) { AgentRemove(this, agent); });
+ while (sceneAgents.Count > 0)
+ {
+ Dictionary.ValueCollection.Enumerator e = sceneAgents.Values.GetEnumerator();
+ e.MoveNext();
+ AgentRemove(this, e.Current);
+ }
}
+ public void ObjectAddOrUpdate(object sender, SimulationObject obj, UUID ownerID, int scriptStartParam, PrimFlags creatorFlags, UpdateFlags updateFlags)
+ {
+ if (OnObjectAddOrUpdate != null)
+ {
+ OnObjectAddOrUpdate(sender, obj, ownerID, scriptStartParam, creatorFlags, updateFlags);
+ }
+
+ #region Initialize new objects
+
+ // Check if the object already exists in the scene
+ if (!sceneObjects.ContainsKey(obj.Prim.ID))
+ {
+ // Enable some default flags that all objects will have
+ obj.Prim.Flags |= server.Permissions.GetDefaultObjectFlags();
+
+ // Object did not exist before, so there's no way it could contain inventory
+ obj.Prim.Flags |= PrimFlags.InventoryEmpty;
+
+ // Fun Fact: Prim.OwnerID is only used by the LL viewer to mute sounds
+ obj.Prim.OwnerID = ownerID;
+
+ // Other than storing tree species, I have no idea what this does
+ obj.Prim.ScratchPad = Utils.EmptyBytes;
+
+ // Assign a unique LocalID to this object if no LocalID is set
+ if (obj.Prim.LocalID == 0)
+ obj.Prim.LocalID = (uint)Interlocked.Increment(ref currentLocalID);
+
+ // Assign a random ID to this object if no ID is set
+ if (obj.Prim.ID == UUID.Zero)
+ obj.Prim.ID = UUID.Random();
+
+ // Set the RegionHandle if no RegionHandle is set
+ if (obj.Prim.RegionHandle == 0)
+ obj.Prim.RegionHandle = server.Scene.RegionHandle;
+
+ // Make sure this object has properties
+ if (obj.Prim.Properties == null)
+ {
+ obj.Prim.Properties = new Primitive.ObjectProperties();
+ obj.Prim.Properties.CreationDate = DateTime.Now;
+ obj.Prim.Properties.CreatorID = ownerID;
+ obj.Prim.Properties.Name = "New Object";
+ obj.Prim.Properties.ObjectID = obj.Prim.ID;
+ obj.Prim.Properties.OwnerID = ownerID;
+ obj.Prim.Properties.Permissions = server.Permissions.GetDefaultPermissions();
+ obj.Prim.Properties.SalePrice = 10;
+ }
+
+ // Set the default scale
+ if (obj.Prim.Scale == Vector3.Zero)
+ obj.Prim.Scale = new Vector3(0.5f, 0.5f, 0.5f);
+
+ // Set the collision plane
+ if (obj.Prim.CollisionPlane == Vector4.Zero)
+ obj.Prim.CollisionPlane = Vector4.UnitW;
+
+ // Set default textures if none are set
+ if (obj.Prim.Textures == null)
+ obj.Prim.Textures = new Primitive.TextureEntry(new UUID("89556747-24cb-43ed-920b-47caed15465f")); // Plywood
+
+ // Add the object to the scene dictionary
+ sceneObjects.Add(obj.Prim.LocalID, obj.Prim.ID, obj);
+ }
+
+ #endregion Initialize new objects
+
+ // Reset the prim CRC
+ obj.CRC = 0;
+
+ #region UpdateFlags to packet type conversion
+
+ bool canUseCompressed = true;
+ bool canUseImproved = true;
+
+ if ((updateFlags & UpdateFlags.FullUpdate) == UpdateFlags.FullUpdate || creatorFlags != PrimFlags.None)
+ {
+ canUseCompressed = false;
+ canUseImproved = false;
+ }
+ else
+ {
+ if ((updateFlags & UpdateFlags.Velocity) != 0 ||
+ (updateFlags & UpdateFlags.Acceleration) != 0 ||
+ (updateFlags & UpdateFlags.CollisionPlane) != 0 ||
+ (updateFlags & UpdateFlags.Joint) != 0)
+ {
+ canUseCompressed = false;
+ }
+
+ if ((updateFlags & UpdateFlags.PrimFlags) != 0 ||
+ (updateFlags & UpdateFlags.ParentID) != 0 ||
+ (updateFlags & UpdateFlags.Scale) != 0 ||
+ (updateFlags & UpdateFlags.PrimData) != 0 ||
+ (updateFlags & UpdateFlags.Text) != 0 ||
+ (updateFlags & UpdateFlags.NameValue) != 0 ||
+ (updateFlags & UpdateFlags.ExtraData) != 0 ||
+ (updateFlags & UpdateFlags.TextureAnim) != 0 ||
+ (updateFlags & UpdateFlags.Sound) != 0 ||
+ (updateFlags & UpdateFlags.Particles) != 0 ||
+ (updateFlags & UpdateFlags.Material) != 0 ||
+ (updateFlags & UpdateFlags.ClickAction) != 0 ||
+ (updateFlags & UpdateFlags.MediaURL) != 0 ||
+ (updateFlags & UpdateFlags.Joint) != 0)
+ {
+ canUseImproved = false;
+ }
+ }
+
+ #endregion UpdateFlags to packet type conversion
+
+ 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;
+ Agent agent;
+
+ if (sceneObjects.TryGetValue(localID, out obj))
+ {
+ if (sceneAgents.TryGetValue(obj.Prim.ID, out agent))
+ AgentRemove(sender, agent);
+
+ if (OnObjectRemove != null)
+ OnObjectRemove(sender, obj);
+
+ sceneObjects.Remove(obj.Prim.LocalID, obj.Prim.ID);
+
+ KillObjectPacket kill = new KillObjectPacket();
+ kill.ObjectData = new KillObjectPacket.ObjectDataBlock[1];
+ kill.ObjectData[0] = new KillObjectPacket.ObjectDataBlock();
+ kill.ObjectData[0].ID = obj.Prim.LocalID;
+
+ server.UDP.BroadcastPacket(kill, PacketCategory.State);
+ return true;
+ }
+
+ return false;
+ }
+
+ public bool ObjectRemove(object sender, UUID id)
+ {
+ SimulationObject obj;
+ Agent agent;
+
+ if (sceneAgents.TryGetValue(id, out agent))
+ AgentRemove(sender, agent);
+
+ if (sceneObjects.TryGetValue(id, out obj))
+ {
+ if (OnObjectRemove != null)
+ OnObjectRemove(sender, obj);
+
+ sceneObjects.Remove(obj.Prim.LocalID, obj.Prim.ID);
+
+ KillObjectPacket kill = new KillObjectPacket();
+ kill.ObjectData = new KillObjectPacket.ObjectDataBlock[1];
+ kill.ObjectData[0] = new KillObjectPacket.ObjectDataBlock();
+ kill.ObjectData[0].ID = obj.Prim.LocalID;
+
+ server.UDP.BroadcastPacket(kill, PacketCategory.State);
+ return true;
+ }
+
+ 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)
+ {
+ OnObjectSetRotationAxis(sender, obj, rotationAxis);
+ }
+
+ // Update the object
+ obj.RotationAxis = rotationAxis;
+ }
+
+ public void ObjectApplyImpulse(object sender, SimulationObject obj, Vector3 impulse)
+ {
+ if (OnObjectApplyImpulse != null)
+ {
+ OnObjectApplyImpulse(sender, obj, impulse);
+ }
+
+ // FIXME:
+ }
+
+ public void ObjectApplyRotationalImpulse(object sender, SimulationObject obj, Vector3 impulse)
+ {
+ if (OnObjectApplyRotationalImpulse != null)
+ {
+ OnObjectApplyRotationalImpulse(sender, obj, impulse);
+ }
+
+ // FIXME:
+ }
+
+ public void ObjectSetTorque(object sender, SimulationObject obj, Vector3 torque)
+ {
+ if (OnObjectSetTorque != null)
+ {
+ OnObjectSetTorque(sender, obj, torque);
+ }
+
+ obj.Torque = torque;
+ }
+
+ public void ObjectAnimate(object sender, UUID senderID, UUID objectID, AnimationTrigger[] animations)
+ {
+ if (OnObjectAnimate != null)
+ {
+ OnObjectAnimate(sender, senderID, objectID, animations);
+ }
+
+ AvatarAnimationPacket sendAnim = new AvatarAnimationPacket();
+ sendAnim.Sender.ID = senderID;
+ sendAnim.AnimationSourceList = new AvatarAnimationPacket.AnimationSourceListBlock[1];
+ sendAnim.AnimationSourceList[0] = new AvatarAnimationPacket.AnimationSourceListBlock();
+ sendAnim.AnimationSourceList[0].ObjectID = objectID;
+
+ sendAnim.AnimationList = new AvatarAnimationPacket.AnimationListBlock[animations.Length];
+ for (int i = 0; i < animations.Length; i++)
+ {
+ sendAnim.AnimationList[i] = new AvatarAnimationPacket.AnimationListBlock();
+ sendAnim.AnimationList[i].AnimID = animations[i].AnimationID;
+ sendAnim.AnimationList[i].AnimSequenceID = animations[i].SequenceID;
+ }
+
+ server.UDP.BroadcastPacket(sendAnim, PacketCategory.State);
+ }
+
+ public void ObjectChat(object sender, UUID ownerID, UUID sourceID, ChatAudibleLevel audible, ChatType type, ChatSourceType sourceType,
+ string fromName, Vector3 position, int channel, string message)
+ {
+ if (OnObjectChat != null)
+ {
+ OnObjectChat(sender, ownerID, sourceID, audible, type, sourceType, fromName, position, channel, message);
+ }
+
+ if (channel == 0)
+ {
+ // TODO: Reduction provider will impose the chat radius
+ ChatFromSimulatorPacket chat = new ChatFromSimulatorPacket();
+ chat.ChatData.Audible = (byte)audible;
+ chat.ChatData.ChatType = (byte)type;
+ chat.ChatData.OwnerID = ownerID;
+ chat.ChatData.SourceID = sourceID;
+ chat.ChatData.SourceType = (byte)sourceType;
+ chat.ChatData.Position = position;
+ chat.ChatData.FromName = Utils.StringToBytes(fromName);
+ chat.ChatData.Message = Utils.StringToBytes(message);
+
+ server.UDP.BroadcastPacket(chat, PacketCategory.Messaging);
+ }
+ }
+
+ public void ObjectUndo(object sender, SimulationObject obj)
+ {
+ if (OnObjectUndo != null)
+ {
+ OnObjectUndo(sender, obj);
+ }
+
+ Primitive prim = obj.UndoSteps.DequeueLast();
+ if (prim != null)
+ {
+ Logger.Log(String.Format("Performing undo on object {0}", obj.Prim.ID), Helpers.LogLevel.Debug);
+
+ obj.RedoSteps.Enqueue(prim);
+ obj.Prim = prim;
+
+ // Inform clients
+ server.Scene.ObjectAddOrUpdate(this, obj, obj.Prim.OwnerID, 0, PrimFlags.None, UpdateFlags.FullUpdate);
+ }
+ else
+ {
+ Logger.Log(String.Format("Undo requested on object {0} with no remaining undo steps", obj.Prim.ID),
+ Helpers.LogLevel.Debug);
+ }
+ }
+
+ public void ObjectRedo(object sender, SimulationObject obj)
+ {
+ if (OnObjectRedo != null)
+ {
+ OnObjectRedo(sender, obj);
+ }
+
+ Primitive prim = obj.RedoSteps.DequeueLast();
+ if (prim != null)
+ {
+ Logger.Log(String.Format("Performing redo on object {0}", obj.Prim.ID), Helpers.LogLevel.Debug);
+
+ obj.UndoSteps.Enqueue(prim);
+ obj.Prim = prim;
+
+ // Inform clients
+ server.Scene.ObjectAddOrUpdate(this, obj, obj.Prim.OwnerID, 0, PrimFlags.None, UpdateFlags.FullUpdate);
+ }
+ else
+ {
+ Logger.Log(String.Format("Redo requested on object {0} with no remaining redo steps", obj.Prim.ID),
+ Helpers.LogLevel.Debug);
+ }
+ }
+
+ public void TriggerSound(object sender, UUID objectID, UUID parentID, UUID ownerID, UUID soundID, Vector3 position, float gain)
+ {
+ if (OnTriggerSound != null)
+ {
+ OnTriggerSound(sender, objectID, parentID, ownerID, soundID, position, gain);
+ }
+
+ SoundTriggerPacket sound = new SoundTriggerPacket();
+ sound.SoundData.Handle = server.Scene.RegionHandle;
+ sound.SoundData.ObjectID = objectID;
+ sound.SoundData.ParentID = parentID;
+ sound.SoundData.OwnerID = ownerID;
+ sound.SoundData.Position = position;
+ sound.SoundData.SoundID = soundID;
+ sound.SoundData.Gain = gain;
+
+ server.UDP.BroadcastPacket(sound, PacketCategory.State);
+ }
+
+ public void TriggerEffects(object sender, ViewerEffect[] effects)
+ {
+ if (OnTriggerEffects != null)
+ {
+ OnTriggerEffects(sender, effects);
+ }
+
+ ViewerEffectPacket effect = new ViewerEffectPacket();
+ effect.AgentData.AgentID = UUID.Zero;
+ effect.AgentData.SessionID = UUID.Zero;
+
+ effect.Effect = new ViewerEffectPacket.EffectBlock[effects.Length];
+
+ for (int i = 0; i < effects.Length; i++)
+ {
+ ViewerEffect currentEffect = effects[i];
+ ViewerEffectPacket.EffectBlock block = new ViewerEffectPacket.EffectBlock();
+
+ block.AgentID = currentEffect.AgentID;
+ block.Color = currentEffect.Color.GetBytes(true);
+ block.Duration = currentEffect.Duration;
+ block.ID = currentEffect.EffectID;
+ block.Type = (byte)currentEffect.Type;
+ block.TypeData = currentEffect.TypeData;
+
+ effect.Effect[i] = block;
+ }
+
+ server.UDP.BroadcastPacket(effect, PacketCategory.State);
+ }
+
+ 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 bool AgentAdd(object sender, Agent agent, PrimFlags creatorFlags)
+ {
+ // Check if the agent already exists in the scene
+ lock (sceneAgents)
+ {
+ if (sceneAgents.ContainsKey(agent.ID))
+ sceneAgents.Remove(agent.ID);
+ }
+
+ // Avatars always have physics
+ agent.Avatar.Prim.Flags |= PrimFlags.Physics;
+
+ // Default avatar values
+ agent.Avatar.Prim.Position = new Vector3(128f, 128f, 25f);
+ agent.Avatar.Prim.Rotation = Quaternion.Identity;
+ agent.Avatar.Prim.Scale = new Vector3(0.45f, 0.6f, 1.9f);
+ agent.Avatar.Prim.PrimData.Material = Material.Flesh;
+ agent.Avatar.Prim.PrimData.PCode = PCode.Avatar;
+ agent.Avatar.Prim.Textures = new Primitive.TextureEntry(new UUID("c228d1cf-4b5d-4ba8-84f4-899a0796aa97"));
+
+ // Set the avatar name
+ NameValue[] name = new NameValue[2];
+ name[0] = new NameValue("FirstName", NameValue.ValueType.String, NameValue.ClassType.ReadWrite,
+ NameValue.SendtoType.SimViewer, agent.FirstName);
+ name[1] = new NameValue("LastName", NameValue.ValueType.String, NameValue.ClassType.ReadWrite,
+ NameValue.SendtoType.SimViewer, agent.LastName);
+ agent.Avatar.Prim.NameValues = name;
+
+ // Give testers a provisionary balance of 1000L
+ agent.Balance = 1000;
+
+ // Some default avatar prim properties
+ agent.Avatar.Prim.Properties = new Primitive.ObjectProperties();
+ agent.Avatar.Prim.Properties.CreationDate = Utils.UnixTimeToDateTime(agent.CreationTime);
+ agent.Avatar.Prim.Properties.Name = agent.FullName;
+ agent.Avatar.Prim.Properties.ObjectID = agent.ID;
+
+ if (agent.Avatar.Prim.LocalID == 0)
+ {
+ // Assign a unique LocalID to this agent
+ agent.Avatar.Prim.LocalID = (uint)Interlocked.Increment(ref currentLocalID);
+ }
+
+ if (OnAgentAdd != null)
+ OnAgentAdd(sender, agent, creatorFlags);
+
+ // Add the agent to the scene dictionary
+ lock (sceneAgents) sceneAgents[agent.ID] = agent;
+
+ // Send out an update to everyone
+ //ObjectAdd(this, agent.Avatar, agent.Avatar.Prim.OwnerID, 0, PrimFlags.None);
+
+ return true;
+ }
+
+ public void AgentAppearance(object sender, Agent agent, Primitive.TextureEntry textures, byte[] visualParams)
+ {
+ if (OnAgentAppearance != null)
+ {
+ OnAgentAppearance(sender, agent, textures, visualParams);
+ }
+
+ // Broadcast an object update for this avatar
+ // TODO: Is this necessary here?
+ //ObjectUpdatePacket update = SimulationObject.BuildFullUpdate(agent.Avatar,
+ // regionHandle, agent.Flags);
+ //server.UDP.BroadcastPacket(update, PacketCategory.State);
+
+ // Update the avatar
+ agent.Avatar.Prim.Textures = textures;
+ if (visualParams != null && visualParams.Length > 1)
+ agent.VisualParams = visualParams;
+
+ if (agent.VisualParams != null)
+ {
+ // Send the appearance packet to all other clients
+ AvatarAppearancePacket appearance = BuildAppearancePacket(agent);
+ ForEachAgent(
+ delegate(Agent recipient)
+ {
+ if (recipient != agent)
+ server.UDP.SendPacket(recipient.ID, appearance, PacketCategory.State);
+ }
+ );
+ }
+ }
+
+ 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);
+ }
+
+ public int AgentCount()
+ {
+ return sceneAgents.Count;
+ }
+
+ public void ForEachAgent(Action action)
+ {
+ lock (sceneAgents)
+ {
+ foreach (Agent agent in sceneAgents.Values)
+ action(agent);
+ }
+ }
+
+ public Agent FindAgent(Predicate predicate)
+ {
+ lock (sceneAgents)
+ {
+ foreach (Agent agent in sceneAgents.Values)
+ {
+ if (predicate(agent))
+ return agent;
+ }
+ }
+
+ return null;
+ }
+
+ #region Terrain and Wind
+
public float GetTerrainHeightAt(float fx, float fy)
{
int x = (int)fx;
@@ -208,656 +944,7 @@ namespace Simian.Extensions
windSpeeds[y, x] = windSpeed;
}
- public bool ObjectAddOrUpdate(object sender, SimulationObject obj, UUID ownerID, int scriptStartParam, PrimFlags creatorFlags)
- {
- if (OnObjectAdd != null)
- {
- OnObjectAdd(sender, obj, ownerID, scriptStartParam, creatorFlags);
- }
-
- // Check if the object already exists in the scene
- SimulationObject oldObj;
- if (sceneObjects.TryGetValue(obj.Prim.ID, out oldObj))
- {
- sceneObjects.Remove(oldObj.Prim.LocalID, oldObj.Prim.ID);
-
- // Point the new object at the old undo/redo queues
- obj.UndoSteps = oldObj.UndoSteps;
- obj.RedoSteps = oldObj.RedoSteps;
- }
- else
- {
- // Enable some default flags that all objects will have
- obj.Prim.Flags |= server.Permissions.GetDefaultObjectFlags();
-
- // Object did not exist before, so there's no way it could contain inventory
- obj.Prim.Flags |= PrimFlags.InventoryEmpty;
-
- // Fun Fact: Prim.OwnerID is only used by the LL viewer to mute sounds
- obj.Prim.OwnerID = ownerID;
-
- // Assign a unique LocalID to this object if no LocalID is set
- if (obj.Prim.LocalID == 0)
- obj.Prim.LocalID = (uint)Interlocked.Increment(ref currentLocalID);
-
- // Assign a random ID to this object if no ID is set
- if (obj.Prim.ID == UUID.Zero)
- obj.Prim.ID = UUID.Random();
-
- // Set the RegionHandle if no RegionHandle is set
- if (obj.Prim.RegionHandle == 0)
- obj.Prim.RegionHandle = server.Scene.RegionHandle;
-
- // Make sure this object has properties
- if (obj.Prim.Properties == null)
- {
- obj.Prim.Properties = new Primitive.ObjectProperties();
- obj.Prim.Properties.CreationDate = DateTime.Now;
- obj.Prim.Properties.CreatorID = ownerID;
- obj.Prim.Properties.Name = "New Object";
- obj.Prim.Properties.ObjectID = obj.Prim.ID;
- obj.Prim.Properties.OwnerID = ownerID;
- obj.Prim.Properties.Permissions = server.Permissions.GetDefaultPermissions();
- obj.Prim.Properties.SalePrice = 10;
- }
-
- // Set the default scale
- if (obj.Prim.Scale == Vector3.Zero)
- obj.Prim.Scale = new Vector3(0.5f, 0.5f, 0.5f);
-
- // Set default textures if none are set
- if (obj.Prim.Textures == null)
- obj.Prim.Textures = new Primitive.TextureEntry(new UUID("89556747-24cb-43ed-920b-47caed15465f")); // Plywood
- }
-
- // Reset the prim CRC
- obj.CRC = 0;
-
- // Add the object to the scene dictionary
- sceneObjects.Add(obj.Prim.LocalID, obj.Prim.ID, obj);
-
- 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);
- }
- );
-
- return true;
- }
-
- public bool ObjectRemove(object sender, uint localID)
- {
- SimulationObject obj;
- Agent agent;
-
- if (sceneObjects.TryGetValue(localID, out obj))
- {
- if (sceneAgents.TryGetValue(obj.Prim.ID, out agent))
- AgentRemove(sender, agent);
-
- if (OnObjectRemove != null)
- OnObjectRemove(sender, obj);
-
- sceneObjects.Remove(obj.Prim.LocalID, obj.Prim.ID);
-
- KillObjectPacket kill = new KillObjectPacket();
- kill.ObjectData = new KillObjectPacket.ObjectDataBlock[1];
- kill.ObjectData[0] = new KillObjectPacket.ObjectDataBlock();
- kill.ObjectData[0].ID = obj.Prim.LocalID;
-
- server.UDP.BroadcastPacket(kill, PacketCategory.State);
- return true;
- }
-
- return false;
- }
-
- public bool ObjectRemove(object sender, UUID id)
- {
- SimulationObject obj;
- Agent agent;
-
- if (sceneAgents.TryGetValue(id, out agent))
- AgentRemove(sender, agent);
-
- if (sceneObjects.TryGetValue(id, out obj))
- {
- if (OnObjectRemove != null)
- OnObjectRemove(sender, obj);
-
- sceneObjects.Remove(obj.Prim.LocalID, obj.Prim.ID);
-
- KillObjectPacket kill = new KillObjectPacket();
- kill.ObjectData = new KillObjectPacket.ObjectDataBlock[1];
- kill.ObjectData[0] = new KillObjectPacket.ObjectDataBlock();
- kill.ObjectData[0].ID = obj.Prim.LocalID;
-
- server.UDP.BroadcastPacket(kill, PacketCategory.State);
- return true;
- }
-
- 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);
-
- 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 ObjectTransform(object sender, SimulationObject obj, Vector3 position, Quaternion rotation,
- Vector3 velocity, Vector3 acceleration, Vector3 angularVelocity)
- {
- if (OnObjectTransform != null)
- {
- OnObjectTransform(sender, obj, position, rotation, velocity, acceleration, angularVelocity);
- }
-
- // Add an undo step for prims (not avatars)
- if (!(obj.Prim is Avatar))
- obj.CreateUndoStep();
-
- // Update the object
- obj.Prim.Position = position;
- obj.Prim.Rotation = rotation;
- obj.Prim.Velocity = velocity;
- obj.Prim.Acceleration = acceleration;
- obj.Prim.AngularVelocity = angularVelocity;
-
- // Reset the prim CRC
- obj.CRC = 0;
-
- // Inform clients
- BroadcastObjectUpdate(obj.Prim);
- }
-
- public void ObjectFlags(object sender, SimulationObject obj, PrimFlags flags)
- {
- if (OnObjectFlags != null)
- {
- OnObjectFlags(sender, obj, flags);
- }
-
- // Add an undo step for prims (not avatars)
- if (!(obj.Prim is Avatar))
- obj.CreateUndoStep();
-
- // Update the object
- obj.Prim.Flags = flags;
-
- // Reset the prim CRC
- obj.CRC = 0;
-
- // Inform clients
- BroadcastObjectUpdate(obj.Prim);
- }
-
- public void ObjectModify(object sender, SimulationObject obj, Primitive.ConstructionData data)
- {
- if (OnObjectModify != null)
- {
- OnObjectModify(sender, obj, data);
- }
-
- // Add an undo step for prims (not avatars)
- if (!(obj.Prim is Avatar))
- obj.CreateUndoStep();
-
- // Update the object
- obj.Prim.PrimData = data;
-
- // Reset the prim CRC
- obj.CRC = 0;
-
- // Inform clients
- BroadcastObjectUpdate(obj.Prim);
- }
-
- public void ObjectModifyTextures(object sender, SimulationObject obj, string mediaURL, Primitive.TextureEntry textureEntry)
- {
- if (OnObjectModifyTextures != null)
- {
- OnObjectModifyTextures(sender, obj, mediaURL, textureEntry);
- }
-
- // Add an undo step for prims (not avatars)
- if (!(obj.Prim is Avatar))
- obj.CreateUndoStep();
-
- // Update the object
- obj.Prim.Textures = textureEntry;
- obj.Prim.MediaURL = mediaURL;
-
- // Reset the prim CRC
- obj.CRC = 0;
-
- // Inform clients
- BroadcastObjectUpdate(obj.Prim);
- }
-
- public void ObjectSetRotationAxis(object sender, SimulationObject obj, Vector3 rotationAxis)
- {
- if (OnObjectSetRotationAxis != null)
- {
- OnObjectSetRotationAxis(sender, obj, rotationAxis);
- }
-
- // Update the object
- obj.RotationAxis = rotationAxis;
- }
-
- public void ObjectApplyImpulse(object sender, SimulationObject obj, Vector3 impulse)
- {
- if (OnObjectApplyImpulse != null)
- {
- OnObjectApplyImpulse(sender, obj, impulse);
- }
-
- // FIXME:
- }
-
- public void ObjectApplyRotationalImpulse(object sender, SimulationObject obj, Vector3 impulse)
- {
- if (OnObjectApplyRotationalImpulse != null)
- {
- OnObjectApplyRotationalImpulse(sender, obj, impulse);
- }
-
- // FIXME:
- }
-
- public void ObjectSetTorque(object sender, SimulationObject obj, Vector3 torque)
- {
- if (OnObjectSetTorque != null)
- {
- OnObjectSetTorque(sender, obj, torque);
- }
-
- obj.Torque = torque;
- }
-
- public void ObjectAnimate(object sender, UUID senderID, UUID objectID, AnimationTrigger[] animations)
- {
- if (OnObjectAnimate != null)
- {
- OnObjectAnimate(sender, senderID, objectID, animations);
- }
-
- AvatarAnimationPacket sendAnim = new AvatarAnimationPacket();
- sendAnim.Sender.ID = senderID;
- sendAnim.AnimationSourceList = new AvatarAnimationPacket.AnimationSourceListBlock[1];
- sendAnim.AnimationSourceList[0] = new AvatarAnimationPacket.AnimationSourceListBlock();
- sendAnim.AnimationSourceList[0].ObjectID = objectID;
-
- sendAnim.AnimationList = new AvatarAnimationPacket.AnimationListBlock[animations.Length];
- for (int i = 0; i < animations.Length; i++)
- {
- sendAnim.AnimationList[i] = new AvatarAnimationPacket.AnimationListBlock();
- sendAnim.AnimationList[i].AnimID = animations[i].AnimationID;
- sendAnim.AnimationList[i].AnimSequenceID = animations[i].SequenceID;
- }
-
- server.UDP.BroadcastPacket(sendAnim, PacketCategory.State);
- }
-
- public void ObjectChat(object sender, UUID ownerID, UUID sourceID, ChatAudibleLevel audible, ChatType type, ChatSourceType sourceType,
- string fromName, Vector3 position, int channel, string message)
- {
- if (OnObjectChat != null)
- {
- OnObjectChat(sender, ownerID, sourceID, audible, type, sourceType, fromName, position, channel, message);
- }
-
- if (channel == 0)
- {
- // TODO: Reduction provider will impose the chat radius
- ChatFromSimulatorPacket chat = new ChatFromSimulatorPacket();
- chat.ChatData.Audible = (byte)audible;
- chat.ChatData.ChatType = (byte)type;
- chat.ChatData.OwnerID = ownerID;
- chat.ChatData.SourceID = sourceID;
- chat.ChatData.SourceType = (byte)sourceType;
- chat.ChatData.Position = position;
- chat.ChatData.FromName = Utils.StringToBytes(fromName);
- chat.ChatData.Message = Utils.StringToBytes(message);
-
- server.UDP.BroadcastPacket(chat, PacketCategory.Messaging);
- }
- }
-
- public void ObjectUndo(object sender, SimulationObject obj)
- {
- if (OnObjectUndo != null)
- {
- OnObjectUndo(sender, obj);
- }
-
- Primitive prim = obj.UndoSteps.DequeueLast();
- if (prim != null)
- {
- Logger.Log(String.Format("Performing undo on object {0}", obj.Prim.ID), Helpers.LogLevel.Debug);
-
- obj.RedoSteps.Enqueue(prim);
- obj.Prim = prim;
-
- // Inform clients
- BroadcastObjectUpdate(obj.Prim);
- }
- else
- {
- Logger.Log(String.Format("Undo requested on object {0} with no remaining undo steps", obj.Prim.ID),
- Helpers.LogLevel.Debug);
- }
- }
-
- public void ObjectRedo(object sender, SimulationObject obj)
- {
- if (OnObjectRedo != null)
- {
- OnObjectRedo(sender, obj);
- }
-
- Primitive prim = obj.RedoSteps.DequeueLast();
- if (prim != null)
- {
- Logger.Log(String.Format("Performing redo on object {0}", obj.Prim.ID), Helpers.LogLevel.Debug);
-
- obj.UndoSteps.Enqueue(prim);
- obj.Prim = prim;
-
- // Inform clients
- BroadcastObjectUpdate(obj.Prim);
- }
- else
- {
- Logger.Log(String.Format("Redo requested on object {0} with no remaining redo steps", obj.Prim.ID),
- Helpers.LogLevel.Debug);
- }
- }
-
- public void TriggerSound(object sender, UUID objectID, UUID parentID, UUID ownerID, UUID soundID, Vector3 position, float gain)
- {
- if (OnTriggerSound != null)
- {
- OnTriggerSound(sender, objectID, parentID, ownerID, soundID, position, gain);
- }
-
- SoundTriggerPacket sound = new SoundTriggerPacket();
- sound.SoundData.Handle = server.Scene.RegionHandle;
- sound.SoundData.ObjectID = objectID;
- sound.SoundData.ParentID = parentID;
- sound.SoundData.OwnerID = ownerID;
- sound.SoundData.Position = position;
- sound.SoundData.SoundID = soundID;
- sound.SoundData.Gain = gain;
-
- server.UDP.BroadcastPacket(sound, PacketCategory.State);
- }
-
- public void TriggerEffects(object sender, ViewerEffect[] effects)
- {
- if (OnTriggerEffects != null)
- {
- OnTriggerEffects(sender, effects);
- }
-
- ViewerEffectPacket effect = new ViewerEffectPacket();
- effect.AgentData.AgentID = UUID.Zero;
- effect.AgentData.SessionID = UUID.Zero;
-
- effect.Effect = new ViewerEffectPacket.EffectBlock[effects.Length];
-
- for (int i = 0; i < effects.Length; i++)
- {
- ViewerEffect currentEffect = effects[i];
- ViewerEffectPacket.EffectBlock block = new ViewerEffectPacket.EffectBlock();
-
- block.AgentID = currentEffect.AgentID;
- block.Color = currentEffect.Color.GetBytes(true);
- block.Duration = currentEffect.Duration;
- block.ID = currentEffect.EffectID;
- block.Type = (byte)currentEffect.Type;
- block.TypeData = currentEffect.TypeData;
-
- effect.Effect[i] = block;
- }
-
- server.UDP.BroadcastPacket(effect, PacketCategory.State);
- }
-
- 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 bool AgentAdd(object sender, Agent agent, PrimFlags creatorFlags)
- {
- // Check if the agent already exists in the scene
- if (sceneAgents.ContainsKey(agent.ID))
- sceneAgents.Remove(agent.ID);
-
- // Avatars always have physics
- agent.Avatar.Prim.Flags |= PrimFlags.Physics;
-
- // Default avatar values
- agent.Avatar.Prim.Position = new Vector3(128f, 128f, 25f);
- agent.Avatar.Prim.Rotation = Quaternion.Identity;
- agent.Avatar.Prim.Scale = new Vector3(0.45f, 0.6f, 1.9f);
- agent.Avatar.Prim.PrimData.Material = Material.Flesh;
- agent.Avatar.Prim.PrimData.PCode = PCode.Avatar;
- agent.Avatar.Prim.Textures = new Primitive.TextureEntry(new UUID("c228d1cf-4b5d-4ba8-84f4-899a0796aa97"));
-
- // Set the avatar name
- NameValue[] name = new NameValue[2];
- name[0] = new NameValue("FirstName", NameValue.ValueType.String, NameValue.ClassType.ReadWrite,
- NameValue.SendtoType.SimViewer, agent.FirstName);
- name[1] = new NameValue("LastName", NameValue.ValueType.String, NameValue.ClassType.ReadWrite,
- NameValue.SendtoType.SimViewer, agent.LastName);
- agent.Avatar.Prim.NameValues = name;
-
- // Give testers a provisionary balance of 1000L
- agent.Balance = 1000;
-
- // Some default avatar prim properties
- agent.Avatar.Prim.Properties = new Primitive.ObjectProperties();
- agent.Avatar.Prim.Properties.CreationDate = Utils.UnixTimeToDateTime(agent.CreationTime);
- agent.Avatar.Prim.Properties.Name = agent.FullName;
- agent.Avatar.Prim.Properties.ObjectID = agent.ID;
-
- if (agent.Avatar.Prim.LocalID == 0)
- {
- // Assign a unique LocalID to this agent
- agent.Avatar.Prim.LocalID = (uint)Interlocked.Increment(ref currentLocalID);
- }
-
- if (OnAgentAdd != null)
- OnAgentAdd(sender, agent, creatorFlags);
-
- // Add the agent to the scene dictionary
- sceneAgents[agent.ID] = agent;
-
- // Send out an update to everyone
- //ObjectAdd(this, agent.Avatar, agent.Avatar.Prim.OwnerID, 0, PrimFlags.None);
-
- return true;
- }
-
- public void AgentAppearance(object sender, Agent agent, Primitive.TextureEntry textures, byte[] visualParams)
- {
- if (OnAgentAppearance != null)
- {
- OnAgentAppearance(sender, agent, textures, visualParams);
- }
-
- // Broadcast an object update for this avatar
- // TODO: Is this necessary here?
- //ObjectUpdatePacket update = SimulationObject.BuildFullUpdate(agent.Avatar,
- // regionHandle, agent.Flags);
- //server.UDP.BroadcastPacket(update, PacketCategory.State);
-
- // Update the avatar
- agent.Avatar.Prim.Textures = textures;
- if (visualParams != null && visualParams.Length > 1)
- agent.VisualParams = visualParams;
-
- if (agent.VisualParams != null)
- {
- // Send the appearance packet to all other clients
- AvatarAppearancePacket appearance = BuildAppearancePacket(agent);
- ForEachAgent(
- delegate(Agent recipient)
- {
- if (recipient != agent)
- server.UDP.SendPacket(recipient.ID, appearance, PacketCategory.State);
- }
- );
- }
- }
-
- 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);
- }
-
- public int AgentCount()
- {
- return sceneAgents.Count;
- }
-
- public void ForEachAgent(Action action)
- {
- lock (sceneAgents)
- {
- foreach (Agent agent in sceneAgents.Values)
- action(agent);
- }
- }
-
- public Agent FindAgent(Predicate predicate)
- {
- lock (sceneAgents)
- {
- foreach (Agent agent in sceneAgents.Values)
- {
- if (predicate(agent))
- return agent;
- }
- }
-
- return null;
- }
-
- public bool SeedCapabilityHandler(IHttpClientContext context, IHttpRequest request, IHttpResponse response, object state)
- {
- UUID agentID = (UUID)state;
-
- OSDArray array = OSDParser.DeserializeLLSDXml(request.Body) as OSDArray;
- if (array != null)
- {
- OSDMap osdResponse = new OSDMap();
-
- for (int i = 0; i < array.Count; i++)
- {
- string capName = array[i].AsString();
-
- switch (capName)
- {
- case "EventQueueGet":
- Uri eqCap = null;
-
- // Check if this agent already has an event queue
- EventQueueServerCap eqServer;
- if (eventQueues.TryGetValue(agentID, out eqServer))
- eqCap = eqServer.Capability;
-
- // If not, create one
- if (eqCap == null)
- eqCap = CreateEventQueue(agentID);
-
- osdResponse.Add("EventQueueGet", OSD.FromUri(eqCap));
- break;
- }
- }
-
- byte[] responseData = OSDParser.SerializeLLSDXmlBytes(osdResponse);
- response.ContentLength = responseData.Length;
- response.Body.Write(responseData, 0, responseData.Length);
- response.Body.Flush();
- }
- else
- {
- response.Status = HttpStatusCode.BadRequest;
- }
-
- return true;
- }
+ #endregion Terrain and Wind
public Uri CreateEventQueue(UUID agentID)
{
@@ -907,52 +994,83 @@ namespace Simian.Extensions
}
}
+ public bool SeedCapabilityHandler(IHttpClientContext context, IHttpRequest request, IHttpResponse response, object state)
+ {
+ UUID agentID = (UUID)state;
+
+ OSDArray array = OSDParser.DeserializeLLSDXml(request.Body) as OSDArray;
+ if (array != null)
+ {
+ OSDMap osdResponse = new OSDMap();
+
+ for (int i = 0; i < array.Count; i++)
+ {
+ string capName = array[i].AsString();
+
+ switch (capName)
+ {
+ case "EventQueueGet":
+ Uri eqCap = null;
+
+ // Check if this agent already has an event queue
+ EventQueueServerCap eqServer;
+ if (eventQueues.TryGetValue(agentID, out eqServer))
+ eqCap = eqServer.Capability;
+
+ // If not, create one
+ if (eqCap == null)
+ eqCap = CreateEventQueue(agentID);
+
+ osdResponse.Add("EventQueueGet", OSD.FromUri(eqCap));
+ break;
+ }
+ }
+
+ byte[] responseData = OSDParser.SerializeLLSDXmlBytes(osdResponse);
+ response.ContentLength = responseData.Length;
+ response.Body.Write(responseData, 0, responseData.Length);
+ response.Body.Flush();
+ }
+ else
+ {
+ response.Status = HttpStatusCode.BadRequest;
+ }
+
+ return true;
+ }
+
bool EventQueueHandler(IHttpClientContext context, IHttpRequest request, IHttpResponse response, object state)
{
EventQueueServer eqServer = (EventQueueServer)state;
return eqServer.EventQueueHandler(context, request, response);
}
- // FIXME: This function needs to go away as soon as we stop sending full object updates for everything
- void BroadcastObjectUpdate(Primitive prim)
- {
- SimulationObject obj;
- if (TryGetObject(prim.ID, out obj))
- ObjectAddOrUpdate(this, obj, obj.Prim.OwnerID, 0, PrimFlags.None);
- }
-
void CompleteAgentMovementHandler(Packet packet, Agent agent)
{
// Add this avatar as an object in the scene
- if (ObjectAddOrUpdate(this, agent.Avatar, agent.Avatar.Prim.OwnerID, 0, PrimFlags.None))
- {
- // Send a response back to the client
- AgentMovementCompletePacket complete = new AgentMovementCompletePacket();
- complete.AgentData.AgentID = agent.ID;
- complete.AgentData.SessionID = agent.SessionID;
- complete.Data.LookAt = Vector3.UnitX;
- complete.Data.Position = agent.Avatar.Prim.Position;
- complete.Data.RegionHandle = regionHandle;
- complete.Data.Timestamp = Utils.DateTimeToUnixTime(DateTime.Now);
- complete.SimData.ChannelVersion = Utils.StringToBytes("Simian");
+ ObjectAddOrUpdate(this, agent.Avatar, agent.Avatar.Prim.OwnerID, 0, PrimFlags.None, UpdateFlags.FullUpdate);
- server.UDP.SendPacket(agent.ID, complete, PacketCategory.Transaction);
+ // Send a response back to the client
+ AgentMovementCompletePacket complete = new AgentMovementCompletePacket();
+ complete.AgentData.AgentID = agent.ID;
+ complete.AgentData.SessionID = agent.SessionID;
+ complete.Data.LookAt = Vector3.UnitX;
+ complete.Data.Position = agent.Avatar.Prim.Position;
+ complete.Data.RegionHandle = regionHandle;
+ complete.Data.Timestamp = Utils.DateTimeToUnixTime(DateTime.Now);
+ complete.SimData.ChannelVersion = Utils.StringToBytes("Simian");
- // Send updates and appearances for every avatar to this new avatar
- SynchronizeStateTo(agent);
+ server.UDP.SendPacket(agent.ID, complete, PacketCategory.Transaction);
- //HACK: Notify everyone when someone logs on to the simulator
- OnlineNotificationPacket online = new OnlineNotificationPacket();
- online.AgentBlock = new OnlineNotificationPacket.AgentBlockBlock[1];
- online.AgentBlock[0] = new OnlineNotificationPacket.AgentBlockBlock();
- online.AgentBlock[0].AgentID = agent.ID;
- server.UDP.BroadcastPacket(online, PacketCategory.State);
- }
- else
- {
- Logger.Log("Received a CompleteAgentMovement but failed to insert avatar into the scene: " +
- agent.FullName, Helpers.LogLevel.Warning);
- }
+ // Send updates and appearances for every avatar to this new avatar
+ SynchronizeStateTo(agent);
+
+ //HACK: Notify everyone when someone logs on to the simulator
+ OnlineNotificationPacket online = new OnlineNotificationPacket();
+ online.AgentBlock = new OnlineNotificationPacket.AgentBlockBlock[1];
+ online.AgentBlock[0] = new OnlineNotificationPacket.AgentBlockBlock();
+ online.AgentBlock[0].AgentID = agent.ID;
+ server.UDP.BroadcastPacket(online, PacketCategory.State);
}
// HACK: The reduction provider will deprecate this at some point
@@ -1069,7 +1187,7 @@ namespace Simian.Extensions
static AvatarAppearancePacket BuildAppearancePacket(Agent agent)
{
AvatarAppearancePacket appearance = new AvatarAppearancePacket();
- appearance.ObjectData.TextureEntry = agent.Avatar.Prim.Textures.ToBytes();
+ appearance.ObjectData.TextureEntry = agent.Avatar.Prim.Textures.GetBytes();
appearance.Sender.ID = agent.ID;
appearance.Sender.IsTrial = false;
diff --git a/Programs/Simian/Extensions/ScriptApi.cs b/Programs/Simian/Extensions/ScriptApi.cs
index a563aafd..b6441e7c 100644
--- a/Programs/Simian/Extensions/ScriptApi.cs
+++ b/Programs/Simian/Extensions/ScriptApi.cs
@@ -942,22 +942,22 @@ namespace Simian.Extensions
if ((status & ScriptTypes.STATUS_PHYSICS) == ScriptTypes.STATUS_PHYSICS)
{
if (value == 1)
- server.Scene.ObjectFlags(this, hostObject, hostObject.Prim.Flags | PrimFlags.Physics);
+ hostObject.Prim.Flags |= PrimFlags.Physics;
else
- server.Scene.ObjectFlags(this, hostObject, hostObject.Prim.Flags & ~PrimFlags.Physics);
+ hostObject.Prim.Flags &= ~PrimFlags.Physics;
}
if ((status & ScriptTypes.STATUS_PHANTOM) == ScriptTypes.STATUS_PHANTOM)
{
if (value == 1)
- server.Scene.ObjectFlags(this, hostObject, hostObject.Prim.Flags | PrimFlags.Phantom);
+ hostObject.Prim.Flags |= PrimFlags.Phantom;
else
- server.Scene.ObjectFlags(this, hostObject, hostObject.Prim.Flags & ~PrimFlags.Phantom);
+ hostObject.Prim.Flags &= ~PrimFlags.Phantom;
}
if ((status & ScriptTypes.STATUS_CAST_SHADOWS) == ScriptTypes.STATUS_CAST_SHADOWS)
{
- server.Scene.ObjectFlags(this, hostObject, hostObject.Prim.Flags | PrimFlags.CastShadows);
+ hostObject.Prim.Flags |= PrimFlags.CastShadows;
}
if ((status & ScriptTypes.STATUS_ROTATE_X) == ScriptTypes.STATUS_ROTATE_X)
@@ -983,25 +983,25 @@ namespace Simian.Extensions
if ((status & ScriptTypes.STATUS_DIE_AT_EDGE) == ScriptTypes.STATUS_DIE_AT_EDGE)
{
if (value == 1)
- server.Scene.ObjectFlags(this, hostObject, hostObject.Prim.Flags | PrimFlags.DieAtEdge);
+ hostObject.Prim.Flags |= PrimFlags.DieAtEdge;
else
- server.Scene.ObjectFlags(this, hostObject, hostObject.Prim.Flags & ~PrimFlags.DieAtEdge);
+ hostObject.Prim.Flags &= ~PrimFlags.DieAtEdge;
}
if ((status & ScriptTypes.STATUS_RETURN_AT_EDGE) == ScriptTypes.STATUS_RETURN_AT_EDGE)
{
if (value == 1)
- server.Scene.ObjectFlags(this, hostObject, hostObject.Prim.Flags | PrimFlags.ReturnAtEdge);
+ hostObject.Prim.Flags |= PrimFlags.ReturnAtEdge;
else
- server.Scene.ObjectFlags(this, hostObject, hostObject.Prim.Flags & ~PrimFlags.ReturnAtEdge);
+ hostObject.Prim.Flags &= ~PrimFlags.ReturnAtEdge;
}
if ((status & ScriptTypes.STATUS_SANDBOX) == ScriptTypes.STATUS_SANDBOX)
{
if (value == 1)
- server.Scene.ObjectFlags(this, hostObject, hostObject.Prim.Flags | PrimFlags.Sandbox);
+ hostObject.Prim.Flags |= PrimFlags.Sandbox;
else
- server.Scene.ObjectFlags(this, hostObject, hostObject.Prim.Flags & ~PrimFlags.Sandbox);
+ hostObject.Prim.Flags &= ~PrimFlags.Sandbox;
}
if (statusrotationaxis != 0)
@@ -1021,6 +1021,8 @@ namespace Simian.Extensions
server.Scene.ObjectSetRotationAxis(this, parent, rotationAxis);
}
+
+ server.Scene.ObjectAddOrUpdate(this, hostObject, hostObject.Prim.OwnerID, 0, PrimFlags.None, UpdateFlags.PrimFlags);
}
public LSL_Integer llGetStatus(int status)
@@ -1076,7 +1078,7 @@ namespace Simian.Extensions
// TODO: Apply constraints
hostObject.Prim.Scale = new Vector3((float)scale.x, (float)scale.y, (float)scale.z);
- server.Scene.ObjectAddOrUpdate(this, hostObject, hostObject.Prim.Properties.OwnerID, 0, PrimFlags.None);
+ server.Scene.ObjectAddOrUpdate(this, hostObject, hostObject.Prim.Properties.OwnerID, 0, PrimFlags.None, UpdateFlags.Scale);
}
public LSL_Vector llGetScale()
@@ -1090,7 +1092,7 @@ namespace Simian.Extensions
hostObject.AddScriptLPS(1);
hostObject.Prim.ClickAction = (ClickAction)action;
- server.Scene.ObjectAddOrUpdate(this, hostObject, hostObject.Prim.Properties.OwnerID, 0, PrimFlags.None);
+ server.Scene.ObjectAddOrUpdate(this, hostObject, hostObject.Prim.Properties.OwnerID, 0, PrimFlags.None, UpdateFlags.ClickAction);
}
public void llSetColor(LSL_Vector color, int face)
@@ -1255,8 +1257,8 @@ namespace Simian.Extensions
// Child prims do not have velocity, only parents
SimulationObject parent = hostObject.GetLinksetParent();
- server.Scene.ObjectTransform(this, parent, parent.Prim.Position, parent.Prim.Rotation, velocity, parent.Prim.Acceleration,
- parent.Prim.AngularVelocity);
+ parent.Prim.Velocity = velocity;
+ server.Scene.ObjectAddOrUpdate(this, parent, parent.Prim.OwnerID, 0, PrimFlags.None, UpdateFlags.Velocity);
}
public LSL_Vector llGetForce()
@@ -1459,28 +1461,55 @@ namespace Simian.Extensions
hostObject.Prim.Sound = KeyOrName(sound);
hostObject.Prim.SoundGain = (float)volume;
- hostObject.Prim.SoundFlags = 1; // TODO: ???
- hostObject.Prim.SoundRadius = 20; // TODO: Randomly selected
+ hostObject.Prim.SoundFlags = SoundFlags.Loop;
+ hostObject.Prim.SoundRadius = 20f; // TODO: Randomly selected
- server.Scene.ObjectAddOrUpdate(this, hostObject, hostObject.Prim.Properties.OwnerID, 0, PrimFlags.None);
+ server.Scene.ObjectAddOrUpdate(this, hostObject, hostObject.Prim.Properties.OwnerID, 0, PrimFlags.None, UpdateFlags.Sound);
}
public void llLoopSoundMaster(string sound, double volume)
{
hostObject.AddScriptLPS(1);
- NotImplemented("llLoopSoundMaster");
+
+ if (hostObject.Prim.Sound != UUID.Zero)
+ llStopSound();
+
+ hostObject.Prim.Sound = KeyOrName(sound);
+ hostObject.Prim.SoundGain = (float)volume;
+ hostObject.Prim.SoundFlags = SoundFlags.Loop | SoundFlags.SyncMaster;
+ hostObject.Prim.SoundRadius = 20f; // TODO: Randomly selected
+
+ server.Scene.ObjectAddOrUpdate(this, hostObject, hostObject.Prim.Properties.OwnerID, 0, PrimFlags.None, UpdateFlags.Sound);
}
public void llLoopSoundSlave(string sound, double volume)
{
hostObject.AddScriptLPS(1);
- NotImplemented("llLoopSoundSlave");
+
+ if (hostObject.Prim.Sound != UUID.Zero)
+ llStopSound();
+
+ hostObject.Prim.Sound = KeyOrName(sound);
+ hostObject.Prim.SoundGain = (float)volume;
+ hostObject.Prim.SoundFlags = SoundFlags.Loop | SoundFlags.SyncSlave;
+ hostObject.Prim.SoundRadius = 20f; // TODO: Randomly selected
+
+ server.Scene.ObjectAddOrUpdate(this, hostObject, hostObject.Prim.Properties.OwnerID, 0, PrimFlags.None, UpdateFlags.Sound);
}
public void llPlaySoundSlave(string sound, double volume)
{
hostObject.AddScriptLPS(1);
- NotImplemented("llPlaySoundSlave");
+
+ if (hostObject.Prim.Sound != UUID.Zero)
+ llStopSound();
+
+ hostObject.Prim.Sound = KeyOrName(sound);
+ hostObject.Prim.SoundGain = (float)volume;
+ hostObject.Prim.SoundFlags = SoundFlags.SyncSlave;
+ hostObject.Prim.SoundRadius = 20f; // TODO: Randomly selected
+
+ server.Scene.ObjectAddOrUpdate(this, hostObject, hostObject.Prim.Properties.OwnerID, 0, PrimFlags.None, UpdateFlags.Sound);
}
public void llTriggerSound(string sound, double volume)
@@ -1498,17 +1527,26 @@ namespace Simian.Extensions
hostObject.AddScriptLPS(1);
hostObject.Prim.Sound = UUID.Zero;
- hostObject.Prim.SoundGain = 0;
- hostObject.Prim.SoundFlags = 0;
- hostObject.Prim.SoundRadius = 0;
+ hostObject.Prim.SoundGain = 0f;
+ hostObject.Prim.SoundFlags = SoundFlags.None;
+ hostObject.Prim.SoundRadius = 0f;
- server.Scene.ObjectAddOrUpdate(this, hostObject, hostObject.Prim.Properties.OwnerID, 0, PrimFlags.None);
+ server.Scene.ObjectAddOrUpdate(this, hostObject, hostObject.Prim.Properties.OwnerID, 0, PrimFlags.None, UpdateFlags.Sound);
}
public void llPreloadSound(string sound)
{
hostObject.AddScriptLPS(1);
- NotImplemented("llPreloadSound");
+
+ if (hostObject.Prim.Sound != UUID.Zero)
+ llStopSound();
+
+ hostObject.Prim.Sound = KeyOrName(sound);
+ hostObject.Prim.SoundGain = 0f;
+ hostObject.Prim.SoundFlags = SoundFlags.Queue; // TODO: Is this correct?
+ hostObject.Prim.SoundRadius = 20f; // TODO: Randomly selected
+
+ server.Scene.ObjectAddOrUpdate(this, hostObject, hostObject.Prim.Properties.OwnerID, 0, PrimFlags.None, UpdateFlags.Sound);
// ScriptSleep(1000);
}
@@ -1838,11 +1876,10 @@ namespace Simian.Extensions
newObj.Prim.Rotation = llrot;
}
- if (server.Scene.ObjectAddOrUpdate(this, newObj, hostObject.Prim.Properties.OwnerID, param, PrimFlags.None) &&
- newObj.Prim.ParentID == 0)
- {
+ server.Scene.ObjectAddOrUpdate(this, newObj, hostObject.Prim.Properties.OwnerID, param, PrimFlags.None, UpdateFlags.FullUpdate);
+
+ if (newObj.Prim.ParentID == 0)
newParent = newObj;
- }
}
if (newParent != null)
@@ -2064,8 +2101,9 @@ namespace Simian.Extensions
if (targetHeight > 0f)
newPosition.Z = targetHeight;
- server.Scene.ObjectTransform(this, parent, newPosition, parent.Prim.Rotation, parent.Prim.Velocity,
- parent.Prim.Acceleration, parent.Prim.AngularVelocity);
+ parent.Prim.Position = newPosition;
+ // Don't set UpdateFlags.PrimFlags since Flying is a server-side only flag
+ server.Scene.ObjectAddOrUpdate(this, parent, parent.Prim.OwnerID, 0, PrimFlags.None, UpdateFlags.Position);
}
public void llStopHover()
@@ -2075,8 +2113,9 @@ namespace Simian.Extensions
SimulationObject parent = hostObject.GetLinksetParent();
parent.Prim.Flags &= ~PrimFlags.Flying;
- server.Scene.ObjectTransform(this, parent, parent.Prim.Position, parent.Prim.Rotation, parent.Prim.Velocity,
- parent.Prim.Acceleration, parent.Prim.AngularVelocity);
+ // Trigger an object transformation even though we don't directly manipulate any parameters that are sent
+ // to the client. This will make sure the physics engine realizes the flying flag has been turned off
+ server.Scene.ObjectAddOrUpdate(this, parent, parent.Prim.OwnerID, 0, PrimFlags.None, UpdateFlags.Position);
}
public void llMinEventDelay(double delay)
@@ -2184,8 +2223,8 @@ namespace Simian.Extensions
Vector3 angVel = new Vector3((float)axis.x, (float)axis.y, (float)axis.z);
angVel *= (float)spinrate;
- server.Scene.ObjectTransform(this, hostObject, hostObject.Prim.Position, hostObject.Prim.Rotation,
- hostObject.Prim.Velocity, hostObject.Prim.Acceleration, angVel);
+ hostObject.Prim.AngularVelocity = angVel;
+ server.Scene.ObjectAddOrUpdate(this, hostObject, hostObject.Prim.OwnerID, 0, PrimFlags.None, UpdateFlags.AngularVelocity);
}
public LSL_Integer llGetStartParameter()
@@ -2510,7 +2549,7 @@ namespace Simian.Extensions
(float)Utils.Clamp(alpha, 0f, 1f));
hostObject.Prim.Text = text;
- server.Scene.ObjectAddOrUpdate(this, hostObject, hostObject.Prim.Properties.OwnerID, 0, PrimFlags.None);
+ server.Scene.ObjectAddOrUpdate(this, hostObject, hostObject.Prim.Properties.OwnerID, 0, PrimFlags.None, UpdateFlags.Text);
}
public LSL_Float llWater(LSL_Vector offset)
@@ -3406,7 +3445,7 @@ namespace Simian.Extensions
pTexAnim.Start = (float)start;
hostObject.Prim.TextureAnim = pTexAnim;
- server.Scene.ObjectAddOrUpdate(this, hostObject, hostObject.Prim.Properties.OwnerID, 0, PrimFlags.None);
+ server.Scene.ObjectAddOrUpdate(this, hostObject, hostObject.Prim.Properties.OwnerID, 0, PrimFlags.None, UpdateFlags.TextureAnim);
}
public void llTriggerSoundLimited(string sound, double volume, LSL_Vector top_north_east, LSL_Vector bottom_south_west)
@@ -3754,7 +3793,7 @@ namespace Simian.Extensions
hostObject.Prim.ParticleSys = prules;
}
- server.Scene.ObjectAddOrUpdate(this, hostObject, hostObject.Prim.Properties.OwnerID, 0, PrimFlags.None);
+ server.Scene.ObjectAddOrUpdate(this, hostObject, hostObject.Prim.Properties.OwnerID, 0, PrimFlags.None, UpdateFlags.Particles);
}
public void llGroundRepel(double height, int water, double tau)
@@ -5158,7 +5197,7 @@ namespace Simian.Extensions
texcolor.A = Utils.Clamp((float)alpha, 0.0f, 1.0f);
tex.FaceTextures[face].RGBA = texcolor;
- server.Scene.ObjectModifyTextures(this, part, part.Prim.MediaURL, tex);
+ server.Scene.ObjectAddOrUpdate(this, part, part.Prim.OwnerID, 0, PrimFlags.None, UpdateFlags.Textures);
}
else if (face == ScriptTypes.ALL_SIDES)
{
@@ -5176,7 +5215,7 @@ namespace Simian.Extensions
texcolor.A = Utils.Clamp((float)alpha, 0.0f, 1.0f);
tex.DefaultTexture.RGBA = texcolor;
- server.Scene.ObjectModifyTextures(this, part, part.Prim.MediaURL, tex);
+ server.Scene.ObjectAddOrUpdate(this, part, part.Prim.OwnerID, 0, PrimFlags.None, UpdateFlags.Textures);
}
}
@@ -5202,7 +5241,7 @@ namespace Simian.Extensions
part.Prim.PrimData.PathCurve = PathCurve.Line;
}
- server.Scene.ObjectAddOrUpdate(this, part, hostObject.Prim.Properties.OwnerID, 0, PrimFlags.None);
+ server.Scene.ObjectAddOrUpdate(this, part, hostObject.Prim.Properties.OwnerID, 0, PrimFlags.None, UpdateFlags.ExtraData | UpdateFlags.PrimData);
}
private void SetPointLight(SimulationObject part, bool light, LSL_Vector color, float intensity, float radius, float falloff)
@@ -5225,7 +5264,7 @@ namespace Simian.Extensions
part.Prim.Light = null;
}
- server.Scene.ObjectAddOrUpdate(this, part, hostObject.Prim.Properties.OwnerID, 0, PrimFlags.None);
+ server.Scene.ObjectAddOrUpdate(this, part, hostObject.Prim.Properties.OwnerID, 0, PrimFlags.None, UpdateFlags.ExtraData);
}
private LSL_Vector GetColor(SimulationObject part, int face)
@@ -5528,7 +5567,7 @@ namespace Simian.Extensions
prim.Prim.PrimData.ProfileBegin = Primitive.UnpackBeginCut((ushort)(50000.0 * dimple.x));
prim.Prim.PrimData.ProfileEnd = Primitive.UnpackBeginCut((ushort)(50000.0 * (1.0 - dimple.y)));
- server.Scene.ObjectAddOrUpdate(this, prim, hostObject.Prim.Properties.OwnerID, 0, PrimFlags.None);
+ server.Scene.ObjectAddOrUpdate(this, prim, hostObject.Prim.Properties.OwnerID, 0, PrimFlags.None, UpdateFlags.PrimData);
}
private void SetPrimitiveShapeParams(SimulationObject prim, int holeshape, LSL_Vector cut, float hollow, LSL_Vector twist,
@@ -5919,10 +5958,11 @@ namespace Simian.Extensions
string ph = rules.Data[idx++].ToString();
if (ph.Equals("1"))
- server.Scene.ObjectFlags(this, parent, parent.Prim.Flags | PrimFlags.Phantom);
+ parent.Prim.Flags |= PrimFlags.Phantom;
else
- server.Scene.ObjectFlags(this, parent, parent.Prim.Flags & ~PrimFlags.Phantom);
+ parent.Prim.Flags &= ~PrimFlags.Phantom;
+ server.Scene.ObjectAddOrUpdate(this, parent, parent.Prim.OwnerID, 0, PrimFlags.None, UpdateFlags.PrimFlags);
break;
case ScriptTypes.PRIM_PHYSICS:
if (remain < 1) return;
@@ -5930,10 +5970,11 @@ namespace Simian.Extensions
string phy = rules.Data[idx++].ToString();
if (phy.Equals("1"))
- server.Scene.ObjectFlags(this, parent, parent.Prim.Flags & ~PrimFlags.Phantom);
+ parent.Prim.Flags |= PrimFlags.Phantom;
else
- server.Scene.ObjectFlags(this, parent, parent.Prim.Flags & ~PrimFlags.Physics);
+ parent.Prim.Flags &= ~PrimFlags.Physics;
+ server.Scene.ObjectAddOrUpdate(this, parent, parent.Prim.OwnerID, 0, PrimFlags.None, UpdateFlags.PrimFlags);
break;
case ScriptTypes.PRIM_TEMP_ON_REZ:
if (remain < 1) return;
@@ -5941,10 +5982,11 @@ namespace Simian.Extensions
string temp = rules.Data[idx++].ToString();
if (temp.Equals("1"))
- server.Scene.ObjectFlags(this, parent, parent.Prim.Flags & ~PrimFlags.TemporaryOnRez);
+ parent.Prim.Flags |= PrimFlags.TemporaryOnRez;
else
- server.Scene.ObjectFlags(this, parent, parent.Prim.Flags & ~PrimFlags.TemporaryOnRez);
+ parent.Prim.Flags &= ~PrimFlags.TemporaryOnRez;
+ server.Scene.ObjectAddOrUpdate(this, parent, parent.Prim.OwnerID, 0, PrimFlags.None, UpdateFlags.PrimFlags);
break;
}
}
@@ -5959,7 +6001,7 @@ namespace Simian.Extensions
return;
part.Prim.Scale = new Vector3((float)scale.x, (float)scale.y, (float)scale.z);
- server.Scene.ObjectAddOrUpdate(this, part, hostObject.Prim.Properties.OwnerID, 0, PrimFlags.None);
+ server.Scene.ObjectAddOrUpdate(this, part, hostObject.Prim.Properties.OwnerID, 0, PrimFlags.None, UpdateFlags.Scale);
}
private void SetColor(SimulationObject part, LSL_Vector color, int face)
@@ -5974,11 +6016,15 @@ namespace Simian.Extensions
texcolor.G = Utils.Clamp((float)color.y, 0.0f, 1.0f);
texcolor.B = Utils.Clamp((float)color.z, 0.0f, 1.0f);
tex.FaceTextures[face].RGBA = texcolor;
-
- server.Scene.ObjectModifyTextures(this, part, part.Prim.MediaURL, tex);
}
else if (face == ScriptTypes.ALL_SIDES)
{
+ texcolor = tex.DefaultTexture.RGBA;
+ texcolor.R = Utils.Clamp((float)color.x, 0.0f, 1.0f);
+ texcolor.G = Utils.Clamp((float)color.y, 0.0f, 1.0f);
+ texcolor.B = Utils.Clamp((float)color.z, 0.0f, 1.0f);
+ tex.DefaultTexture.RGBA = texcolor;
+
for (uint i = 0; i < GetNumberOfSides(part); i++)
{
if (tex.FaceTextures[i] != null)
@@ -5989,15 +6035,11 @@ namespace Simian.Extensions
texcolor.B = Utils.Clamp((float)color.z, 0.0f, 1.0f);
tex.FaceTextures[i].RGBA = texcolor;
}
- texcolor = tex.DefaultTexture.RGBA;
- texcolor.R = Utils.Clamp((float)color.x, 0.0f, 1.0f);
- texcolor.G = Utils.Clamp((float)color.y, 0.0f, 1.0f);
- texcolor.B = Utils.Clamp((float)color.z, 0.0f, 1.0f);
- tex.DefaultTexture.RGBA = texcolor;
}
-
- server.Scene.ObjectModifyTextures(this, part, part.Prim.MediaURL, tex);
}
+
+ part.Prim.Textures = tex;
+ server.Scene.ObjectAddOrUpdate(this, part, part.Prim.OwnerID, 0, PrimFlags.None, UpdateFlags.Textures);
}
public void SetGlow(SimulationObject part, int face, float glow)
@@ -6008,26 +6050,24 @@ namespace Simian.Extensions
{
tex.CreateFace((uint)face);
tex.FaceTextures[face].Glow = glow;
-
- server.Scene.ObjectModifyTextures(this, part, part.Prim.MediaURL, tex);
}
else if (face == ScriptTypes.ALL_SIDES)
{
+ tex.DefaultTexture.Glow = glow;
+
for (uint i = 0; i < GetNumberOfSides(part); i++)
{
if (tex.FaceTextures[i] != null)
tex.FaceTextures[i].Glow = glow;
-
- tex.DefaultTexture.Glow = glow;
}
-
- server.Scene.ObjectModifyTextures(this, part, part.Prim.MediaURL, tex);
}
+
+ part.Prim.Textures = tex;
+ server.Scene.ObjectAddOrUpdate(this, part, part.Prim.OwnerID, 0, PrimFlags.None, UpdateFlags.Textures);
}
public void SetShiny(SimulationObject part, int face, int shiny, Bumpiness bump)
{
-
Shininess sval = new Shininess();
switch (shiny)
@@ -6056,11 +6096,12 @@ namespace Simian.Extensions
tex.CreateFace((uint)face);
tex.FaceTextures[face].Shiny = sval;
tex.FaceTextures[face].Bump = bump;
-
- server.Scene.ObjectModifyTextures(this, part, part.Prim.MediaURL, tex);
}
else if (face == ScriptTypes.ALL_SIDES)
{
+ tex.DefaultTexture.Shiny = sval;
+ tex.DefaultTexture.Bump = bump;
+
for (uint i = 0; i < GetNumberOfSides(part); i++)
{
if (tex.FaceTextures[i] != null)
@@ -6068,12 +6109,11 @@ namespace Simian.Extensions
tex.FaceTextures[i].Shiny = sval;
tex.FaceTextures[i].Bump = bump; ;
}
- tex.DefaultTexture.Shiny = sval;
- tex.DefaultTexture.Bump = bump;
}
-
- server.Scene.ObjectModifyTextures(this, part, part.Prim.MediaURL, tex);
}
+
+ part.Prim.Textures = tex;
+ server.Scene.ObjectAddOrUpdate(this, part, part.Prim.OwnerID, 0, PrimFlags.None, UpdateFlags.Textures);
}
public void SetFullBright(SimulationObject part, int face, bool bright)
@@ -6084,11 +6124,11 @@ namespace Simian.Extensions
{
tex.CreateFace((uint)face);
tex.FaceTextures[face].Fullbright = bright;
-
- server.Scene.ObjectModifyTextures(this, part, part.Prim.MediaURL, tex);
}
else if (face == ScriptTypes.ALL_SIDES)
{
+ tex.DefaultTexture.Fullbright = bright;
+
for (uint i = 0; i < GetNumberOfSides(part); i++)
{
if (tex.FaceTextures[i] != null)
@@ -6096,11 +6136,10 @@ namespace Simian.Extensions
tex.FaceTextures[i].Fullbright = bright;
}
}
-
- tex.DefaultTexture.Fullbright = bright;
-
- server.Scene.ObjectModifyTextures(this, part, part.Prim.MediaURL, tex);
}
+
+ part.Prim.Textures = tex;
+ server.Scene.ObjectAddOrUpdate(this, part, part.Prim.OwnerID, 0, PrimFlags.None, UpdateFlags.Textures);
}
private void SetTexture(SimulationObject part, string texture, int face)
@@ -6120,11 +6159,11 @@ namespace Simian.Extensions
Primitive.TextureEntryFace texface = tex.CreateFace((uint)face);
texface.TextureID = textureID;
tex.FaceTextures[face] = texface;
-
- server.Scene.ObjectModifyTextures(this, part, part.Prim.MediaURL, tex);
}
else if (face == ScriptTypes.ALL_SIDES)
{
+ tex.DefaultTexture.TextureID = textureID;
+
for (uint i = 0; i < GetNumberOfSides(part); i++)
{
if (tex.FaceTextures[i] != null)
@@ -6132,11 +6171,10 @@ namespace Simian.Extensions
tex.FaceTextures[i].TextureID = textureID;
}
}
-
- tex.DefaultTexture.TextureID = textureID;
-
- server.Scene.ObjectModifyTextures(this, part, part.Prim.MediaURL, tex);
}
+
+ part.Prim.Textures = tex;
+ server.Scene.ObjectAddOrUpdate(this, part, part.Prim.OwnerID, 0, PrimFlags.None, UpdateFlags.Textures);
}
private void ScaleTexture(SimulationObject part, double u, double v, int face)
@@ -6149,11 +6187,12 @@ namespace Simian.Extensions
texface.RepeatU = (float)u;
texface.RepeatV = (float)v;
tex.FaceTextures[face] = texface;
-
- server.Scene.ObjectModifyTextures(this, part, part.Prim.MediaURL, tex);
}
if (face == ScriptTypes.ALL_SIDES)
{
+ tex.DefaultTexture.RepeatU = (float)u;
+ tex.DefaultTexture.RepeatV = (float)v;
+
for (int i = 0; i < GetNumberOfSides(part); i++)
{
if (tex.FaceTextures[i] != null)
@@ -6162,12 +6201,10 @@ namespace Simian.Extensions
tex.FaceTextures[i].RepeatV = (float)v;
}
}
-
- tex.DefaultTexture.RepeatU = (float)u;
- tex.DefaultTexture.RepeatV = (float)v;
-
- server.Scene.ObjectModifyTextures(this, part, part.Prim.MediaURL, tex);
}
+
+ part.Prim.Textures = tex;
+ server.Scene.ObjectAddOrUpdate(this, part, part.Prim.OwnerID, 0, PrimFlags.None, UpdateFlags.Textures);
}
private void OffsetTexture(SimulationObject part, double u, double v, int face)
@@ -6180,11 +6217,12 @@ namespace Simian.Extensions
texface.OffsetU = (float)u;
texface.OffsetV = (float)v;
tex.FaceTextures[face] = texface;
-
- server.Scene.ObjectModifyTextures(this, part, part.Prim.MediaURL, tex);
}
if (face == ScriptTypes.ALL_SIDES)
{
+ tex.DefaultTexture.OffsetU = (float)u;
+ tex.DefaultTexture.OffsetV = (float)v;
+
for (int i = 0; i < GetNumberOfSides(part); i++)
{
if (tex.FaceTextures[i] != null)
@@ -6193,12 +6231,10 @@ namespace Simian.Extensions
tex.FaceTextures[i].OffsetV = (float)v;
}
}
-
- tex.DefaultTexture.OffsetU = (float)u;
- tex.DefaultTexture.OffsetV = (float)v;
-
- server.Scene.ObjectModifyTextures(this, part, part.Prim.MediaURL, tex);
}
+
+ part.Prim.Textures = tex;
+ server.Scene.ObjectAddOrUpdate(this, part, part.Prim.OwnerID, 0, PrimFlags.None, UpdateFlags.Textures);
}
private void RotateTexture(SimulationObject part, double rotation, int face)
@@ -6210,11 +6246,11 @@ namespace Simian.Extensions
Primitive.TextureEntryFace texface = tex.CreateFace((uint)face);
texface.Rotation = (float)rotation;
tex.FaceTextures[face] = texface;
-
- server.Scene.ObjectModifyTextures(this, part, part.Prim.MediaURL, tex);
}
if (face == ScriptTypes.ALL_SIDES)
{
+ tex.DefaultTexture.Rotation = (float)rotation;
+
for (int i = 0; i < GetNumberOfSides(part); i++)
{
if (tex.FaceTextures[i] != null)
@@ -6222,11 +6258,10 @@ namespace Simian.Extensions
tex.FaceTextures[i].Rotation = (float)rotation;
}
}
-
- tex.DefaultTexture.Rotation = (float)rotation;
-
- server.Scene.ObjectModifyTextures(this, part, part.Prim.MediaURL, tex);
}
+
+ part.Prim.Textures = tex;
+ server.Scene.ObjectAddOrUpdate(this, part, part.Prim.OwnerID, 0, PrimFlags.None, UpdateFlags.Textures);
}
private void SetPos(SimulationObject part, LSL_Vector targetPos)
@@ -6236,16 +6271,14 @@ namespace Simian.Extensions
if (llVecDist(currentPos, targetPos) > 10.0f * SCRIPT_DISTANCE_FACTOR)
targetPos = currentPos + SCRIPT_DISTANCE_FACTOR * 10.0f * llVecNorm(targetPos - currentPos);
- Vector3 newPos = new Vector3((float)targetPos.x, (float)targetPos.y, (float)targetPos.z);
-
- server.Scene.ObjectTransform(this, part, newPos, part.Prim.Rotation, part.Prim.Velocity, part.Prim.Acceleration,
- part.Prim.AngularVelocity);
+ part.Prim.Position = new Vector3((float)targetPos.x, (float)targetPos.y, (float)targetPos.z);
+ server.Scene.ObjectAddOrUpdate(this, part, part.Prim.OwnerID, 0, PrimFlags.None, UpdateFlags.Position);
}
private void SetRot(SimulationObject part, Quaternion rot)
{
- server.Scene.ObjectTransform(this, part, part.Prim.Position, rot, part.Prim.Velocity, part.Prim.Acceleration,
- part.Prim.AngularVelocity);
+ part.Prim.Rotation = rot;
+ server.Scene.ObjectAddOrUpdate(this, part, part.Prim.OwnerID, 0, PrimFlags.None, UpdateFlags.Rotation);
}
private LSL_Vector GetTextureOffset(SimulationObject part, int face)
diff --git a/Programs/Simian/Interfaces/ISceneProvider.cs b/Programs/Simian/Interfaces/ISceneProvider.cs
index 8f6ec2e5..f506677c 100644
--- a/Programs/Simian/Interfaces/ISceneProvider.cs
+++ b/Programs/Simian/Interfaces/ISceneProvider.cs
@@ -6,6 +6,39 @@ using OpenMetaverse.StructuredData;
namespace Simian
{
+ ///
+ /// Specifies that fields that have been changed in a call to ISceneProvider.ObjectAddOrUpdate
+ ///
+ [Flags]
+ public enum UpdateFlags : uint
+ {
+ None = 0,
+ AttachmentPoint = 1 << 0,
+ Material = 1 << 1,
+ ClickAction = 1 << 2,
+ Scale = 1 << 3,
+ ParentID = 1 << 4,
+ PrimFlags = 1 << 5,
+ PrimData = 1 << 6,
+ MediaURL = 1 << 7,
+ ScratchPad = 1 << 8,
+ Textures = 1 << 9,
+ TextureAnim = 1 << 10,
+ NameValue = 1 << 11,
+ Position = 1 << 12,
+ Rotation = 1 << 13,
+ Velocity = 1 << 14,
+ Acceleration = 1 << 15,
+ AngularVelocity = 1 << 16,
+ CollisionPlane = 1 << 17,
+ Text = 1 << 18,
+ Particles = 1 << 19,
+ ExtraData = 1 << 20,
+ Sound = 1 << 21,
+ Joint = 1 << 22,
+ FullUpdate = UInt32.MaxValue
+ }
+
#region Scene related classes
public class TerrainPatch
@@ -52,12 +85,8 @@ namespace Simian
#endregion Scene related classes
- public delegate void ObjectAddCallback(object sender, SimulationObject obj, UUID ownerID, int scriptStartParam, PrimFlags creatorFlags);
+ public delegate void ObjectAddOrUpdateCallback(object sender, SimulationObject obj, UUID ownerID, int scriptStartParam, PrimFlags creatorFlags, UpdateFlags updateFlags);
public delegate void ObjectRemoveCallback(object sender, SimulationObject obj);
- public delegate void ObjectTransformCallback(object sender, SimulationObject obj, Vector3 position, Quaternion rotation, Vector3 velocity, Vector3 acceleration, Vector3 angularVelocity);
- public delegate void ObjectFlagsCallback(object sender, SimulationObject obj, PrimFlags flags);
- public delegate void ObjectModifyCallback(object sender, SimulationObject obj, Primitive.ConstructionData data);
- public delegate void ObjectModifyTexturesCallback(object sender, SimulationObject obj, string mediaURL, Primitive.TextureEntry textureEntry);
public delegate void ObjectSetRotationAxisCallback(object sender, SimulationObject obj, Vector3 rotationAxis);
public delegate void ObjectApplyImpulseCallback(object sender, SimulationObject obj, Vector3 impulse);
public delegate void ObjectApplyRotationalImpulseCallback(object sender, SimulationObject obj, Vector3 impulse);
@@ -76,12 +105,8 @@ namespace Simian
public interface ISceneProvider
{
- event ObjectAddCallback OnObjectAdd;
+ event ObjectAddOrUpdateCallback OnObjectAddOrUpdate;
event ObjectRemoveCallback OnObjectRemove;
- event ObjectTransformCallback OnObjectTransform;
- event ObjectFlagsCallback OnObjectFlags;
- event ObjectModifyCallback OnObjectModify;
- event ObjectModifyTexturesCallback OnObjectModifyTextures;
event ObjectSetRotationAxisCallback OnObjectSetRotationAxis;
event ObjectApplyImpulseCallback OnObjectApplyImpulse;
event ObjectApplyRotationalImpulseCallback OnObjectApplyRotationalImpulse;
@@ -112,13 +137,9 @@ namespace Simian
uint TerrainPatchCountWidth { get; }
uint TerrainPatchCountHeight { get; }
- bool ObjectAddOrUpdate(object sender, SimulationObject obj, UUID ownerID, int scriptStartParam, PrimFlags creatorFlags);
+ void ObjectAddOrUpdate(object sender, SimulationObject obj, UUID ownerID, int scriptStartParam, PrimFlags creatorFlags, UpdateFlags updateFlags);
bool ObjectRemove(object sender, uint localID);
bool ObjectRemove(object sender, UUID id);
- void ObjectTransform(object sender, SimulationObject obj, Vector3 position, Quaternion rotation, Vector3 velocity, Vector3 acceleration, Vector3 angularVelocity);
- void ObjectFlags(object sender, SimulationObject obj, PrimFlags flags);
- void ObjectModify(object sender, SimulationObject obj, Primitive.ConstructionData data);
- void ObjectModifyTextures(object sender, SimulationObject obj, string mediaURL, Primitive.TextureEntry textureEntry);
void ObjectSetRotationAxis(object sender, SimulationObject obj, Vector3 rotationAxis);
void ObjectApplyImpulse(object sender, SimulationObject obj, Vector3 impulse);
void ObjectApplyRotationalImpulse(object sender, SimulationObject obj, Vector3 impulse);
diff --git a/Programs/Simian/SimulationObject.cs b/Programs/Simian/SimulationObject.cs
index 38b91727..fc530693 100644
--- a/Programs/Simian/SimulationObject.cs
+++ b/Programs/Simian/SimulationObject.cs
@@ -27,10 +27,20 @@ namespace Simian
public Vector3 Torque;
/// Last point the object was attached to (right hand by default)
public AttachmentPoint LastAttachmentPoint = AttachmentPoint.RightHand;
- /// Seat offset
+ /// Saved seat offset. Applied to avatars that sit on this object
public Vector3 SitPosition;
- /// Seat rotation
+ /// Saved seat rotation. Applied to avatars that sit on this object
public Quaternion SitRotation = Quaternion.Identity;
+ /// Saved attachment offset. Applied to this object when it is attached
+ /// to an avatar
+ public Vector3 AttachmentPosition;
+ /// Saved attachment rotation. Applied to this object when it is attached
+ /// to an avatar
+ public Quaternion AttachmentRotation = Quaternion.Identity;
+ /// Rotation that is saved when this object is attached to an avatar.
+ /// Will be applied to the object when it is dropped. This is always the world
+ /// rotation, since it is only applicable to parent objects
+ public Quaternion BeforeAttachmentRotation = Quaternion.Identity;
protected Simian Server;
protected SimpleMesh[] Meshes;
@@ -247,62 +257,74 @@ namespace Simian
return update;
}
- public static ObjectUpdatePacket.ObjectDataBlock BuildUpdateBlock(Primitive obj, PrimFlags flags, uint crc)
+ public static ObjectUpdatePacket.ObjectDataBlock BuildUpdateBlock(Primitive prim, PrimFlags flags, uint crc)
{
byte[] objectData = new byte[60];
- obj.Position.ToBytes(objectData, 0);
- obj.Velocity.ToBytes(objectData, 12);
- obj.Acceleration.ToBytes(objectData, 24);
- obj.Rotation.ToBytes(objectData, 36);
- obj.AngularVelocity.ToBytes(objectData, 48);
+ prim.Position.ToBytes(objectData, 0);
+ prim.Velocity.ToBytes(objectData, 12);
+ prim.Acceleration.ToBytes(objectData, 24);
+ prim.Rotation.ToBytes(objectData, 36);
+ prim.AngularVelocity.ToBytes(objectData, 48);
ObjectUpdatePacket.ObjectDataBlock update = new ObjectUpdatePacket.ObjectDataBlock();
- update.ClickAction = (byte)obj.ClickAction;
+ update.ClickAction = (byte)prim.ClickAction;
update.CRC = crc;
- update.ExtraParams = obj.GetExtraParamsBytes();
+ update.ExtraParams = prim.GetExtraParamsBytes();
update.Flags = (byte)flags;
- update.FullID = obj.ID;
- update.Gain = obj.SoundGain;
- update.ID = obj.LocalID;
- update.JointAxisOrAnchor = obj.JointAxisOrAnchor;
- update.JointPivot = obj.JointPivot;
- update.JointType = (byte)obj.Joint;
- update.Material = (byte)obj.PrimData.Material;
- update.MediaURL = Utils.StringToBytes(obj.MediaURL);
- update.NameValue = Utils.StringToBytes(NameValue.NameValuesToString(obj.NameValues));
+ update.FullID = prim.ID;
+ update.Gain = prim.SoundGain;
+ update.ID = prim.LocalID;
+ update.JointAxisOrAnchor = prim.JointAxisOrAnchor;
+ update.JointPivot = prim.JointPivot;
+ update.JointType = (byte)prim.Joint;
+ update.Material = (byte)prim.PrimData.Material;
+ update.MediaURL = Utils.StringToBytes(prim.MediaURL);
+ update.NameValue = Utils.StringToBytes(NameValue.NameValuesToString(prim.NameValues));
update.ObjectData = objectData;
- update.OwnerID = (obj.Properties != null ? obj.Properties.OwnerID : UUID.Zero);
- update.ParentID = obj.ParentID;
- update.PathBegin = Primitive.PackBeginCut(obj.PrimData.PathBegin);
- update.PathCurve = (byte)obj.PrimData.PathCurve;
- update.PathEnd = Primitive.PackEndCut(obj.PrimData.PathEnd);
- update.PathRadiusOffset = Primitive.PackPathTwist(obj.PrimData.PathRadiusOffset);
- update.PathRevolutions = Primitive.PackPathRevolutions(obj.PrimData.PathRevolutions);
- update.PathScaleX = Primitive.PackPathScale(obj.PrimData.PathScaleX);
- update.PathScaleY = Primitive.PackPathScale(obj.PrimData.PathScaleY);
- update.PathShearX = (byte)Primitive.PackPathShear(obj.PrimData.PathShearX);
- update.PathShearY = (byte)Primitive.PackPathShear(obj.PrimData.PathShearY);
- update.PathSkew = Primitive.PackPathTwist(obj.PrimData.PathSkew);
- update.PathTaperX = Primitive.PackPathTaper(obj.PrimData.PathTaperX);
- update.PathTaperY = Primitive.PackPathTaper(obj.PrimData.PathTaperY);
- update.PathTwist = Primitive.PackPathTwist(obj.PrimData.PathTwist);
- update.PathTwistBegin = Primitive.PackPathTwist(obj.PrimData.PathTwistBegin);
- update.PCode = (byte)obj.PrimData.PCode;
- update.ProfileBegin = Primitive.PackBeginCut(obj.PrimData.ProfileBegin);
- update.ProfileCurve = (byte)obj.PrimData.ProfileCurve;
- update.ProfileEnd = Primitive.PackEndCut(obj.PrimData.ProfileEnd);
- update.ProfileHollow = Primitive.PackProfileHollow(obj.PrimData.ProfileHollow);
- update.PSBlock = obj.ParticleSys.GetBytes();
- update.TextColor = obj.TextColor.GetBytes(true);
- update.TextureAnim = obj.TextureAnim.GetBytes();
- update.TextureEntry = obj.Textures == null ? Utils.EmptyBytes : obj.Textures.ToBytes();
- update.Radius = obj.SoundRadius;
- update.Scale = obj.Scale;
- update.Sound = obj.Sound;
- update.State = obj.PrimData.State;
- update.Text = Utils.StringToBytes(obj.Text);
+ update.OwnerID = (prim.Properties != null ? prim.Properties.OwnerID : UUID.Zero);
+ update.ParentID = prim.ParentID;
+ update.PathBegin = Primitive.PackBeginCut(prim.PrimData.PathBegin);
+ update.PathCurve = (byte)prim.PrimData.PathCurve;
+ update.PathEnd = Primitive.PackEndCut(prim.PrimData.PathEnd);
+ update.PathRadiusOffset = Primitive.PackPathTwist(prim.PrimData.PathRadiusOffset);
+ update.PathRevolutions = Primitive.PackPathRevolutions(prim.PrimData.PathRevolutions);
+ update.PathScaleX = Primitive.PackPathScale(prim.PrimData.PathScaleX);
+ update.PathScaleY = Primitive.PackPathScale(prim.PrimData.PathScaleY);
+ update.PathShearX = (byte)Primitive.PackPathShear(prim.PrimData.PathShearX);
+ update.PathShearY = (byte)Primitive.PackPathShear(prim.PrimData.PathShearY);
+ update.PathSkew = Primitive.PackPathTwist(prim.PrimData.PathSkew);
+ update.PathTaperX = Primitive.PackPathTaper(prim.PrimData.PathTaperX);
+ update.PathTaperY = Primitive.PackPathTaper(prim.PrimData.PathTaperY);
+ update.PathTwist = Primitive.PackPathTwist(prim.PrimData.PathTwist);
+ update.PathTwistBegin = Primitive.PackPathTwist(prim.PrimData.PathTwistBegin);
+ update.PCode = (byte)prim.PrimData.PCode;
+ update.ProfileBegin = Primitive.PackBeginCut(prim.PrimData.ProfileBegin);
+ update.ProfileCurve = (byte)prim.PrimData.ProfileCurve;
+ update.ProfileEnd = Primitive.PackEndCut(prim.PrimData.ProfileEnd);
+ update.ProfileHollow = Primitive.PackProfileHollow(prim.PrimData.ProfileHollow);
+ update.PSBlock = prim.ParticleSys.GetBytes();
+ update.TextColor = prim.TextColor.GetBytes(true);
+ update.TextureAnim = prim.TextureAnim.GetBytes();
+ update.TextureEntry = prim.Textures == null ? Utils.EmptyBytes : prim.Textures.GetBytes();
+ update.Radius = prim.SoundRadius;
+ update.Scale = prim.Scale;
+ update.Sound = prim.Sound;
+ update.State = prim.PrimData.State;
+ update.Text = Utils.StringToBytes(prim.Text);
update.UpdateFlags = (uint)flags;
- update.Data = obj.GenericData == null ? Utils.EmptyBytes : obj.GenericData;
+ switch (prim.PrimData.PCode)
+ {
+ case PCode.Grass:
+ case PCode.Tree:
+ case PCode.NewTree:
+ update.Data = new byte[1];
+ update.Data[0] = (byte)prim.TreeSpecies;
+ break;
+ default:
+ update.Data = new byte[prim.ScratchPad.Length];
+ Buffer.BlockCopy(prim.ScratchPad, 0, update.Data, 0, update.Data.Length);
+ break;
+ }
return update;
}