diff --git a/libsecondlife/AvatarManager.cs b/libsecondlife/AvatarManager.cs index 9291e657..00d3bcbb 100644 --- a/libsecondlife/AvatarManager.cs +++ b/libsecondlife/AvatarManager.cs @@ -78,6 +78,39 @@ namespace libsecondlife /// /// public delegate void AvatarNameSearchCallback(LLUUID queryID, Dictionary avatars); + /// + /// + /// + /// + /// + /// + /// + /// + /// + public delegate void PointAtCallback(LLUUID sourceID, LLUUID targetID, LLVector3d targetPos, + MainAvatar.PointAtType pointType, float duration, LLUUID id); + /// + /// + /// + /// + /// + /// + /// + /// + /// + public delegate void LookAtCallback(LLUUID sourceID, LLUUID targetID, LLVector3d targetPos, + MainAvatar.LookAtType lookType, float duration, LLUUID id); + /// + /// + /// + /// + /// + /// + /// + /// + /// + public delegate void EffectCallback(MainAvatar.EffectType type, LLUUID sourceID, LLUUID targetID, + LLVector3d targetPos, float duration, LLUUID id); /// Triggered whenever a friend comes online or goes offline @@ -94,6 +127,12 @@ namespace libsecondlife public event AvatarGroupsCallback OnAvatarGroups; /// public event AvatarNameSearchCallback OnAvatarNameSearch; + /// + public event PointAtCallback OnPointAt; + /// + public event LookAtCallback OnLookAt; + /// + public event EffectCallback OnEffect; private SecondLife Client; @@ -190,6 +229,8 @@ namespace libsecondlife Client.Network.SendPacket(aprp); } + #region Packet Handlers + /// /// Process an incoming UUIDNameReply Packet and insert Full Names into the Avatars Dictionary /// @@ -368,18 +409,7 @@ namespace libsecondlife foreach (ViewerEffectPacket.EffectBlock block in effect.Effect) { - MainAvatar.EffectType type; - - try - { - type = (MainAvatar.EffectType)block.Type; - } - catch (Exception) - { - Client.Log("Received a ViewerEffect block with an unknown type " + block.Type, - Helpers.LogLevel.Warning); - continue; - } + MainAvatar.EffectType type = (MainAvatar.EffectType)block.Type; //LLColor color; //if (block.Color.Length == 4) @@ -388,87 +418,120 @@ namespace libsecondlife //} //else //{ - // Client.Log("Received a ViewerEffect.EffectBlock.Color array with " + block.Color.Length + " bytes", - // Helpers.LogLevel.Warning); - // color = new LLColor(); + // Client.Log("Received a ViewerEffect.EffectBlock.Color array with " + block.Color.Length + + // " bytes", Helpers.LogLevel.Warning); + // color = LLColor.Black; //} // Each ViewerEffect type uses it's own custom binary format for additional data. Fun eh? switch (type) { case MainAvatar.EffectType.Text: - //Client.DebugLog("Received a ViewerEffect of type " + type.ToString() + ", implement me!"); + Client.Log("Received a ViewerEffect of type " + type.ToString() + ", implement me!", + Helpers.LogLevel.Warning); break; case MainAvatar.EffectType.Icon: - //Client.DebugLog("Received a ViewerEffect of type " + type.ToString() + ", implement me!"); + Client.Log("Received a ViewerEffect of type " + type.ToString() + ", implement me!", + Helpers.LogLevel.Warning); break; case MainAvatar.EffectType.Connector: - //Client.DebugLog("Received a ViewerEffect of type " + type.ToString() + ", implement me!"); + Client.Log("Received a ViewerEffect of type " + type.ToString() + ", implement me!", + Helpers.LogLevel.Warning); break; case MainAvatar.EffectType.FlexibleObject: - //Client.DebugLog("Received a ViewerEffect of type " + type.ToString() + ", implement me!"); + Client.Log("Received a ViewerEffect of type " + type.ToString() + ", implement me!", + Helpers.LogLevel.Warning); break; case MainAvatar.EffectType.AnimalControls: - //Client.DebugLog("Received a ViewerEffect of type " + type.ToString() + ", implement me!"); + Client.Log("Received a ViewerEffect of type " + type.ToString() + ", implement me!", + Helpers.LogLevel.Warning); break; case MainAvatar.EffectType.AnimationObject: - //Client.DebugLog("Received a ViewerEffect of type " + type.ToString() + ", implement me!"); + Client.Log("Received a ViewerEffect of type " + type.ToString() + ", implement me!", + Helpers.LogLevel.Warning); break; case MainAvatar.EffectType.Cloth: - //Client.DebugLog("Received a ViewerEffect of type " + type.ToString() + ", implement me!"); - break; - case MainAvatar.EffectType.Beam: - //Client.DebugLog("Received a ViewerEffect of type " + type.ToString() + ", implement me!"); + Client.Log("Received a ViewerEffect of type " + type.ToString() + ", implement me!", + Helpers.LogLevel.Warning); break; case MainAvatar.EffectType.Glow: Client.Log("Received a Glow ViewerEffect which is not implemented yet", Helpers.LogLevel.Warning); break; + case MainAvatar.EffectType.Beam: case MainAvatar.EffectType.Point: - //Client.DebugLog("Received a ViewerEffect of type " + type.ToString() + ", implement me!"); - break; case MainAvatar.EffectType.Trail: - //Client.DebugLog("Received a ViewerEffect of type " + type.ToString() + ", implement me!"); - break; case MainAvatar.EffectType.Sphere: - //Client.DebugLog("Received a ViewerEffect of type " + type.ToString() + ", implement me!"); - break; case MainAvatar.EffectType.Spiral: - //Client.DebugLog("Received a ViewerEffect of type " + type.ToString() + ", implement me!"); - break; case MainAvatar.EffectType.Edit: - //Client.DebugLog("Received a ViewerEffect of type " + type.ToString() + ", implement me!"); + if (OnEffect != null) + { + if (block.TypeData.Length == 56) + { + LLUUID sourceAvatar = new LLUUID(block.TypeData, 0); + LLUUID targetObject = new LLUUID(block.TypeData, 16); + LLVector3d targetPos = new LLVector3d(block.TypeData, 32); + + try { OnEffect(type, sourceAvatar, targetObject, targetPos, block.Duration, block.ID); } + catch (Exception e) { Client.Log(e.ToString(), Helpers.LogLevel.Error); } + } + else + { + Client.Log("Received a " + type.ToString() + + " ViewerEffect with an incorrect TypeData size of " + + block.TypeData.Length + " bytes", Helpers.LogLevel.Warning); + } + } break; case MainAvatar.EffectType.LookAt: - //Client.DebugLog("Received a ViewerEffect of type " + type.ToString() + ", implement me!"); + if (OnLookAt != null) + { + if (block.TypeData.Length == 57) + { + LLUUID sourceAvatar = new LLUUID(block.TypeData, 0); + LLUUID targetObject = new LLUUID(block.TypeData, 16); + LLVector3d targetPos = new LLVector3d(block.TypeData, 32); + MainAvatar.LookAtType lookAt = (MainAvatar.LookAtType)block.TypeData[56]; + + try { OnLookAt(sourceAvatar, targetObject, targetPos, lookAt, block.Duration, + block.ID); } + catch (Exception e) { Client.Log(e.ToString(), Helpers.LogLevel.Error); } + } + else + { + Client.Log("Received a LookAt ViewerEffect with an incorrect TypeData size of " + + block.TypeData.Length + " bytes", Helpers.LogLevel.Warning); + } + } break; case MainAvatar.EffectType.PointAt: -/* if (block.TypeData.Length == 57) + if (OnPointAt != null) { - LLUUID sourceAvatar = new LLUUID(block.TypeData, 0); - LLUUID targetObject = new LLUUID(block.TypeData, 16); - LLVector3d targetPos = new LLVector3d(block.TypeData, 32); - MainAvatar.PointAtType pointAt; - try + if (block.TypeData.Length == 57) { - pointAt = (MainAvatar.PointAtType)block.TypeData[56]; - } - catch (Exception) - { - Client.Log("Unrecognized PointAtType " + block.TypeData[56], Helpers.LogLevel.Warning); - pointAt = MainAvatar.PointAtType.Clear; - } + LLUUID sourceAvatar = new LLUUID(block.TypeData, 0); + LLUUID targetObject = new LLUUID(block.TypeData, 16); + LLVector3d targetPos = new LLVector3d(block.TypeData, 32); + MainAvatar.PointAtType pointAt = (MainAvatar.PointAtType)block.TypeData[56]; - // TODO: Create a OnAvatarPointAt event and call it here + try { OnPointAt(sourceAvatar, targetObject, targetPos, pointAt, block.Duration, + block.ID); } + catch (Exception e) { Client.Log(e.ToString(), Helpers.LogLevel.Error); } + } + else + { + Client.Log("Received a PointAt ViewerEffect with an incorrect TypeData size of " + + block.TypeData.Length + " bytes", Helpers.LogLevel.Warning); + } } - else - { - Client.Log("Received a PointAt ViewerEffect with an incorrect TypeData size of " + - block.TypeData.Length + " bytes", Helpers.LogLevel.Warning); - } */ + break; + default: + Client.Log("Received a ViewerEffect with an unknown type " + type, Helpers.LogLevel.Warning); break; } } } + + #endregion Packet Handlers } } diff --git a/libsecondlife/MainAvatar.cs b/libsecondlife/MainAvatar.cs index 5ed0c490..5b4ea243 100644 --- a/libsecondlife/MainAvatar.cs +++ b/libsecondlife/MainAvatar.cs @@ -402,7 +402,7 @@ namespace libsecondlife /// The action an avatar is doing when looking at something, used in /// ViewerEffect packets for the LookAt effect /// - public enum LookAtTarget : byte + public enum LookAtType : byte { /// None, @@ -979,7 +979,7 @@ namespace libsecondlife /// /// /// - public void LookAtEffect(LLUUID sourceAvatar, LLUUID targetObject, LLVector3d globalOffset, LookAtTarget type) + public void LookAtEffect(LLUUID sourceAvatar, LLUUID targetObject, LLVector3d globalOffset, LookAtType type) { ViewerEffectPacket effect = new ViewerEffectPacket(); @@ -990,27 +990,27 @@ namespace libsecondlife switch (type) { - case LookAtTarget.Clear: + case LookAtType.Clear: duration = 0.0f; break; - case LookAtTarget.Hover: + case LookAtType.Hover: duration = 1.0f; break; - case LookAtTarget.FreeLook: + case LookAtType.FreeLook: duration = 2.0f; break; - case LookAtTarget.Idle: + case LookAtType.Idle: duration = 3.0f; break; - case LookAtTarget.AutoListen: - case LookAtTarget.Respond: + case LookAtType.AutoListen: + case LookAtType.Respond: duration = 4.0f; break; - case LookAtTarget.None: - case LookAtTarget.Conversation: - case LookAtTarget.Select: - case LookAtTarget.Focus: - case LookAtTarget.Mouselook: + case LookAtType.None: + case LookAtType.Conversation: + case LookAtType.Select: + case LookAtType.Focus: + case LookAtType.Mouselook: duration = Single.MaxValue / 2.0f; break; default: diff --git a/libsecondlife/examples/TestClient/Commands/ExportCommand.cs b/libsecondlife/examples/TestClient/Commands/ExportCommand.cs index 2e61d56a..da4e45f2 100644 --- a/libsecondlife/examples/TestClient/Commands/ExportCommand.cs +++ b/libsecondlife/examples/TestClient/Commands/ExportCommand.cs @@ -14,6 +14,7 @@ namespace libsecondlife.TestClient AutoResetEvent GotPermissionsEvent = new AutoResetEvent(false); LLObject.ObjectPropertiesFamily Properties; bool GotPermissions = false; + LLUUID SelectedObject = LLUUID.Zero; Dictionary PrimsWaiting = new Dictionary(); AutoResetEvent AllPropertiesReceived = new AutoResetEvent(false); @@ -22,22 +23,33 @@ namespace libsecondlife.TestClient { testClient.Objects.OnObjectPropertiesFamily += new ObjectManager.ObjectPropertiesFamilyCallback(Objects_OnObjectPropertiesFamily); testClient.Objects.OnObjectProperties += new ObjectManager.ObjectPropertiesCallback(Objects_OnObjectProperties); + testClient.Avatars.OnPointAt += new AvatarManager.PointAtCallback(Avatars_OnPointAt); + Name = "export"; Description = "Exports an object to an xml file. Usage: export uuid outputfile.xml"; } public override string Execute(string[] args, LLUUID fromAgentID) { - if (args.Length != 2) + if (args.Length != 2 && !(args.Length == 1 && SelectedObject != LLUUID.Zero)) return "Usage: export uuid outputfile.xml"; LLUUID id; uint localid = 0; int count = 0; - string file = args[1]; + string file; - if (!LLUUID.TryParse(args[0], out id)) - return "Usage: export uuid outputfile.xml"; + if (args.Length == 2) + { + file = args[1]; + if (!LLUUID.TryParse(args[0], out id)) + return "Usage: export uuid outputfile.xml"; + } + else + { + file = args[0]; + id = SelectedObject; + } lock (Client.SimPrims) { @@ -48,13 +60,9 @@ namespace libsecondlife.TestClient if (prim.ID == id) { if (prim.ParentID != 0) - { localid = prim.ParentID; - } else - { localid = prim.LocalID; - } break; } @@ -75,9 +83,10 @@ namespace libsecondlife.TestClient else { GotPermissions = false; - if (Properties.OwnerID != Client.Network.AgentID && Client.Network.AgentID != Client.Self.ID) + if (Properties.OwnerID != Client.Network.AgentID && + Properties.OwnerID != Client.MasterKey && + Client.Network.AgentID != Client.Self.ID) { - // FIXME: We need a MasterID field, those exports should be allowed as well return "That object is owned by " + Properties.OwnerID + ", we don't have permission " + "to export it"; } @@ -164,6 +173,16 @@ namespace libsecondlife.TestClient return AllPropertiesReceived.WaitOne(2000 + msPerRequest * objects.Count, false); } + void Avatars_OnPointAt(LLUUID sourceID, LLUUID targetID, LLVector3d targetPos, + MainAvatar.PointAtType pointType, float duration, LLUUID id) + { + if (sourceID == Client.MasterKey) + { + //Client.DebugLog("Master is now selecting " + targetID.ToStringHyphenated()); + SelectedObject = targetID; + } + } + void Objects_OnObjectPropertiesFamily(Simulator simulator, LLObject.ObjectPropertiesFamily properties) { Properties = properties; diff --git a/libsecondlife/examples/TestClient/Commands/ShowEffectsCommand.cs b/libsecondlife/examples/TestClient/Commands/ShowEffectsCommand.cs new file mode 100644 index 00000000..4d46e35a --- /dev/null +++ b/libsecondlife/examples/TestClient/Commands/ShowEffectsCommand.cs @@ -0,0 +1,76 @@ +using System; +using libsecondlife; + +namespace libsecondlife.TestClient +{ + public class ShowEffectsCommand : Command + { + bool ShowEffects = false; + + public ShowEffectsCommand(TestClient testClient) + { + Name = "showeffects"; + Description = "Prints out information for every viewer effect that is received. Usage: showeffects [on/off]"; + + testClient.Avatars.OnEffect += new AvatarManager.EffectCallback(Avatars_OnEffect); + testClient.Avatars.OnLookAt += new AvatarManager.LookAtCallback(Avatars_OnLookAt); + testClient.Avatars.OnPointAt += new AvatarManager.PointAtCallback(Avatars_OnPointAt); + } + + public override string Execute(string[] args, LLUUID fromAgentID) + { + if (args.Length == 0) + { + ShowEffects = true; + return "Viewer effects will be shown on the console"; + } + else if (args.Length == 1) + { + if (args[0] == "on") + { + ShowEffects = true; + return "Viewer effects will be shown on the console"; + } + else + { + ShowEffects = false; + return "Viewer effects will not be shown"; + } + } + else + { + return "Usage: showeffects [on/off]"; + } + } + + private void Avatars_OnPointAt(LLUUID sourceID, LLUUID targetID, LLVector3d targetPos, + MainAvatar.PointAtType pointType, float duration, LLUUID id) + { + if (ShowEffects) + Console.WriteLine( + "ViewerEffect [PointAt]: SourceID: {0} TargetID: {1} TargetPos: {2} Type: {3} Duration: {4} ID: {5}", + sourceID.ToStringHyphenated(), targetID.ToStringHyphenated(), targetPos, pointType, duration, + id.ToStringHyphenated()); + } + + private void Avatars_OnLookAt(LLUUID sourceID, LLUUID targetID, LLVector3d targetPos, + MainAvatar.LookAtType lookType, float duration, LLUUID id) + { + if (ShowEffects) + Console.WriteLine( + "ViewerEffect [LookAt]: SourceID: {0} TargetID: {1} TargetPos: {2} Type: {3} Duration: {4} ID: {5}", + sourceID.ToStringHyphenated(), targetID.ToStringHyphenated(), targetPos, lookType, duration, + id.ToStringHyphenated()); + } + + private void Avatars_OnEffect(MainAvatar.EffectType type, LLUUID sourceID, LLUUID targetID, + LLVector3d targetPos, float duration, LLUUID id) + { + if (ShowEffects) + Console.WriteLine( + "ViewerEffect [{0}]: SourceID: {1} TargetID: {2} TargetPos: {3} Duration: {4} ID: {5}", + type, sourceID.ToStringHyphenated(), targetID.ToStringHyphenated(), targetPos, duration, + id.ToStringHyphenated()); + } + } +} diff --git a/libsecondlife/examples/TestClient/TestClient.csproj b/libsecondlife/examples/TestClient/TestClient.csproj index db88e8e8..16d4afe0 100644 --- a/libsecondlife/examples/TestClient/TestClient.csproj +++ b/libsecondlife/examples/TestClient/TestClient.csproj @@ -80,6 +80,7 @@ + @@ -116,4 +117,4 @@ --> - + \ No newline at end of file