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 +