diff --git a/libsecondlife-cs/NetworkManager.cs b/libsecondlife-cs/NetworkManager.cs
index efb7ebbe..465640ad 100644
--- a/libsecondlife-cs/NetworkManager.cs
+++ b/libsecondlife-cs/NetworkManager.cs
@@ -48,9 +48,13 @@ namespace libsecondlife
///
public class Simulator
{
+ /// A public reference to the client that this Simulator object
+ /// is attached to
+ public SecondLife Client;
+
/// The maximum size of the sequence number inbox, used to
/// check for resent and/or duplicate packets
- public const int INBOX_SIZE = 200;
+ public const int INBOX_SIZE = 100;
/// The Region class that this Simulator wraps
public Region Region;
@@ -89,7 +93,6 @@ namespace libsecondlife
///
public bool DisconnectCandidate = false;
- private SecondLife Client;
private NetworkManager Network;
private Dictionary> Callbacks;
private ushort Sequence = 0;
@@ -470,13 +473,6 @@ namespace libsecondlife
}
else
{
- if (Inbox.Count >= INBOX_SIZE)
- {
- Inbox.Dequeue();
- }
-
- Inbox.Enqueue(packet.Header.Sequence);
-
lock (PendingAcks)
{
PendingAcks.Add((uint)packet.Header.Sequence);
@@ -485,6 +481,13 @@ namespace libsecondlife
}
}
+ // Add this packet to our inbox
+ if (Inbox.Count >= INBOX_SIZE)
+ {
+ Inbox.Dequeue();
+ }
+ Inbox.Enqueue(packet.Header.Sequence);
+
// Handle appended ACKs
if (packet.Header.AppendedAcks)
{
diff --git a/libsecondlife-cs/ObjectManager.cs b/libsecondlife-cs/ObjectManager.cs
index 41b853cb..4319fad7 100644
--- a/libsecondlife-cs/ObjectManager.cs
+++ b/libsecondlife-cs/ObjectManager.cs
@@ -890,7 +890,7 @@ namespace libsecondlife
break;
case (byte)PCode.ParticleSystem:
// FIXME: Handle ParticleSystem
- Client.Log("Got an ObjectUpdate block with a ParticleSystem PCode", Helpers.LogLevel.Debug);
+ Client.DebugLog("Got an ObjectUpdate block with a ParticleSystem PCode");
break;
default:
break;
@@ -1072,9 +1072,8 @@ namespace libsecondlife
byte Unknown1 = block.Data[i++];
byte Unknown2 = block.Data[i++];
- Client.Log("Compressed object with Tree flag set: " + Environment.NewLine +
- "Unknown byte 1: " + Unknown1 + Environment.NewLine +
- "Unknown byte 2: " + Unknown2, Helpers.LogLevel.Debug);
+ Client.DebugLog("Compressed object with Tree flag set: " + Environment.NewLine +
+ "Unknown byte 1: " + Unknown1 + Environment.NewLine + "Unknown byte 2: " + Unknown2);
}
if ((flags & CompressedFlags.HasParent) != 0)
@@ -1167,17 +1166,17 @@ namespace libsecondlife
if ((flags & CompressedFlags.Unknown1) != 0)
{
// TODO: Is this even a valid flag?
- Client.Log("Compressed object with Unknown1 flag set: " + Environment.NewLine +
+ Client.DebugLog("Compressed object with Unknown1 flag set: " + Environment.NewLine +
"Flags: " + flags.ToString() + Environment.NewLine +
- Helpers.FieldToString(block.Data), Helpers.LogLevel.Debug);
+ Helpers.FieldToString(block.Data));
}
if ((flags & CompressedFlags.Unknown2) != 0)
{
// FIXME: Implement CompressedFlags.Unknown2
- //Client.Log("Compressed object with Unknown2 flag set: " + Environment.NewLine +
+ //Client.DebugLog("Compressed object with Unknown2 flag set: " + Environment.NewLine +
// "Flags: " + flags.ToString() + Environment.NewLine +
- // Helpers.FieldToString(block.Data), Helpers.LogLevel.Debug);
+ // Helpers.FieldToString(block.Data));
}
prim.PathCurve = (uint)block.Data[i++];
@@ -1240,8 +1239,7 @@ namespace libsecondlife
else if (pcode == (byte)PCode.Grass || pcode == (byte)PCode.Tree || pcode == (byte)PCode.NewTree)
{
// FIXME: Implement this
- //Client.Log("######### Got an ObjectUpdateCompressed for grass/tree, implement this! #########",
- // Helpers.LogLevel.Debug);
+ //Client.DebugLog("######### Got an ObjectUpdateCompressed for grass/tree, implement this! #########");
}
else
{
diff --git a/libsecondlife-cs/SecondLife.cs b/libsecondlife-cs/SecondLife.cs
index a25b3934..8cd03f6c 100644
--- a/libsecondlife-cs/SecondLife.cs
+++ b/libsecondlife-cs/SecondLife.cs
@@ -134,6 +134,8 @@ namespace libsecondlife
/// The severity of the log entry
public void Log(string message, Helpers.LogLevel level)
{
+ if (level == Helpers.LogLevel.Debug && !Debug) return;
+
if (OnLogMessage != null)
{
OnLogMessage(message, level);
diff --git a/libsecondlife-cs/examples/TestClient/Command.cs b/libsecondlife-cs/examples/TestClient/Command.cs
index 2df06c1f..40f297c0 100644
--- a/libsecondlife-cs/examples/TestClient/Command.cs
+++ b/libsecondlife-cs/examples/TestClient/Command.cs
@@ -10,15 +10,9 @@ namespace libsecondlife.TestClient
{
public string Name;
public string Description;
-
public TestClient TestClient;
- public SecondLife Client
- {
- get { return TestClient.Client; }
- }
-
- public abstract string Execute(string[] args, LLUUID fromAgentID);
+ public abstract string Execute(SecondLife Client, string[] args, LLUUID fromAgentID);
///
/// When set to true, think will be called.
@@ -28,7 +22,7 @@ namespace libsecondlife.TestClient
///
/// Called twice per second, when Command.Active is set to true.
///
- public virtual void Think()
+ public virtual void Think(SecondLife Client)
{
}
}
diff --git a/libsecondlife-cs/examples/TestClient/Commands/BalanceCommand.cs b/libsecondlife-cs/examples/TestClient/Commands/BalanceCommand.cs
index bff9aed1..17bdaef3 100644
--- a/libsecondlife-cs/examples/TestClient/Commands/BalanceCommand.cs
+++ b/libsecondlife-cs/examples/TestClient/Commands/BalanceCommand.cs
@@ -14,7 +14,7 @@ namespace libsecondlife.TestClient
Description = "Shows the amount of L$.";
}
- public override string Execute(string[] args, LLUUID fromAgentID)
+ public override string Execute(SecondLife Client, string[] args, LLUUID fromAgentID)
{
return "L$: " + Client.Self.Balance;
}
diff --git a/libsecondlife-cs/examples/TestClient/Commands/FollowCommand.cs b/libsecondlife-cs/examples/TestClient/Commands/FollowCommand.cs
index 4397d439..7fd65052 100644
--- a/libsecondlife-cs/examples/TestClient/Commands/FollowCommand.cs
+++ b/libsecondlife-cs/examples/TestClient/Commands/FollowCommand.cs
@@ -14,7 +14,7 @@ namespace libsecondlife.TestClient
Description = "Follow another avatar. (usage: follow FirstName LastName)";
}
- public override string Execute(string[] args, LLUUID fromAgentID)
+ public override string Execute(SecondLife Client, string[] args, LLUUID fromAgentID)
{
string target = String.Empty;
for (int ct = 0; ct < args.Length;ct++)
@@ -46,7 +46,7 @@ namespace libsecondlife.TestClient
return false;
}
- public override void Think()
+ public override void Think(SecondLife Client)
{
if (vecDist(followAvatar.Position, Client.Self.Position) > DISTANCE_BUFFER)
{
@@ -62,7 +62,7 @@ namespace libsecondlife.TestClient
// Client.Self.AutoPilot((ulong)myPos.X, (ulong)myPos.Y, myPos.Z);
//}
- base.Think();
+ base.Think(Client);
}
//void SendAgentUpdate(uint ControlID)
diff --git a/libsecondlife-cs/examples/TestClient/Commands/GiveAllCommand.cs b/libsecondlife-cs/examples/TestClient/Commands/GiveAllCommand.cs
index da9054b0..8f55d457 100644
--- a/libsecondlife-cs/examples/TestClient/Commands/GiveAllCommand.cs
+++ b/libsecondlife-cs/examples/TestClient/Commands/GiveAllCommand.cs
@@ -14,7 +14,7 @@ namespace libsecondlife.TestClient
Description = "Gives you all it's money.";
}
- public override string Execute(string[] args, LLUUID fromAgentID)
+ public override string Execute(SecondLife Client, string[] args, LLUUID fromAgentID)
{
if (fromAgentID == null)
return "Unable to send money to console. This command only works when IMed.";
diff --git a/libsecondlife-cs/examples/TestClient/Commands/GotoCommand.cs b/libsecondlife-cs/examples/TestClient/Commands/GotoCommand.cs
index 59df5b1e..dc0a27ba 100644
--- a/libsecondlife-cs/examples/TestClient/Commands/GotoCommand.cs
+++ b/libsecondlife-cs/examples/TestClient/Commands/GotoCommand.cs
@@ -14,7 +14,7 @@ namespace libsecondlife.TestClient
Description = "Goto location. (e.g. \"goto simname/100/100/30\")";
}
- public override string Execute(string[] args, LLUUID fromAgentID)
+ public override string Execute(SecondLife Client, string[] args, LLUUID fromAgentID)
{
if (args.Length < 1)
return "Destination should be specified as: sim/x/y/z";
diff --git a/libsecondlife-cs/examples/TestClient/Commands/HelpCommand.cs b/libsecondlife-cs/examples/TestClient/Commands/HelpCommand.cs
index 23c3f900..416c6e73 100644
--- a/libsecondlife-cs/examples/TestClient/Commands/HelpCommand.cs
+++ b/libsecondlife-cs/examples/TestClient/Commands/HelpCommand.cs
@@ -14,7 +14,7 @@ namespace libsecondlife.TestClient
Description = "Lists available commands.";
}
- public override string Execute(string[] args, LLUUID fromAgentID)
+ public override string Execute(SecondLife Client, string[] args, LLUUID fromAgentID)
{
StringBuilder result = new StringBuilder();
result.AppendFormat("\n\nHELP\nClient accept teleport lures from master and group members.\n");
diff --git a/libsecondlife-cs/examples/TestClient/Commands/JumpCommand.cs b/libsecondlife-cs/examples/TestClient/Commands/JumpCommand.cs
index c14733a1..1457c1ff 100644
--- a/libsecondlife-cs/examples/TestClient/Commands/JumpCommand.cs
+++ b/libsecondlife-cs/examples/TestClient/Commands/JumpCommand.cs
@@ -14,7 +14,7 @@ namespace libsecondlife.TestClient
Description = "Teleports to the specified height. (e.g. \"jump 1000\")";
}
- public override string Execute(string[] args, LLUUID fromAgentID)
+ public override string Execute(SecondLife Client, string[] args, LLUUID fromAgentID)
{
if (args.Length < 1)
return "usage: jump 1000";
diff --git a/libsecondlife-cs/examples/TestClient/Commands/LocationCommand.cs b/libsecondlife-cs/examples/TestClient/Commands/LocationCommand.cs
index 914111af..3ca0a912 100644
--- a/libsecondlife-cs/examples/TestClient/Commands/LocationCommand.cs
+++ b/libsecondlife-cs/examples/TestClient/Commands/LocationCommand.cs
@@ -14,7 +14,7 @@ namespace libsecondlife.TestClient
Description = "Show the location.";
}
- public override string Execute(string[] args, LLUUID fromAgentID)
+ public override string Execute(SecondLife Client, string[] args, LLUUID fromAgentID)
{
return "CurrentSim: '" + Client.Network.CurrentSim.Region.Name + "' Position: " + Client.Self.Position.ToString();
}
diff --git a/libsecondlife-cs/examples/TestClient/Commands/LoginCommand.cs b/libsecondlife-cs/examples/TestClient/Commands/LoginCommand.cs
new file mode 100644
index 00000000..3186f498
--- /dev/null
+++ b/libsecondlife-cs/examples/TestClient/Commands/LoginCommand.cs
@@ -0,0 +1,56 @@
+using System;
+using System.Collections.Generic;
+using System.Reflection;
+using libsecondlife;
+using libsecondlife.Packets;
+
+namespace libsecondlife.TestClient
+{
+ public class LoginCommand : Command
+ {
+ public LoginCommand()
+ {
+ Name = "login";
+ Description = "Logs in another avatar";
+ }
+
+ public override string Execute(SecondLife Client, string[] args, LLUUID fromAgentID)
+ {
+ if (args.Length != 3)
+ return "usage: login firstname lastname password";
+
+ LoginDetails account = new LoginDetails();
+ account.FirstName = args[0];
+ account.LastName = args[1];
+ account.Password = args[2];
+ account.Master = TestClient.Master;
+
+ // Check if this client is already logged in
+ foreach (SecondLife client in TestClient.Clients.Values)
+ {
+ if (client.Self.FirstName == account.FirstName && client.Self.LastName == account.LastName)
+ {
+ TestClient.Clients.Remove(client.Network.AgentID);
+
+ client.Network.Logout();
+
+ break;
+ }
+ }
+
+ SecondLife newClient = TestClient.InitializeClient(account);
+
+ if (newClient.Network.Connected)
+ {
+ TestClient.Clients[newClient.Network.AgentID] = newClient;
+
+ return "Logged in " + newClient.ToString();
+ }
+ else
+ {
+ return "Failed to login " + account.FirstName + " " + account.LastName + ": " +
+ newClient.Network.LoginError;
+ }
+ }
+ }
+}
diff --git a/libsecondlife-cs/examples/TestClient/Commands/LogoutCommand.cs b/libsecondlife-cs/examples/TestClient/Commands/LogoutCommand.cs
new file mode 100644
index 00000000..303e4b0d
--- /dev/null
+++ b/libsecondlife-cs/examples/TestClient/Commands/LogoutCommand.cs
@@ -0,0 +1,35 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using libsecondlife;
+using libsecondlife.Packets;
+
+namespace libsecondlife.TestClient
+{
+ public class LogoutCommand : Command
+ {
+ public LogoutCommand()
+ {
+ Name = "logout";
+ Description = "Log this avatar out";
+ }
+
+ public override string Execute(SecondLife Client, string[] args, LLUUID fromAgentID)
+ {
+ string name = Client.ToString();
+ TestClient.Clients.Remove(Client.Network.AgentID);
+ Client.Network.Logout();
+ Client = null;
+
+ if (TestClient.Clients.Count > 0)
+ {
+ return "Logged " + name + " out";
+ }
+ else
+ {
+ TestClient.Running = false;
+ return "All avatars logged out";
+ }
+ }
+ }
+}
diff --git a/libsecondlife-cs/examples/TestClient/Commands/PrimCountCommand.cs b/libsecondlife-cs/examples/TestClient/Commands/PrimCountCommand.cs
index 3482587a..2d1aeef0 100644
--- a/libsecondlife-cs/examples/TestClient/Commands/PrimCountCommand.cs
+++ b/libsecondlife-cs/examples/TestClient/Commands/PrimCountCommand.cs
@@ -14,7 +14,7 @@ namespace libsecondlife.TestClient
Description = "Shows the number of prims that have been received.";
}
- public override string Execute(string[] args, LLUUID fromAgentID)
+ public override string Execute(SecondLife Client, string[] args, LLUUID fromAgentID)
{
return TestClient.Prims.Count.ToString();
}
diff --git a/libsecondlife-cs/examples/TestClient/Commands/QuitCommand.cs b/libsecondlife-cs/examples/TestClient/Commands/QuitCommand.cs
index 13c77a87..2883676a 100644
--- a/libsecondlife-cs/examples/TestClient/Commands/QuitCommand.cs
+++ b/libsecondlife-cs/examples/TestClient/Commands/QuitCommand.cs
@@ -11,14 +11,18 @@ namespace libsecondlife.TestClient
public QuitCommand()
{
Name = "quit";
- Description = "Log off";
+ Description = "Log all avatars out and shut down";
}
- public override string Execute(string[] args, LLUUID fromAgentID)
+ public override string Execute(SecondLife Client, string[] args, LLUUID fromAgentID)
{
- Client.Network.Logout();
- TestClient.Running = false;
- return "Logging off.";
+ foreach (SecondLife client in TestClient.Clients.Values)
+ {
+ client.Network.Logout();
+ }
+
+ TestClient.Running = false;
+ return "All avatars logged out";
}
}
}
diff --git a/libsecondlife-cs/examples/TestClient/Commands/SayCommand.cs b/libsecondlife-cs/examples/TestClient/Commands/SayCommand.cs
index 1c725232..7f40e617 100644
--- a/libsecondlife-cs/examples/TestClient/Commands/SayCommand.cs
+++ b/libsecondlife-cs/examples/TestClient/Commands/SayCommand.cs
@@ -14,7 +14,7 @@ namespace libsecondlife.TestClient
Description = "Say something.";
}
- public override string Execute(string[] args, LLUUID fromAgentID)
+ public override string Execute(SecondLife Client, string[] args, LLUUID fromAgentID)
{
if (args.Length < 1)
return "usage: say whatever";
diff --git a/libsecondlife-cs/examples/TestClient/Commands/SetMasterCommand.cs b/libsecondlife-cs/examples/TestClient/Commands/SetMasterCommand.cs
index 8c32ddcc..c7e27f90 100644
--- a/libsecondlife-cs/examples/TestClient/Commands/SetMasterCommand.cs
+++ b/libsecondlife-cs/examples/TestClient/Commands/SetMasterCommand.cs
@@ -16,7 +16,7 @@ namespace libsecondlife.TestClient
Description = "Sets the user name of the master user. The master user can IM to run commands.";
}
- public override string Execute(string[] args, LLUUID fromAgentID)
+ public override string Execute(SecondLife Client, string[] args, LLUUID fromAgentID)
{
string masterName = String.Empty;
for (int ct = 0; ct < args.Length;ct++)
diff --git a/libsecondlife-cs/examples/TestClient/Commands/SitCommand.cs b/libsecondlife-cs/examples/TestClient/Commands/SitCommand.cs
index 9959159a..06a76a16 100644
--- a/libsecondlife-cs/examples/TestClient/Commands/SitCommand.cs
+++ b/libsecondlife-cs/examples/TestClient/Commands/SitCommand.cs
@@ -14,7 +14,7 @@ namespace libsecondlife.TestClient
Description = "Sit on closest touchable prim.";
}
- public string Sit(LLUUID target)
+ public string Sit(SecondLife Client, LLUUID target)
{
AgentRequestSitPacket sitPacket = new AgentRequestSitPacket();
@@ -31,7 +31,7 @@ namespace libsecondlife.TestClient
return String.Empty;
}
- public override string Execute(string[] args, LLUUID fromAgentID)
+ public override string Execute(SecondLife Client, string[] args, LLUUID fromAgentID)
{
PrimObject closest = null;
double closestDistance = Double.MaxValue;
@@ -54,7 +54,7 @@ namespace libsecondlife.TestClient
if (closest != null)
{
- Sit(closest.ID);
+ Sit(Client, closest.ID);
return TestClient.Prims.Count + " prims. Sat on " + closest.ID + ". Distance: " + closestDistance;
}
diff --git a/libsecondlife-cs/examples/TestClient/Commands/TreeCommand.cs b/libsecondlife-cs/examples/TestClient/Commands/TreeCommand.cs
index 7e645948..042cedef 100644
--- a/libsecondlife-cs/examples/TestClient/Commands/TreeCommand.cs
+++ b/libsecondlife-cs/examples/TestClient/Commands/TreeCommand.cs
@@ -14,7 +14,7 @@ namespace libsecondlife.TestClient
Description = "Rez a tree.";
}
- public override string Execute(string[] args, LLUUID fromAgentID)
+ public override string Execute(SecondLife Client, string[] args, LLUUID fromAgentID)
{
if (args.Length == 1)
{
diff --git a/libsecondlife-cs/examples/TestClient/Commands/UptimeCommand.cs b/libsecondlife-cs/examples/TestClient/Commands/UptimeCommand.cs
index 1de6485d..538580a8 100644
--- a/libsecondlife-cs/examples/TestClient/Commands/UptimeCommand.cs
+++ b/libsecondlife-cs/examples/TestClient/Commands/UptimeCommand.cs
@@ -16,7 +16,7 @@ namespace libsecondlife.TestClient
Description = "Shows the login time and length of time logged on.";
}
- public override string Execute(string[] args, LLUUID fromAgentID)
+ public override string Execute(SecondLife Client, string[] args, LLUUID fromAgentID)
{
return "Up Since: " + Created + " (" + (DateTime.Now - Created) + ")";
}
diff --git a/libsecondlife-cs/examples/TestClient/Commands/WhoCommand.cs b/libsecondlife-cs/examples/TestClient/Commands/WhoCommand.cs
index b6ff4319..05520aae 100644
--- a/libsecondlife-cs/examples/TestClient/Commands/WhoCommand.cs
+++ b/libsecondlife-cs/examples/TestClient/Commands/WhoCommand.cs
@@ -14,7 +14,7 @@ namespace libsecondlife.TestClient
Description = "Lists seen avatars.";
}
- public override string Execute(string[] args, LLUUID fromAgentID)
+ public override string Execute(SecondLife Client, string[] args, LLUUID fromAgentID)
{
StringBuilder result = new StringBuilder();
foreach (Avatar av in TestClient.Avatars.Values)
diff --git a/libsecondlife-cs/examples/TestClient/Program.cs b/libsecondlife-cs/examples/TestClient/Program.cs
index 1bb68387..0ee676ef 100644
--- a/libsecondlife-cs/examples/TestClient/Program.cs
+++ b/libsecondlife-cs/examples/TestClient/Program.cs
@@ -5,17 +5,47 @@ using System.Text;
namespace libsecondlife.TestClient
{
- public class Program
- {
- static void Main(string[] args)
- {
- if(args.Length < 3 || args.Length == 4)
- {
- Console.WriteLine("Usage: TestClient.ext firstname lastname password [master name]");
- }
- TestClient testTool = new TestClient(args[0], args[1], args[2]);
- if(args.Length > 4) testTool.Master = args[3] + " " + args[4];
- testTool.Run();
- }
+ public class Program
+ {
+ static void Main(string[] args)
+ {
+ if (args.Length < 1 || args.Length > 5)
+ {
+ Console.WriteLine("Usage: " + Environment.NewLine +
+ "TestClient.exe firstname lastname password [master name]" + Environment.NewLine +
+ "TestClient.exe filename [master name]");
+ }
+
+ TestClient tester;
+ List accounts = new List();
+ LoginDetails account;
+
+ if (args.Length <= 2)
+ {
+ // Loading names from a file
+ // FIXME:
+
+ Console.WriteLine("FIXME!");
+ return;
+ }
+ else
+ {
+ // Taking a single login off the command-line
+ account = new LoginDetails();
+ account.FirstName = args[0];
+ account.LastName = args[1];
+ account.Password = args[2];
+
+ if (args.Length == 5)
+ {
+ account.Master = args[3] + " " + args[4];
+ }
+
+ accounts.Add(account);
+ }
+
+ tester = new TestClient(accounts);
+ tester.Run();
}
+ }
}
diff --git a/libsecondlife-cs/examples/TestClient/TestClient.cs b/libsecondlife-cs/examples/TestClient/TestClient.cs
index 4e31d14a..bfc71165 100644
--- a/libsecondlife-cs/examples/TestClient/TestClient.cs
+++ b/libsecondlife-cs/examples/TestClient/TestClient.cs
@@ -7,145 +7,263 @@ using libsecondlife.Packets;
namespace libsecondlife.TestClient
{
+ public struct LoginDetails
+ {
+ public string FirstName;
+ public string LastName;
+ public string Password;
+ public string Master;
+ }
+
public class TestClient
{
- public SecondLife Client;
- public LLUUID GroupID;
+ public Dictionary Clients = new Dictionary();
+ public LLUUID GroupID = LLUUID.Zero;
public Dictionary GroupMembers;
public Dictionary Prims = new Dictionary();
public Dictionary Avatars = new Dictionary();
public Dictionary Commands = new Dictionary();
public bool Running = true;
- public string Master;
+ public string Master = "";
- LLQuaternion bodyRotation;
- System.Timers.Timer updateTimer;
+ private LLQuaternion bodyRotation = LLQuaternion.Identity;
+ private LLVector3 forward = new LLVector3(0, 0.9999f, 0);
+ private LLVector3 left = new LLVector3(0.9999f, 0, 0);
+ private LLVector3 up = new LLVector3(0, 0, 0.9999f);
+ private int DrawDistance = 64;
+ private System.Timers.Timer updateTimer;
- public TestClient(string first, string last, string password)
+ ///
+ ///
+ ///
+ ///
+ public TestClient(List accounts)
{
- Client = new SecondLife();
-
- GroupID = LLUUID.Zero;
- Client.Objects.RequestAllObjects = true;
- bodyRotation = LLQuaternion.Identity;
updateTimer = new System.Timers.Timer(1000);
updateTimer.Elapsed += new System.Timers.ElapsedEventHandler(updateTimer_Elapsed);
- Client.Network.RegisterCallback(PacketType.AgentDataUpdate, new NetworkManager.PacketCallback(AgentDataUpdateHandler));
+ RegisterAllCommands(Assembly.GetExecutingAssembly());
- Client.Objects.OnNewPrim += new ObjectManager.NewPrimCallback(Objects_OnNewPrim);
- Client.Objects.OnPrimMoved += new ObjectManager.PrimMovedCallback(Objects_OnPrimMoved);
- Client.Objects.OnObjectKilled += new ObjectManager.KillObjectCallback(Objects_OnObjectKilled);
- Client.Objects.OnNewAvatar += new ObjectManager.NewAvatarCallback(Objects_OnNewAvatar);
- Client.Objects.OnAvatarMoved += new ObjectManager.AvatarMovedCallback(Objects_OnAvatarMoved);
- Client.Self.OnInstantMessage += new InstantMessageCallback(Self_OnInstantMessage);
-
- RegisterAllCommands(Assembly.GetExecutingAssembly());
-
- if (Client.Network.Login(first, last, password, "TestTool", "contact@libsecondlife.org"))
+ foreach (LoginDetails account in accounts)
{
- updateTimer.Start();
+ SecondLife client = InitializeClient(account);
+
+ if (client.Network.Connected)
+ {
+ Clients[client.Network.AgentID] = client;
+
+ Console.WriteLine("Logged in " + client.ToString());
+ }
+ else
+ {
+ Console.WriteLine("Failed to login " + account.FirstName + " " + account.LastName +
+ ": " + client.Network.LoginError);
+ }
+ }
+
+ updateTimer.Start();
+ }
+
+ ///
+ ///
+ ///
+ ///
+ ///
+ public SecondLife InitializeClient(LoginDetails account)
+ {
+ SecondLife client = new SecondLife();
+
+ client.Debug = false;
+
+ client.Network.RegisterCallback(PacketType.AgentDataUpdate, new NetworkManager.PacketCallback(AgentDataUpdateHandler));
+
+ client.Objects.OnNewPrim += new ObjectManager.NewPrimCallback(Objects_OnNewPrim);
+ client.Objects.OnPrimMoved += new ObjectManager.PrimMovedCallback(Objects_OnPrimMoved);
+ client.Objects.OnObjectKilled += new ObjectManager.KillObjectCallback(Objects_OnObjectKilled);
+ client.Objects.OnNewAvatar += new ObjectManager.NewAvatarCallback(Objects_OnNewAvatar);
+ client.Objects.OnAvatarMoved += new ObjectManager.AvatarMovedCallback(Objects_OnAvatarMoved);
+ client.Self.OnInstantMessage += new InstantMessageCallback(Self_OnInstantMessage);
+
+ client.Objects.RequestAllObjects = true;
+
+ client.Network.Login(account.FirstName, account.LastName, account.Password,
+ "TestClient", "contact@libsecondlife.org");
+
+ return client;
+ }
+
+ ///
+ ///
+ ///
+ public void Run()
+ {
+ Console.WriteLine("Type quit to exit. Type help for a command list.");
+
+ while (Running)
+ {
+ PrintPrompt();
+ string input = Console.ReadLine();
+ DoCommandAll(input, null, null);
+ }
+
+ foreach (SecondLife client in Clients.Values)
+ {
+ if (client.Network.Connected)
+ client.Network.Logout();
}
}
- public void RegisterAllCommands(Assembly assembly)
- {
- foreach (Type t in assembly.GetTypes())
- {
- if (t.IsSubclassOf(typeof(Command)))
- {
- Command command = (Command)t.GetConstructor(new Type[0]).Invoke(new object[0]);
- RegisterCommand(command);
- }
- }
- }
+ private void RegisterAllCommands(Assembly assembly)
+ {
+ foreach (Type t in assembly.GetTypes())
+ {
+ if (t.IsSubclassOf(typeof(Command)))
+ {
+ Command command = (Command)t.GetConstructor(new Type[0]).Invoke(new object[0]);
+ RegisterCommand(command);
+ }
+ }
+ }
- public void RegisterCommand(Command command)
+ private void RegisterCommand(Command command)
{
command.TestClient = this;
+
Commands.Add(command.Name.ToLower(), command);
}
- public void DoCommand(string cmd, LLUUID fromAgentID, LLUUID imSessionID)
+ private void DoCommand(SecondLife client, string cmd, LLUUID fromAgentID, LLUUID imSessionID)
{
string[] tokens = cmd.Trim().Split(new char[] { ' ', '\t' });
+ string firstToken = tokens[0].ToLower();
+
if (tokens.Length == 0)
return;
- string response = "";
- if (Commands.ContainsKey(tokens[0].ToLower()))
+ // "all balance" will send the balance command to all currently logged in bots
+ if (firstToken == "all" && tokens.Length > 1)
+ {
+ cmd = "";
+
+ // Reserialize all of the arguments except for "all"
+ for (int i = 1; i < tokens.Length; i++)
+ {
+ cmd += tokens[i] + " ";
+ }
+
+ DoCommandAll(cmd, fromAgentID, imSessionID);
+
+ return;
+ }
+
+ if (Commands.ContainsKey(firstToken))
{
string[] args = new string[tokens.Length - 1];
Array.Copy(tokens, 1, args, 0, args.Length);
- response = Commands[tokens[0].ToLower()].Execute(args, fromAgentID);
- }
- else
- {
- response = "Unknown command.";
- }
+ string response = response = Commands[firstToken].Execute(client, args, fromAgentID);
- if (response.Length > 0)
- {
- if (fromAgentID != null)
- Client.Self.InstantMessage(fromAgentID, response, imSessionID);
- Console.WriteLine(response);
+ if (response.Length > 0)
+ {
+ if (fromAgentID != null && client.Network.Connected)
+ client.Self.InstantMessage(fromAgentID, response, imSessionID);
+ Console.WriteLine(response);
+ }
}
}
- public void Run()
- {
- Console.WriteLine("Type quit to exit. Type help for a command list.");
-
- while (Running && Client.Network.Connected)
- {
- PrintPrompt();
- string input = Console.ReadLine();
- DoCommand(input, null, null);
- }
-
- if (Client.Network.Connected)
- Client.Network.Logout();
- }
-
- public void PrintPrompt()
- {
- Console.Write(String.Format("{0} {1} - {2}> ", Client.Self.FirstName, Client.Self.LastName, Client.Network.CurrentSim.Region.Name));
- }
-
- void updateTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
+ private void DoCommandAll(string cmd, LLUUID fromAgentID, LLUUID imSessionID)
{
- LLVector3 forward = new LLVector3(0, 0.9999f, 0);
- LLVector3 left = new LLVector3(0.9999f, 0, 0);
- LLVector3 up = new LLVector3(0, 0, 0.9999f);
+ string[] tokens = cmd.Trim().Split(new char[] { ' ', '\t' });
+ string firstToken = tokens[0].ToLower();
- Client.Self.UpdateCamera(0, Client.Self.Position, forward, left, up, bodyRotation,
- LLQuaternion.Identity, 64, false);
+ if (tokens.Length == 0)
+ return;
- foreach (Command c in Commands.Values)
- if (c.Active)
- c.Think();
+Begin:
+
+ int avatars = Clients.Count;
+
+ if (Commands.ContainsKey(firstToken))
+ {
+ foreach (SecondLife client in Clients.Values)
+ {
+ if (client.Network.Connected)
+ {
+ string[] args = new string[tokens.Length - 1];
+ Array.Copy(tokens, 1, args, 0, args.Length);
+ string response = Commands[firstToken].Execute(client, args, fromAgentID);
+
+ if (response.Length > 0)
+ {
+ if (fromAgentID != null && client.Network.Connected)
+ client.Self.InstantMessage(fromAgentID, response, imSessionID);
+ Console.WriteLine(response);
+ }
+
+ if (firstToken == "login")
+ {
+ // Special login case: Only call it once
+ break;
+ }
+ }
+
+ if (avatars != Clients.Count)
+ {
+ // The dictionary size changed, start over since the
+ // foreach is shot
+ goto Begin;
+ }
+ }
+ }
}
- void AgentDataUpdateHandler(Packet packet, Simulator sim)
+ private void PrintPrompt()
+ {
+ //Console.Write(String.Format("{0} {1} - {2}> ", Client.Self.FirstName, Client.Self.LastName, Client.Network.CurrentSim.Region.Name));
+
+ int online = 0;
+
+ foreach (SecondLife client in Clients.Values)
+ {
+ if (client.Network.Connected) online++;
+ }
+
+ Console.Write(online + " avatars online> ");
+ }
+
+ private void updateTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
+ {
+ foreach (SecondLife client in Clients.Values)
+ {
+ client.Self.UpdateCamera(0, client.Self.Position, forward, left, up, bodyRotation,
+ LLQuaternion.Identity, DrawDistance, false);
+
+ foreach (Command c in Commands.Values)
+ if (c.Active)
+ c.Think(client);
+ }
+ }
+
+ private void AgentDataUpdateHandler(Packet packet, Simulator sim)
{
AgentDataUpdatePacket p = (AgentDataUpdatePacket)packet;
- if (p.AgentData.AgentID == Client.Network.AgentID)
+ if (p.AgentData.AgentID == sim.Client.Network.AgentID)
{
- Console.WriteLine("Got my group ID, requesting group members...");
+ Console.WriteLine("Got the group ID for " + sim.Client.ToString() + ", requesting group members...");
GroupID = p.AgentData.ActiveGroupID;
- Client.Groups.BeginGetGroupMembers(GroupID, new GroupManager.GroupMembersCallback(OnGroupMembers));
+ sim.Client.Groups.BeginGetGroupMembers(GroupID, new GroupManager.GroupMembersCallback(OnGroupMembers));
}
}
- void OnGroupMembers(Dictionary members)
+ private void OnGroupMembers(Dictionary members)
{
Console.WriteLine("Got " + members.Count + " group members.");
GroupMembers = members;
PrintPrompt();
}
- void Objects_OnObjectKilled(Simulator simulator, uint objectID)
+ private void Objects_OnObjectKilled(Simulator simulator, uint objectID)
{
lock (Prims)
{
@@ -160,7 +278,7 @@ namespace libsecondlife.TestClient
}
}
- void Objects_OnPrimMoved(Simulator simulator, PrimUpdate prim, ulong regionHandle, ushort timeDilation)
+ private void Objects_OnPrimMoved(Simulator simulator, PrimUpdate prim, ulong regionHandle, ushort timeDilation)
{
lock (Prims)
{
@@ -172,7 +290,7 @@ namespace libsecondlife.TestClient
}
}
- void Objects_OnNewPrim(Simulator simulator, PrimObject prim, ulong regionHandle, ushort timeDilation)
+ private void Objects_OnNewPrim(Simulator simulator, PrimObject prim, ulong regionHandle, ushort timeDilation)
{
lock (Prims)
{
@@ -180,7 +298,7 @@ namespace libsecondlife.TestClient
}
}
- void Objects_OnNewAvatar(Simulator simulator, Avatar avatar, ulong regionHandle, ushort timeDilation)
+ private void Objects_OnNewAvatar(Simulator simulator, Avatar avatar, ulong regionHandle, ushort timeDilation)
{
lock (Avatars)
{
@@ -188,7 +306,7 @@ namespace libsecondlife.TestClient
}
}
- void Objects_OnAvatarMoved(Simulator simulator, AvatarUpdate avatar, ulong regionHandle, ushort timeDilation)
+ private void Objects_OnAvatarMoved(Simulator simulator, AvatarUpdate avatar, ulong regionHandle, ushort timeDilation)
{
lock (Avatars)
{
@@ -200,25 +318,38 @@ namespace libsecondlife.TestClient
}
}
- void Self_OnInstantMessage(LLUUID fromAgentID, string fromAgentName, LLUUID toAgentID, uint parentEstateID, LLUUID regionID, LLVector3 position, byte dialog, bool groupIM, LLUUID imSessionID, DateTime timestamp, string message, byte offline, byte[] binaryBucket)
+ private void Self_OnInstantMessage(LLUUID fromAgentID, string fromAgentName, LLUUID toAgentID, uint parentEstateID,
+ LLUUID regionID, LLVector3 position, byte dialog, bool groupIM, LLUUID imSessionID, DateTime timestamp,
+ string message, byte offline, byte[] binaryBucket)
{
- Console.WriteLine("" + fromAgentName + ": " + message + "\n");
-
if (GroupMembers != null && !GroupMembers.ContainsKey(fromAgentID) && fromAgentName.ToLower().TrimEnd() != Master.ToLower().TrimEnd())
{
- //Not a member of my group, ignore the IM.
+ // Not a member of my group and not master, ignore the IM
+ Console.WriteLine("" + fromAgentName + " (ignored): " + message);
+
return;
}
-
- if (dialog == 22)
+ else
{
- Console.WriteLine("Accepting teleport lure.");
- Client.Self.TeleportLureRespond(fromAgentID, true);
-
- return;
+ Console.WriteLine("" + fromAgentName + ": " + message);
}
- DoCommand(message, fromAgentID, imSessionID);
+ if (Clients.ContainsKey(toAgentID))
+ {
+ if (dialog == 22)
+ {
+ Console.WriteLine("Accepting teleport lure");
+ Clients[toAgentID].Self.TeleportLureRespond(fromAgentID, true);
+ }
+ else
+ {
+ DoCommand(Clients[toAgentID], message, fromAgentID, imSessionID);
+ }
+ }
+ else
+ {
+ Console.WriteLine("A bot that we aren't tracking received an IM?");
+ }
}
}
}
diff --git a/libsecondlife-cs/examples/TestClient/TestClient.csproj b/libsecondlife-cs/examples/TestClient/TestClient.csproj
index 13dff56f..24a188dc 100644
--- a/libsecondlife-cs/examples/TestClient/TestClient.csproj
+++ b/libsecondlife-cs/examples/TestClient/TestClient.csproj
@@ -34,8 +34,9 @@
-
+
+
diff --git a/libsecondlife-cs/examples/examples.build b/libsecondlife-cs/examples/examples.build
index 1b10c82a..1be39667 100644
--- a/libsecondlife-cs/examples/examples.build
+++ b/libsecondlife-cs/examples/examples.build
@@ -59,7 +59,7 @@
-
+