diff --git a/libsecondlife-cs/Helpers.cs b/libsecondlife-cs/Helpers.cs
index 0f06aada..90208f64 100644
--- a/libsecondlife-cs/Helpers.cs
+++ b/libsecondlife-cs/Helpers.cs
@@ -46,12 +46,10 @@ namespace libsecondlife
public const byte MSG_RELIABLE = 0x40;
/// This header flag signals that the message is compressed using zerocoding
public const byte MSG_ZEROCODED = 0x80;
- /// Used for converting a byte to a variable range float
- public const float ONE_OVER_BYTEMAX = 1.0f / (float)byte.MaxValue;
/// Used for converting degrees to radians
- public const double DEG_TO_RAD = Math.PI / 180;
+ public const double DEG_TO_RAD = Math.PI / 180.0d;
/// Used for converting radians to degrees
- public const double RAD_TO_DEG = 180 / Math.PI;
+ public const double RAD_TO_DEG = 180.0d / Math.PI;
///
/// Passed to SecondLife.Log() to identify the severity of a log entry
@@ -162,6 +160,34 @@ namespace libsecondlife
return bytes;
}
+ ///
+ /// Convert the first two bytes starting at the given position in
+ /// little endian ordering to an unsigned short
+ ///
+ /// Byte array containing the ushort
+ /// Position to start reading the ushort from
+ /// An unsigned short, will be zero if a ushort can't be read
+ /// at the given position
+ public static ushort BytesToUInt16(byte[] bytes, int pos)
+ {
+ if (bytes.Length <= pos + 1) return 0;
+ return (ushort)(bytes[pos + 1] + (bytes[pos] << 8));
+ }
+
+ ///
+ /// Convert the first four bytes starting at the given position in
+ /// little endian ordering to an unsigned integer
+ ///
+ /// Byte array containing the uint
+ /// Position to start reading the uint from
+ /// An unsigned integer, will be zero if a uint can't be read
+ /// at the given position
+ public static uint BytesToUInt(byte[] bytes, int pos)
+ {
+ if (bytes.Length <= pos + 4) return 0;
+ return (uint)(bytes[pos + 3] + (bytes[pos + 2] << 8) + (bytes[pos + 1] << 16) + (bytes[pos] << 24));
+ }
+
///
/// Convert the first four bytes of the given array in little endian
/// ordering to an unsigned integer
@@ -175,6 +201,20 @@ namespace libsecondlife
return (uint)(bytes[3] + (bytes[2] << 8) + (bytes[1] << 16) + (bytes[0] << 24));
}
+ ///
+ /// Convert the first four bytes starting at the given position in
+ /// big endian ordering to an unsigned integer
+ ///
+ /// Byte array containing the uint
+ /// Position to start reading the uint from
+ /// An unsigned integer, will be zero if a uint can't be read
+ /// at the given position
+ public static uint BytesToUIntBig(byte[] bytes, int pos)
+ {
+ if (bytes.Length <= pos + 4) return 0;
+ return (uint)(bytes[pos] + (bytes[pos + 1] << 8) + (bytes[pos + 2] << 16) + (bytes[pos + 3] << 24));
+ }
+
///
/// Convert the first four bytes of the given array in big endian
/// ordering to an unsigned integer
@@ -253,6 +293,20 @@ namespace libsecondlife
return (byte)Math.Floor(val * (float)byte.MaxValue);
}
+ ///
+ /// Convert a byte to a float value given a minimum and maximum range
+ ///
+ /// Byte array to get the byte from
+ /// Position in the byte array the desired byte is at
+ /// Minimum value range
+ /// Maximum value range
+ /// A float value inclusively between lower and upper
+ public static float ByteToFloat(byte[] bytes, int pos, float lower, float upper)
+ {
+ if (bytes.Length <= pos) return 0;
+ return ByteToFloat(bytes[pos], lower, upper);
+ }
+
///
/// Convert a byte to a float value given a minimum and maximum range
///
@@ -262,6 +316,8 @@ namespace libsecondlife
/// A float value inclusively between lower and upper
public static float ByteToFloat(byte val, float lower, float upper)
{
+ const float ONE_OVER_BYTEMAX = 1.0f / (float)byte.MaxValue;
+
float fval = (float)val * ONE_OVER_BYTEMAX;
float delta = (upper - lower);
fval *= delta;
@@ -275,6 +331,44 @@ namespace libsecondlife
return fval;
}
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static float UInt16ToFloat(byte[] bytes, int pos, float lower, float upper)
+ {
+ ushort val = BytesToUInt16(bytes, pos);
+ return UInt16ToFloat(val, lower, upper);
+ }
+
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static float UInt16ToFloat(ushort val, float lower, float upper)
+ {
+ const float ONE_OVER_U16_MAX = 1.0f / 65535.0f;
+
+ float fval = (float)val * ONE_OVER_U16_MAX;
+ float delta = upper - lower;
+ fval *= delta;
+ fval += lower;
+
+ // Make sure zeroes come through as zero
+ float maxError = delta * ONE_OVER_U16_MAX;
+ if (Math.Abs(fval) < maxError)
+ fval = 0.0f;
+
+ return fval;
+ }
+
///
/// Clamp a given value between a range
///
diff --git a/libsecondlife-cs/LLObject.cs b/libsecondlife-cs/LLObject.cs
index f3728bd9..11d1f812 100644
--- a/libsecondlife-cs/LLObject.cs
+++ b/libsecondlife-cs/LLObject.cs
@@ -111,6 +111,77 @@ namespace libsecondlife
#region Structs
+ ///
+ ///
+ ///
+ [Serializable]
+ public struct ObjectData
+ {
+ ///
+ [XmlAttribute("pathtwistbegin")]
+ public int PathTwistBegin;
+ ///
+ [XmlAttribute("pathend")]
+ public float PathEnd;
+ ///
+ [XmlAttribute("profilebegin")]
+ public float ProfileBegin;
+ ///
+ [XmlAttribute("pathradiusoffset")]
+ public float PathRadiusOffset;
+ ///
+ [XmlAttribute("pathskew")]
+ public float PathSkew;
+ ///
+ [XmlAttribute("profilecurve")]
+ public uint ProfileCurve;
+ ///
+ [XmlAttribute("pathscalex")]
+ public float PathScaleX;
+ ///
+ [XmlAttribute("pathscaley")]
+ public float PathScaleY;
+ ///
+ [XmlAttribute("material")]
+ public uint Material;
+ ///
+ [XmlAttribute("pathshearx")]
+ public float PathShearX;
+ ///
+ [XmlAttribute("pathsheary")]
+ public float PathShearY;
+ ///
+ [XmlAttribute("pathtaperx")]
+ public float PathTaperX;
+ ///
+ [XmlAttribute("pathtapery")]
+ public float PathTaperY;
+ ///
+ [XmlAttribute("profileend")]
+ public float ProfileEnd;
+ ///
+ [XmlAttribute("pathbegin")]
+ public float PathBegin;
+ ///
+ [XmlAttribute("pathcurve")]
+ public uint PathCurve;
+ ///
+ [XmlAttribute("pathtwist")]
+ public int PathTwist;
+ ///
+ [XmlAttribute("profilehollow")]
+ public uint ProfileHollow;
+ ///
+ [XmlAttribute("pathrevolutions")]
+ public float PathRevolutions;
+ ///
+ [XmlAttribute("state")]
+ public uint State;
+ ///
+ [XmlIgnore]
+ public ObjectManager.PCode PCode;
+ }
+
///
///
///
@@ -151,104 +222,47 @@ namespace libsecondlife
#endregion Structs
- #region Public Properties
+ #region Public Members
///
- [XmlAttribute("pathtwistbegin")]
- public int PathTwistBegin;
- ///
- [XmlAttribute("pathend")]
- public float PathEnd;
- ///
- [XmlAttribute("profilebegin")]
- public float ProfileBegin;
- ///
- [XmlAttribute("pathradiusoffset")]
- public float PathRadiusOffset;
- ///
- [XmlAttribute("pathskew")]
- public float PathSkew;
- ///
- [XmlAttribute("profilecurve")]
- public uint ProfileCurve;
- ///
- [XmlAttribute("pathscalex")]
- public float PathScaleX;
- ///
- [XmlAttribute("pathscaley")]
- public float PathScaleY;
- ///
- [XmlAttribute("localid")]
- public uint LocalID;
- ///
- [XmlAttribute("parentid")]
- public uint ParentID;
- ///
- [XmlAttribute("material")]
- public uint Material;
- ///
- [XmlAttribute("pathshearx")]
- public float PathShearX;
- ///
- [XmlAttribute("pathsheary")]
- public float PathShearY;
- ///
- [XmlAttribute("pathtaperx")]
- public float PathTaperX;
- ///
- [XmlAttribute("pathtapery")]
- public float PathTaperY;
- ///
- [XmlAttribute("profileend")]
- public float ProfileEnd;
- ///
- [XmlAttribute("pathbegin")]
- public float PathBegin;
- ///
- [XmlAttribute("pathcurve")]
- public uint PathCurve;
- ///
- [XmlAttribute("pathtwist")]
- public int PathTwist;
- ///
- [XmlAttribute("profilehollow")]
- public uint ProfileHollow;
- ///
- [XmlAttribute("pathrevolutions")]
- public float PathRevolutions;
- ///
- [XmlAttribute("state")]
- public uint State;
- ///
- [XmlAttribute("text")]
- public string Text = String.Empty;
- ///
- [XmlAttribute("regionhandle")]
- public ulong RegionHandle;
- ///
- [XmlAttribute("flags")]
- public ObjectFlags Flags;
- ///
- [XmlIgnore]
- public ObjectManager.PCode PCode = ObjectManager.PCode.Prim;
- ///
- [XmlElement("id")]
public LLUUID ID = LLUUID.Zero;
///
- [XmlElement("groupid")]
public LLUUID GroupID = LLUUID.Zero;
///
+ public uint LocalID;
+ ///
+ public uint ParentID;
+ ///
+ public ulong RegionHandle;
+ ///
+ public ObjectFlags Flags;
+ /// Unknown
+ public byte[] GenericData;
+ ///
public LLVector3 Position = LLVector3.Zero;
///
public LLVector3 Scale = LLVector3.Zero;
///
public LLQuaternion Rotation = LLQuaternion.Identity;
+
+ public LLVector3 Velocity;
+ public LLVector3 AngularVelocity;
+ public LLVector3 Acceleration;
+ public LLVector4 CollisionPlane;
+
///
public TextureEntry Textures = new TextureEntry();
///
public ObjectPropertiesFamily PropertiesFamily;
- #endregion Public Properties
+ #endregion Public Members
+
+
+ ///
+ public ObjectData Data { get { return data; } }
+
+
+ internal ObjectData data = new ObjectData();
#region Static Methods
diff --git a/libsecondlife-cs/MainAvatar.cs b/libsecondlife-cs/MainAvatar.cs
index 24bae795..8f02a45b 100644
--- a/libsecondlife-cs/MainAvatar.cs
+++ b/libsecondlife-cs/MainAvatar.cs
@@ -466,6 +466,14 @@ namespace libsecondlife
public LLVector3 Position = LLVector3.Zero;
/// Current rotation of avatar
public LLQuaternion Rotation = LLQuaternion.Identity;
+ ///
+ public LLVector4 CollisionPlane = LLVector4.Zero;
+ ///
+ public LLVector3 Velocity = LLVector3.Zero;
+ ///
+ public LLVector3 Acceleration = LLVector3.Zero;
+ ///
+ public LLVector3 AngularVelocity = LLVector3.Zero;
/// The point the avatar is currently looking at
/// (may not stay updated)
public LLVector3 LookAt = LLVector3.Zero;
diff --git a/libsecondlife-cs/NetworkManager.cs b/libsecondlife-cs/NetworkManager.cs
index f1f250c7..2c70e7c0 100644
--- a/libsecondlife-cs/NetworkManager.cs
+++ b/libsecondlife-cs/NetworkManager.cs
@@ -1565,6 +1565,7 @@ namespace libsecondlife
CurrentSim.SendPacket(logout, true);
LogoutTimer = new System.Timers.Timer(Client.Settings.LOGOUT_TIMEOUT);
+ LogoutTimer.AutoReset = false;
LogoutTimer.Elapsed += new ElapsedEventHandler(LogoutTimer_Elapsed);
LogoutTimer.Start();
}
@@ -1731,6 +1732,7 @@ namespace libsecondlife
///
private void LogoutTimer_Elapsed(object sender, ElapsedEventArgs ev)
{
+ LogoutTimer.Stop();
Client.Log("Logout due to timeout on server acknowledgement", Helpers.LogLevel.Debug);
ForceLogout();
}
diff --git a/libsecondlife-cs/ObjectManager.cs b/libsecondlife-cs/ObjectManager.cs
index fd7b72d5..c3f892b6 100644
--- a/libsecondlife-cs/ObjectManager.cs
+++ b/libsecondlife-cs/ObjectManager.cs
@@ -33,16 +33,20 @@ using libsecondlife.Packets;
namespace libsecondlife
{
///
- /// Contains the shared variables sent in an object update packet for
- /// objects. Used to track position and movement of prims and avatars
+ /// Contains the variables sent in an object update packet for objects.
+ /// Used to track position and movement of prims and avatars
///
- public abstract class ObjectUpdate
+ public struct ObjectUpdate
{
///
- public uint LocalID;
+ public bool Avatar;
+ ///
+ public LLVector4 CollisionPlane;
///
public byte State;
///
+ public uint LocalID;
+ ///
public LLVector3 Position;
///
public LLVector3 Velocity;
@@ -51,29 +55,11 @@ namespace libsecondlife
///
public LLQuaternion Rotation;
///
- public LLVector3 RotationVelocity;
+ public LLVector3 AngularVelocity;
///
public LLObject.TextureEntry Textures;
}
- ///
- /// Contains all of the variables sent in an object update packet for a
- /// primitive. Used to track position and movement of primitives
- ///
- public class PrimUpdate : ObjectUpdate
- {
- }
-
- ///
- /// Contains all of the variables sent in an object update packet for an
- /// avatar. Used to track position and movement of avatars
- ///
- public class AvatarUpdate : ObjectUpdate
- {
- ///
- public LLVector4 CollisionPlane;
- }
-
///
/// Handles all network traffic related to prims and avatar positions and
/// movement.
@@ -127,19 +113,10 @@ namespace libsecondlife
///
///
///
- ///
+ ///
///
///
- public delegate void PrimMovedCallback(Simulator simulator, PrimUpdate prim, ulong regionHandle,
- ushort timeDilation);
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- public delegate void AvatarMovedCallback(Simulator simulator, AvatarUpdate avatar, ulong regionHandle,
+ public delegate void ObjectUpdatedCallback(Simulator simulator, ObjectUpdate update, ulong regionHandle,
ushort timeDilation);
///
///
@@ -256,7 +233,7 @@ namespace libsecondlife
public enum CompressedFlags
{
/// Hasn't been spotted in the wild yet
- Unknown1 = 0x01,
+ ScratchPad = 0x01,
/// This may be incorrect
Tree = 0x02,
/// Whether the object has floating text ala llSetText
@@ -267,12 +244,14 @@ namespace libsecondlife
HasSound = 0x10,
/// Whether the object is attached to a root object or not
HasParent = 0x20,
- /// Semi-common flag, currently unknown
- Unknown2 = 0x40,
+ /// Unknown
+ Unknown = 0x40,
/// Whether the object has an angular velocity
HasAngularVelocity = 0x80,
- /// Whether the object is an attachment or not
- Attachment = 0x100
+ /// Whether the object has a name value pairs string
+ HasNameValues = 0x100,
+ /// Whether the object has a Media URL set
+ MediaURL = 0x200
}
///
@@ -390,17 +369,11 @@ namespace libsecondlife
///
public event NewFoliageCallback OnNewFoliage;
///
- /// This event will be raised when a prim movement packet is received,
- /// containing the updated position, rotation, and movement-related
- /// vectors.
- ///
- public event PrimMovedCallback OnPrimMoved;
- ///
- /// This event will be raised when an avatar movement packet is
+ /// This event will be raised when a terse object update packet is
/// received, containing the updated position, rotation, and
- /// movement-related vectors.
+ /// movement-related vectors
///
- public event AvatarMovedCallback OnAvatarMoved;
+ public event ObjectUpdatedCallback OnObjectUpdated;
///
/// This event will be raised when the main avatar sits on an
/// object or stands up, with a local ID of the current seat or
@@ -525,27 +498,31 @@ namespace libsecondlife
/// Create, or "rez" a new prim object in a simulator
///
/// The target simulator
- /// The prim object to rez
+ /// Data describing the prim object to rez
+ /// Group ID that this prim is set to, or LLUUID.Zero
/// An approximation of the position at which to rez the prim
+ /// Scale vector to size this prim
+ /// Rotation quaternion to rotate this prim
/// Due to the way client prim rezzing is done on the server,
/// the requested position for an object is only close to where the prim
/// actually ends up. If you desire exact placement you'll need to
/// follow up by moving the object after it has been created.
- public void AddPrim(Simulator simulator, Primitive prim, LLVector3 position)
+ public void AddPrim(Simulator simulator, LLObject.ObjectData prim, LLUUID groupID, LLVector3 position,
+ LLVector3 scale, LLQuaternion rotation)
{
ObjectAddPacket packet = new ObjectAddPacket();
packet.AgentData.AgentID = Client.Network.AgentID;
packet.AgentData.SessionID = Client.Network.SessionID;
- packet.AgentData.GroupID = prim.GroupID;
+ packet.AgentData.GroupID = groupID;
packet.ObjectData.State = (byte)prim.State;
packet.ObjectData.AddFlags = (uint)LLObject.ObjectFlags.CreateSelected;
packet.ObjectData.PCode = (byte)PCode.Prim;
packet.ObjectData.Material = (byte)prim.Material;
- packet.ObjectData.Scale = prim.Scale;
- packet.ObjectData.Rotation = prim.Rotation;
+ packet.ObjectData.Scale = scale;
+ packet.ObjectData.Rotation = rotation;
packet.ObjectData.PathBegin = LLObject.PathBeginByte(prim.PathBegin);
packet.ObjectData.PathCurve = (byte)prim.PathCurve;
@@ -573,9 +550,7 @@ namespace libsecondlife
packet.ObjectData.RayTargetID = LLUUID.Zero;
packet.ObjectData.BypassRaycast = 1;
- // TODO: This is no longer a field in ObjectAdd. Detect if there actually is
- // texture information for this prim and send an ObjectUpdate
- //packet.ObjectData.TextureEntry = prim.Textures.GetBytes();
+ // TODO: Automatically send another packet to set the TextureEntry?
Client.Network.SendPacket(packet, simulator);
}
@@ -919,66 +894,218 @@ namespace libsecondlife
foreach (ObjectUpdatePacket.ObjectDataBlock block in update.ObjectData)
{
+ LLVector4 collisionPlane = LLVector4.Zero;
+ LLVector3 position;
+ LLVector3 velocity;
+ LLVector3 acceleration;
+ LLQuaternion rotation;
+ LLVector3 angularVelocity;
+
+ // TODO: Parse NameValue here
+ string nameValue = Helpers.FieldToString(block.NameValue);
+
+ // Object (primitive) parameters
+ LLObject.ObjectData data = new LLObject.ObjectData();
+ data.State = block.State;
+ data.Material = block.Material;
+ data.PathCurve = block.PathCurve;
+ data.ProfileCurve = block.ProfileCurve;
+ data.PathBegin = LLObject.PathBeginFloat(block.PathBegin);
+ data.PathEnd = LLObject.PathEndFloat(block.PathEnd);
+ data.PathScaleX = LLObject.PathScaleFloat(block.PathScaleX);
+ data.PathScaleY = LLObject.PathScaleFloat(block.PathScaleY);
+ data.PathShearX = LLObject.PathShearFloat(block.PathShearX);
+ data.PathShearY = LLObject.PathShearFloat(block.PathShearY);
+ data.PathTwist = block.PathTwist;
+ data.PathTwistBegin = block.PathTwistBegin;
+ data.PathRadiusOffset = LLObject.PathRadiusOffsetFloat(block.PathRadiusOffset);
+ data.PathTaperX = LLObject.PathTaperFloat(block.PathTaperX);
+ data.PathTaperY = LLObject.PathTaperFloat(block.PathTaperY);
+ data.PathRevolutions = LLObject.PathRevolutionsFloat(block.PathRevolutions);
+ data.PathSkew = LLObject.PathSkewFloat(block.PathSkew);
+ data.ProfileBegin = LLObject.ProfileBeginFloat(block.ProfileBegin);
+ data.ProfileEnd = LLObject.ProfileEndFloat(block.ProfileEnd);
+ data.ProfileHollow = block.ProfileHollow;
+
+ // Additional packed parameters in ObjectData
+ int pos = 0;
+ switch (block.ObjectData.Length)
+ {
+ case 76:
+ // Collision normal for avatar
+ collisionPlane = new LLVector4(block.ObjectData, pos);
+ pos += 16;
+
+ goto case 60;
+ case 60:
+ // Position
+ position = new LLVector3(block.ObjectData, pos);
+ pos += 12;
+ // Velocity
+ velocity = new LLVector3(block.ObjectData, pos);
+ pos += 12;
+ // Acceleration
+ acceleration = new LLVector3(block.ObjectData, pos);
+ pos += 12;
+ // Rotation (theta)
+ rotation = new LLQuaternion(block.ObjectData, pos, true);
+ pos += 12;
+ // Angular velocity (omega)
+ angularVelocity = new LLVector3(block.ObjectData, pos);
+ pos += 12;
+
+ break;
+ case 48:
+ // Collision normal for avatar
+ collisionPlane = new LLVector4(block.ObjectData, pos);
+ pos += 16;
+
+ goto case 32;
+ case 32:
+ // The data is an array of unsigned shorts
+
+ // Position
+ position = new LLVector3(
+ Helpers.UInt16ToFloat(block.ObjectData, pos, -0.5f * 256.0f, 1.5f * 256.0f),
+ Helpers.UInt16ToFloat(block.ObjectData, pos + 2, -0.5f * 256.0f, 1.5f * 256.0f),
+ Helpers.UInt16ToFloat(block.ObjectData, pos + 4, -256.0f, 3.0f * 256.0f));
+ pos += 6;
+ // Velocity
+ velocity = new LLVector3(
+ Helpers.UInt16ToFloat(block.ObjectData, pos, -256.0f, 256.0f),
+ Helpers.UInt16ToFloat(block.ObjectData, pos + 2, -256.0f, 256.0f),
+ Helpers.UInt16ToFloat(block.ObjectData, pos + 4, -256.0f, 256.0f));
+ pos += 6;
+ // Acceleration
+ acceleration = new LLVector3(
+ Helpers.UInt16ToFloat(block.ObjectData, pos, -256.0f, 256.0f),
+ Helpers.UInt16ToFloat(block.ObjectData, pos + 2, -256.0f, 256.0f),
+ Helpers.UInt16ToFloat(block.ObjectData, pos + 4, -256.0f, 256.0f));
+ pos += 6;
+ // Rotation (theta)
+ rotation = new LLQuaternion(
+ Helpers.UInt16ToFloat(block.ObjectData, pos, -1.0f, 1.0f),
+ Helpers.UInt16ToFloat(block.ObjectData, pos + 2, -1.0f, 1.0f),
+ Helpers.UInt16ToFloat(block.ObjectData, pos + 4, -1.0f, 1.0f),
+ Helpers.UInt16ToFloat(block.ObjectData, pos + 6, -1.0f, 1.0f));
+ pos += 8;
+ // Angular velocity (omega)
+ angularVelocity = new LLVector3(
+ Helpers.UInt16ToFloat(block.ObjectData, pos, -256.0f, 256.0f),
+ Helpers.UInt16ToFloat(block.ObjectData, pos + 2, -256.0f, 256.0f),
+ Helpers.UInt16ToFloat(block.ObjectData, pos + 4, -256.0f, 256.0f));
+ pos += 6;
+
+ break;
+ case 16:
+ // The data is an array of single bytes (8-bit numbers)
+
+ // Position
+ position = new LLVector3(
+ Helpers.ByteToFloat(block.ObjectData, pos, -256.0f, 256.0f),
+ Helpers.ByteToFloat(block.ObjectData, pos + 1, -256.0f, 256.0f),
+ Helpers.ByteToFloat(block.ObjectData, pos + 2, -256.0f, 256.0f));
+ pos += 3;
+ // Velocity
+ velocity = new LLVector3(
+ Helpers.ByteToFloat(block.ObjectData, pos, -256.0f, 256.0f),
+ Helpers.ByteToFloat(block.ObjectData, pos + 1, -256.0f, 256.0f),
+ Helpers.ByteToFloat(block.ObjectData, pos + 2, -256.0f, 256.0f));
+ pos += 3;
+ // Accleration
+ acceleration = new LLVector3(
+ Helpers.ByteToFloat(block.ObjectData, pos, -256.0f, 256.0f),
+ Helpers.ByteToFloat(block.ObjectData, pos + 1, -256.0f, 256.0f),
+ Helpers.ByteToFloat(block.ObjectData, pos + 2, -256.0f, 256.0f));
+ pos += 3;
+ // Rotation
+ rotation = new LLQuaternion(
+ Helpers.ByteToFloat(block.ObjectData, pos, -1.0f, 1.0f),
+ Helpers.ByteToFloat(block.ObjectData, pos + 1, -1.0f, 1.0f),
+ Helpers.ByteToFloat(block.ObjectData, pos + 2, -1.0f, 1.0f),
+ Helpers.ByteToFloat(block.ObjectData, pos + 3, -1.0f, 1.0f));
+ pos += 4;
+ // Angular Velocity
+ angularVelocity = new LLVector3(
+ Helpers.ByteToFloat(block.ObjectData, pos, -256.0f, 256.0f),
+ Helpers.ByteToFloat(block.ObjectData, pos + 1, -256.0f, 256.0f),
+ Helpers.ByteToFloat(block.ObjectData, pos + 2, -256.0f, 256.0f));
+ pos += 3;
+
+ break;
+ default:
+ Client.Log("Got an ObjectUpdate block with ObjectUpdate field length of " +
+ block.ObjectData.Length, Helpers.LogLevel.Warning);
+
+ continue;
+ }
+
+ // Unknown
+ if (block.Data.Length != 0)
+ Client.DebugLog("Got an ObjectUpdate block with Data length " + block.Data.Length);
+
+ // Determine the object type and create the appropriate class
byte pcode = block.PCode;
switch (pcode)
{
case (byte)PCode.Grass:
case (byte)PCode.Tree:
case (byte)PCode.Prim:
- // New prim spotted
Primitive prim = new Primitive();
+
+ prim.Flags = (LLObject.ObjectFlags)block.UpdateFlags;
- prim.NameValue = Helpers.FieldToString(block.NameValue);
+ if ((prim.Flags & LLObject.ObjectFlags.ZlibCompressed) != 0)
+ {
+ Client.Log("Got a ZlibCompressed ObjectUpdate, implement me!", Helpers.LogLevel.Info);
+ continue;
+ }
- prim.RegionHandle = update.RegionData.RegionHandle;
- prim.Position = new LLVector3(block.ObjectData, 0);
- prim.Rotation = new LLQuaternion(block.ObjectData, 36, true);
- // TODO: Parse the rest of the ObjectData byte array fields
+ prim.NameValue = nameValue;
prim.LocalID = block.ID;
- prim.State = block.State;
prim.ID = block.FullID;
prim.ParentID = block.ParentID;
- //block.OwnerID Sound-related
- prim.Material = block.Material;
- prim.PathCurve = block.PathCurve;
- prim.ProfileCurve = block.ProfileCurve;
- prim.PathBegin = LLObject.PathBeginFloat(block.PathBegin);
- prim.PathEnd = LLObject.PathEndFloat(block.PathEnd);
- prim.PathScaleX = LLObject.PathScaleFloat(block.PathScaleX);
- prim.PathScaleY = LLObject.PathScaleFloat(block.PathScaleY);
- prim.PathShearX = LLObject.PathShearFloat(block.PathShearX);
- prim.PathShearY = LLObject.PathShearFloat(block.PathShearY);
- prim.PathTwist = block.PathTwist;
- prim.PathTwistBegin = block.PathTwistBegin;
- prim.PathRadiusOffset = LLObject.PathRadiusOffsetFloat(block.PathRadiusOffset);
- prim.PathTaperX = LLObject.PathTaperFloat(block.PathTaperX);
- prim.PathTaperY = LLObject.PathTaperFloat(block.PathTaperY);
- prim.PathRevolutions = LLObject.PathRevolutionsFloat(block.PathRevolutions);
- prim.PathSkew = LLObject.PathSkewFloat(block.PathSkew);
- prim.ProfileBegin = LLObject.ProfileBeginFloat(block.ProfileBegin);
- prim.ProfileEnd = LLObject.ProfileEndFloat(block.ProfileEnd);
- prim.ProfileHollow = block.ProfileHollow;
+ prim.RegionHandle = update.RegionData.RegionHandle;
+ prim.Scale = block.Scale;
+ prim.ClickAction = block.ClickAction;
+ prim.OwnerID = block.OwnerID;
+ prim.MediaURL = Helpers.FieldToUTF8String(block.MediaURL);
+ prim.Text = Helpers.FieldToUTF8String(block.Text);
+ prim.TextColor = new LLColor(block.TextColor, 0);
+ // Alpha is inversed to help zero encoding
+ prim.TextColor.A = (byte)(255 - prim.TextColor.A);
+ // Sound information
+ prim.Sound = block.Sound;
+ prim.SoundFlags = block.Flags;
+ prim.SoundGain = block.Gain;
+ prim.SoundRadius = block.Radius;
- //block.Data ?
- prim.Text = ASCIIEncoding.ASCII.GetString(block.Text);
- //block.TextColor LLColor4U of the hovering text
- //block.MediaURL Quicktime stream
+ // Joint information
+ prim.Joint = (Primitive.JointType)block.JointType;
+ prim.JointPivot = block.JointPivot;
+ prim.JointAxisOrAnchor = block.JointAxisOrAnchor;
+
+ // Object parameters
+ prim.data = data;
+
+ // Textures, texture animations, particle system, and extra params
prim.Textures = new Primitive.TextureEntry(block.TextureEntry, 0, block.TextureEntry.Length);
prim.TextureAnim = new Primitive.TextureAnimation(block.TextureAnim, 0);
- //block.JointType ?
- //block.JointPivot ?
- //block.JointAxisOrAnchor ?
prim.ParticleSys = new Primitive.ParticleSystem(block.PSBlock, 0);
prim.SetExtraParamsFromBytes(block.ExtraParams, 0);
- prim.Scale = block.Scale;
- //block.Flags ?
- prim.Flags = (LLObject.ObjectFlags)block.UpdateFlags;
- //block.ClickAction ?
- //block.Gain Sound-related
- //block.Sound Sound-related
- //block.Radius Sound-related
+
+ // Unknown
+ prim.GenericData = block.Data;
+
+ // Packed parameters
+ prim.CollisionPlane = collisionPlane;
+ prim.Position = position;
+ prim.Velocity = velocity;
+ prim.Acceleration = acceleration;
+ prim.Rotation = rotation;
+ prim.AngularVelocity = angularVelocity;
if (prim.NameValue.StartsWith("AttachItemID"))
{
@@ -998,12 +1125,16 @@ namespace libsecondlife
// Update some internals if this is our avatar
if (block.FullID == Client.Network.AgentID)
{
- // Update our current position information
+ // Interesting to know
Client.Self.LocalID = block.ID;
- //avatar.CollisionPlane = new LLQuaternion(block.ObjectData, 0);
- Client.Self.Position = new LLVector3(block.ObjectData, 16);
- Client.Self.Rotation = new LLQuaternion(block.ObjectData, 52, true);
- // TODO: Parse the rest of the ObjectData byte array fields
+
+ // Packed parameters
+ Client.Self.CollisionPlane = collisionPlane;
+ Client.Self.Position = position;
+ Client.Self.Velocity = velocity;
+ Client.Self.Acceleration = acceleration;
+ Client.Self.Rotation = rotation;
+ Client.Self.AngularVelocity = angularVelocity;
// Detect if we are sitting or standing
uint oldSittingOn = Client.Self.SittingOn;
@@ -1020,36 +1151,55 @@ namespace libsecondlife
{
Avatar avatar = new Avatar();
+ avatar.ID = block.FullID;
+ avatar.LocalID = block.ID;
+
+ // TODO: This will probably change with the NameValue parsing
string FirstName = String.Empty;
string LastName = String.Empty;
string GroupName = String.Empty;
- //avatar.CollisionPlane = new LLQuaternion(block.ObjectData, 0);
- avatar.Position = new LLVector3(block.ObjectData, 16);
- avatar.Rotation = new LLQuaternion(block.ObjectData, 52, true);
- // TODO: Parse the rest of the ObjectData byte array fields
+ // Packed parameters
+ avatar.CollisionPlane = collisionPlane;
+ avatar.Position = position;
+ avatar.Velocity = velocity;
+ avatar.Acceleration = acceleration;
+ avatar.Rotation = rotation;
+ avatar.AngularVelocity = angularVelocity;
SetAvatarSittingOn(avatar, block.ParentID);
+ // Object parameters
+ avatar.data = data;
+
+ // Unknown
+ avatar.GenericData = block.Data;
+
+ // TODO: Replace this
ParseAvName(Helpers.FieldToString(block.NameValue), ref FirstName, ref LastName, ref GroupName);
- avatar.ID = block.FullID;
- avatar.LocalID = block.ID;
+ // Basic vitals
avatar.Name = FirstName + " " + LastName;
avatar.GroupName = GroupName;
avatar.Online = true;
avatar.CurrentRegion = simulator.Region;
+ // Texutres
avatar.Textures = new Primitive.TextureEntry(block.TextureEntry, 0, block.TextureEntry.Length);
FireOnNewAvatar(simulator, avatar, update.RegionData.RegionHandle, update.RegionData.TimeDilation);
}
+
break;
case (byte)PCode.ParticleSystem:
// FIXME: Handle ParticleSystem
Client.DebugLog("Got an ObjectUpdate block with a ParticleSystem PCode");
+
break;
default:
+ Client.DebugLog("Got an ObjectUpdate block with an unrecognized PCode " +
+ ((PCode)pcode).ToString());
+
break;
}
}
@@ -1063,120 +1213,68 @@ namespace libsecondlife
///
protected void TerseUpdateHandler(Packet packet, Simulator simulator)
{
- float x, y, z, w;
- uint localid;
- LLVector4 CollisionPlane = LLVector4.Zero;
- LLVector3 Position;
- LLVector3 Velocity;
- LLVector3 Acceleration;
- LLQuaternion Rotation;
- LLVector3 RotationVelocity;
-
- ImprovedTerseObjectUpdatePacket update = (ImprovedTerseObjectUpdatePacket)packet;
-
- UpdateDilation(simulator, update.RegionData.TimeDilation);
+ ImprovedTerseObjectUpdatePacket terse = (ImprovedTerseObjectUpdatePacket)packet;
+ UpdateDilation(simulator, terse.RegionData.TimeDilation);
- foreach (ImprovedTerseObjectUpdatePacket.ObjectDataBlock block in update.ObjectData)
+ foreach (ImprovedTerseObjectUpdatePacket.ObjectDataBlock block in terse.ObjectData)
{
- int i = 0;
- bool avatar;
-
- localid = (uint)(block.Data[i++] + (block.Data[i++] << 8) +
- (block.Data[i++] << 16) + (block.Data[i++] << 24));
-
- byte state = block.Data[i++];
-
- avatar = Convert.ToBoolean(block.Data[i++]);
-
- if (avatar)
+ try
{
- if (OnAvatarMoved == null) return;
+ ObjectUpdate update = new ObjectUpdate();
+ int pos = 0;
- CollisionPlane = new LLVector4(block.Data, i);
- i += 16;
- }
- else
- {
- if (OnPrimMoved == null) return;
- }
-
- // Position
- Position = new LLVector3(block.Data, i);
- i += 12;
- // Velocity
- x = Dequantize(block.Data, i, -128.0F, 128.0F);
- i += 2;
- y = Dequantize(block.Data, i, -128.0F, 128.0F);
- i += 2;
- z = Dequantize(block.Data, i, -128.0F, 128.0F);
- i += 2;
- Velocity = new LLVector3(x, y, z);
- // Acceleration
- x = Dequantize(block.Data, i, -64.0F, 64.0F);
- i += 2;
- y = Dequantize(block.Data, i, -64.0F, 64.0F);
- i += 2;
- z = Dequantize(block.Data, i, -64.0F, 64.0F);
- i += 2;
- Acceleration = new LLVector3(x, y, z);
- // Rotation
- x = Dequantize(block.Data, i, -1.0F, 1.0F);
- i += 2;
- y = Dequantize(block.Data, i, -1.0F, 1.0F);
- i += 2;
- z = Dequantize(block.Data, i, -1.0F, 1.0F);
- i += 2;
- w = Dequantize(block.Data, i, -1.0F, 1.0F);
- i += 2;
- Rotation = new LLQuaternion(x, y, z, w);
- // Rotation velocity
- x = Dequantize(block.Data, i, -64.0F, 64.0F);
- i += 2;
- y = Dequantize(block.Data, i, -64.0F, 64.0F);
- i += 2;
- z = Dequantize(block.Data, i, -64.0F, 64.0F);
- i += 2;
- RotationVelocity = new LLVector3(x, y, z);
-
- if (avatar)
- {
- if (localid == Client.Self.LocalID)
+ // Local ID
+ update.LocalID = Helpers.BytesToUIntBig(block.Data, pos);
+ pos += 4;
+ // State
+ update.State = block.Data[pos++];
+ // Avatar boolean
+ update.Avatar = (block.Data[pos++] != 0);
+ // Collision normal for avatar
+ if (update.Avatar)
{
- Client.Self.Position = Position;
- Client.Self.Rotation = Rotation;
+ update.CollisionPlane = new LLVector4(block.Data, pos);
+ pos += 16;
}
+ // Position
+ update.Position = new LLVector3(block.Data, pos);
+ pos += 12;
+ // Velocity
+ update.Velocity = new LLVector3(
+ Helpers.UInt16ToFloat(block.Data, pos, -128.0f, 128.0f),
+ Helpers.UInt16ToFloat(block.Data, pos + 2, -128.0f, 128.0f),
+ Helpers.UInt16ToFloat(block.Data, pos + 4, -128.0f, 128.0f));
+ pos += 6;
+ // Acceleration
+ update.Velocity = new LLVector3(
+ Helpers.UInt16ToFloat(block.Data, pos, -64.0f, 64.0f),
+ Helpers.UInt16ToFloat(block.Data, pos + 2, -64.0f, 64.0f),
+ Helpers.UInt16ToFloat(block.Data, pos + 4, -64.0f, 64.0f));
+ pos += 6;
+ // Rotation (theta)
+ update.Rotation = new LLQuaternion(
+ Helpers.UInt16ToFloat(block.Data, pos, -1.0f, 1.0f),
+ Helpers.UInt16ToFloat(block.Data, pos + 2, -1.0f, 1.0f),
+ Helpers.UInt16ToFloat(block.Data, pos + 4, -1.0f, 1.0f),
+ Helpers.UInt16ToFloat(block.Data, pos + 8, -1.0f, 1.0f));
+ pos += 8;
+ // Angular velocity
+ update.AngularVelocity = new LLVector3(
+ Helpers.UInt16ToFloat(block.Data, pos, -64.0f, 64.0f),
+ Helpers.UInt16ToFloat(block.Data, pos + 2, -64.0f, 64.0f),
+ Helpers.UInt16ToFloat(block.Data, pos + 4, -64.0f, 64.0f));
+ pos += 6;
- AvatarUpdate avupdate = new AvatarUpdate();
- avupdate.LocalID = localid;
- avupdate.State = state;
- avupdate.Position = Position;
- avupdate.CollisionPlane = CollisionPlane;
- avupdate.Velocity = Velocity;
- avupdate.Acceleration = Acceleration;
- avupdate.Rotation = Rotation;
- avupdate.RotationVelocity = RotationVelocity;
- avupdate.Textures = new Primitive.TextureEntry(block.TextureEntry, 4, block.TextureEntry.Length - 4);
+ // Textures
+ // FIXME: Why are we ignoring the first four bytes here?
+ update.Textures = new LLObject.TextureEntry(block.TextureEntry, 4, block.TextureEntry.Length - 4);
- FireOnAvatarMoved(simulator, avupdate, update.RegionData.RegionHandle, update.RegionData.TimeDilation);
+ // Fire the callback
+ FireOnObjectUpdated(simulator, update, terse.RegionData.RegionHandle, terse.RegionData.TimeDilation);
}
- else
+ catch (Exception e)
{
- // TODO: Is there an easy way to distinguish prims from trees in this packet,
- // or would the client have to do it's own lookup to determine whether it's a
- // prim or a tree? If the latter, we should rename this update to something
- // less prim specific
-
- PrimUpdate primupdate = new PrimUpdate();
- primupdate.LocalID = localid;
- primupdate.State = state;
- primupdate.Position = Position;
- primupdate.Velocity = Velocity;
- primupdate.Acceleration = Acceleration;
- primupdate.Rotation = Rotation;
- primupdate.RotationVelocity = RotationVelocity;
- primupdate.Textures = new Primitive.TextureEntry(block.TextureEntry, 4, block.TextureEntry.Length - 4);
-
- FireOnPrimMoved(simulator, primupdate, update.RegionData.RegionHandle, update.RegionData.TimeDilation);
+ Client.Log(e.ToString(), Helpers.LogLevel.Warning);
}
}
}
@@ -1208,30 +1306,35 @@ namespace libsecondlife
(block.Data[i++] << 16) + (block.Data[i++] << 24));
byte pcode = block.Data[i++];
- if (pcode == (byte)PCode.Prim)
+ if (pcode == (byte)PCode.Prim || pcode == (byte)PCode.Grass || pcode == (byte)PCode.Tree ||
+ pcode == (byte)PCode.NewTree)
{
#region Prim
- prim.State = (uint)block.Data[i++];
- i += 4; // CRC
- prim.Material = (uint)block.Data[i++];
- i++; // TODO: ClickAction
+ // State
+ prim.data.State = (uint)block.Data[i++];
+ // CRC
+ i += 4;
+ // Material
+ prim.data.Material = (uint)block.Data[i++];
+ // Click action
+ prim.ClickAction = block.Data[i++];
+ // Scale
prim.Scale = new LLVector3(block.Data, i);
i += 12;
+ // Position
prim.Position = new LLVector3(block.Data, i);
i += 12;
+ // Rotation
prim.Rotation = new LLQuaternion(block.Data, i, true);
i += 12;
-
- int flagsValue = (int)block.Data[i++] + (int)(block.Data[i++] << 8) +
- (int)(block.Data[i++] << 16) + (int)(block.Data[i++] << 24);
- CompressedFlags flags = (CompressedFlags)flagsValue;
+ // Compressed flags
+ CompressedFlags flags = (CompressedFlags)Helpers.BytesToUIntBig(block.Data, i);
+ i += 4;
if ((flags & CompressedFlags.Tree) != 0)
{
- // FIXME: I don't think this is even Tree data, as it would have
- // a different PCode. Figure out what this flag is and how to
- // decode it
+ // FIXME: Decode the tree data
byte Unknown1 = block.Data[i++];
byte Unknown2 = block.Data[i++];
@@ -1251,8 +1354,7 @@ namespace libsecondlife
if ((flags & CompressedFlags.HasAngularVelocity) != 0)
{
- // TODO: Use this
- LLVector3 Omega = new LLVector3(block.Data, i);
+ prim.AngularVelocity = new LLVector3(block.Data, i);
i += 12;
}
@@ -1261,14 +1363,17 @@ namespace libsecondlife
string text = String.Empty;
while (block.Data[i] != 0)
{
+ // TODO: Make this UTF8 compliant?
text += (char)block.Data[i];
i++;
}
i++;
+ // Floating text
prim.Text = text;
- // TODO: Text color
+ // Text color
+ prim.TextColor = new LLColor(block.Data, i);
i += 4;
}
else
@@ -1287,10 +1392,9 @@ namespace libsecondlife
//Sound data
if ((flags & CompressedFlags.HasSound) != 0)
{
- //TODO: use this data
- LLUUID SoundUUID = new LLUUID(block.Data, i);
+ prim.Sound = new LLUUID(block.Data, i);
i += 16;
- LLUUID OwnerUUID = new LLUUID(block.Data, i);
+ prim.OwnerID = new LLUUID(block.Data, i);
i += 16;
if (!BitConverter.IsLittleEndian)
@@ -1299,64 +1403,64 @@ namespace libsecondlife
Array.Reverse(block.Data, i + 5, 4);
}
- float SoundGain = BitConverter.ToSingle(block.Data, i);
+ prim.SoundGain = BitConverter.ToSingle(block.Data, i);
i += 4;
- byte SoundFlags = block.Data[i++];
- float SoundRadius = BitConverter.ToSingle(block.Data, i);
+ prim.SoundFlags = block.Data[i++];
+ prim.SoundRadius = BitConverter.ToSingle(block.Data, i);
i += 4;
}
- // Indicates that this is an attachment
- if ((flags & CompressedFlags.Attachment) != 0)
+ if ((flags & CompressedFlags.HasNameValues) != 0)
{
- // Get the attachment string
- // Example: "AttachItemID STRING RW SV fa9a5ab8-1bad-b449-9873-cf5b803e664e"
string text = String.Empty;
while (block.Data[i] != 0)
{
+ // TODO: Make UTF-8 compliant?
text += (char)block.Data[i];
i++;
}
i++;
+ // FIXME: Parse the NameValue pairs
+
prim.NameValue = text;
}
- if ((flags & CompressedFlags.Unknown1) != 0)
+ if ((flags & CompressedFlags.ScratchPad) != 0)
{
- // TODO: Is this even a valid flag?
- Client.DebugLog("Compressed object with Unknown1 flag set: " + Environment.NewLine +
+ // TODO: What is this?
+ Client.DebugLog("Compressed object with ScratchPad flag set: " + Environment.NewLine +
"Flags: " + flags.ToString() + Environment.NewLine +
Helpers.FieldToString(block.Data));
}
- if ((flags & CompressedFlags.Unknown2) != 0)
+ if ((flags & CompressedFlags.Unknown) != 0)
{
- // FIXME: Implement CompressedFlags.Unknown2
- //Client.DebugLog("Compressed object with Unknown2 flag set: " + Environment.NewLine +
- // "Flags: " + flags.ToString() + Environment.NewLine +
- // Helpers.FieldToString(block.Data));
+ // TODO: Implement CompressedFlags.Unknown2
+ Client.DebugLog("Compressed object with Unknown flag set: " + Environment.NewLine +
+ "Flags: " + flags.ToString() + Environment.NewLine +
+ Helpers.FieldToString(block.Data));
}
- prim.PathCurve = (uint)block.Data[i++];
- prim.PathBegin = LLObject.PathBeginFloat(block.Data[i++]);
- prim.PathEnd = LLObject.PathEndFloat(block.Data[i++]);
- prim.PathScaleX = LLObject.PathScaleFloat(block.Data[i++]);
- prim.PathScaleY = LLObject.PathScaleFloat(block.Data[i++]);
- prim.PathShearX = LLObject.PathShearFloat(block.Data[i++]);
- prim.PathShearY = LLObject.PathShearFloat(block.Data[i++]);
- prim.PathTwist = (int)block.Data[i++];
- prim.PathTwistBegin = (int)block.Data[i++];
- prim.PathRadiusOffset = LLObject.PathRadiusOffsetFloat((sbyte)block.Data[i++]);
- prim.PathTaperX = LLObject.PathTaperFloat((sbyte)block.Data[i++]);
- prim.PathTaperY = LLObject.PathTaperFloat((sbyte)block.Data[i++]);
- prim.PathRevolutions = LLObject.PathRevolutionsFloat(block.Data[i++]);
- prim.PathSkew = LLObject.PathSkewFloat((sbyte)block.Data[i++]);
+ prim.data.PathCurve = (uint)block.Data[i++];
+ prim.data.PathBegin = LLObject.PathBeginFloat(block.Data[i++]);
+ prim.data.PathEnd = LLObject.PathEndFloat(block.Data[i++]);
+ prim.data.PathScaleX = LLObject.PathScaleFloat(block.Data[i++]);
+ prim.data.PathScaleY = LLObject.PathScaleFloat(block.Data[i++]);
+ prim.data.PathShearX = LLObject.PathShearFloat(block.Data[i++]);
+ prim.data.PathShearY = LLObject.PathShearFloat(block.Data[i++]);
+ prim.data.PathTwist = (int)block.Data[i++];
+ prim.data.PathTwistBegin = (int)block.Data[i++];
+ prim.data.PathRadiusOffset = LLObject.PathRadiusOffsetFloat((sbyte)block.Data[i++]);
+ prim.data.PathTaperX = LLObject.PathTaperFloat((sbyte)block.Data[i++]);
+ prim.data.PathTaperY = LLObject.PathTaperFloat((sbyte)block.Data[i++]);
+ prim.data.PathRevolutions = LLObject.PathRevolutionsFloat(block.Data[i++]);
+ prim.data.PathSkew = LLObject.PathSkewFloat((sbyte)block.Data[i++]);
- prim.ProfileCurve = (uint)block.Data[i++];
- prim.ProfileBegin = Primitive.ProfileBeginFloat(block.Data[i++]);
- prim.ProfileEnd = Primitive.ProfileEndFloat(block.Data[i++]);
- prim.ProfileHollow = (uint)block.Data[i++];
+ prim.data.ProfileCurve = (uint)block.Data[i++];
+ prim.data.ProfileBegin = Primitive.ProfileBeginFloat(block.Data[i++]);
+ prim.data.ProfileEnd = Primitive.ProfileEndFloat(block.Data[i++]);
+ prim.data.ProfileHollow = (uint)block.Data[i++];
int textureEntryLength = (int)(block.Data[i++] + (block.Data[i++] << 8) +
(block.Data[i++] << 16) + (block.Data[i++] << 24));
@@ -1375,8 +1479,9 @@ namespace libsecondlife
}
// Fire the appropriate callback
- if ((flags & CompressedFlags.Attachment) != 0)
+ if ((flags & CompressedFlags.HasNameValues) != 0)
{
+ // TODO: We should use a better check to see if this is actually an attachment
FireOnNewAttachment(simulator, prim, update.RegionData.RegionHandle, update.RegionData.TimeDilation);
}
else if ((flags & CompressedFlags.Tree) != 0)
@@ -1387,13 +1492,9 @@ namespace libsecondlife
{
FireOnNewPrim(simulator, prim, update.RegionData.RegionHandle, update.RegionData.TimeDilation);
}
+
#endregion Prim
}
- else if (pcode == (byte)PCode.Grass || pcode == (byte)PCode.Tree || pcode == (byte)PCode.NewTree)
- {
- // FIXME: Implement this
- //Client.DebugLog("######### Got an ObjectUpdateCompressed for grass/tree, implement this! #########");
- }
else
{
Client.Log("######### Got an ObjectUpdateCompressed for PCode=" + pcode.ToString() +
@@ -1592,20 +1693,11 @@ namespace libsecondlife
}
}
- protected void FireOnPrimMoved(Simulator simulator, PrimUpdate primupdate, ulong RegionHandle, ushort TimeDilation)
+ protected void FireOnObjectUpdated(Simulator simulator, ObjectUpdate update, ulong RegionHandle, ushort TimeDilation)
{
- if (OnPrimMoved != null)
+ if (OnObjectUpdated != null)
{
- try { OnPrimMoved(simulator, primupdate, RegionHandle, TimeDilation); }
- catch (Exception e) { Client.Log(e.ToString(), Helpers.LogLevel.Error); }
- }
- }
-
- protected void FireOnAvatarMoved(Simulator simulator, AvatarUpdate avupdate, ulong RegionHandle, ushort TimeDilation)
- {
- if (OnAvatarMoved != null)
- {
- try { OnAvatarMoved(simulator, avupdate, RegionHandle, TimeDilation); }
+ try { OnObjectUpdated(simulator, update, RegionHandle, TimeDilation); }
catch (Exception e) { Client.Log(e.ToString(), Helpers.LogLevel.Error); }
}
}
diff --git a/libsecondlife-cs/Prims.cs b/libsecondlife-cs/Prims.cs
index e009375d..0252ca15 100644
--- a/libsecondlife-cs/Prims.cs
+++ b/libsecondlife-cs/Prims.cs
@@ -48,6 +48,25 @@ namespace libsecondlife
Light = 0x20
}
+ ///
+ ///
+ ///
+ public enum JointType : byte
+ {
+ ///
+ Invalid = 0,
+ ///
+ Hinge = 1,
+ ///
+ Point = 2,
+ ///
+ [Obsolete]
+ LPoint = 3,
+ ///
+ [Obsolete]
+ Wheel = 4
+ }
+
#region Subclasses
@@ -229,8 +248,31 @@ namespace libsecondlife
public LightData Light = new LightData();
///
public ParticleSystem ParticleSys = new ParticleSystem();
+ ///
+ public byte ClickAction;
+ ///
+ public LLUUID Sound = LLUUID.Zero;
+ /// Identifies the owner of the audio or particle system
+ public LLUUID OwnerID = LLUUID.Zero;
+ ///
+ public byte SoundFlags;
+ ///
+ public float SoundGain;
+ ///
+ public float SoundRadius;
+ ///
+ public string Text;
+ ///
+ public LLColor TextColor;
+ ///
+ public string MediaURL;
+ public JointType Joint;
+ public LLVector3 JointPivot;
+ public LLVector3 JointAxisOrAnchor;
-
+ ///
+ /// Default constructor
+ ///
public Primitive()
{
}
@@ -280,9 +322,9 @@ namespace libsecondlife
output += "ParentID: " + ParentID + ", ";
output += "LocalID: " + LocalID + ", ";
output += "Flags: " + Flags + ", ";
- output += "State: " + State + ", ";
- output += "PCode: " + PCode + ", ";
- output += "Material: " + Material + ", ";
+ output += "State: " + data.State + ", ";
+ output += "PCode: " + data.PCode + ", ";
+ output += "Material: " + data.Material + ", ";
return output;
}
diff --git a/libsecondlife-cs/examples/TestClient/Commands/ImportCommand.cs b/libsecondlife-cs/examples/TestClient/Commands/ImportCommand.cs
index 063c0bd1..08c2fa4d 100644
--- a/libsecondlife-cs/examples/TestClient/Commands/ImportCommand.cs
+++ b/libsecondlife-cs/examples/TestClient/Commands/ImportCommand.cs
@@ -124,7 +124,8 @@ namespace libsecondlife.TestClient
rezzingRootPrim = true;
currentPrim = linkset.RootPrim;
- Client.Objects.AddPrim(Client.Network.CurrentSim, linkset.RootPrim, linkset.RootPrim.Position);
+ Client.Objects.AddPrim(Client.Network.CurrentSim, linkset.RootPrim.Data, LLUUID.Zero,
+ linkset.RootPrim.Position, linkset.RootPrim.Scale, linkset.RootPrim.Rotation);
if (!primDone.WaitOne(10000, false))
return "Rez failed, timed out while creating a prim.";
@@ -138,7 +139,8 @@ namespace libsecondlife.TestClient
currentPrim = prim;
currentPosition = prim.Position + linkset.RootPrim.Position;
- Client.Objects.AddPrim(Client.Network.CurrentSim, prim, currentPosition);
+ Client.Objects.AddPrim(Client.Network.CurrentSim, prim.Data, LLUUID.Zero,
+ currentPosition, prim.Scale, prim.Rotation);
if (!primDone.WaitOne(10000, false))
return "Rez failed, timed out while creating a prim.";
diff --git a/libsecondlife-cs/examples/TestClient/TestClient.cs b/libsecondlife-cs/examples/TestClient/TestClient.cs
index 1220644b..7f48e419 100644
--- a/libsecondlife-cs/examples/TestClient/TestClient.cs
+++ b/libsecondlife-cs/examples/TestClient/TestClient.cs
@@ -53,10 +53,9 @@ namespace libsecondlife.TestClient
Network.RegisterCallback(PacketType.AgentDataUpdate, new NetworkManager.PacketCallback(AgentDataUpdateHandler));
Objects.OnNewPrim += new ObjectManager.NewPrimCallback(Objects_OnNewPrim);
- Objects.OnPrimMoved += new ObjectManager.PrimMovedCallback(Objects_OnPrimMoved);
+ Objects.OnObjectUpdated += new ObjectManager.ObjectUpdatedCallback(Objects_OnObjectUpdated);
Objects.OnObjectKilled += new ObjectManager.KillObjectCallback(Objects_OnObjectKilled);
Objects.OnNewAvatar += new ObjectManager.NewAvatarCallback(Objects_OnNewAvatar);
- Objects.OnAvatarMoved += new ObjectManager.AvatarMovedCallback(Objects_OnAvatarMoved);
Self.OnInstantMessage += new MainAvatar.InstantMessageCallback(Self_OnInstantMessage);
this.OnLogMessage += new LogCallback(TestClient_OnLogMessage);
@@ -203,14 +202,41 @@ namespace libsecondlife.TestClient
}
}
- private void Objects_OnPrimMoved(Simulator simulator, PrimUpdate prim, ulong regionHandle, ushort timeDilation)
+ private void Objects_OnObjectUpdated(Simulator simulator, ObjectUpdate update, ulong regionHandle, ushort timeDilation)
{
- lock (SimPrims)
+ regionX = (int)(regionHandle >> 32);
+ regionY = (int)(regionHandle & 0xFFFFFFFF);
+
+ if (update.Avatar)
{
- if (SimPrims.ContainsKey(simulator) && SimPrims[simulator].ContainsKey(prim.LocalID))
+ lock (AvatarList)
{
- SimPrims[simulator][prim.LocalID].Position = prim.Position;
- SimPrims[simulator][prim.LocalID].Rotation = prim.Rotation;
+ // TODO: We really need a solid avatar and object tracker in Utilities to use here
+ if (AvatarList.ContainsKey(update.LocalID))
+ {
+ AvatarList[update.LocalID].CollisionPlane = update.CollisionPlane;
+ AvatarList[update.LocalID].Position = update.Position;
+ AvatarList[update.LocalID].Velocity = update.Velocity;
+ AvatarList[update.LocalID].Acceleration = update.Acceleration;
+ AvatarList[update.LocalID].Rotation = update.Rotation;
+ AvatarList[update.LocalID].AngularVelocity = update.AngularVelocity;
+ AvatarList[update.LocalID].Textures = update.Textures;
+ }
+ }
+ }
+ else
+ {
+ lock (SimPrims)
+ {
+ if (SimPrims.ContainsKey(simulator) && SimPrims[simulator].ContainsKey(update.LocalID))
+ {
+ SimPrims[simulator][update.LocalID].Position = update.Position;
+ SimPrims[simulator][update.LocalID].Velocity = update.Velocity;
+ SimPrims[simulator][update.LocalID].Acceleration = update.Acceleration;
+ SimPrims[simulator][update.LocalID].Rotation = update.Rotation;
+ SimPrims[simulator][update.LocalID].AngularVelocity = update.AngularVelocity;
+ SimPrims[simulator][update.LocalID].Textures = update.Textures;
+ }
}
}
}
@@ -241,20 +267,6 @@ namespace libsecondlife.TestClient
}
}
- private void Objects_OnAvatarMoved(Simulator simulator, AvatarUpdate avatar, ulong regionHandle, ushort timeDilation)
- {
- regionX = (int)(regionHandle >> 32);
- regionY = (int)(regionHandle & 0xFFFFFFFF);
- lock (AvatarList)
- {
- if (AvatarList.ContainsKey(avatar.LocalID))
- {
- AvatarList[avatar.LocalID].Position = avatar.Position;
- AvatarList[avatar.LocalID].Rotation = avatar.Rotation;
- }
- }
- }
-
private void AvatarAppearanceHandler(Packet packet, Simulator simulator)
{
AvatarAppearancePacket appearance = (AvatarAppearancePacket)packet;
diff --git a/libsecondlife-cs/examples/primexport/frmPrimExport.cs b/libsecondlife-cs/examples/primexport/frmPrimExport.cs
index b8c7abd3..b3c36653 100644
--- a/libsecondlife-cs/examples/primexport/frmPrimExport.cs
+++ b/libsecondlife-cs/examples/primexport/frmPrimExport.cs
@@ -443,7 +443,9 @@ namespace primexport
output += "" + Environment.NewLine +
"" + Environment.NewLine;
- switch (prim.ProfileCurve + prim.PathCurve)
+ LLObject.ObjectData data = prim.Data;
+
+ switch (data.ProfileCurve + data.PathCurve)
{
case 17:
// PRIM_TYPE_BOX
@@ -475,7 +477,7 @@ namespace primexport
break;
default:
Log("Not exporting an unhandled prim, ProfileCurve=" +
- prim.ProfileCurve + ", PathCurve=" + prim.PathCurve + Environment.NewLine);
+ data.ProfileCurve + ", PathCurve=" + data.PathCurve + Environment.NewLine);
continue;
}
@@ -493,27 +495,27 @@ namespace primexport
if (type == 1)
{
- output += "" + Environment.NewLine;
- output += "" + Environment.NewLine;
+ output += "" + Environment.NewLine;
+ output += "" + Environment.NewLine;
}
else
{
- output += "" + Environment.NewLine;
- output += "" + Environment.NewLine;
+ output += "" + Environment.NewLine;
+ output += "" + Environment.NewLine;
}
- output += "" + Environment.NewLine;
- output += "" + Environment.NewLine;
- output += "" + Environment.NewLine;
- output += "" + Environment.NewLine;
- output += "" + Environment.NewLine;
- output += "" + Environment.NewLine;
- output += "" + Environment.NewLine;
- output += "" + Environment.NewLine;
- output += "" + Environment.NewLine;
- output += "" + Environment.NewLine;
- output += "" + Environment.NewLine;
+ output += "" + Environment.NewLine;
+ output += "" + Environment.NewLine;
+ output += "" + Environment.NewLine;
+ output += "" + Environment.NewLine;
+ output += "" + Environment.NewLine;
+ output += "" + Environment.NewLine;
+ output += "" + Environment.NewLine;
+ output += "" + Environment.NewLine;
+ output += "" + Environment.NewLine;
+ output += "" + Environment.NewLine;
+ output += "" + Environment.NewLine;
// FIXME: Hollowshape. 16-21 = circle, 32-37 = square, 48-53 = triangle
output += "" + Environment.NewLine;
diff --git a/libsecondlife-cs/libsecondlife.Utilities/Utilities.cs b/libsecondlife-cs/libsecondlife.Utilities/Utilities.cs
index d82c5928..dc4fe05f 100644
--- a/libsecondlife-cs/libsecondlife.Utilities/Utilities.cs
+++ b/libsecondlife-cs/libsecondlife.Utilities/Utilities.cs
@@ -156,7 +156,7 @@ namespace libsecondlife.Utilities
Client.Avatars.OnAvatarGroups += new AvatarManager.AvatarGroupsCallback(Avatars_OnAvatarGroups);
Client.Objects.OnNewAvatar += new ObjectManager.NewAvatarCallback(Objects_OnNewAvatar);
- Client.Objects.OnAvatarMoved += new ObjectManager.AvatarMovedCallback(Objects_OnAvatarMoved);
+ Client.Objects.OnObjectUpdated += new ObjectManager.ObjectUpdatedCallback(Objects_OnObjectUpdated);
}
///
@@ -359,17 +359,14 @@ namespace libsecondlife.Utilities
}
}
- void Objects_OnAvatarMoved(Simulator simulator, AvatarUpdate avatar, ulong regionHandle, ushort timeDilation)
+ void Objects_OnNewAvatar(Simulator simulator, Avatar avatar, ulong regionHandle, ushort timeDilation)
{
// TODO:
}
- void Objects_OnNewAvatar(Simulator simulator, Avatar avatar, ulong regionHandle, ushort timeDilation)
+ void Objects_OnObjectUpdated(Simulator simulator, ObjectUpdate update, ulong regionHandle, ushort timeDilation)
{
- lock (avatars)
- {
- avatars[avatar.ID] = avatar;
- }
+ // TODO:
}
private void Avatars_OnAvatarNames(Dictionary names)