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
This commit is contained in:
Michael Cortez
2007-01-19 20:53:05 +00:00
parent 2cbfdfef13
commit a4ddb0d8db
3 changed files with 210 additions and 94 deletions

View File

@@ -88,6 +88,7 @@ namespace libsecondlife
/// </summary>
public class ObjectManager
{
#region CallBack Definitions
/// <summary>
///
/// </summary>
@@ -162,6 +163,10 @@ namespace libsecondlife
/// on. If this is zero the avatar is not sitting on an object</param>
public delegate void AvatarSitChanged(Simulator simulator, uint sittingOn);
#endregion
#region Object/Prim Enums
/// <summary>
///
/// </summary>
@@ -345,6 +350,10 @@ namespace libsecondlife
undergrowth_1
}
#endregion
#region Events
/// <summary>
/// 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.
/// </summary>
///
#endregion
public bool RequestAllObjects = false;
private SecondLife Client;
protected SecondLife Client;
/// <summary>
/// Instantiates a new ObjectManager class. This class should only be accessed
@@ -431,7 +443,27 @@ namespace libsecondlife
public ObjectManager(SecondLife client)
{
Client = client;
RegisterCallbacks();
}
/// <summary>
/// Instantiates a new ObjectManager class. This class should only be accessed
/// through SecondLife.Objects, client applications should never create their own
/// </summary>
/// <remarks>This constructor allows a subclass to determine if callbacks should be registered here or not.</remarks>
/// <param name="client">A reference to the client</param>
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
/// <summary>
/// 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)
/// <summary>
/// Used for new prims, or significant changes to existing prims
/// </summary>
/// <param name="packet"></param>
/// <param name="simulator"></param>
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)
/// <summary>
/// Usually called when an Prim moves.
/// </summary>
/// <param name="packet"></param>
/// <param name="simulator"></param>
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
/// <param name="lower">The lower quantization range</param>
/// <param name="upper">The upper quantization range</param>
/// <returns>A 32-bit floating point representation of the dequantized value</returns>
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
}
}