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