diff --git a/libsecondlife/CapsEventQueue.cs b/libsecondlife/CapsEventQueue.cs
index 40d64436..9ac098a5 100644
--- a/libsecondlife/CapsEventQueue.cs
+++ b/libsecondlife/CapsEventQueue.cs
@@ -183,7 +183,7 @@ namespace libsecondlife
// We are connected to the event queue
_Running = true;
- Simulator.Client.Log("Capabilities event queue connected for " + Simulator.ToString(), Helpers.LogLevel.Info);
+ Simulator.Client.DebugLog("Capabilities event queue connected for " + Simulator.ToString());
}
try
diff --git a/libsecondlife/Helpers.cs b/libsecondlife/Helpers.cs
index 270f9070..e48e309a 100644
--- a/libsecondlife/Helpers.cs
+++ b/libsecondlife/Helpers.cs
@@ -722,6 +722,16 @@ namespace libsecondlife
return (float)Math.Sqrt(v.X * v.X + v.Y * v.Y + v.Z * v.Z);
}
+ ///
+ /// Calculate the squared magnitude of the supplied vector
+ ///
+ ///
+ ///
+ public static float VecMagSquared(LLVector3 v)
+ {
+ return v.X * v.X + v.Y * v.Y + v.Z * v.Z;
+ }
+
///
/// Calculate the magnitude of the supplied quaternion
///
diff --git a/libsecondlife/MainAvatar.cs b/libsecondlife/MainAvatar.cs
index 16c239ae..87958247 100644
--- a/libsecondlife/MainAvatar.cs
+++ b/libsecondlife/MainAvatar.cs
@@ -2127,7 +2127,7 @@ namespace libsecondlife
TeleportStat = TeleportStatus.Finished;
// Disconnect from the previous sim
- Client.Network.DisconnectSim(simulator);
+ Client.Network.DisconnectSim(simulator, true);
Client.Log("Moved to new sim " + newSimulator.ToString(), Helpers.LogLevel.Info);
}
diff --git a/libsecondlife/NetworkManager.cs b/libsecondlife/NetworkManager.cs
index 0d4114ef..bcd34127 100644
--- a/libsecondlife/NetworkManager.cs
+++ b/libsecondlife/NetworkManager.cs
@@ -140,6 +140,9 @@ namespace libsecondlife
/// An event for the connection to a simulator other than the currently
/// occupied one disconnecting
///
+ /// The Simulators list is locked when this event is
+ /// triggered, do not attempt to modify the collection or acquire a
+ /// lock on it when this callback is fired
public event SimDisconnectedCallback OnSimDisconnected;
///
/// An event for being logged out either through client request, server
@@ -204,6 +207,7 @@ namespace libsecondlife
RegisterCallback(PacketType.StartPingCheck, new PacketCallback(StartPingCheckHandler));
RegisterCallback(PacketType.ParcelOverlay, new PacketCallback(ParcelOverlayHandler));
RegisterCallback(PacketType.EnableSimulator, new PacketCallback(EnableSimulatorHandler));
+ RegisterCallback(PacketType.DisableSimulator, new PacketCallback(DisableSimulatorHandler));
RegisterCallback(PacketType.KickUser, new PacketCallback(KickUserHandler));
RegisterCallback(PacketType.LogoutReply, new PacketCallback(LogoutReplyHandler));
RegisterCallback(PacketType.CompletePingCheck, new PacketCallback(PongHandler));
@@ -456,11 +460,11 @@ namespace libsecondlife
///
///
///
- public void DisconnectSim(Simulator sim)
+ public void DisconnectSim(Simulator sim, bool sendCloseCircuit)
{
if (sim != null)
{
- sim.Disconnect();
+ sim.Disconnect(sendCloseCircuit);
// Fire the SimDisconnected event if a handler is registered
if (OnSimDisconnected != null)
@@ -641,6 +645,9 @@ namespace libsecondlife
{
Client.Log("NetworkManager shutdown initiated", Helpers.LogLevel.Info);
+ // Send a CloseCircuit packet to simulators if we are initiating the disconnect
+ bool sendCloseCircuit = (type == DisconnectType.ClientInitiated || type == DisconnectType.NetworkTimeout);
+
lock (Simulators)
{
// Disconnect all simulators except the current one
@@ -648,11 +655,9 @@ namespace libsecondlife
{
if (Simulators[i] != null && Simulators[i] != CurrentSim)
{
- Simulators[i].Disconnect();
+ Simulators[i].Disconnect(sendCloseCircuit);
// Fire the SimDisconnected event if a handler is registered
- // FIXME: This is a recipe for disaster, locking Simulators and
- // firing a callback
if (OnSimDisconnected != null)
{
try { OnSimDisconnected(Simulators[i], type); }
@@ -667,7 +672,7 @@ namespace libsecondlife
if (CurrentSim != null)
{
// Kill the connection to the curent simulator
- CurrentSim.Disconnect();
+ CurrentSim.Disconnect(sendCloseCircuit);
// Fire the SimDisconnected event if a handler is registered
if (OnSimDisconnected != null)
@@ -786,7 +791,7 @@ namespace libsecondlife
Client.Log("Network timeout for simulator " + disconnectedSims[i].ToString() +
", disconnecting", Helpers.LogLevel.Warning);
- DisconnectSim(disconnectedSims[i]);
+ DisconnectSim(disconnectedSims[i], true);
}
}
}
@@ -848,12 +853,12 @@ namespace libsecondlife
private void PongHandler(Packet packet, Simulator simulator)
{
CompletePingCheckPacket pong = (CompletePingCheckPacket)packet;
- String retval = "Pong2: " + (Environment.TickCount - simulator.LastPingSent);
- if ((pong.PingID.PingID - simulator.LastPingID + 1) != 0)
- retval += " (gap of " + (pong.PingID.PingID - simulator.LastPingID + 1) + ")";
+ String retval = "Pong2: " + (Environment.TickCount - simulator.Stats.LastPingSent);
+ if ((pong.PingID.PingID - simulator.Stats.LastPingID + 1) != 0)
+ retval += " (gap of " + (pong.PingID.PingID - simulator.Stats.LastPingID + 1) + ")";
- simulator.LastLag = Environment.TickCount - simulator.LastPingSent;
- simulator.ReceivedPongs++;
+ simulator.Stats.LastLag = Environment.TickCount - simulator.Stats.LastPingSent;
+ simulator.Stats.ReceivedPongs++;
// Client.Log(retval, Helpers.LogLevel.Info);
}
@@ -868,76 +873,76 @@ namespace libsecondlife
switch (s.StatID )
{
case 0:
- simulator.Dilation = s.StatValue;
+ simulator.Stats.Dilation = s.StatValue;
break;
case 1:
- simulator.FPS = Convert.ToInt32(s.StatValue);
+ simulator.Stats.FPS = Convert.ToInt32(s.StatValue);
break;
case 2:
- simulator.PhysicsFPS = s.StatValue;
+ simulator.Stats.PhysicsFPS = s.StatValue;
break;
case 3:
- simulator.AgentUpdates = s.StatValue;
+ simulator.Stats.AgentUpdates = s.StatValue;
break;
case 4:
- simulator.FrameTime = s.StatValue;
+ simulator.Stats.FrameTime = s.StatValue;
break;
case 5:
- simulator.NetTime = s.StatValue;
+ simulator.Stats.NetTime = s.StatValue;
break;
case 7:
- simulator.PhysicsTime = s.StatValue;
+ simulator.Stats.PhysicsTime = s.StatValue;
break;
case 8:
- simulator.ImageTime = s.StatValue;
+ simulator.Stats.ImageTime = s.StatValue;
break;
case 9:
- simulator.ScriptTime = s.StatValue;
+ simulator.Stats.ScriptTime = s.StatValue;
break;
case 10:
- simulator.OtherTime = s.StatValue;
+ simulator.Stats.OtherTime = s.StatValue;
break;
case 11:
- simulator.Objects = Convert.ToInt32(s.StatValue);
+ simulator.Stats.Objects = Convert.ToInt32(s.StatValue);
break;
case 12:
- simulator.ScriptedObjects = Convert.ToInt32(s.StatValue);
+ simulator.Stats.ScriptedObjects = Convert.ToInt32(s.StatValue);
break;
case 13:
- simulator.Agents = Convert.ToInt32(s.StatValue);
+ simulator.Stats.Agents = Convert.ToInt32(s.StatValue);
break;
case 14:
- simulator.ChildAgents = Convert.ToInt32(s.StatValue);
+ simulator.Stats.ChildAgents = Convert.ToInt32(s.StatValue);
break;
case 15:
- simulator.ActiveScripts = Convert.ToInt32(s.StatValue);
+ simulator.Stats.ActiveScripts = Convert.ToInt32(s.StatValue);
break;
case 16:
- simulator.LSLIPS = Convert.ToInt32(s.StatValue);
+ simulator.Stats.LSLIPS = Convert.ToInt32(s.StatValue);
break;
case 17:
- simulator.INPPS = Convert.ToInt32(s.StatValue);
+ simulator.Stats.INPPS = Convert.ToInt32(s.StatValue);
break;
case 18:
- simulator.OUTPPS = Convert.ToInt32(s.StatValue);
+ simulator.Stats.OUTPPS = Convert.ToInt32(s.StatValue);
break;
case 19:
- simulator.PendingDownloads = Convert.ToInt32(s.StatValue);
+ simulator.Stats.PendingDownloads = Convert.ToInt32(s.StatValue);
break;
case 20:
- simulator.PendingUploads = Convert.ToInt32(s.StatValue);
+ simulator.Stats.PendingUploads = Convert.ToInt32(s.StatValue);
break;
case 21:
- simulator.VirtualSize = Convert.ToInt32(s.StatValue);
+ simulator.Stats.VirtualSize = Convert.ToInt32(s.StatValue);
break;
case 22:
- simulator.ResidentSize = Convert.ToInt32(s.StatValue);
+ simulator.Stats.ResidentSize = Convert.ToInt32(s.StatValue);
break;
case 23:
- simulator.PendingLocalUploads = Convert.ToInt32(s.StatValue);
+ simulator.Stats.PendingLocalUploads = Convert.ToInt32(s.StatValue);
break;
case 24:
- simulator.UnackedBytes = Convert.ToInt32(s.StatValue);
+ simulator.Stats.UnackedBytes = Convert.ToInt32(s.StatValue);
break;
}
}
@@ -1029,6 +1034,13 @@ namespace libsecondlife
}
}
+ private void DisableSimulatorHandler(Packet packet, Simulator simulator)
+ {
+ Client.DebugLog("Received a DisableSimulator packet from " + simulator + ", shutting it down");
+
+ DisconnectSim(simulator, false);
+ }
+
private void KickUserHandler(Packet packet, Simulator simulator)
{
string message = Helpers.FieldToUTF8String(((KickUserPacket)packet).UserInfo.Reason);
diff --git a/libsecondlife/ObjectManager.cs b/libsecondlife/ObjectManager.cs
index 56cde8f9..1c95caa9 100644
--- a/libsecondlife/ObjectManager.cs
+++ b/libsecondlife/ObjectManager.cs
@@ -1470,9 +1470,6 @@ namespace libsecondlife
prim.AngularVelocity = angularVelocity;
#endregion
- // Used to notify subclasses that a prim was updated
- llObjectUpdated(simulator, prim);
-
if (attachment)
FireOnNewAttachment(simulator, prim, update.RegionData.RegionHandle,
update.RegionData.TimeDilation);
@@ -1603,7 +1600,9 @@ namespace libsecondlife
}
///
- /// Usually called when an Prim moves.
+ /// A terse object update, used when a transformation matrix or
+ /// velocity/acceleration for an object changes but nothing else
+ /// (scale/position/rotation/acceleration/velocity)
///
///
///
@@ -1699,8 +1698,6 @@ namespace libsecondlife
obj.Rotation = update.Rotation;
obj.Textures = update.Textures;
obj.Velocity = update.Velocity;
-
- llObjectUpdated(simulator, obj);
// Fire the callback
FireOnObjectUpdated(simulator, update, terse.RegionData.RegionHandle, terse.RegionData.TimeDilation);
@@ -2013,8 +2010,6 @@ namespace libsecondlife
", implement this!");
break;
}
-
- llObjectUpdated(simulator, prim);
}
catch (IndexOutOfRangeException e)
{
@@ -2029,13 +2024,13 @@ namespace libsecondlife
{
if (Client.Settings.ALWAYS_REQUEST_OBJECTS)
{
- List ids = new List();
ObjectUpdateCachedPacket update = (ObjectUpdateCachedPacket)packet;
+ List ids = new List(update.ObjectData.Length);
- // Assume clients aren't caching objects for now, so request updates for all of these objects
- foreach (ObjectUpdateCachedPacket.ObjectDataBlock block in update.ObjectData)
+ // No object caching implemented yet, so request updates for all of these objects
+ for (int i = 0; i < update.ObjectData.Length; i++)
{
- ids.Add(block.ID);
+ ids.Add(update.ObjectData[i].ID);
}
RequestObjects(simulator, ids);
@@ -2044,9 +2039,24 @@ namespace libsecondlife
protected void KillObjectHandler(Packet packet, Simulator simulator)
{
- foreach (KillObjectPacket.ObjectDataBlock block in ((KillObjectPacket)packet).ObjectData)
+ KillObjectPacket kill = (KillObjectPacket)packet;
+
+ for (int i = 0; i < kill.ObjectData.Length; i++)
{
- FireOnObjectKilled(simulator, block.ID);
+ uint localID = kill.ObjectData[i].ID;
+
+ if (simulator.Objects.Prims.ContainsKey(localID))
+ {
+ lock (simulator.Objects.Prims)
+ simulator.Objects.Prims.Remove(localID);
+ }
+ if (simulator.Objects.Avatars.ContainsKey(localID))
+ {
+ lock (simulator.Objects.Avatars)
+ simulator.Objects.Avatars.Remove(localID);
+ }
+
+ FireOnObjectKilled(simulator, localID);
}
}
@@ -2121,7 +2131,7 @@ namespace libsecondlife
FireOnObjectPropertiesFamily(sim, props);
}
- #endregion
+ #endregion Packet Handlers
#region Utility Functions
@@ -2156,40 +2166,10 @@ namespace libsecondlife
protected void UpdateDilation(Simulator s, uint dilation)
{
- s.Dilation = (float)dilation / 65535.0f;
- }
-
- protected void InterpolationTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
- {
- if (Client.Network.Connected)
- {
- // For now we only update Client.Self since there is no object tracking
- // built in to the library
-
- // Only do movement interpolation (extrapolation) when there is a non-zero velocity but
- // no acceleration
- if (Client.Self.Velocity != LLVector3.Zero || Client.Self.Acceleration != LLVector3.Zero)
- {
- try
- {
- TimeSpan interval = DateTime.Now - Client.Self.lastInterpolation;
- float adjSeconds = (float)interval.TotalSeconds * Client.Network.CurrentSim.Dilation;
-
- Client.Self.Position += (Client.Self.Velocity + (0.5f * (adjSeconds - HAVOK_TIMESTEP)) *
- Client.Self.Acceleration) * adjSeconds;
- }
- catch (Exception except)
- {
- Client.Log(except.ToString(), Helpers.LogLevel.Warning);
- }
- }
- }
-
- // Make sure the last interpolated time is always updated
- Client.Self.lastInterpolation = DateTime.Now;
+ s.Stats.Dilation = (float)dilation / 65535.0f;
}
- #endregion
+ #endregion Utility Functions
#region Event Notification
@@ -2227,10 +2207,6 @@ namespace libsecondlife
try { OnNewPrim(simulator, prim, RegionHandle, TimeDilation); }
catch (Exception e) { Client.Log(e.ToString(), Helpers.LogLevel.Error); }
}
- else
- {
- prim = null;
- }
}
protected void FireOnNewFoliage(Simulator simulator, Primitive prim, ulong RegionHandle, ushort TimeDilation)
@@ -2240,10 +2216,6 @@ namespace libsecondlife
try { OnNewFoliage(simulator, prim, RegionHandle, TimeDilation); }
catch (Exception e) { Client.Log(e.ToString(), Helpers.LogLevel.Error); }
}
- else
- {
- prim = null;
- }
}
protected void FireOnNewAttachment(Simulator simulator, Primitive prim, ulong RegionHandle, ushort TimeDilation)
@@ -2253,10 +2225,6 @@ namespace libsecondlife
try { OnNewAttachment(simulator, prim, RegionHandle, TimeDilation); }
catch (Exception e) { Client.Log(e.ToString(), Helpers.LogLevel.Error); }
}
- else
- {
- prim = null;
- }
}
protected void FireOnAvatarSitChanged(Simulator simulator, uint LocalID)
@@ -2275,10 +2243,6 @@ namespace libsecondlife
try { OnNewAvatar(simulator, avatar, RegionHandle, TimeDilation); }
catch (Exception e) { Client.Log(e.ToString(), Helpers.LogLevel.Error); }
}
- else
- {
- avatar = null;
- }
}
protected void FireOnObjectUpdated(Simulator simulator, ObjectUpdate update, ulong RegionHandle, ushort TimeDilation)
@@ -2292,43 +2256,130 @@ namespace libsecondlife
#endregion
- #region Subclass Indirection
+ #region Object Tracking Link
- ///
- /// Primitive Factory, this allows a subclass to lookup a copy of the Primitive
- /// and return it for updating, rather then always creating a new Primitive
- ///
- ///
- ///
- ///
- ///
- virtual protected Primitive GetPrimitive(Simulator simulator, uint LocalID, LLUUID UUID)
+ protected Primitive GetPrimitive(Simulator simulator, uint localID, LLUUID fullID)
{
- return new Primitive();
+ if (simulator.Objects.Prims.ContainsKey(localID))
+ {
+ return simulator.Objects.Prims[localID];
+ }
+ else
+ {
+ Primitive prim = new Primitive();
+ prim.LocalID = localID;
+ prim.ID = fullID;
+ lock (simulator.Objects.Prims)
+ simulator.Objects.Prims[localID] = prim;
+
+ return prim;
+ }
}
- ///
- /// Primitive Factory, this allows a subclass to lookup a copy of the Avatar
- /// and return it for updating, rather then always creating a new Avatar
- ///
- ///
- ///
- ///
- ///
- virtual protected Avatar GetAvatar(Simulator simulator, uint LocalID, LLUUID UUID)
+ protected Avatar GetAvatar(Simulator simulator, uint localID, LLUUID fullID)
{
- return new Avatar();
+ if (simulator.Objects.Avatars.ContainsKey(localID))
+ {
+ return simulator.Objects.Avatars[localID];
+ }
+ else
+ {
+ Avatar avatar = new Avatar();
+ avatar.LocalID = localID;
+ avatar.ID = fullID;
+ lock (simulator.Objects.Avatars)
+ simulator.Objects.Avatars[localID] = avatar;
+
+ return avatar;
+ }
}
- ///
- /// Used to flag to a subclass that an LLObject was updated/created
- ///
- ///
- ///
- virtual protected void llObjectUpdated(Simulator simulator, LLObject obj)
- {
- }
+ #endregion Object Tracking Link
- #endregion
+ protected void InterpolationTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
+ {
+ if (Client.Network.Connected)
+ {
+ TimeSpan interval = DateTime.Now - Client.Self.lastInterpolation;
+
+ // Iterate through all of the simulators
+ lock (Client.Network.Simulators)
+ {
+ for (int i = 0; i < Client.Network.Simulators.Count; i++)
+ {
+ float adjSeconds = (float)interval.TotalSeconds * Client.Network.Simulators[i].Stats.Dilation;
+
+ // Iterate through all of this sims avatars
+ lock (Client.Network.Simulators[i].Objects.Avatars)
+ {
+ foreach (Avatar avatar in Client.Network.Simulators[i].Objects.Avatars.Values)
+ {
+ #region Linear Motion
+ // Only do movement interpolation (extrapolation) when there is a non-zero velocity but
+ // no acceleration
+ if (avatar.Acceleration != LLVector3.Zero && avatar.Velocity == LLVector3.Zero)
+ {
+ avatar.Position += (avatar.Velocity + (0.5f * (adjSeconds - HAVOK_TIMESTEP)) *
+ avatar.Acceleration) * adjSeconds;
+ avatar.Velocity = avatar.Velocity + avatar.Acceleration * adjSeconds;
+ }
+ #endregion Linear Motion
+ }
+ }
+
+ // Iterate through all of this sims primitives
+ lock (Client.Network.Simulators[i].Objects.Prims)
+ {
+ foreach (Primitive prim in Client.Network.Simulators[i].Objects.Prims.Values)
+ {
+ if (prim.Joint == Primitive.JointType.Invalid)
+ {
+ #region Angular Velocity
+ LLVector3 angVel = prim.AngularVelocity;
+ float omega = Helpers.VecMagSquared(angVel);
+
+ if (omega > 0.00001f)
+ {
+ omega = (float)Math.Sqrt(omega);
+ float angle = omega * adjSeconds;
+ angVel *= 1.0f / omega;
+ LLQuaternion dQ = new LLQuaternion(angle, angVel);
+
+ prim.Rotation *= dQ;
+ }
+ #endregion Angular Velocity
+
+ #region Linear Motion
+ // Only do movement interpolation (extrapolation) when there is a non-zero velocity but
+ // no acceleration
+ if (prim.Acceleration != LLVector3.Zero && prim.Velocity == LLVector3.Zero)
+ {
+ prim.Position += (prim.Velocity + (0.5f * (adjSeconds - HAVOK_TIMESTEP)) *
+ prim.Acceleration) * adjSeconds;
+ prim.Velocity = prim.Velocity + prim.Acceleration * adjSeconds;
+ }
+ #endregion Linear Motion
+ }
+ else if (prim.Joint == Primitive.JointType.Hinge)
+ {
+ //FIXME: Hinge movement extrapolation
+ }
+ else if (prim.Joint == Primitive.JointType.Point)
+ {
+ //FIXME: Point movement extrapolation
+ }
+ else
+ {
+ Client.Log("Unhandled joint type " + prim.Joint, Helpers.LogLevel.Warning);
+ }
+ }
+ }
+ }
+ }
+
+ // Make sure the last interpolated time is always updated
+ Client.Self.lastInterpolation = DateTime.Now;
+ }
+ }
}
}
diff --git a/libsecondlife/ObjectTracker.cs b/libsecondlife/ObjectTracker.cs
new file mode 100644
index 00000000..e5c6ff31
--- /dev/null
+++ b/libsecondlife/ObjectTracker.cs
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2007, Second Life Reverse Engineering Team
+ * All rights reserved.
+ *
+ * - Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * - Neither the name of the Second Life Reverse Engineering Team nor the names
+ * of its contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+using System;
+using System.Collections.Generic;
+using libsecondlife.Packets;
+
+namespace libsecondlife
+{
+ public class ObjectTracker
+ {
+ public Dictionary Avatars = new Dictionary();
+ public Dictionary Prims = new Dictionary();
+ }
+}
diff --git a/libsecondlife/Simulator.cs b/libsecondlife/Simulator.cs
index 67412eb4..840e3585 100644
--- a/libsecondlife/Simulator.cs
+++ b/libsecondlife/Simulator.cs
@@ -128,6 +128,77 @@ namespace libsecondlife
#endregion Enums
+ #region Structs
+
+ public struct SimStats
+ {
+ ///
+ public ulong SentPackets;
+ ///
+ public ulong RecvPackets;
+ ///
+ public ulong SentBytes;
+ ///
+ public ulong RecvBytes;
+ ///
+ public int ConnectTime;
+ ///
+ public int ResentPackets;
+ ///
+ public int ReceivedResends;
+ ///
+ public int SentPings;
+ ///
+ public int ReceivedPongs;
+ ///
+ /// Incoming bytes per second
+ ///
+ /// It would be nice to have this claculated on the fly, but
+ /// this is far, far easier
+ public int IncomingBPS;
+ ///
+ /// Outgoing bytes per second
+ ///
+ /// It would be nice to have this claculated on the fly, but
+ /// this is far, far easier
+ public int OutgoingBPS;
+ ///
+ public int LastPingSent;
+ ///
+ public byte LastPingID;
+ ///
+ public int LastLag;
+ ///
+ public int MissedPings;
+ /// Current time dilation of this simulator
+ public float Dilation;
+ public int FPS;
+ public float PhysicsFPS;
+ public float AgentUpdates;
+ public float FrameTime;
+ public float NetTime;
+ public float PhysicsTime;
+ public float ImageTime;
+ public float ScriptTime;
+ public float OtherTime;
+ public int Objects;
+ public int ScriptedObjects;
+ public int Agents;
+ public int ChildAgents;
+ public int ActiveScripts;
+ public int LSLIPS;
+ public int INPPS;
+ public int OUTPPS;
+ public int PendingDownloads;
+ public int PendingUploads;
+ public int VirtualSize;
+ public int ResidentSize;
+ public int PendingLocalUploads;
+ public int UnackedBytes;
+ }
+
+ #endregion Structs
+
#region Public Members
/// A public reference to the client that this Simulator object
@@ -191,69 +262,14 @@ namespace libsecondlife
public SimAccess Access;
///
public float BillableFactor;
- ///
- public ulong SentPackets = 0;
- ///
- public ulong RecvPackets = 0;
- ///
- public ulong SentBytes = 0;
- ///
- public ulong RecvBytes = 0;
- ///
- public int ConnectTime = 0;
- ///
- public int ResentPackets = 0;
- ///
- public int ReceivedResends = 0;
- ///
- public int SentPings = 0;
- ///
- public int ReceivedPongs = 0;
- ///
- /// Incoming bytes per second
- ///
- /// It would be nice to have this claculated on the fly, but
- /// this is far, far easier
- public int IncomingBPS = 0;
- ///
- /// Outgoing bytes per second
- ///
- /// It would be nice to have this claculated on the fly, but
- /// this is far, far easier
- public int OutgoingBPS = 0;
- ///
- public int LastPingSent = 0;
- ///
- public byte LastPingID = 0;
- ///
- public int LastLag = 0;
- ///
- public int MissedPings = 0;
- /// Current time dilation of this simulator
- public float Dilation = 0;
- public int FPS = 0;
- public float PhysicsFPS = 0;
- public float AgentUpdates = 0;
- public float FrameTime = 0;
- public float NetTime = 0;
- public float PhysicsTime = 0;
- public float ImageTime = 0;
- public float ScriptTime = 0;
- public float OtherTime = 0;
- public int Objects = 0;
- public int ScriptedObjects = 0;
- public int Agents = 0;
- public int ChildAgents = 0;
- public int ActiveScripts = 0;
- public int LSLIPS = 0;
- public int INPPS = 0;
- public int OUTPPS = 0;
- public int PendingDownloads = 0;
- public int PendingUploads = 0;
- public int VirtualSize = 0;
- public int ResidentSize = 0;
- public int PendingLocalUploads = 0;
- public int UnackedBytes = 0;
+ /// Statistics information for this simulator and the
+ /// connection to the simulator, calculated by the simulator itself
+ /// and libsecondlife
+ public SimStats Stats;
+
+ /// Provides access to two thread-safe dictionaries containing
+ /// avatars and primitives found in this simulator
+ public ObjectTracker Objects = new ObjectTracker();
/// Used to obtain a lock on the sequence number for packets
/// sent to this simulator. Only useful for applications manipulating
@@ -262,7 +278,7 @@ namespace libsecondlife
/// The current sequence number for packets sent to this
/// simulator. Must be locked with SequenceLock before modifying. Only
/// useful for applications manipulating sequence numbers
- public volatile uint Sequence = 0;
+ public volatile uint Sequence;
#endregion Public Members
@@ -388,7 +404,7 @@ namespace libsecondlife
// Send the initial packet out
SendPacket(use, true);
- ConnectTime = Environment.TickCount;
+ Stats.ConnectTime = Environment.TickCount;
// Move our agent in to the sim to complete the connection
if (moveToSim) Client.Self.CompleteAgentMovement(this);
@@ -437,7 +453,7 @@ namespace libsecondlife
///
/// Disconnect from this simulator
///
- public void Disconnect()
+ public void Disconnect(bool sendCloseCircuit)
{
if (connected)
{
@@ -454,13 +470,16 @@ namespace libsecondlife
SimCaps = null;
}
- // Try to send the CloseCircuit notice
- CloseCircuitPacket close = new CloseCircuitPacket();
- UDPPacketBuffer buf = new UDPPacketBuffer(ipEndPoint, false);
- buf.Data = close.ToBytes();
- buf.DataLength = buf.Data.Length;
+ if (sendCloseCircuit)
+ {
+ // Try to send the CloseCircuit notice
+ CloseCircuitPacket close = new CloseCircuitPacket();
+ UDPPacketBuffer buf = new UDPPacketBuffer(ipEndPoint, false);
+ buf.Data = close.ToBytes();
+ buf.DataLength = buf.Data.Length;
- AsyncBeginSend(buf);
+ AsyncBeginSend(buf);
+ }
// Shut the socket communication down
Stop();
@@ -537,8 +556,8 @@ namespace libsecondlife
// Serialize the packet
buffer = packet.ToBytes();
bytes = buffer.Length;
- SentBytes += (ulong)bytes;
- SentPackets++;
+ Stats.SentBytes += (ulong)bytes;
+ Stats.SentPackets++;
UDPPacketBuffer buf;
@@ -582,8 +601,8 @@ namespace libsecondlife
}
}
- SentBytes += (ulong)payload.Length;
- SentPackets++;
+ Stats.SentBytes += (ulong)payload.Length;
+ Stats.SentPackets++;
UDPPacketBuffer buf = new UDPPacketBuffer(ipEndPoint, false);
buf.Data = payload;
@@ -597,7 +616,7 @@ namespace libsecondlife
" byte payload on a closed socket, shutting down " + this.ToString(),
Helpers.LogLevel.Info);
- Network.DisconnectSim(this);
+ Network.DisconnectSim(this, false);
return;
}
catch (Exception e)
@@ -622,11 +641,11 @@ namespace libsecondlife
public void SendPing()
{
StartPingCheckPacket ping = new StartPingCheckPacket();
- ping.PingID.PingID = LastPingID++;
+ ping.PingID.PingID = Stats.LastPingID++;
ping.PingID.OldestUnacked = 0; // FIXME
ping.Header.Reliable = false;
SendPacket(ping, true);
- LastPingSent = Environment.TickCount;
+ Stats.LastPingSent = Environment.TickCount;
}
///
@@ -704,8 +723,8 @@ namespace libsecondlife
return;
}
- RecvBytes += (ulong)buffer.DataLength;
- RecvPackets++;
+ Stats.RecvBytes += (ulong)buffer.DataLength;
+ Stats.RecvPackets++;
#endregion Packet Decoding
@@ -724,7 +743,7 @@ namespace libsecondlife
if (PendingAcks.Count >= Client.Settings.MAX_PENDING_ACKS)
SendAcks();
- if (packet.Header.Resent) ++ReceivedResends;
+ if (packet.Header.Resent) ++Stats.ReceivedResends;
}
#endregion Reliable Handling
@@ -797,7 +816,7 @@ namespace libsecondlife
packet.Header.Sequence, packet.GetType(), now - packet.TickCount));
packet.Header.Resent = true;
- ++ResentPackets;
+ ++Stats.ResentPackets;
SendPacket(packet, false);
}
catch (Exception ex)
@@ -824,13 +843,13 @@ namespace libsecondlife
if (OutBytes.Count >= Client.Settings.STATS_QUEUE_SIZE)
old_out = OutBytes.Dequeue();
- InBytes.Enqueue(RecvBytes);
- OutBytes.Enqueue(SentBytes);
+ InBytes.Enqueue(Stats.RecvBytes);
+ OutBytes.Enqueue(Stats.SentBytes);
if (old_in > 0 && old_out > 0)
{
- IncomingBPS = (int)(RecvBytes - old_in) / Client.Settings.STATS_QUEUE_SIZE;
- OutgoingBPS = (int)(SentBytes - old_out) / Client.Settings.STATS_QUEUE_SIZE;
+ Stats.IncomingBPS = (int)(Stats.RecvBytes - old_in) / Client.Settings.STATS_QUEUE_SIZE;
+ Stats.OutgoingBPS = (int)(Stats.SentBytes - old_out) / Client.Settings.STATS_QUEUE_SIZE;
//Client.Log("Incoming: " + IncomingBPS + " Out: " + OutgoingBPS +
// " Lag: " + LastLag + " Pings: " + ReceivedPongs +
// "/" + SentPings, Helpers.LogLevel.Debug);
@@ -840,7 +859,7 @@ namespace libsecondlife
private void PingTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs ea)
{
SendPing();
- SentPings++;
+ Stats.SentPings++;
}
}
}
diff --git a/libsecondlife/Types.cs b/libsecondlife/Types.cs
index c705fc0f..ac36c7d9 100644
--- a/libsecondlife/Types.cs
+++ b/libsecondlife/Types.cs
@@ -1002,6 +1002,56 @@ namespace libsecondlife
W = w;
}
+ ///
+ /// Build a quaternion from an angle and a vector
+ ///
+ /// Angle value
+ /// Vector value
+ public LLQuaternion(float angle, LLVector3 vector)
+ {
+ vector = Helpers.VecNorm(vector);
+ angle *= 0.5f;
+
+ float c = (float)Math.Cos(angle);
+ float s = (float)Math.Sin(angle);
+
+ X = vector.X * s;
+ Y = vector.Y * s;
+ Z = vector.Z * s;
+ W = c;
+
+ Normalize();
+ }
+
+ ///
+ /// Normalize this quaternion
+ ///
+ /// Magnitude of the quaternion
+ public float Normalize()
+ {
+ const float MAG_THRESHOLD = 0.0000001f;
+
+ float mag = (float)Math.Sqrt(X * X + Y * Y + Z * Z + W * W);
+
+ if (mag > MAG_THRESHOLD)
+ {
+ float oomag = 1.0f / mag;
+ X *= oomag;
+ Y *= oomag;
+ Z *= oomag;
+ W *= oomag;
+ }
+ else
+ {
+ X = 0.0f;
+ Y = 0.0f;
+ Z = 0.0f;
+ W = 1.0f;
+ }
+
+ return mag;
+ }
+
///
/// Normalize this quaternion and serialize it to a byte array
///
diff --git a/libsecondlife/examples/TestClient/ClientManager.cs b/libsecondlife/examples/TestClient/ClientManager.cs
index c65ea4a9..bcbe1757 100644
--- a/libsecondlife/examples/TestClient/ClientManager.cs
+++ b/libsecondlife/examples/TestClient/ClientManager.cs
@@ -95,7 +95,6 @@ namespace libsecondlife.TestClient
client.Throttle.Land = 1000000;
client.Throttle.Task = 1000000;
- client.SimPrims = SimPrims;
client.MasterName = account.MasterName;
client.MasterKey = account.MasterKey;
diff --git a/libsecondlife/examples/TestClient/Commands/Inventory/DumpOutfitCommand.cs b/libsecondlife/examples/TestClient/Commands/Inventory/DumpOutfitCommand.cs
index 18c71f68..98a1c218 100644
--- a/libsecondlife/examples/TestClient/Commands/Inventory/DumpOutfitCommand.cs
+++ b/libsecondlife/examples/TestClient/Commands/Inventory/DumpOutfitCommand.cs
@@ -28,40 +28,46 @@ namespace libsecondlife.TestClient
if (!LLUUID.TryParse(args[0], out target))
return "Usage: dumpoutfit [avatar-uuid]";
- lock (Client.AvatarList)
+ lock (Client.Network.Simulators)
{
- foreach (Avatar avatar in Client.AvatarList.Values)
+ for (int i = 0; i < Client.Network.Simulators.Count; i++)
{
- if (avatar.ID == target)
+ lock (Client.Network.Simulators[i].Objects.Avatars)
{
- StringBuilder output = new StringBuilder("Downloading ");
-
- lock (OutfitAssets) OutfitAssets.Clear();
- Client.Assets.OnImageReceived += ImageReceivedHandler;
-
- foreach (KeyValuePair face in avatar.Textures.FaceTextures)
+ foreach (Avatar avatar in Client.Network.Simulators[i].Objects.Avatars.Values)
{
- ImageType type = ImageType.Normal;
-
- switch ((AppearanceManager.TextureIndex)face.Key)
+ if (avatar.ID == target)
{
- case AppearanceManager.TextureIndex.HeadBaked:
- case AppearanceManager.TextureIndex.EyesBaked:
- case AppearanceManager.TextureIndex.UpperBaked:
- case AppearanceManager.TextureIndex.LowerBaked:
- case AppearanceManager.TextureIndex.SkirtBaked:
- type = ImageType.Baked;
- break;
+ StringBuilder output = new StringBuilder("Downloading ");
+
+ lock (OutfitAssets) OutfitAssets.Clear();
+ Client.Assets.OnImageReceived += ImageReceivedHandler;
+
+ foreach (KeyValuePair face in avatar.Textures.FaceTextures)
+ {
+ ImageType type = ImageType.Normal;
+
+ switch ((AppearanceManager.TextureIndex)face.Key)
+ {
+ case AppearanceManager.TextureIndex.HeadBaked:
+ case AppearanceManager.TextureIndex.EyesBaked:
+ case AppearanceManager.TextureIndex.UpperBaked:
+ case AppearanceManager.TextureIndex.LowerBaked:
+ case AppearanceManager.TextureIndex.SkirtBaked:
+ type = ImageType.Baked;
+ break;
+ }
+
+ OutfitAssets.Add(face.Value.TextureID);
+ Client.Assets.RequestImage(face.Value.TextureID, type, 100000.0f, 0);
+
+ output.Append(((AppearanceManager.TextureIndex)face.Key).ToString());
+ output.Append(" ");
+ }
+
+ return output.ToString();
}
-
- OutfitAssets.Add(face.Value.TextureID);
- Client.Assets.RequestImage(face.Value.TextureID, type, 100000.0f, 0);
-
- output.Append(((AppearanceManager.TextureIndex)face.Key).ToString());
- output.Append(" ");
}
-
- return output.ToString();
}
}
}
diff --git a/libsecondlife/examples/TestClient/Commands/Movement/FollowCommand.cs b/libsecondlife/examples/TestClient/Commands/Movement/FollowCommand.cs
index fa0dd8ef..b6ce0e93 100644
--- a/libsecondlife/examples/TestClient/Commands/Movement/FollowCommand.cs
+++ b/libsecondlife/examples/TestClient/Commands/Movement/FollowCommand.cs
@@ -44,14 +44,23 @@ namespace libsecondlife.TestClient
bool Follow(string name)
{
- foreach (Avatar av in Client.AvatarList.Values)
+ lock (Client.Network.Simulators)
{
- if (av.Name == name)
- {
- targetLocalID = av.LocalID;
- Active = true;
- return true;
- }
+ for (int i = 0; i < Client.Network.Simulators.Count; i++)
+ {
+ lock (Client.Network.Simulators[i].Objects.Avatars)
+ {
+ foreach (Avatar avatar in Client.Network.Simulators[i].Objects.Avatars.Values)
+ {
+ if (avatar.Name == name)
+ {
+ targetLocalID = avatar.LocalID;
+ Active = true;
+ return true;
+ }
+ }
+ }
+ }
}
Active = false;
@@ -60,13 +69,22 @@ namespace libsecondlife.TestClient
bool Follow(LLUUID id)
{
- foreach (Avatar av in Client.AvatarList.Values)
+ lock (Client.Network.Simulators)
{
- if (av.ID == id)
+ for (int i = 0; i < Client.Network.Simulators.Count; i++)
{
- targetLocalID = av.LocalID;
- Active = true;
- return true;
+ lock (Client.Network.Simulators[i].Objects.Avatars)
+ {
+ foreach (Avatar avatar in Client.Network.Simulators[i].Objects.Avatars.Values)
+ {
+ if (avatar.ID == id)
+ {
+ targetLocalID = avatar.LocalID;
+ Active = true;
+ return true;
+ }
+ }
+ }
}
}
@@ -77,29 +95,44 @@ namespace libsecondlife.TestClient
public override void Think()
{
// Find the target position
- if (Client.Network.CurrentSim != null && Client.AvatarList.ContainsKey(targetLocalID))
+ lock (Client.Network.Simulators)
{
- Avatar targetAv = Client.AvatarList[targetLocalID];
- float distance = Helpers.VecDist(targetAv.Position, Client.Self.Position);
-
- if (distance > DISTANCE_BUFFER)
+ for (int i = 0; i < Client.Network.Simulators.Count; i++)
{
- uint regionX, regionY;
- Helpers.LongToUInts(Client.Network.CurrentSim.Handle, out regionX, out regionY);
+ if (Client.Network.Simulators[i].Objects.Avatars.ContainsKey(targetLocalID))
+ {
+ Avatar targetAv = Client.Network.Simulators[i].Objects.Avatars[targetLocalID];
+ float distance = 0.0f;
- double xTarget = (double)targetAv.Position.X + (double)regionX;
- double yTarget = (double)targetAv.Position.Y + (double)regionY;
- double zTarget = targetAv.Position.Z - 2f;
+ if (Client.Network.Simulators[i] == Client.Network.CurrentSim)
+ {
+ distance = Helpers.VecDist(targetAv.Position, Client.Self.Position);
+ }
+ else
+ {
+ // FIXME: Calculate global distances
+ }
- Client.DebugLog(String.Format("[Autopilot] {0} meters away from the target, starting autopilot to <{1},{2},{3}>",
- distance, xTarget, yTarget, zTarget));
+ if (distance > DISTANCE_BUFFER)
+ {
+ uint regionX, regionY;
+ Helpers.LongToUInts(Client.Network.Simulators[i].Handle, out regionX, out regionY);
- Client.Self.AutoPilot(xTarget, yTarget, zTarget);
- }
- else
- {
- // We are in range of the target and moving, stop moving
- Client.Self.AutoPilotCancel();
+ double xTarget = (double)targetAv.Position.X + (double)regionX;
+ double yTarget = (double)targetAv.Position.Y + (double)regionY;
+ double zTarget = targetAv.Position.Z - 2f;
+
+ Client.DebugLog(String.Format("[Autopilot] {0} meters away from the target, starting autopilot to <{1},{2},{3}>",
+ distance, xTarget, yTarget, zTarget));
+
+ Client.Self.AutoPilot(xTarget, yTarget, zTarget);
+ }
+ else
+ {
+ // We are in range of the target and moving, stop moving
+ Client.Self.AutoPilotCancel();
+ }
+ }
}
}
diff --git a/libsecondlife/examples/TestClient/Commands/Movement/SitCommand.cs b/libsecondlife/examples/TestClient/Commands/Movement/SitCommand.cs
index b9ef6be3..bb915c03 100644
--- a/libsecondlife/examples/TestClient/Commands/Movement/SitCommand.cs
+++ b/libsecondlife/examples/TestClient/Commands/Movement/SitCommand.cs
@@ -19,19 +19,16 @@ namespace libsecondlife.TestClient
Primitive closest = null;
double closestDistance = Double.MaxValue;
- lock (Client.SimPrims)
+ lock (Client.Network.CurrentSim.Objects.Prims)
{
- if (Client.SimPrims.ContainsKey(Client.Network.CurrentSim))
+ foreach (Primitive p in Client.Network.CurrentSim.Objects.Prims.Values)
{
- foreach (Primitive p in Client.SimPrims[Client.Network.CurrentSim].Values)
- {
- float distance = Helpers.VecDist(Client.Self.Position, p.Position);
+ float distance = Helpers.VecDist(Client.Self.Position, p.Position);
- if (closest == null || distance < closestDistance)
- {
- closest = p;
- closestDistance = distance;
- }
+ if (closest == null || distance < closestDistance)
+ {
+ closest = p;
+ closestDistance = distance;
}
}
}
diff --git a/libsecondlife/examples/TestClient/Commands/Movement/SitOnCommand.cs b/libsecondlife/examples/TestClient/Commands/Movement/SitOnCommand.cs
index ec9d201f..75baefe2 100644
--- a/libsecondlife/examples/TestClient/Commands/Movement/SitOnCommand.cs
+++ b/libsecondlife/examples/TestClient/Commands/Movement/SitOnCommand.cs
@@ -6,49 +6,39 @@ using libsecondlife.Packets;
namespace libsecondlife.TestClient
{
- public class SitOnCommand: Command
+ public class SitOnCommand : Command
{
public SitOnCommand(TestClient testClient)
- {
- Name = "siton";
- Description = "Attempt to sit on a particular prim, with specified UUID";
- }
-
+ {
+ Name = "siton";
+ Description = "Attempt to sit on a particular prim, with specified UUID";
+ }
+
public override string Execute(string[] args, LLUUID fromAgentID)
- {
- LLObject targetSeat = null;
+ {
+ if (args.Length != 1)
+ return "Usage: siton UUID";
- lock (Client.SimPrims)
- {
- if (Client.SimPrims.ContainsKey(Client.Network.CurrentSim))
+ LLUUID target;
+
+ if (LLUUID.TryParse(args[0], out target))
+ {
+ lock (Client.Network.CurrentSim.Objects.Prims)
{
- foreach (LLObject p in Client.SimPrims[Client.Network.CurrentSim].Values)
- {
- try
- {
- if (p.ID == args[0])
- targetSeat = p;
- }
- catch
- {
- // handle exception
- return "Sorry, I don't think " + args[0] + " is a valid UUID. I'm unable to sit there.";
- }
- }
+ foreach (Primitive prim in Client.Network.CurrentSim.Objects.Prims.Values)
+ {
+ if (prim.ID == target)
+ {
+ Client.Self.RequestSit(prim.ID, LLVector3.Zero);
+ Client.Self.Sit();
+ return "Requested to sit on prim " + prim.ID.ToStringHyphenated() +
+ " (" + prim.LocalID + ")";
+ }
+ }
}
- }
-
- if (targetSeat != null)
- {
- Client.Self.RequestSit(targetSeat.ID, LLVector3.Zero);
- Client.Self.Sit();
-
- return "Sat on prim " + targetSeat.ID + ".";
}
- else
- {
- return "Couldn't find specified prim to sit on";
- }
- }
+
+ return "Couldn't find a prim to sit on with UUID " + args[0];
+ }
}
}
\ No newline at end of file
diff --git a/libsecondlife/examples/TestClient/Commands/Prims/ExportCommand.cs b/libsecondlife/examples/TestClient/Commands/Prims/ExportCommand.cs
index 2baac1a8..0444af90 100644
--- a/libsecondlife/examples/TestClient/Commands/Prims/ExportCommand.cs
+++ b/libsecondlife/examples/TestClient/Commands/Prims/ExportCommand.cs
@@ -50,22 +50,19 @@ namespace libsecondlife.TestClient
file = args[0];
id = SelectedObject;
}
-
- lock (Client.SimPrims)
- {
- if (Client.SimPrims.ContainsKey(Client.Network.CurrentSim))
- {
- foreach (Primitive prim in Client.SimPrims[Client.Network.CurrentSim].Values)
- {
- if (prim.ID == id)
- {
- if (prim.ParentID != 0)
- localid = prim.ParentID;
- else
- localid = prim.LocalID;
- break;
- }
+ lock (Client.Network.CurrentSim.Objects.Prims)
+ {
+ foreach (Primitive prim in Client.Network.CurrentSim.Objects.Prims.Values)
+ {
+ if (prim.ID == id)
+ {
+ if (prim.ParentID != 0)
+ localid = prim.ParentID;
+ else
+ localid = prim.LocalID;
+
+ break;
}
}
}
@@ -102,17 +99,14 @@ namespace libsecondlife.TestClient
{
List prims = new List();
- lock (Client.SimPrims)
- {
- if (Client.SimPrims.ContainsKey(Client.Network.CurrentSim))
- {
- foreach (Primitive prim in Client.SimPrims[Client.Network.CurrentSim].Values)
+ lock (Client.Network.CurrentSim.Objects.Prims)
+ {
+ foreach (Primitive prim in Client.Network.CurrentSim.Objects.Prims.Values)
+ {
+ if (prim.LocalID == localid || prim.ParentID == localid)
{
- if (prim.LocalID == localid || prim.ParentID == localid)
- {
- prims.Add(prim);
- count++;
- }
+ prims.Add(prim);
+ count++;
}
}
}
@@ -147,7 +141,7 @@ namespace libsecondlife.TestClient
else
{
return "Couldn't find UUID " + id.ToString() + " in the " +
- Client.SimPrims[Client.Network.CurrentSim].Count +
+ Client.Network.CurrentSim.Objects.Prims.Count +
"objects currently indexed in the current simulator";
}
}
diff --git a/libsecondlife/examples/TestClient/Commands/Prims/ExportParticlesCommand.cs b/libsecondlife/examples/TestClient/Commands/Prims/ExportParticlesCommand.cs
index 4b2c3227..5081337a 100644
--- a/libsecondlife/examples/TestClient/Commands/Prims/ExportParticlesCommand.cs
+++ b/libsecondlife/examples/TestClient/Commands/Prims/ExportParticlesCommand.cs
@@ -23,91 +23,88 @@ namespace libsecondlife.TestClient
if (!LLUUID.TryParse(args[0], out id))
return "Usage: exportparticles [prim-uuid]";
- lock (Client.SimPrims)
+ lock (Client.Network.CurrentSim.Objects.Prims)
{
- if (Client.SimPrims.ContainsKey(Client.Network.CurrentSim))
+ foreach (Primitive prim in Client.Network.CurrentSim.Objects.Prims.Values)
{
- foreach (Primitive prim in Client.SimPrims[Client.Network.CurrentSim].Values)
+ if (prim.ID == id)
{
- if (prim.ID == id)
+ if (prim.ParticleSys.CRC != 0)
{
- if (prim.ParticleSys.CRC != 0)
- {
- StringBuilder lsl = new StringBuilder();
+ StringBuilder lsl = new StringBuilder();
- lsl.Append("default" + Environment.NewLine);
- lsl.Append("{" + Environment.NewLine);
- lsl.Append(" state_entry()" + Environment.NewLine);
- lsl.Append(" {" + Environment.NewLine);
- lsl.Append(" llParticleSystem([" + Environment.NewLine);
+ lsl.Append("default" + Environment.NewLine);
+ lsl.Append("{" + Environment.NewLine);
+ lsl.Append(" state_entry()" + Environment.NewLine);
+ lsl.Append(" {" + Environment.NewLine);
+ lsl.Append(" llParticleSystem([" + Environment.NewLine);
- lsl.Append(" PSYS_PART_FLAGS, 0");
+ lsl.Append(" PSYS_PART_FLAGS, 0");
- if ((prim.ParticleSys.PartDataFlags & Primitive.ParticleSystem.ParticleDataFlags.InterpColor) != 0)
- lsl.Append(" | PSYS_PART_INTERP_COLOR_MASK");
- if ((prim.ParticleSys.PartDataFlags & Primitive.ParticleSystem.ParticleDataFlags.InterpScale) != 0)
- lsl.Append(" | PSYS_PART_INTERP_SCALE_MASK");
- if ((prim.ParticleSys.PartDataFlags & Primitive.ParticleSystem.ParticleDataFlags.Bounce) != 0)
- lsl.Append(" | PSYS_PART_BOUNCE_MASK");
- if ((prim.ParticleSys.PartDataFlags & Primitive.ParticleSystem.ParticleDataFlags.Wind) != 0)
- lsl.Append(" | PSYS_PART_WIND_MASK");
- if ((prim.ParticleSys.PartDataFlags & Primitive.ParticleSystem.ParticleDataFlags.FollowSrc) != 0)
- lsl.Append(" | PSYS_PART_FOLLOW_SRC_MASK");
- if ((prim.ParticleSys.PartDataFlags & Primitive.ParticleSystem.ParticleDataFlags.FollowVelocity) != 0)
- lsl.Append(" | PSYS_PART_FOLLOW_VELOCITY_MASK");
- if ((prim.ParticleSys.PartDataFlags & Primitive.ParticleSystem.ParticleDataFlags.TargetPos) != 0)
- lsl.Append(" | PSYS_PART_TARGET_POS_MASK");
- if ((prim.ParticleSys.PartDataFlags & Primitive.ParticleSystem.ParticleDataFlags.TargetLinear) != 0)
- lsl.Append(" | PSYS_PART_TARGET_LINEAR_MASK");
- if ((prim.ParticleSys.PartDataFlags & Primitive.ParticleSystem.ParticleDataFlags.Emissive) != 0)
- lsl.Append(" | PSYS_PART_EMISSIVE_MASK");
+ if ((prim.ParticleSys.PartDataFlags & Primitive.ParticleSystem.ParticleDataFlags.InterpColor) != 0)
+ lsl.Append(" | PSYS_PART_INTERP_COLOR_MASK");
+ if ((prim.ParticleSys.PartDataFlags & Primitive.ParticleSystem.ParticleDataFlags.InterpScale) != 0)
+ lsl.Append(" | PSYS_PART_INTERP_SCALE_MASK");
+ if ((prim.ParticleSys.PartDataFlags & Primitive.ParticleSystem.ParticleDataFlags.Bounce) != 0)
+ lsl.Append(" | PSYS_PART_BOUNCE_MASK");
+ if ((prim.ParticleSys.PartDataFlags & Primitive.ParticleSystem.ParticleDataFlags.Wind) != 0)
+ lsl.Append(" | PSYS_PART_WIND_MASK");
+ if ((prim.ParticleSys.PartDataFlags & Primitive.ParticleSystem.ParticleDataFlags.FollowSrc) != 0)
+ lsl.Append(" | PSYS_PART_FOLLOW_SRC_MASK");
+ if ((prim.ParticleSys.PartDataFlags & Primitive.ParticleSystem.ParticleDataFlags.FollowVelocity) != 0)
+ lsl.Append(" | PSYS_PART_FOLLOW_VELOCITY_MASK");
+ if ((prim.ParticleSys.PartDataFlags & Primitive.ParticleSystem.ParticleDataFlags.TargetPos) != 0)
+ lsl.Append(" | PSYS_PART_TARGET_POS_MASK");
+ if ((prim.ParticleSys.PartDataFlags & Primitive.ParticleSystem.ParticleDataFlags.TargetLinear) != 0)
+ lsl.Append(" | PSYS_PART_TARGET_LINEAR_MASK");
+ if ((prim.ParticleSys.PartDataFlags & Primitive.ParticleSystem.ParticleDataFlags.Emissive) != 0)
+ lsl.Append(" | PSYS_PART_EMISSIVE_MASK");
- lsl.Append(","); lsl.Append(Environment.NewLine);
- lsl.Append(" PSYS_SRC_PATTERN, 0");
+ lsl.Append(","); lsl.Append(Environment.NewLine);
+ lsl.Append(" PSYS_SRC_PATTERN, 0");
- if ((prim.ParticleSys.Pattern & Primitive.ParticleSystem.SourcePattern.Drop) != 0)
- lsl.Append(" | PSYS_SRC_PATTERN_DROP");
- if ((prim.ParticleSys.Pattern & Primitive.ParticleSystem.SourcePattern.Explode) != 0)
- lsl.Append(" | PSYS_SRC_PATTERN_EXPLODE");
- if ((prim.ParticleSys.Pattern & Primitive.ParticleSystem.SourcePattern.Angle) != 0)
- lsl.Append(" | PSYS_SRC_PATTERN_ANGLE");
- if ((prim.ParticleSys.Pattern & Primitive.ParticleSystem.SourcePattern.AngleCone) != 0)
- lsl.Append(" | PSYS_SRC_PATTERN_ANGLE_CONE");
- if ((prim.ParticleSys.Pattern & Primitive.ParticleSystem.SourcePattern.AngleConeEmpty) != 0)
- lsl.Append(" | PSYS_SRC_PATTERN_ANGLE_CONE_EMPTY");
+ if ((prim.ParticleSys.Pattern & Primitive.ParticleSystem.SourcePattern.Drop) != 0)
+ lsl.Append(" | PSYS_SRC_PATTERN_DROP");
+ if ((prim.ParticleSys.Pattern & Primitive.ParticleSystem.SourcePattern.Explode) != 0)
+ lsl.Append(" | PSYS_SRC_PATTERN_EXPLODE");
+ if ((prim.ParticleSys.Pattern & Primitive.ParticleSystem.SourcePattern.Angle) != 0)
+ lsl.Append(" | PSYS_SRC_PATTERN_ANGLE");
+ if ((prim.ParticleSys.Pattern & Primitive.ParticleSystem.SourcePattern.AngleCone) != 0)
+ lsl.Append(" | PSYS_SRC_PATTERN_ANGLE_CONE");
+ if ((prim.ParticleSys.Pattern & Primitive.ParticleSystem.SourcePattern.AngleConeEmpty) != 0)
+ lsl.Append(" | PSYS_SRC_PATTERN_ANGLE_CONE_EMPTY");
- lsl.Append("," + Environment.NewLine);
+ lsl.Append("," + Environment.NewLine);
- lsl.Append(" PSYS_PART_START_ALPHA, " + String.Format("{0:0.00000}", prim.ParticleSys.PartStartColor.A) + "," + Environment.NewLine);
- lsl.Append(" PSYS_PART_END_ALPHA, " + String.Format("{0:0.00000}", prim.ParticleSys.PartEndColor.A) + "," + Environment.NewLine);
- lsl.Append(" PSYS_PART_START_COLOR, " + prim.ParticleSys.PartStartColor.ToStringRGB() + "," + Environment.NewLine);
- lsl.Append(" PSYS_PART_END_COLOR, " + prim.ParticleSys.PartEndColor.ToStringRGB() + "," + Environment.NewLine);
- lsl.Append(" PSYS_PART_START_SCALE, <" + String.Format("{0:0.00000}", prim.ParticleSys.PartStartScaleX) + ", " + String.Format("{0:0.00000}", prim.ParticleSys.PartStartScaleY) + ", 0>, " + Environment.NewLine);
- lsl.Append(" PSYS_PART_END_SCALE, <" + String.Format("{0:0.00000}", prim.ParticleSys.PartEndScaleX) + ", " + String.Format("{0:0.00000}", prim.ParticleSys.PartEndScaleY) + ", 0>, " + Environment.NewLine);
- lsl.Append(" PSYS_PART_MAX_AGE, " + String.Format("{0:0.00000}", prim.ParticleSys.PartMaxAge) + "," + Environment.NewLine);
- lsl.Append(" PSYS_SRC_MAX_AGE, " + String.Format("{0:0.00000}", prim.ParticleSys.MaxAge) + "," + Environment.NewLine);
- lsl.Append(" PSYS_SRC_ACCEL, " + prim.ParticleSys.PartAcceleration.ToString() + "," + Environment.NewLine);
- lsl.Append(" PSYS_SRC_BURST_PART_COUNT, " + String.Format("{0:0}", prim.ParticleSys.BurstPartCount) + "," + Environment.NewLine);
- lsl.Append(" PSYS_SRC_BURST_RADIUS, " + String.Format("{0:0.00000}", prim.ParticleSys.BurstRadius) + "," + Environment.NewLine);
- lsl.Append(" PSYS_SRC_BURST_RATE, " + String.Format("{0:0.00000}", prim.ParticleSys.BurstRate) + "," + Environment.NewLine);
- lsl.Append(" PSYS_SRC_BURST_SPEED_MIN, " + String.Format("{0:0.00000}", prim.ParticleSys.BurstSpeedMin) + "," + Environment.NewLine);
- lsl.Append(" PSYS_SRC_BURST_SPEED_MAX, " + String.Format("{0:0.00000}", prim.ParticleSys.BurstSpeedMax) + "," + Environment.NewLine);
- lsl.Append(" PSYS_SRC_INNERANGLE, " + String.Format("{0:0.00000}", prim.ParticleSys.InnerAngle) + "," + Environment.NewLine);
- lsl.Append(" PSYS_SRC_OUTERANGLE, " + String.Format("{0:0.00000}", prim.ParticleSys.OuterAngle) + "," + Environment.NewLine);
- lsl.Append(" PSYS_SRC_OMEGA, " + prim.ParticleSys.AngularVelocity.ToString() + "," + Environment.NewLine);
- lsl.Append(" PSYS_SRC_TEXTURE, (key)\"" + prim.ParticleSys.Texture.ToStringHyphenated() + "\"," + Environment.NewLine);
- lsl.Append(" PSYS_SRC_TARGET_KEY, (key)\"" + prim.ParticleSys.Target.ToStringHyphenated() + "\"" + Environment.NewLine);
-
- lsl.Append(" ]);" + Environment.NewLine);
- lsl.Append(" }" + Environment.NewLine);
- lsl.Append("}" + Environment.NewLine);
+ lsl.Append(" PSYS_PART_START_ALPHA, " + String.Format("{0:0.00000}", prim.ParticleSys.PartStartColor.A) + "," + Environment.NewLine);
+ lsl.Append(" PSYS_PART_END_ALPHA, " + String.Format("{0:0.00000}", prim.ParticleSys.PartEndColor.A) + "," + Environment.NewLine);
+ lsl.Append(" PSYS_PART_START_COLOR, " + prim.ParticleSys.PartStartColor.ToStringRGB() + "," + Environment.NewLine);
+ lsl.Append(" PSYS_PART_END_COLOR, " + prim.ParticleSys.PartEndColor.ToStringRGB() + "," + Environment.NewLine);
+ lsl.Append(" PSYS_PART_START_SCALE, <" + String.Format("{0:0.00000}", prim.ParticleSys.PartStartScaleX) + ", " + String.Format("{0:0.00000}", prim.ParticleSys.PartStartScaleY) + ", 0>, " + Environment.NewLine);
+ lsl.Append(" PSYS_PART_END_SCALE, <" + String.Format("{0:0.00000}", prim.ParticleSys.PartEndScaleX) + ", " + String.Format("{0:0.00000}", prim.ParticleSys.PartEndScaleY) + ", 0>, " + Environment.NewLine);
+ lsl.Append(" PSYS_PART_MAX_AGE, " + String.Format("{0:0.00000}", prim.ParticleSys.PartMaxAge) + "," + Environment.NewLine);
+ lsl.Append(" PSYS_SRC_MAX_AGE, " + String.Format("{0:0.00000}", prim.ParticleSys.MaxAge) + "," + Environment.NewLine);
+ lsl.Append(" PSYS_SRC_ACCEL, " + prim.ParticleSys.PartAcceleration.ToString() + "," + Environment.NewLine);
+ lsl.Append(" PSYS_SRC_BURST_PART_COUNT, " + String.Format("{0:0}", prim.ParticleSys.BurstPartCount) + "," + Environment.NewLine);
+ lsl.Append(" PSYS_SRC_BURST_RADIUS, " + String.Format("{0:0.00000}", prim.ParticleSys.BurstRadius) + "," + Environment.NewLine);
+ lsl.Append(" PSYS_SRC_BURST_RATE, " + String.Format("{0:0.00000}", prim.ParticleSys.BurstRate) + "," + Environment.NewLine);
+ lsl.Append(" PSYS_SRC_BURST_SPEED_MIN, " + String.Format("{0:0.00000}", prim.ParticleSys.BurstSpeedMin) + "," + Environment.NewLine);
+ lsl.Append(" PSYS_SRC_BURST_SPEED_MAX, " + String.Format("{0:0.00000}", prim.ParticleSys.BurstSpeedMax) + "," + Environment.NewLine);
+ lsl.Append(" PSYS_SRC_INNERANGLE, " + String.Format("{0:0.00000}", prim.ParticleSys.InnerAngle) + "," + Environment.NewLine);
+ lsl.Append(" PSYS_SRC_OUTERANGLE, " + String.Format("{0:0.00000}", prim.ParticleSys.OuterAngle) + "," + Environment.NewLine);
+ lsl.Append(" PSYS_SRC_OMEGA, " + prim.ParticleSys.AngularVelocity.ToString() + "," + Environment.NewLine);
+ lsl.Append(" PSYS_SRC_TEXTURE, (key)\"" + prim.ParticleSys.Texture.ToStringHyphenated() + "\"," + Environment.NewLine);
+ lsl.Append(" PSYS_SRC_TARGET_KEY, (key)\"" + prim.ParticleSys.Target.ToStringHyphenated() + "\"" + Environment.NewLine);
+
+ lsl.Append(" ]);" + Environment.NewLine);
+ lsl.Append(" }" + Environment.NewLine);
+ lsl.Append("}" + Environment.NewLine);
- return lsl.ToString();
- }
- else
- {
- return "Prim " + prim.LocalID + " does not have a particle system";
- }
+ return lsl.ToString();
+ }
+ else
+ {
+ return "Prim " + prim.LocalID + " does not have a particle system";
}
}
}
diff --git a/libsecondlife/examples/TestClient/Commands/Prims/ImportCommand.cs b/libsecondlife/examples/TestClient/Commands/Prims/ImportCommand.cs
index e1f42681..c7cceab1 100644
--- a/libsecondlife/examples/TestClient/Commands/Prims/ImportCommand.cs
+++ b/libsecondlife/examples/TestClient/Commands/Prims/ImportCommand.cs
@@ -83,7 +83,7 @@ namespace libsecondlife.TestClient
if (!registeredCreateEvent)
{
- Client.OnPrimCreated += new TestClient.PrimCreatedCallback(TestClient_OnPrimCreated);
+ Client.Objects.OnNewPrim += new ObjectManager.NewPrimCallback(Objects_OnNewPrim);
registeredCreateEvent = true;
}
@@ -197,7 +197,7 @@ namespace libsecondlife.TestClient
return "Import complete.";
}
- void TestClient_OnPrimCreated(Simulator simulator, Primitive prim)
+ void Objects_OnNewPrim(Simulator simulator, Primitive prim, ulong regionHandle, ushort timeDilation)
{
if ((prim.Flags & LLObject.ObjectFlags.CreateSelected) == 0)
return; // We received an update for an object we didn't create
@@ -220,7 +220,7 @@ namespace libsecondlife.TestClient
if (!String.IsNullOrEmpty(currentPrim.Properties.Name))
currentClient.Objects.SetName(simulator, prim.LocalID, currentPrim.Properties.Name);
if (!String.IsNullOrEmpty(currentPrim.Properties.Description))
- currentClient.Objects.SetDescription(simulator, prim.LocalID,
+ currentClient.Objects.SetDescription(simulator, prim.LocalID,
currentPrim.Properties.Description);
primsCreated.Add(prim);
diff --git a/libsecondlife/examples/TestClient/Commands/Prims/PrimCountCommand.cs b/libsecondlife/examples/TestClient/Commands/Prims/PrimCountCommand.cs
index 8adc563c..0ac24faf 100644
--- a/libsecondlife/examples/TestClient/Commands/Prims/PrimCountCommand.cs
+++ b/libsecondlife/examples/TestClient/Commands/Prims/PrimCountCommand.cs
@@ -11,22 +11,28 @@ namespace libsecondlife.TestClient
public PrimCountCommand(TestClient testClient)
{
Name = "primcount";
- Description = "Shows the number of prims that have been received.";
+ Description = "Shows the number of objects currently being tracked.";
}
public override string Execute(string[] args, LLUUID fromAgentID)
{
int count = 0;
- lock (Client.SimPrims)
+ lock (Client.Network.Simulators)
{
- foreach (Dictionary prims in Client.SimPrims.Values)
+ for (int i = 0; i < Client.Network.Simulators.Count; i++)
{
- count += prims.Count;
+ Console.WriteLine("{0} (Avatars: {1} Primitives: {2})",
+ Client.Network.Simulators[i].Name,
+ Client.Network.Simulators[i].Objects.Avatars.Count,
+ Client.Network.Simulators[i].Objects.Prims.Count);
+
+ count += Client.Network.Simulators[i].Objects.Avatars.Count;
+ count += Client.Network.Simulators[i].Objects.Prims.Count;
}
}
- return count.ToString();
+ return "Tracking a total of " + count + " objects";
}
}
}
diff --git a/libsecondlife/examples/TestClient/Commands/Stats/DilationCommand.cs b/libsecondlife/examples/TestClient/Commands/Stats/DilationCommand.cs
index c1d3c043..979282c4 100644
--- a/libsecondlife/examples/TestClient/Commands/Stats/DilationCommand.cs
+++ b/libsecondlife/examples/TestClient/Commands/Stats/DilationCommand.cs
@@ -16,7 +16,7 @@ namespace libsecondlife.TestClient
public override string Execute(string[] args, LLUUID fromAgentID)
{
- return "Dilation is " + Client.Network.CurrentSim.Dilation.ToString();
+ return "Dilation is " + Client.Network.CurrentSim.Stats.Dilation.ToString();
}
}
}
\ No newline at end of file
diff --git a/libsecondlife/examples/TestClient/Commands/Stats/StatsCommand.cs b/libsecondlife/examples/TestClient/Commands/Stats/StatsCommand.cs
index 4e171c58..bbb67579 100644
--- a/libsecondlife/examples/TestClient/Commands/Stats/StatsCommand.cs
+++ b/libsecondlife/examples/TestClient/Commands/Stats/StatsCommand.cs
@@ -26,17 +26,20 @@ namespace libsecondlife.TestClient
output.AppendLine(String.Format(
"[{0}] Dilation: {1} InBPS: {2} OutBPS: {3} ResentOut: {4} ResentIn: {5}",
- sim.ToString(), sim.Dilation, sim.IncomingBPS, sim.OutgoingBPS, sim.ResentPackets,
- sim.ReceivedResends));
+ sim.ToString(), sim.Stats.Dilation, sim.Stats.IncomingBPS, sim.Stats.OutgoingBPS,
+ sim.Stats.ResentPackets, sim.Stats.ReceivedResends));
}
}
+
+ Simulator csim = Client.Network.CurrentSim;
+
output.Append("Packets in the queue: " + Client.Network.InboxCount);
output.AppendLine(String.Format("FPS : {0} PhysicsFPS : {1} AgentUpdates : {2} Objects : {3} Scripted Objects : {4}",
- Client.Network.CurrentSim.FPS, Client.Network.CurrentSim.PhysicsFPS, Client.Network.CurrentSim.AgentUpdates, Client.Network.CurrentSim.Objects, Client.Network.CurrentSim.ScriptedObjects));
+ csim.Stats.FPS, csim.Stats.PhysicsFPS, csim.Stats.AgentUpdates, csim.Stats.Objects, csim.Stats.ScriptedObjects));
output.AppendLine(String.Format("Frame Time : {0} Net Time : {1} Image Time : {2} Physics Time : {3} Script Time : {4} Other Time : {5}",
- Client.Network.CurrentSim.FrameTime, Client.Network.CurrentSim.NetTime, Client.Network.CurrentSim.ImageTime, Client.Network.CurrentSim.PhysicsTime, Client.Network.CurrentSim.ScriptTime, Client.Network.CurrentSim.OtherTime));
+ csim.Stats.FrameTime, csim.Stats.NetTime, csim.Stats.ImageTime, csim.Stats.PhysicsTime, csim.Stats.ScriptTime, csim.Stats.OtherTime));
output.AppendLine(String.Format("Agents : {0} Child Agents : {1} Active Scripts : {2}",
- Client.Network.CurrentSim.Agents, Client.Network.CurrentSim.ChildAgents, Client.Network.CurrentSim.ActiveScripts));
+ csim.Stats.Agents, csim.Stats.ChildAgents, csim.Stats.ActiveScripts));
return output.ToString();
}
diff --git a/libsecondlife/examples/TestClient/Commands/System/SetMasterCommand.cs b/libsecondlife/examples/TestClient/Commands/System/SetMasterCommand.cs
index 66f009ef..49039dd8 100644
--- a/libsecondlife/examples/TestClient/Commands/System/SetMasterCommand.cs
+++ b/libsecondlife/examples/TestClient/Commands/System/SetMasterCommand.cs
@@ -16,9 +16,8 @@ namespace libsecondlife.TestClient
public SetMasterCommand(TestClient testClient)
{
- Name = "setMaster";
- Description = "Sets the user name of the master user. The master user can IM to run commands.";
-
+ Name = "setmaster";
+ Description = "Sets the user name of the master user. The master user can IM to run commands. Usage: setmaster name";
}
public override string Execute(string[] args, LLUUID fromAgentID)
@@ -29,11 +28,13 @@ namespace libsecondlife.TestClient
masterName = masterName.TrimEnd();
if (masterName.Length == 0)
- return "Usage setMaster name";
+ return "Usage: setmaster name";
DirectoryManager.DirPeopleReplyCallback callback = new DirectoryManager.DirPeopleReplyCallback(KeyResolvHandler);
Client.Directory.OnDirPeopleReply += callback;
+
query = Client.Directory.StartPeopleSearch(DirectoryManager.DirFindFlags.People, masterName, 0);
+
if (keyResolution.WaitOne(TimeSpan.FromMinutes(1), false))
{
Client.MasterKey = resolvedMasterKey;
@@ -47,17 +48,28 @@ namespace libsecondlife.TestClient
return "Unable to obtain UUID for \"" + masterName + "\". Master unchanged.";
}
+ // If we see this avatar standing around, IM them. Otherwise don't bother
+ // because they may be offline
+ lock (Client.Network.Simulators)
+ {
+ for (int i = 0; i < Client.Network.Simulators.Count; i++)
+ {
+ lock (Client.Network.Simulators[i].Objects.Avatars)
+ {
+ foreach (Avatar avatar in Client.Network.Simulators[i].Objects.Avatars.Values)
+ {
+ if (avatar.ID == Client.MasterKey)
+ {
+ Client.Self.InstantMessage(avatar.ID,
+ "You are now my master. IM me with \"help\" for a command list.");
+ break;
+ }
+ }
+ }
+ }
+ }
- foreach (Avatar av in Client.AvatarList.Values)
- {
- if (av.ID == Client.MasterKey)
- {
- Client.Self.InstantMessage(av.ID, "You are now my master. IM me with \"help\" for a command list.");
- break;
- }
- }
-
- return "Master set to " + masterName + " (" + Client.MasterKey.ToStringHyphenated() + ")";
+ return String.Format("Master set to {0} ({1})", masterName, Client.MasterKey.ToStringHyphenated());
}
private void KeyResolvHandler(LLUUID queryid, List matches)
diff --git a/libsecondlife/examples/TestClient/Commands/System/SetMasterKeyCommand.cs b/libsecondlife/examples/TestClient/Commands/System/SetMasterKeyCommand.cs
index 0085f791..837eaccd 100644
--- a/libsecondlife/examples/TestClient/Commands/System/SetMasterKeyCommand.cs
+++ b/libsecondlife/examples/TestClient/Commands/System/SetMasterKeyCommand.cs
@@ -20,16 +20,26 @@ namespace libsecondlife.TestClient
{
Client.MasterKey = LLUUID.Parse(args[0]);
- foreach (Avatar av in Client.AvatarList.Values)
+ lock (Client.Network.Simulators)
{
- if (av.ID == Client.MasterKey)
+ for (int i = 0; i < Client.Network.Simulators.Count; i++)
{
- Client.Self.InstantMessage(av.ID, "You are now my master. IM me with \"help\" for a command list.");
- break;
+ lock (Client.Network.Simulators[i].Objects.Avatars)
+ {
+ foreach (Avatar avatar in Client.Network.Simulators[i].Objects.Avatars.Values)
+ {
+ if (avatar.ID == Client.MasterKey)
+ {
+ Client.Self.InstantMessage(avatar.ID,
+ "You are now my master. IM me with \"help\" for a command list.");
+ break;
+ }
+ }
+ }
}
}
- return "Master set to " + Client.MasterKey;
+ return "Master set to " + Client.MasterKey.ToStringHyphenated();
}
}
}
diff --git a/libsecondlife/examples/TestClient/Commands/TouchCommand.cs b/libsecondlife/examples/TestClient/Commands/TouchCommand.cs
index 4103d210..c5cc59bc 100644
--- a/libsecondlife/examples/TestClient/Commands/TouchCommand.cs
+++ b/libsecondlife/examples/TestClient/Commands/TouchCommand.cs
@@ -16,40 +16,27 @@ namespace libsecondlife.TestClient
public override string Execute(string[] args, LLUUID fromAgentID)
{
- Primitive target = null;
+ LLUUID target;
- lock (Client.SimPrims)
- {
- if (Client.SimPrims.ContainsKey(Client.Network.CurrentSim))
+ if (args.Length != 1)
+ return "Usage: touch UUID";
+
+ if (LLUUID.TryParse(args[0], out target))
+ {
+ lock (Client.Network.CurrentSim.Objects.Prims)
{
- foreach (Primitive p in Client.SimPrims[Client.Network.CurrentSim].Values)
+ foreach (Primitive prim in Client.Network.CurrentSim.Objects.Prims.Values)
{
- if (args.Length == 0)
- return "You must specify a UUID of the prim.";
-
- try
+ if (prim.ID == target)
{
- if (p.ID == args[0])
- target = p;
- }
- catch
- {
- // handle exception
- return "Sorry, I don't think " + args[0] + " is a valid UUID. I'm unable to touch it.";
+ Client.Self.Touch(prim.LocalID);
+ return "Touched prim " + prim.LocalID;
}
}
}
- }
+ }
- if (target != null)
- {
- Client.Self.Touch(target.LocalID);
- return "Touched prim " + target.ID + ".";
- }
- else
- {
- return "Couldn't find that prim.";
- }
+ return "Couldn't find a prim to touch with UUID " + args[0];
}
}
}
\ No newline at end of file
diff --git a/libsecondlife/examples/TestClient/Commands/WhoCommand.cs b/libsecondlife/examples/TestClient/Commands/WhoCommand.cs
index 83d8610c..87950ed7 100644
--- a/libsecondlife/examples/TestClient/Commands/WhoCommand.cs
+++ b/libsecondlife/examples/TestClient/Commands/WhoCommand.cs
@@ -17,11 +17,23 @@ namespace libsecondlife.TestClient
public override string Execute(string[] args, LLUUID fromAgentID)
{
StringBuilder result = new StringBuilder();
- foreach (Avatar av in Client.AvatarList.Values)
- {
- result.AppendFormat("\n{0} {1} {2}/{3} ID: {4}", av.Name, av.GroupName,
- (av.CurrentSim != null ? av.CurrentSim.Name : String.Empty), av.Position, av.ID);
- }
+
+ lock (Client.Network.Simulators)
+ {
+ for (int i = 0; i < Client.Network.Simulators.Count; i++)
+ {
+ lock (Client.Network.Simulators[i].Objects.Avatars)
+ {
+ foreach (Avatar av in Client.Network.Simulators[i].Objects.Avatars.Values)
+ {
+ result.AppendLine();
+ result.AppendFormat("{0} (Group: {1}, Location: {2}/{3}, UUID: {4})", av.Name,
+ av.GroupName, (av.CurrentSim != null ? av.CurrentSim.Name : String.Empty),
+ av.Position, av.ID.ToStringHyphenated());
+ }
+ }
+ }
+ }
return result.ToString();
}
diff --git a/libsecondlife/examples/TestClient/TestClient.cs b/libsecondlife/examples/TestClient/TestClient.cs
index f3e35710..fee2e37c 100644
--- a/libsecondlife/examples/TestClient/TestClient.cs
+++ b/libsecondlife/examples/TestClient/TestClient.cs
@@ -9,14 +9,8 @@ namespace libsecondlife.TestClient
{
public class TestClient : SecondLife
{
- public delegate void PrimCreatedCallback(Simulator simulator, Primitive prim);
-
- public event PrimCreatedCallback OnPrimCreated;
-
- public Dictionary> SimPrims;
public LLUUID GroupID = LLUUID.Zero;
public Dictionary GroupMembers;
- public Dictionary AvatarList = new Dictionary();
public Dictionary Appearances = new Dictionary();
public Dictionary Commands = new Dictionary();
public bool Running = true;
@@ -46,15 +40,12 @@ namespace libsecondlife.TestClient
Settings.DEBUG = true;
Settings.STORE_LAND_PATCHES = true;
+ Settings.ALWAYS_DECODE_OBJECTS = true;
Settings.ALWAYS_REQUEST_OBJECTS = true;
Settings.SEND_AGENT_UPDATES = true;
Network.RegisterCallback(PacketType.AgentDataUpdate, new NetworkManager.PacketCallback(AgentDataUpdateHandler));
- Objects.OnNewPrim += new ObjectManager.NewPrimCallback(Objects_OnNewPrim);
- Objects.OnObjectUpdated += new ObjectManager.ObjectUpdatedCallback(Objects_OnObjectUpdated);
- Objects.OnObjectKilled += new ObjectManager.KillObjectCallback(Objects_OnObjectKilled);
- Objects.OnNewAvatar += new ObjectManager.NewAvatarCallback(Objects_OnNewAvatar);
Self.OnInstantMessage += new MainAvatar.InstantMessageCallback(Self_OnInstantMessage);
Groups.OnGroupMembers += new GroupManager.GroupMembersCallback(GroupMembersHandler);
Inventory.OnInventoryObjectReceived += new InventoryManager.InventoryObjectReceived(Inventory_OnInventoryObjectReceived);
@@ -182,83 +173,6 @@ namespace libsecondlife.TestClient
GroupMembers = members;
}
- private void Objects_OnObjectKilled(Simulator simulator, uint objectID)
- {
- lock (SimPrims)
- {
- if (SimPrims.ContainsKey(simulator) && SimPrims[simulator].ContainsKey(objectID))
- SimPrims[simulator].Remove(objectID);
- }
-
- lock (AvatarList)
- {
- if (AvatarList.ContainsKey(objectID))
- AvatarList.Remove(objectID);
- }
- }
-
- private void Objects_OnObjectUpdated(Simulator simulator, ObjectUpdate update, ulong regionHandle, ushort timeDilation)
- {
- if (update.Avatar)
- {
- lock (AvatarList)
- {
- // 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;
- }
- }
- }
- }
-
- private void Objects_OnNewPrim(Simulator simulator, Primitive prim, ulong regionHandle, ushort timeDilation)
- {
- lock (SimPrims)
- {
- if (!SimPrims.ContainsKey(simulator))
- {
- SimPrims[simulator] = new Dictionary(10000);
- }
-
- SimPrims[simulator][prim.LocalID] = prim;
- }
-
- if ((prim.Flags & LLObject.ObjectFlags.CreateSelected) != 0 && OnPrimCreated != null)
- {
- OnPrimCreated(simulator, prim);
- }
- }
-
- private void Objects_OnNewAvatar(Simulator simulator, Avatar avatar, ulong regionHandle, ushort timeDilation)
- {
- lock (AvatarList)
- {
- AvatarList[avatar.LocalID] = avatar;
- }
- }
-
private void AvatarAppearanceHandler(Packet packet, Simulator simulator)
{
AvatarAppearancePacket appearance = (AvatarAppearancePacket)packet;
diff --git a/libsecondlife/libsecondlife.csproj b/libsecondlife/libsecondlife.csproj
index 43c857e2..ec3056f0 100644
--- a/libsecondlife/libsecondlife.csproj
+++ b/libsecondlife/libsecondlife.csproj
@@ -132,6 +132,7 @@
Code
+