From a4ddb0d8db93e58dddbd2b242d1247cab9d90bec Mon Sep 17 00:00:00 2001 From: Michael Cortez Date: Fri, 19 Jan 2007 20:53:05 +0000 Subject: [PATCH] Refactor ObjectManager to allow subclassing. For an example of a subclass see the ObjectOverlord (ObjectManager w/ Object tracking) in the Feathertail project (http://code.google.com/p/feathertail/) git-svn-id: http://libopenmetaverse.googlecode.com/svn/trunk@861 52acb1d6-8a22-11de-b505-999d5b087335 --- .../InventorySystem/InventoryItem.cs | 1 - libsecondlife-cs/MainAvatar.cs | 5 + libsecondlife-cs/ObjectManager.cs | 298 ++++++++++++------ 3 files changed, 210 insertions(+), 94 deletions(-) diff --git a/libsecondlife-cs/InventorySystem/InventoryItem.cs b/libsecondlife-cs/InventorySystem/InventoryItem.cs index 795fcf2a..671e5d57 100644 --- a/libsecondlife-cs/InventorySystem/InventoryItem.cs +++ b/libsecondlife-cs/InventorySystem/InventoryItem.cs @@ -130,7 +130,6 @@ namespace libsecondlife.InventorySystem { if ((AssetID != null) && (AssetID != LLUUID.Zero)) { - Console.WriteLine("Using the base asset download"); AssetRequestDownload request = base.iManager.AssetManager.RequestInventoryAsset(this); if (request.Wait(AssetManager.DefaultTimeout) != AssetRequestDownload.RequestStatus.Success) { diff --git a/libsecondlife-cs/MainAvatar.cs b/libsecondlife-cs/MainAvatar.cs index 9503bd98..809eae49 100644 --- a/libsecondlife-cs/MainAvatar.cs +++ b/libsecondlife-cs/MainAvatar.cs @@ -39,6 +39,7 @@ namespace libsecondlife /// public partial class MainAvatar { + #region Enums /// /// Current teleport status /// @@ -253,7 +254,9 @@ namespace libsecondlife Clear } + #endregion + #region Callbacks & Events /// /// Triggered on incoming chat messages /// @@ -353,6 +356,8 @@ namespace libsecondlife /// Callback for informing the avatar that it is no longer a member of a group public event GroupDroppedCallback OnGroupDropped; + #endregion + /// Your (client) Avatar UUID, asset server public LLUUID ID = LLUUID.Zero; /// Your (client) Avatar ID, local to Region/sim diff --git a/libsecondlife-cs/ObjectManager.cs b/libsecondlife-cs/ObjectManager.cs index 3f2cebf1..80eeb869 100644 --- a/libsecondlife-cs/ObjectManager.cs +++ b/libsecondlife-cs/ObjectManager.cs @@ -88,6 +88,7 @@ namespace libsecondlife /// public class ObjectManager { + #region CallBack Definitions /// /// /// @@ -162,6 +163,10 @@ namespace libsecondlife /// on. If this is zero the avatar is not sitting on an object public delegate void AvatarSitChanged(Simulator simulator, uint sittingOn); + #endregion + + #region Object/Prim Enums + /// /// /// @@ -345,6 +350,10 @@ namespace libsecondlife undergrowth_1 } + #endregion + + #region Events + /// /// This event will be raised for every ObjectUpdate block that /// contains a prim that isn't attached to an avatar. @@ -419,9 +428,12 @@ namespace libsecondlife /// the full object info will automatically be requested. /// /// + + #endregion + public bool RequestAllObjects = false; - private SecondLife Client; + protected SecondLife Client; /// /// Instantiates a new ObjectManager class. This class should only be accessed @@ -431,7 +443,27 @@ namespace libsecondlife public ObjectManager(SecondLife client) { Client = client; + RegisterCallbacks(); + } + /// + /// Instantiates a new ObjectManager class. This class should only be accessed + /// through SecondLife.Objects, client applications should never create their own + /// + /// This constructor allows a subclass to determine if callbacks should be registered here or not. + /// A reference to the client + protected ObjectManager(SecondLife client, bool registerCallbacks) + { + Client = client; + + if (registerCallbacks) + { + RegisterCallbacks(); + } + } + + protected void RegisterCallbacks() + { Client.Network.RegisterCallback(PacketType.ObjectUpdate, new NetworkManager.PacketCallback(UpdateHandler)); Client.Network.RegisterCallback(PacketType.ImprovedTerseObjectUpdate, new NetworkManager.PacketCallback(TerseUpdateHandler)); Client.Network.RegisterCallback(PacketType.ObjectUpdateCompressed, new NetworkManager.PacketCallback(CompressedUpdateHandler)); @@ -440,6 +472,8 @@ namespace libsecondlife Client.Network.RegisterCallback(PacketType.ObjectPropertiesFamily, new NetworkManager.PacketCallback(ObjectPropertiesFamilyHandler)); } + #region Action Methods + /// /// Request object information from the sim, primarily used for stale /// or missing cache entries @@ -868,35 +902,16 @@ namespace libsecondlife Client.Network.SendPacket(properties, simulator); } - private void ParseAvName(string name, ref string firstName, ref string lastName, ref string groupName) - { - // FIXME: This needs to be reworked completely. It fails on anything containing unicode - // (which would break FieldToString as well), or name strings that don't contain the - // most common attributes which is all we handle right now. - string[] lines = name.Split('\n'); + #endregion + + #region Packet Handlers - foreach (string line in lines) - { - if (line.Substring(0, 19) == "Title STRING RW SV ") - { - groupName = line.Substring(19); - } - else if (line.Substring(0, 23) == "FirstName STRING RW SV ") - { - firstName = line.Substring(23); - } - else if (line.Substring(0, 22) == "LastName STRING RW SV ") - { - lastName = line.Substring(22); - } - else - { - Client.Log("Unhandled line in an avatar name: " + line, Helpers.LogLevel.Warning); - } - } - } - - private void UpdateHandler(Packet packet, Simulator simulator) + /// + /// Used for new prims, or significant changes to existing prims + /// + /// + /// + protected void UpdateHandler(Packet packet, Simulator simulator) { if (OnNewPrim != null || OnNewAttachment != null || OnNewAvatar != null || OnNewFoliage != null) { @@ -969,21 +984,15 @@ namespace libsecondlife if (prim.Name.StartsWith("AttachItemID")) { - if (OnNewAttachment != null) - { - OnNewAttachment(simulator, prim, update.RegionData.RegionHandle, update.RegionData.TimeDilation); - } + FireOnNewAttachment(simulator, prim, update.RegionData.RegionHandle, update.RegionData.TimeDilation); } else if (block.PCode == (byte)PCode.Tree || block.PCode == (byte)PCode.Grass) { - if (OnNewFoliage != null) - { - OnNewFoliage(simulator, prim, update.RegionData.RegionHandle, update.RegionData.TimeDilation); - } + FireOnNewFoliage(simulator, prim, update.RegionData.RegionHandle, update.RegionData.TimeDilation); } - else if (OnNewPrim != null) + else { - OnNewPrim(simulator, prim, update.RegionData.RegionHandle, update.RegionData.TimeDilation); + FireOnNewPrim(simulator, prim, update.RegionData.RegionHandle, update.RegionData.TimeDilation); } break; @@ -999,13 +1008,13 @@ namespace libsecondlife // TODO: Parse the rest of the ObjectData byte array fields // Detect if we are sitting or standing - uint oldSittingOn = Client.Self.sittingOn; - Client.Self.sittingOn = block.ParentID; + uint oldSittingOn = Client.Self.SittingOn; // Fire the callback for our sitting orientation changing - if (Client.Self.sittingOn != oldSittingOn && OnAvatarSitChanged != null) + if (block.ParentID != oldSittingOn) { - OnAvatarSitChanged(simulator, Client.Self.sittingOn); + SetAvatarSelfSittingOn(block.ParentID); + FireOnAvatarSitChanged(simulator, Client.Self.SittingOn); } } @@ -1022,7 +1031,7 @@ namespace libsecondlife avatar.Rotation = new LLQuaternion(block.ObjectData, 52, true); // TODO: Parse the rest of the ObjectData byte array fields - avatar.sittingOn = block.ParentID; + SetAvatarSittingOn(avatar, block.ParentID); ParseAvName(Helpers.FieldToString(block.NameValue), ref FirstName, ref LastName, ref GroupName); @@ -1035,10 +1044,7 @@ namespace libsecondlife avatar.Textures = new TextureEntry(block.TextureEntry, 0, block.TextureEntry.Length); - if (OnNewAvatar != null) - { - OnNewAvatar(simulator, avatar, update.RegionData.RegionHandle, update.RegionData.TimeDilation); - } + FireOnNewAvatar(simulator, avatar, update.RegionData.RegionHandle, update.RegionData.TimeDilation); } break; case (byte)PCode.ParticleSystem: @@ -1052,7 +1058,12 @@ namespace libsecondlife } } - private void TerseUpdateHandler(Packet packet, Simulator simulator) + /// + /// Usually called when an Prim moves. + /// + /// + /// + protected void TerseUpdateHandler(Packet packet, Simulator simulator) { float x, y, z, w; uint localid; @@ -1146,10 +1157,7 @@ namespace libsecondlife avupdate.RotationVelocity = RotationVelocity; avupdate.Textures = new TextureEntry(block.TextureEntry, 4, block.TextureEntry.Length - 4); - if (OnAvatarMoved != null) - { - OnAvatarMoved(simulator, avupdate, update.RegionData.RegionHandle, update.RegionData.TimeDilation); - } + FireOnAvatarMoved(simulator, avupdate, update.RegionData.RegionHandle, update.RegionData.TimeDilation); } else { @@ -1168,17 +1176,16 @@ namespace libsecondlife primupdate.RotationVelocity = RotationVelocity; primupdate.Textures = new TextureEntry(block.TextureEntry, 4, block.TextureEntry.Length - 4); - if (OnPrimMoved != null) - { - OnPrimMoved(simulator, primupdate, update.RegionData.RegionHandle, update.RegionData.TimeDilation); - } + FireOnPrimMoved(simulator, primupdate, update.RegionData.RegionHandle, update.RegionData.TimeDilation); } } } + + #pragma warning disable 0219 // disable "value assigned but never used" while this function is incomplete - private void CompressedUpdateHandler(Packet packet, Simulator simulator) + protected void CompressedUpdateHandler(Packet packet, Simulator simulator) { if (OnNewPrim != null || OnNewAvatar != null || OnNewAttachment != null || OnNewFoliage != null) { @@ -1373,21 +1380,15 @@ namespace libsecondlife // Fire the appropriate callback if ((flags & CompressedFlags.Attachment) != 0) { - if (OnNewAttachment != null) - { - OnNewAttachment(simulator, prim, update.RegionData.RegionHandle, update.RegionData.TimeDilation); - } + FireOnNewAttachment(simulator, prim, update.RegionData.RegionHandle, update.RegionData.TimeDilation); } else if ((flags & CompressedFlags.Tree) != 0) { - if (OnNewFoliage != null) - { - OnNewFoliage(simulator, prim, update.RegionData.RegionHandle, update.RegionData.TimeDilation); - } + FireOnNewFoliage(simulator, prim, update.RegionData.RegionHandle, update.RegionData.TimeDilation); } else if (OnNewPrim != null) { - OnNewPrim(simulator, prim, update.RegionData.RegionHandle, update.RegionData.TimeDilation); + FireOnNewPrim(simulator, prim, update.RegionData.RegionHandle, update.RegionData.TimeDilation); } #endregion Prim } @@ -1413,7 +1414,7 @@ namespace libsecondlife } #pragma warning restore 0219 - private void CachedUpdateHandler(Packet packet, Simulator simulator) + protected void CachedUpdateHandler(Packet packet, Simulator simulator) { if (RequestAllObjects) { @@ -1430,13 +1431,74 @@ namespace libsecondlife } } - private void KillObjectHandler(Packet packet, Simulator simulator) + protected void KillObjectHandler(Packet packet, Simulator simulator) { - if (OnObjectKilled != null) + foreach (KillObjectPacket.ObjectDataBlock block in ((KillObjectPacket)packet).ObjectData) { - foreach (KillObjectPacket.ObjectDataBlock block in ((KillObjectPacket)packet).ObjectData) + FireOnObjectKilled(simulator, block.ID); + } + } + + protected void ObjectPropertiesFamilyHandler(Packet p, Simulator sim) + { + ObjectPropertiesFamilyPacket op = (ObjectPropertiesFamilyPacket)p; + ObjectProperties props = new ObjectProperties(); + + props.BaseMask = op.ObjectData.BaseMask; + props.Category = op.ObjectData.Category; + props.Description = Helpers.FieldToString(op.ObjectData.Description); + props.EveryoneMask = op.ObjectData.EveryoneMask; + props.GroupID = op.ObjectData.GroupID; + props.GroupMask = op.ObjectData.GroupMask; + props.LastOwnerID = op.ObjectData.LastOwnerID; + props.Name = Helpers.FieldToString(op.ObjectData.Name); + props.NextOwnerMask = op.ObjectData.NextOwnerMask; + props.ObjectID = op.ObjectData.ObjectID; + props.OwnerID = op.ObjectData.OwnerID; + props.OwnerMask = op.ObjectData.OwnerMask; + props.OwnershipCost = op.ObjectData.OwnershipCost; + props.SalePrice = op.ObjectData.SalePrice; + props.SaleType = op.ObjectData.SaleType; + + FireOnObjectProperties(sim, props); + } + + #endregion + + #region Utility Functions + protected void SetAvatarSelfSittingOn(uint localid) + { + Client.Self.sittingOn = localid; + } + protected void SetAvatarSittingOn(Avatar av, uint localid) + { + av.sittingOn = localid; + } + + protected void ParseAvName(string name, ref string firstName, ref string lastName, ref string groupName) + { + // FIXME: This needs to be reworked completely. It fails on anything containing unicode + // (which would break FieldToString as well), or name strings that don't contain the + // most common attributes which is all we handle right now. + string[] lines = name.Split('\n'); + + foreach (string line in lines) + { + if (line.Substring(0, 19) == "Title STRING RW SV ") { - OnObjectKilled(simulator, block.ID); + groupName = line.Substring(19); + } + else if (line.Substring(0, 23) == "FirstName STRING RW SV ") + { + firstName = line.Substring(23); + } + else if (line.Substring(0, 22) == "LastName STRING RW SV ") + { + lastName = line.Substring(22); + } + else + { + Client.Log("Unhandled line in an avatar name: " + line, Helpers.LogLevel.Warning); } } } @@ -1452,7 +1514,7 @@ namespace libsecondlife /// The lower quantization range /// The upper quantization range /// A 32-bit floating point representation of the dequantized value - private float Dequantize(byte[] byteArray, int pos, float lower, float upper) + protected float Dequantize(byte[] byteArray, int pos, float lower, float upper) { ushort value = (ushort)(byteArray[pos] + (byteArray[pos + 1] << 8)); float QV = (float)value; @@ -1460,32 +1522,82 @@ namespace libsecondlife float QF = range / 65536.0F; return (float)((QV * QF - (0.5F * range)) + QF); } + #endregion - private void ObjectPropertiesFamilyHandler(Packet p, Simulator sim) + #region Event Notification + + protected void FireOnObjectProperties(Simulator sim, ObjectProperties props) { if (OnObjectProperties != null) { - ObjectPropertiesFamilyPacket op = (ObjectPropertiesFamilyPacket)p; - ObjectProperties props = new ObjectProperties(); - - props.BaseMask = op.ObjectData.BaseMask; - props.Category = op.ObjectData.Category; - props.Description = Helpers.FieldToString(op.ObjectData.Description); - props.EveryoneMask = op.ObjectData.EveryoneMask; - props.GroupID = op.ObjectData.GroupID; - props.GroupMask = op.ObjectData.GroupMask; - props.LastOwnerID = op.ObjectData.LastOwnerID; - props.Name = Helpers.FieldToString(op.ObjectData.Name); - props.NextOwnerMask = op.ObjectData.NextOwnerMask; - props.ObjectID = op.ObjectData.ObjectID; - props.OwnerID = op.ObjectData.OwnerID; - props.OwnerMask = op.ObjectData.OwnerMask; - props.OwnershipCost = op.ObjectData.OwnershipCost; - props.SalePrice = op.ObjectData.SalePrice; - props.SaleType = op.ObjectData.SaleType; - OnObjectProperties(sim, props); } } + + protected void FireOnObjectKilled(Simulator simulator, uint localid) + { + if (OnObjectKilled != null) + { + OnObjectKilled(simulator, localid); + } + } + + protected void FireOnNewPrim(Simulator simulator, PrimObject prim, ulong RegionHandle, ushort TimeDilation) + { + if (OnNewPrim != null) + { + OnNewPrim(simulator, prim, RegionHandle, TimeDilation); + } + } + + protected void FireOnNewFoliage(Simulator simulator, PrimObject prim, ulong RegionHandle, ushort TimeDilation) + { + if (OnNewFoliage != null) + { + OnNewFoliage(simulator, prim, RegionHandle, TimeDilation); + } + } + + protected void FireOnNewAttachment(Simulator simulator, PrimObject prim, ulong RegionHandle, ushort TimeDilation) + { + if (OnNewAttachment != null) + { + OnNewAttachment(simulator, prim, RegionHandle, TimeDilation); + } + } + + protected void FireOnAvatarSitChanged(Simulator simulator, uint LocalID) + { + if (OnAvatarSitChanged != null) + { + OnAvatarSitChanged(simulator, Client.Self.sittingOn); + } + } + + protected void FireOnNewAvatar(Simulator simulator, Avatar avatar, ulong RegionHandle, ushort TimeDilation) + { + if (OnNewAvatar != null) + { + OnNewAvatar(simulator, avatar, RegionHandle, TimeDilation); + } + } + + protected void FireOnPrimMoved(Simulator simulator, PrimUpdate primupdate, ulong RegionHandle, ushort TimeDilation) + { + if (OnPrimMoved != null) + { + OnPrimMoved(simulator, primupdate, RegionHandle, TimeDilation); + } + } + + protected void FireOnAvatarMoved(Simulator simulator, AvatarUpdate avupdate, ulong RegionHandle, ushort TimeDilation) + { + if (OnAvatarMoved != null) + { + OnAvatarMoved(simulator, avupdate, RegionHandle, TimeDilation); + } + } + + #endregion } }