diff --git a/libsecondlife-cs/NetworkManager.cs b/libsecondlife-cs/NetworkManager.cs
index 8ca3eef2..1cb7a617 100644
--- a/libsecondlife-cs/NetworkManager.cs
+++ b/libsecondlife-cs/NetworkManager.cs
@@ -722,7 +722,7 @@ namespace libsecondlife
///
public void SendPacket(Packet packet, Simulator simulator)
{
- if (simulator.Connected)
+ if (simulator != null && simulator.Connected)
{
simulator.SendPacket(packet, true);
}
@@ -1282,6 +1282,13 @@ namespace libsecondlife
private void DisconnectTimer_Elapsed(object sender, ElapsedEventArgs ev)
{
+ if (CurrentSim == null)
+ {
+ DisconnectTimer.Stop();
+ connected = false;
+ return;
+ }
+
// If the current simulator is disconnected, shutdown+callback+return
if (CurrentSim.DisconnectCandidate)
{
diff --git a/libsecondlife-cs/ObjectManager.cs b/libsecondlife-cs/ObjectManager.cs
index 559de154..0637a2d9 100644
--- a/libsecondlife-cs/ObjectManager.cs
+++ b/libsecondlife-cs/ObjectManager.cs
@@ -77,11 +77,11 @@ namespace libsecondlife
public LLVector3 RotationVelocity;
}
- ///
- /// Handles all network traffic related to prims and avatar positions and
+ ///
+ /// Handles all network traffic related to prims and avatar positions and
/// movement.
- ///
- public class ObjectManager
+ ///
+ public class ObjectManager
{
///
///
@@ -90,7 +90,7 @@ namespace libsecondlife
///
///
///
- public delegate void NewPrimCallback(Simulator simulator, PrimObject prim, ulong regionHandle,
+ public delegate void NewPrimCallback(Simulator simulator, PrimObject prim, ulong regionHandle,
ushort timeDilation);
///
///
@@ -99,7 +99,7 @@ namespace libsecondlife
///
///
///
- public delegate void NewAvatarCallback(Simulator simulator, Avatar avatar, ulong regionHandle,
+ public delegate void NewAvatarCallback(Simulator simulator, Avatar avatar, ulong regionHandle,
ushort timeDilation);
///
///
@@ -108,7 +108,7 @@ namespace libsecondlife
///
///
///
- public delegate void PrimMovedCallback(Simulator simulator, PrimUpdate prim, ulong regionHandle,
+ public delegate void PrimMovedCallback(Simulator simulator, PrimUpdate prim, ulong regionHandle,
ushort timeDilation);
///
///
@@ -117,7 +117,7 @@ namespace libsecondlife
///
///
///
- public delegate void AvatarMovedCallback(Simulator simulator, AvatarUpdate avatar, ulong regionHandle,
+ public delegate void AvatarMovedCallback(Simulator simulator, AvatarUpdate avatar, ulong regionHandle,
ushort timeDilation);
///
///
@@ -167,6 +167,40 @@ namespace libsecondlife
Transfer = 0x00002000
}
+ public enum AttachmentPoint
+ {
+ Chest = 1,
+ Skull,
+ LeftShoulder,
+ RightShoulder,
+ LeftHand,
+ RightHand,
+ LeftFoot,
+ RightFoot,
+ Spine,
+ Pelvis,
+ Mouth,
+ Chin,
+ LeftEar,
+ RightEar,
+ LeftEyeball,
+ RightEyeball,
+ Nose,
+ RightUpperArm,
+ RightForarm,
+ LeftUpperArm,
+ LeftForearm,
+ RightHip,
+ RightUpperLeg,
+ RightLowerLeg,
+ LeftHip,
+ LeftUpperLeg,
+ LeftLowerLeg,
+ Stomach,
+ LeftPec,
+ RightPec
+ }
+
///
/// This event will be raised for every ObjectUpdate block that
/// contains a new prim.
@@ -388,116 +422,116 @@ namespace libsecondlife
foreach (ObjectUpdatePacket.ObjectDataBlock block in update.ObjectData)
{
- switch(block.PCode)
- {
- case (byte)PCode.Prim:
- if (OnNewPrim != null)
- {
- // New prim spotted
- PrimObject prim = new PrimObject(Client);
-
- 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.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 = PrimObject.PathBeginFloat(block.PathBegin);
- prim.PathEnd = PrimObject.PathEndFloat(block.PathEnd);
- prim.PathScaleX = PrimObject.PathScaleFloat(block.PathScaleX);
- prim.PathScaleY = PrimObject.PathScaleFloat(block.PathScaleY);
- prim.PathShearX = PrimObject.PathShearFloat(block.PathShearX);
- prim.PathShearY = PrimObject.PathShearFloat(block.PathShearY);
- prim.PathTwist = block.PathTwist; //PrimObject.PathTwistFloat(block.PathTwist);
- prim.PathTwistBegin = block.PathTwistBegin; //PrimObject.PathTwistFloat(block.PathTwistBegin);
- prim.PathRadiusOffset = PrimObject.PathRadiusOffsetFloat(block.PathRadiusOffset);
- prim.PathTaperX = PrimObject.PathTaperFloat(block.PathTaperX);
- prim.PathTaperY = PrimObject.PathTaperFloat(block.PathTaperY);
- prim.PathRevolutions = PrimObject.PathRevolutionsFloat(block.PathRevolutions);
- prim.PathSkew = PrimObject.PathSkewFloat(block.PathSkew);
- prim.ProfileBegin = PrimObject.ProfileBeginFloat(block.ProfileBegin);
- prim.ProfileEnd = PrimObject.ProfileEndFloat(block.ProfileEnd);
- prim.ProfileHollow = block.ProfileHollow;
- prim.Name = Helpers.FieldToString(block.NameValue);
- //block.Data ?
- prim.Text = ASCIIEncoding.ASCII.GetString(block.Text);
- //block.TextColor LLColor4U of the hovering text
- //block.MediaURL Quicktime stream
- prim.Textures = new TextureEntry(block.TextureEntry, 0, block.TextureEntry.Length);
- prim.TextureAnim = new TextureAnimation(block.TextureAnim, 0);
- //block.JointType ?
- //block.JointPivot ?
- //block.JointAxisOrAnchor ?
- prim.ParticleSys = new ParticleSystem(block.PSBlock, 0);
- prim.SetExtraParamsFromBytes(block.ExtraParams, 0);
- prim.Scale = block.Scale;
- //block.Flags ?
- prim.Flags = (ObjectFlags)block.UpdateFlags;
- //block.ClickAction ?
- //block.Gain Sound-related
- //block.Sound Sound-related
- //block.Radius Sound-related
-
+ switch (block.PCode)
+ {
+ case (byte)PCode.Prim:
if (OnNewPrim != null)
{
- OnNewPrim(simulator, prim, update.RegionData.RegionHandle, update.RegionData.TimeDilation);
- }
- }
- break;
- case (byte)PCode.Avatar:
- if (OnNewAvatar != null)
- {
- Avatar avatar = new Avatar();
+ // New prim spotted
+ PrimObject prim = new PrimObject(Client);
- string FirstName = "";
- string LastName = "";
- string GroupName = "";
+ prim.Position = new LLVector3(block.ObjectData, 0);
+ prim.Rotation = new LLQuaternion(block.ObjectData, 36, true);
- //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
- // TODO: Parse the rest of the ObjectData byte array fields
+ 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 = PrimObject.PathBeginFloat(block.PathBegin);
+ prim.PathEnd = PrimObject.PathEndFloat(block.PathEnd);
+ prim.PathScaleX = PrimObject.PathScaleFloat(block.PathScaleX);
+ prim.PathScaleY = PrimObject.PathScaleFloat(block.PathScaleY);
+ prim.PathShearX = PrimObject.PathShearFloat(block.PathShearX);
+ prim.PathShearY = PrimObject.PathShearFloat(block.PathShearY);
+ prim.PathTwist = block.PathTwist; //PrimObject.PathTwistFloat(block.PathTwist);
+ prim.PathTwistBegin = block.PathTwistBegin; //PrimObject.PathTwistFloat(block.PathTwistBegin);
+ prim.PathRadiusOffset = PrimObject.PathRadiusOffsetFloat(block.PathRadiusOffset);
+ prim.PathTaperX = PrimObject.PathTaperFloat(block.PathTaperX);
+ prim.PathTaperY = PrimObject.PathTaperFloat(block.PathTaperY);
+ prim.PathRevolutions = PrimObject.PathRevolutionsFloat(block.PathRevolutions);
+ prim.PathSkew = PrimObject.PathSkewFloat(block.PathSkew);
+ prim.ProfileBegin = PrimObject.ProfileBeginFloat(block.ProfileBegin);
+ prim.ProfileEnd = PrimObject.ProfileEndFloat(block.ProfileEnd);
+ prim.ProfileHollow = block.ProfileHollow;
+ prim.Name = Helpers.FieldToString(block.NameValue);
+ //block.Data ?
+ prim.Text = ASCIIEncoding.ASCII.GetString(block.Text);
+ //block.TextColor LLColor4U of the hovering text
+ //block.MediaURL Quicktime stream
+ prim.Textures = new TextureEntry(block.TextureEntry, 0, block.TextureEntry.Length);
+ prim.TextureAnim = new TextureAnimation(block.TextureAnim, 0);
+ //block.JointType ?
+ //block.JointPivot ?
+ //block.JointAxisOrAnchor ?
+ prim.ParticleSys = new ParticleSystem(block.PSBlock, 0);
+ prim.SetExtraParamsFromBytes(block.ExtraParams, 0);
+ prim.Scale = block.Scale;
+ //block.Flags ?
+ prim.Flags = (ObjectFlags)block.UpdateFlags;
+ //block.ClickAction ?
+ //block.Gain Sound-related
+ //block.Sound Sound-related
+ //block.Radius Sound-related
- ParseAvName(Helpers.FieldToString(block.NameValue), ref FirstName, ref LastName, ref GroupName);
-
- avatar.ID = block.FullID;
- avatar.LocalID = block.ID;
- avatar.Name = FirstName + " " + LastName;
- avatar.GroupName = GroupName;
- avatar.Online = true;
- avatar.CurrentRegion = simulator.Region;
-
- avatar.Textures = new TextureEntry(block.TextureEntry, 0, block.TextureEntry.Length);
-
- if (FirstName == Client.Self.FirstName && LastName == Client.Self.LastName)
- {
- // Update our avatar
- Client.Self.LocalID = avatar.LocalID;
- Client.Self.Position = avatar.Position;
- Client.Self.Rotation = avatar.Rotation;
- }
- else
- {
- if (OnNewAvatar != null)
+ if (OnNewPrim != null)
{
- OnNewAvatar(simulator, avatar, update.RegionData.RegionHandle, update.RegionData.TimeDilation);
+ OnNewPrim(simulator, prim, update.RegionData.RegionHandle, update.RegionData.TimeDilation);
}
}
- }
- break;
- case (byte)PCode.Grass: // FIXME: Handle grass objects
- case (byte)PCode.Tree: // FIXME: Handle trees
- case (byte)PCode.ParticleSystem: // FIXME: Handle ParticleSystem
- default:
- break;
+ break;
+ case (byte)PCode.Avatar:
+ if (OnNewAvatar != null)
+ {
+ Avatar avatar = new Avatar();
+
+ string FirstName = "";
+ string LastName = "";
+ string GroupName = "";
+
+ //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
+
+ ParseAvName(Helpers.FieldToString(block.NameValue), ref FirstName, ref LastName, ref GroupName);
+
+ avatar.ID = block.FullID;
+ avatar.LocalID = block.ID;
+ avatar.Name = FirstName + " " + LastName;
+ avatar.GroupName = GroupName;
+ avatar.Online = true;
+ avatar.CurrentRegion = simulator.Region;
+
+ avatar.Textures = new TextureEntry(block.TextureEntry, 0, block.TextureEntry.Length);
+
+ if (FirstName == Client.Self.FirstName && LastName == Client.Self.LastName)
+ {
+ // Update our avatar
+ Client.Self.LocalID = avatar.LocalID;
+ Client.Self.Position = avatar.Position;
+ Client.Self.Rotation = avatar.Rotation;
+ }
+ else
+ {
+ if (OnNewAvatar != null)
+ {
+ OnNewAvatar(simulator, avatar, update.RegionData.RegionHandle, update.RegionData.TimeDilation);
+ }
+ }
+ }
+ break;
+ case (byte)PCode.Grass: // FIXME: Handle grass objects
+ case (byte)PCode.Tree: // FIXME: Handle trees
+ case (byte)PCode.ParticleSystem: // FIXME: Handle ParticleSystem
+ default:
+ break;
}
}
}
@@ -521,7 +555,7 @@ namespace libsecondlife
int i = 0;
bool avatar;
- localid = (uint)(block.Data[i++] + (block.Data[i++] << 8) +
+ localid = (uint)(block.Data[i++] + (block.Data[i++] << 8) +
(block.Data[i++] << 16) + (block.Data[i++] << 24));
byte state = block.Data[i++];
@@ -817,7 +851,7 @@ namespace libsecondlife
}
catch (System.IndexOutOfRangeException e)
{
- Client.Log("Had a problem decoding an ObjectUpdateCompressed packet: " +
+ Client.Log("Had a problem decoding an ObjectUpdateCompressed packet: " +
e.ToString(), Helpers.LogLevel.Warning);
Client.Log(block.ToString(), Helpers.LogLevel.Warning);
}
diff --git a/libsecondlife-cs/Types.cs b/libsecondlife-cs/Types.cs
index 9799e71f..8b6de1b2 100644
--- a/libsecondlife-cs/Types.cs
+++ b/libsecondlife-cs/Types.cs
@@ -681,6 +681,22 @@ namespace libsecondlife
}
}
+ ///
+ /// Build a quaternion from normalized float values
+ ///
+ /// X value from -1.0 to 1.0
+ /// Y value from -1.0 to 1.0
+ /// Z value from -1.0 to 1.0
+ public LLQuaternion(float x, float y, float z)
+ {
+ X = x;
+ Y = y;
+ Z = z;
+
+ float xyzsum = 1 - X * X - Y * Y - Z * Z;
+ W = (xyzsum > 0) ? (float)Math.Sqrt(xyzsum) : 0;
+ }
+
///
///
///