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 @@ - +