* Importing Ming's mass test client
							parent
							
								
									dfb22716b9
								
							
						
					
					
						commit
						e93869c7a7
					
				|  | @ -0,0 +1,111 @@ | |||
| using System; | ||||
| using System.Collections.Specialized; | ||||
| using System.Text.RegularExpressions; | ||||
| 
 | ||||
| namespace CommandLine.Utility | ||||
| { | ||||
|     /// <summary> | ||||
|     /// Arguments class | ||||
|     /// </summary> | ||||
|     public class Arguments | ||||
|     { | ||||
|         // Variables | ||||
|         private StringDictionary Parameters; | ||||
| 
 | ||||
|         // Constructor | ||||
|         public Arguments(string[] Args) | ||||
|         { | ||||
|             Parameters = new StringDictionary(); | ||||
|             Regex Splitter = new Regex(@"^-{1,2}|=|:", | ||||
|                 RegexOptions.IgnoreCase | RegexOptions.Compiled); | ||||
| 
 | ||||
|             Regex Remover = new Regex(@"^['""]?(.*?)['""]?$", | ||||
|                 RegexOptions.IgnoreCase | RegexOptions.Compiled); | ||||
| 
 | ||||
|             string Parameter = null; | ||||
|             string[] Parts; | ||||
| 
 | ||||
|             // Valid parameters forms: | ||||
|             // {-,/,--}param{ ,=,:}((",')value(",')) | ||||
|             // Examples:  | ||||
|             // -param1 value1 --param2 /param3:"Test-:-work"  | ||||
|             //   /param4=happy -param5 '--=nice=--' | ||||
|             foreach (string Txt in Args) | ||||
|             { | ||||
|                 // Look for new parameters (-,/ or --) and a | ||||
|                 // possible enclosed value (=,:) | ||||
|                 Parts = Splitter.Split(Txt, 3); | ||||
| 
 | ||||
|                 switch (Parts.Length) | ||||
|                 { | ||||
|                     // Found a value (for the last parameter  | ||||
|                     // found (space separator)) | ||||
|                     case 1: | ||||
|                         if (Parameter != null) | ||||
|                         { | ||||
|                             if (!Parameters.ContainsKey(Parameter)) | ||||
|                             { | ||||
|                                 Parts[0] = | ||||
|                                     Remover.Replace(Parts[0], "$1"); | ||||
| 
 | ||||
|                                 Parameters.Add(Parameter, Parts[0]); | ||||
|                             } | ||||
|                             Parameter = null; | ||||
|                         } | ||||
|                         // else Error: no parameter waiting for a value (skipped) | ||||
|                         break; | ||||
| 
 | ||||
|                     // Found just a parameter | ||||
|                     case 2: | ||||
|                         // The last parameter is still waiting.  | ||||
|                         // With no value, set it to true. | ||||
|                         if (Parameter != null) | ||||
|                         { | ||||
|                             if (!Parameters.ContainsKey(Parameter)) | ||||
|                                 Parameters.Add(Parameter, "true"); | ||||
|                         } | ||||
|                         Parameter = Parts[1]; | ||||
|                         break; | ||||
| 
 | ||||
|                     // Parameter with enclosed value | ||||
|                     case 3: | ||||
|                         // The last parameter is still waiting.  | ||||
|                         // With no value, set it to true. | ||||
|                         if (Parameter != null) | ||||
|                         { | ||||
|                             if (!Parameters.ContainsKey(Parameter)) | ||||
|                                 Parameters.Add(Parameter, "true"); | ||||
|                         } | ||||
| 
 | ||||
|                         Parameter = Parts[1]; | ||||
| 
 | ||||
|                         // Remove possible enclosing characters (",') | ||||
|                         if (!Parameters.ContainsKey(Parameter)) | ||||
|                         { | ||||
|                             Parts[2] = Remover.Replace(Parts[2], "$1"); | ||||
|                             Parameters.Add(Parameter, Parts[2]); | ||||
|                         } | ||||
| 
 | ||||
|                         Parameter = null; | ||||
|                         break; | ||||
|                 } | ||||
|             } | ||||
|             // In case a parameter is still waiting | ||||
|             if (Parameter != null) | ||||
|             { | ||||
|                 if (!Parameters.ContainsKey(Parameter)) | ||||
|                     Parameters.Add(Parameter, "true"); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         // Retrieve a parameter value if it exists  | ||||
|         // (overriding C# indexer property) | ||||
|         public string this[string Param] | ||||
|         { | ||||
|             get | ||||
|             { | ||||
|                 return (Parameters[Param]); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | @ -0,0 +1,323 @@ | |||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Reflection; | ||||
| using System.Xml; | ||||
| using System.Threading; | ||||
| using libsecondlife; | ||||
| using libsecondlife.Packets; | ||||
| using libsecondlife.AssetSystem; | ||||
| 
 | ||||
| namespace libsecondlife.TestClient | ||||
| { | ||||
|     public class LoginDetails | ||||
|     { | ||||
|         public string FirstName; | ||||
|         public string LastName; | ||||
|         public string Password; | ||||
|         public string StartLocation; | ||||
|         public string MasterName; | ||||
|         public LLUUID MasterKey; | ||||
|         public string LoginURI; | ||||
|     } | ||||
| 
 | ||||
|     public class StartPosition | ||||
|     { | ||||
|         public string sim; | ||||
|         public int x; | ||||
|         public int y; | ||||
|         public int z; | ||||
| 
 | ||||
|         public StartPosition() | ||||
|         { | ||||
|             this.sim = null; | ||||
|             this.x = 0; | ||||
|             this.y = 0; | ||||
|             this.z = 0; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     public class ClientManager | ||||
|     { | ||||
|         public Dictionary<LLUUID, SecondLife> Clients = new Dictionary<LLUUID, SecondLife>(); | ||||
|         public Dictionary<Simulator, Dictionary<uint, Primitive>> SimPrims = new Dictionary<Simulator, Dictionary<uint, Primitive>>(); | ||||
| 
 | ||||
|         public bool Running = true; | ||||
| 
 | ||||
|         string contactPerson = String.Empty; | ||||
|         private LLUUID resolvedMasterKey = LLUUID.Zero; | ||||
|         private ManualResetEvent keyResolution = new ManualResetEvent(false); | ||||
| 
 | ||||
|         /// <summary> | ||||
|         ///  | ||||
|         /// </summary> | ||||
|         /// <param name="accounts"></param> | ||||
|         public ClientManager(List<LoginDetails> accounts, string c) | ||||
|         { | ||||
|             this.contactPerson = c; | ||||
|             foreach (LoginDetails account in accounts) | ||||
|                 Login(account); | ||||
|         } | ||||
| 
 | ||||
|         public ClientManager(List<LoginDetails> accounts, string c, string s) | ||||
|         { | ||||
|             this.contactPerson = c; | ||||
|             char sep = '/'; | ||||
|             string[] startbits = s.Split(sep); | ||||
| 
 | ||||
|             foreach (LoginDetails account in accounts) | ||||
|             { | ||||
|                 account.StartLocation = NetworkManager.StartLocation(startbits[0], Int32.Parse(startbits[1]), | ||||
|                     Int32.Parse(startbits[2]), Int32.Parse(startbits[3])); | ||||
|                 Login(account); | ||||
|             } | ||||
|         } | ||||
|         /// <summary> | ||||
|         ///  | ||||
|         /// </summary> | ||||
|         /// <param name="account"></param> | ||||
|         /// <returns></returns> | ||||
|         public TestClient Login(LoginDetails account) | ||||
|         { | ||||
|              | ||||
|             // Check if this client is already logged in | ||||
|             foreach (TestClient c in Clients.Values) | ||||
|             { | ||||
|                 if (c.Self.FirstName == account.FirstName && c.Self.LastName == account.LastName) | ||||
|                 { | ||||
|                     Logout(c); | ||||
|                     break; | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             TestClient client = new TestClient(this); | ||||
| 
 | ||||
|             // Optimize the throttle | ||||
|             client.Throttle.Wind = 0; | ||||
|             client.Throttle.Cloud = 0; | ||||
|             client.Throttle.Land = 1000000; | ||||
|             client.Throttle.Task = 1000000; | ||||
| 
 | ||||
| 			client.SimPrims = SimPrims; | ||||
| 			client.MasterName = account.MasterName; | ||||
|             client.MasterKey = account.MasterKey; | ||||
| 
 | ||||
|             libsecondlife.NetworkManager.LoginParams loginParams = new NetworkManager.LoginParams(); | ||||
|             loginParams.FirstName = account.FirstName; | ||||
|             loginParams.LastName = account.LastName; | ||||
|             loginParams.Password = account.Password; | ||||
|             loginParams.UserAgent = "MassTestClient"; | ||||
|             loginParams.Start = account.StartLocation; | ||||
|             loginParams.Author = contactPerson; | ||||
|             loginParams.URI = account.LoginURI; | ||||
|              | ||||
| 			 | ||||
|             if (!client.Network.Login(loginParams)) | ||||
|             { | ||||
|                 Console.WriteLine("Failed to login " + account.FirstName + " " + account.LastName + ": " + | ||||
|                     client.Network.LoginMessage); | ||||
|             } | ||||
|              | ||||
| 
 | ||||
|             if (client.Network.Connected) | ||||
|             { | ||||
|                 if (account.MasterKey == LLUUID.Zero && !String.IsNullOrEmpty(account.MasterName)) | ||||
|                 { | ||||
|                     Console.WriteLine("Resolving {0}'s UUID", account.MasterName); | ||||
|                     // Find master's key from name | ||||
|                     DirectoryManager.DirPeopleReplyCallback callback = new DirectoryManager.DirPeopleReplyCallback(KeyResolvHandler); | ||||
|                     client.Directory.OnDirPeopleReply += callback; | ||||
|                     client.Directory.StartPeopleSearch(DirectoryManager.DirFindFlags.People, account.MasterName, 0); | ||||
|                     if (keyResolution.WaitOne(TimeSpan.FromMinutes(1), false)) | ||||
|                     { | ||||
|                         account.MasterKey = resolvedMasterKey; | ||||
|                         Console.WriteLine("\"{0}\" resolved to {1}", account.MasterName, account.MasterKey); | ||||
|                     } | ||||
|                     else | ||||
|                     { | ||||
|                         Console.WriteLine("Unable to obtain UUID for \"{0}\". No master will be used. Try specifying a key with --masterkey.", account.MasterName); | ||||
|                     } | ||||
|                     client.Directory.OnDirPeopleReply -= callback; | ||||
|                     keyResolution.Reset(); | ||||
|                 } | ||||
| 
 | ||||
|                 client.MasterKey = account.MasterKey; | ||||
| 
 | ||||
|                 Clients[client.Network.AgentID] = client; | ||||
| 
 | ||||
|                 Console.WriteLine("Logged in " + client.ToString()); | ||||
|             } | ||||
| 
 | ||||
|             return client; | ||||
|         } | ||||
| 
 | ||||
|         private void KeyResolvHandler(LLUUID queryid, List<DirectoryManager.AgentSearchData> matches) | ||||
|         { | ||||
|             LLUUID master = matches[0].AgentID; | ||||
|             if (matches.Count > 1) | ||||
|             { | ||||
|                 Console.WriteLine("Possible masters:"); | ||||
|                 for (int i = 0; i < matches.Count; ++i) | ||||
|                 { | ||||
|                     Console.WriteLine("{0}: {1}", i, matches[i].FirstName + " " + matches[i].LastName); | ||||
|                 } | ||||
|                 Console.Write("Ambiguous master, choose one:"); | ||||
|                 string read = Console.ReadLine(); | ||||
|                 while (read != null) | ||||
|                 { | ||||
|                     int choice = 0; | ||||
|                     if (int.TryParse(read, out choice)) | ||||
|                     { | ||||
|                         master = matches[choice].AgentID; | ||||
|                         break; | ||||
|                     } | ||||
|                     else | ||||
|                     { | ||||
|                         Console.WriteLine("Responce misunderstood."); | ||||
|                         Console.Write("Type the corresponding number:"); | ||||
|                     } | ||||
|                     read = Console.ReadLine(); | ||||
|                 } | ||||
|             } | ||||
|             resolvedMasterKey = master; | ||||
|             keyResolution.Set(); | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         ///  | ||||
|         /// </summary> | ||||
|         /// <param name="args"></param> | ||||
|         /// <returns></returns> | ||||
|         public TestClient Login(string[] args) | ||||
|         { | ||||
|             LoginDetails account = new LoginDetails(); | ||||
|             account.FirstName = args[0]; | ||||
|             account.LastName = args[1]; | ||||
|             account.Password = args[2]; | ||||
| 
 | ||||
|             if (args.Length == 4) | ||||
|             { | ||||
|                 account.StartLocation = NetworkManager.StartLocation(args[3], 128, 128, 40); | ||||
|             } | ||||
| 
 | ||||
|             return Login(account); | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         ///  | ||||
|         /// </summary> | ||||
|         public void Run(List<string> massTestCommands) | ||||
|         { | ||||
|             Console.WriteLine("Type quit to exit.  Type help for a command list."); | ||||
| 
 | ||||
|             if (massTestCommands.Count == 0) | ||||
|             { | ||||
|                 while (Running) | ||||
|                 { | ||||
|                     PrintPrompt(); | ||||
|                     string input = Console.ReadLine(); | ||||
|                     DoCommandAll(input, null, null); | ||||
|                 } | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 int currentCommand = 0; | ||||
|                 while (Running) | ||||
|                 { | ||||
|                     DoCommandAll(massTestCommands[currentCommand], null, null); | ||||
|                     currentCommand++; | ||||
|                     if (massTestCommands.Count >= currentCommand) | ||||
|                     { | ||||
|                         currentCommand = 0; | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             foreach (SecondLife client in Clients.Values) | ||||
|             { | ||||
|                 if (client.Network.Connected) | ||||
|                     client.Network.Logout(); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         private void PrintPrompt() | ||||
|         { | ||||
|             int online = 0; | ||||
| 
 | ||||
|             foreach (SecondLife client in Clients.Values) | ||||
|             { | ||||
|                 if (client.Network.Connected) online++; | ||||
|             } | ||||
| 
 | ||||
|             Console.Write(online + " avatars online> "); | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         ///  | ||||
|         /// </summary> | ||||
|         /// <param name="cmd"></param> | ||||
|         /// <param name="fromAgentID"></param> | ||||
|         /// <param name="imSessionID"></param> | ||||
|         public void DoCommandAll(string cmd, LLUUID fromAgentID, LLUUID imSessionID) | ||||
|         { | ||||
|             string[] tokens = cmd.Trim().Split(new char[] { ' ', '\t' }); | ||||
|             string firstToken = tokens[0].ToLower(); | ||||
| 
 | ||||
|             if (tokens.Length == 0) | ||||
|                 return; | ||||
| 
 | ||||
|             if (firstToken == "login") | ||||
|             { | ||||
|                 // Special login case: Only call it once, and allow it with | ||||
|                 // no logged in avatars | ||||
|                 string[] args = new string[tokens.Length - 1]; | ||||
|                 Array.Copy(tokens, 1, args, 0, args.Length); | ||||
|                 Login(args); | ||||
|             } | ||||
|             else if (firstToken == "quit") | ||||
|             { | ||||
|                 Quit(); | ||||
|                 Console.WriteLine("All clients logged out and program finished running."); | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 // make a copy of the clients list so that it can be iterated without fear of being changed during iteration | ||||
|                 Dictionary<LLUUID, SecondLife> clientsCopy = new Dictionary<LLUUID, SecondLife>(Clients); | ||||
| 
 | ||||
|                 foreach (TestClient client in clientsCopy.Values) | ||||
|                     client.DoCommand(cmd, fromAgentID, imSessionID); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         ///  | ||||
|         /// </summary> | ||||
|         /// <param name="client"></param> | ||||
|         public void Logout(TestClient client) | ||||
|         { | ||||
|             Clients.Remove(client.Network.AgentID); | ||||
|             client.Network.Logout(); | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         ///  | ||||
|         /// </summary> | ||||
|         public void LogoutAll() | ||||
|         { | ||||
|             // make a copy of the clients list so that it can be iterated without fear of being changed during iteration | ||||
|             Dictionary<LLUUID, SecondLife> clientsCopy = new Dictionary<LLUUID, SecondLife>(Clients); | ||||
| 
 | ||||
|             foreach (TestClient client in clientsCopy.Values) | ||||
|                 Logout(client); | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         ///  | ||||
|         /// </summary> | ||||
|         public void Quit() | ||||
|         { | ||||
|             LogoutAll(); | ||||
|             Running = false; | ||||
|             // TODO: It would be really nice if we could figure out a way to abort the ReadLine here in so that Run() will exit. | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | @ -0,0 +1,29 @@ | |||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Text; | ||||
| using libsecondlife; | ||||
| using libsecondlife.Packets; | ||||
| 
 | ||||
| namespace libsecondlife.TestClient | ||||
| { | ||||
|     public abstract class Command | ||||
|     { | ||||
| 		public string Name; | ||||
| 		public string Description; | ||||
| 		public TestClient Client; | ||||
| 
 | ||||
| 		public abstract string Execute(string[] args, LLUUID fromAgentID); | ||||
| 
 | ||||
| 		/// <summary> | ||||
| 		/// When set to true, think will be called. | ||||
| 		/// </summary> | ||||
| 		public bool Active; | ||||
| 
 | ||||
| 		/// <summary> | ||||
| 		/// Called twice per second, when Command.Active is set to true. | ||||
| 		/// </summary> | ||||
| 		public virtual void Think() | ||||
| 		{ | ||||
| 		} | ||||
|     } | ||||
| } | ||||
|  | @ -0,0 +1,131 @@ | |||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Threading; | ||||
| using libsecondlife; | ||||
| using libsecondlife.Packets; | ||||
| 
 | ||||
| namespace libsecondlife.TestClient | ||||
| { | ||||
|     public class CloneProfileCommand : Command | ||||
|     { | ||||
|         Avatar.AvatarProperties Properties; | ||||
|         Avatar.Interests Interests; | ||||
|         List<LLUUID> Groups = new List<LLUUID>(); | ||||
|         bool ReceivedProperties = false; | ||||
|         bool ReceivedInterests = false; | ||||
|         bool ReceivedGroups = false; | ||||
|         ManualResetEvent ReceivedProfileEvent = new ManualResetEvent(false); | ||||
| 
 | ||||
|         public CloneProfileCommand(TestClient testClient) | ||||
|         { | ||||
|             testClient.Avatars.OnAvatarInterests += new AvatarManager.AvatarInterestsCallback(Avatars_OnAvatarInterests); | ||||
|             testClient.Avatars.OnAvatarProperties += new AvatarManager.AvatarPropertiesCallback(Avatars_OnAvatarProperties); | ||||
|             testClient.Avatars.OnAvatarGroups += new AvatarManager.AvatarGroupsCallback(Avatars_OnAvatarGroups); | ||||
|             testClient.Self.OnJoinGroup += new MainAvatar.JoinGroupCallback(Self_OnJoinGroup); | ||||
| 
 | ||||
|             Name = "cloneprofile"; | ||||
|             Description = "Clones another avatars profile as closely as possible. WARNING: This command will " + | ||||
|                 "destroy your existing profile! Usage: cloneprofile [targetuuid]"; | ||||
|         } | ||||
| 
 | ||||
|         public override string Execute(string[] args, LLUUID fromAgentID) | ||||
|         { | ||||
|             if (args.Length != 1) | ||||
|                 return Description; | ||||
| 
 | ||||
|             LLUUID targetID; | ||||
|             ReceivedProperties = false; | ||||
|             ReceivedInterests = false; | ||||
|             ReceivedGroups = false; | ||||
| 
 | ||||
|             try | ||||
|             { | ||||
|                 targetID = new LLUUID(args[0]); | ||||
|             } | ||||
|             catch (Exception) | ||||
|             { | ||||
|                 return Description; | ||||
|             } | ||||
| 
 | ||||
|             // Request all of the packets that make up an avatar profile | ||||
|             Client.Avatars.RequestAvatarProperties(targetID); | ||||
| 
 | ||||
|             // Wait for all the packets to arrive | ||||
|             ReceivedProfileEvent.Reset(); | ||||
|             ReceivedProfileEvent.WaitOne(5000, false); | ||||
| 
 | ||||
|             // Check if everything showed up | ||||
|             if (!ReceivedInterests || !ReceivedProperties || !ReceivedGroups) | ||||
|                 return "Failed to retrieve a complete profile for that UUID"; | ||||
| 
 | ||||
|             // Synchronize our profile | ||||
|             Client.Self.ProfileInterests = Interests; | ||||
|             Client.Self.ProfileProperties = Properties; | ||||
|             Client.Self.SetAvatarInformation(); | ||||
| 
 | ||||
|             // TODO: Leave all the groups we're currently a member of? This could | ||||
|             // break TestClient connectivity that might be relying on group authentication | ||||
| 
 | ||||
|             // Attempt to join all the groups | ||||
|             foreach (LLUUID groupID in Groups) | ||||
|             { | ||||
|                 Client.Self.RequestJoinGroup(groupID); | ||||
|             } | ||||
| 
 | ||||
|             return "Synchronized our profile to the profile of " + targetID.ToStringHyphenated(); | ||||
|         } | ||||
| 
 | ||||
|         void Avatars_OnAvatarProperties(LLUUID avatarID, Avatar.AvatarProperties properties) | ||||
|         { | ||||
|             lock (ReceivedProfileEvent) | ||||
|             { | ||||
|                 Properties = properties; | ||||
|                 ReceivedProperties = true; | ||||
| 
 | ||||
|                 if (ReceivedInterests && ReceivedProperties && ReceivedGroups) | ||||
|                     ReceivedProfileEvent.Set(); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         void Avatars_OnAvatarInterests(LLUUID avatarID, Avatar.Interests interests) | ||||
|         { | ||||
|             lock (ReceivedProfileEvent) | ||||
|             { | ||||
|                 Interests = interests; | ||||
|                 ReceivedInterests = true; | ||||
| 
 | ||||
|                 if (ReceivedInterests && ReceivedProperties && ReceivedGroups) | ||||
|                     ReceivedProfileEvent.Set(); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         void Avatars_OnAvatarGroups(LLUUID avatarID, AvatarGroupsReplyPacket.GroupDataBlock[] groups) | ||||
|         { | ||||
|             lock (ReceivedProfileEvent) | ||||
|             { | ||||
|                 foreach (AvatarGroupsReplyPacket.GroupDataBlock block in groups) | ||||
|                 { | ||||
|                     Groups.Add(block.GroupID); | ||||
|                 } | ||||
| 
 | ||||
|                 ReceivedGroups = true; | ||||
| 
 | ||||
|                 if (ReceivedInterests && ReceivedProperties && ReceivedGroups) | ||||
|                     ReceivedProfileEvent.Set(); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         void Self_OnJoinGroup(LLUUID groupID, bool success) | ||||
|         { | ||||
|             Console.WriteLine(Client.ToString() + (success ? " joined " : " failed to join ") +  | ||||
|                 groupID.ToStringHyphenated()); | ||||
| 
 | ||||
|             if (success) | ||||
|             { | ||||
|                 Console.WriteLine(Client.ToString() + " setting " + groupID.ToStringHyphenated() +  | ||||
|                     " as the active group"); | ||||
|                 Client.Self.ActivateGroup(groupID); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | @ -0,0 +1,42 @@ | |||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Text; | ||||
| using libsecondlife; | ||||
| using libsecondlife.Packets; | ||||
| 
 | ||||
| namespace libsecondlife.TestClient | ||||
| { | ||||
|     public class EchoMasterCommand: Command | ||||
|     { | ||||
|         public EchoMasterCommand(TestClient testClient) | ||||
| 		{ | ||||
| 			Name = "echoMaster"; | ||||
| 			Description = "Repeat everything that master says."; | ||||
| 		} | ||||
| 
 | ||||
|         public override string Execute(string[] args, LLUUID fromAgentID) | ||||
| 		{ | ||||
| 			if (!Active) | ||||
| 			{ | ||||
| 				Active = true; | ||||
|                 Client.Self.OnChat += new MainAvatar.ChatCallback(Self_OnChat); | ||||
| 				return "Echoing is now on."; | ||||
| 			} | ||||
| 			else | ||||
| 			{ | ||||
| 				Active = false; | ||||
|                 Client.Self.OnChat -= new MainAvatar.ChatCallback(Self_OnChat); | ||||
| 				return "Echoing is now off."; | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		void Self_OnChat(string message, MainAvatar.ChatAudibleLevel audible, MainAvatar.ChatType type,  | ||||
|             MainAvatar.ChatSourceType sourcetype, string fromName, LLUUID id, LLUUID ownerid, LLVector3 position) | ||||
| 		{ | ||||
| 			if (message.Length > 0 && Client.MasterKey == id) | ||||
| 			{ | ||||
| 			    Client.Self.Chat(message, 0, MainAvatar.ChatType.Normal); | ||||
| 			} | ||||
| 		} | ||||
|     } | ||||
| } | ||||
|  | @ -0,0 +1,71 @@ | |||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Threading; | ||||
| using libsecondlife; | ||||
| using libsecondlife.Packets; | ||||
| 
 | ||||
| namespace libsecondlife.TestClient | ||||
| { | ||||
|     public class ImCommand : Command | ||||
|     { | ||||
|         string ToAvatarName = String.Empty; | ||||
|         ManualResetEvent NameSearchEvent = new ManualResetEvent(false); | ||||
|         Dictionary<string, LLUUID> Name2Key = new Dictionary<string, LLUUID>(); | ||||
| 
 | ||||
|         public ImCommand(TestClient testClient) | ||||
|         { | ||||
|             testClient.Avatars.OnAvatarNameSearch += new AvatarManager.AvatarNameSearchCallback(Avatars_OnAvatarNameSearch); | ||||
| 
 | ||||
|             Name = "im"; | ||||
|             Description = "Instant message someone. Usage: im [firstname] [lastname] [message]"; | ||||
|         } | ||||
| 
 | ||||
|         public override string Execute(string[] args, LLUUID fromAgentID) | ||||
|         { | ||||
|             if (args.Length < 3) | ||||
|                 return "Usage: im [firstname] [lastname] [message]"; | ||||
| 
 | ||||
|             ToAvatarName = args[0] + " " + args[1]; | ||||
| 
 | ||||
|             // Build the message | ||||
|             string message = String.Empty; | ||||
|             for (int ct = 2; ct < args.Length; ct++) | ||||
|                 message += args[ct] + " "; | ||||
|             message = message.TrimEnd(); | ||||
|             if (message.Length > 1023) message = message.Remove(1023); | ||||
| 
 | ||||
|             if (!Name2Key.ContainsKey(ToAvatarName.ToLower())) | ||||
|             { | ||||
|                 // Send the Query | ||||
|                 Client.Avatars.RequestAvatarNameSearch(ToAvatarName, LLUUID.Random()); | ||||
| 
 | ||||
|                 NameSearchEvent.WaitOne(6000, false); | ||||
|             } | ||||
| 
 | ||||
|             if (Name2Key.ContainsKey(ToAvatarName.ToLower())) | ||||
|             { | ||||
|                 LLUUID id = Name2Key[ToAvatarName.ToLower()]; | ||||
| 
 | ||||
|                 Client.Self.InstantMessage(id, message, id); | ||||
|                 return "Instant Messaged " + id.ToStringHyphenated() + " with message: " + message; | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 return "Name lookup for " + ToAvatarName + " failed"; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         void Avatars_OnAvatarNameSearch(LLUUID queryID, Dictionary<LLUUID, string> avatars) | ||||
|         { | ||||
|             foreach (KeyValuePair<LLUUID, string> kvp in avatars) | ||||
|             { | ||||
|                 if (kvp.Value.ToLower() == ToAvatarName.ToLower()) | ||||
|                 { | ||||
|                     Name2Key[ToAvatarName.ToLower()] = kvp.Key; | ||||
|                     NameSearchEvent.Set(); | ||||
|                     return; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | @ -0,0 +1,44 @@ | |||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Text; | ||||
| using libsecondlife; | ||||
| 
 | ||||
| namespace libsecondlife.TestClient | ||||
| { | ||||
|     public class SayCommand: Command | ||||
|     { | ||||
|         public SayCommand(TestClient testClient) | ||||
| 		{ | ||||
| 			Name = "say"; | ||||
| 			Description = "Say something.  (usage: say (optional channel) whatever)"; | ||||
| 		} | ||||
| 
 | ||||
|         public override string Execute(string[] args, LLUUID fromAgentID) | ||||
| 		{ | ||||
|             int channel = 0; | ||||
|             int startIndex = 0; | ||||
|              | ||||
|             if (args.Length < 1) | ||||
|             { | ||||
|                 return "usage: say (optional channel) whatever"; | ||||
|             } | ||||
|             else if (args.Length > 1) | ||||
|             { | ||||
|                 if (Int32.TryParse(args[0], out channel)) | ||||
| 					startIndex = 1; | ||||
|             } | ||||
| 
 | ||||
|             StringBuilder message = new StringBuilder(); | ||||
| 
 | ||||
| 			for (int i = startIndex; i < args.Length; i++) | ||||
|             { | ||||
|                 message.Append(args[i]); | ||||
|                 if (i != args.Length - 1) message.Append(" "); | ||||
|             } | ||||
| 
 | ||||
| 			Client.Self.Chat(message.ToString(), channel, MainAvatar.ChatType.Normal); | ||||
| 
 | ||||
|             return "Said " + message.ToString(); | ||||
| 		} | ||||
|     } | ||||
| } | ||||
|  | @ -0,0 +1,49 @@ | |||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Text; | ||||
| using libsecondlife; | ||||
| using libsecondlife.Packets; | ||||
| 
 | ||||
| namespace libsecondlife.TestClient | ||||
| { | ||||
|     public class ShoutCommand : Command | ||||
|     { | ||||
|         public ShoutCommand(TestClient testClient) | ||||
|         { | ||||
|             Name = "shout"; | ||||
|             Description = "Shout something."; | ||||
|         } | ||||
| 
 | ||||
|         public override string Execute(string[] args, LLUUID fromAgentID) | ||||
|         { | ||||
|             int channel = 0; | ||||
|             int startIndex = 0; | ||||
|             string message = String.Empty; | ||||
|             if (args.Length < 1) | ||||
|             { | ||||
|                 return "usage: shout (optional channel) whatever"; | ||||
|             } | ||||
|             else if (args.Length > 1) | ||||
|             { | ||||
|                 try | ||||
|                 { | ||||
|                     channel = Convert.ToInt32(args[0]); | ||||
|                     startIndex = 1; | ||||
|                 } | ||||
|                 catch (FormatException) | ||||
|                 { | ||||
|                     channel = 0; | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             for (int i = startIndex; i < args.Length; i++) | ||||
|             { | ||||
|                 message += args[i] + " "; | ||||
|             } | ||||
| 
 | ||||
|             Client.Self.Chat(message, channel, MainAvatar.ChatType.Shout); | ||||
| 
 | ||||
|             return "Shouted " + message; | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | @ -0,0 +1,51 @@ | |||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Text; | ||||
| using System.Speech.Synthesis; | ||||
| using libsecondlife; | ||||
| using libsecondlife.Packets; | ||||
| using libsecondlife.AssetSystem; | ||||
| 
 | ||||
| 
 | ||||
| // Since this requires .Net 3.0 I've left it out of the project by default. | ||||
| // To use this: include it in the project and add a reference to the System.Speech.dll | ||||
| 
 | ||||
| namespace libsecondlife.TestClient | ||||
| { | ||||
|     public class TtsCommand : Command | ||||
|     { | ||||
| 		SpeechSynthesizer _speechSynthesizer; | ||||
| 
 | ||||
| 		public TtsCommand(TestClient testClient) | ||||
|         { | ||||
|             Name = "tts"; | ||||
|             Description = "Text To Speech.  When activated, client will echo all recieved chat messages out thru the computer's speakers."; | ||||
|         } | ||||
| 
 | ||||
|         public override string Execute(string[] args, LLUUID fromAgentID) | ||||
|         { | ||||
| 			if (!Active) | ||||
| 			{ | ||||
| 				if (_speechSynthesizer == null) | ||||
| 					_speechSynthesizer = new SpeechSynthesizer(); | ||||
| 				Active = true; | ||||
| 				Client.Self.OnChat += new MainAvatar.ChatCallback(Self_OnChat); | ||||
| 				return "TTS is now on."; | ||||
| 			} | ||||
| 			else | ||||
| 			{ | ||||
| 				Active = false; | ||||
| 				Client.Self.OnChat -= new MainAvatar.ChatCallback(Self_OnChat); | ||||
| 				return "TTS is now off."; | ||||
| 			} | ||||
|         } | ||||
| 
 | ||||
| 		void Self_OnChat(string message, byte audible, byte type, byte sourcetype, string fromName, LLUUID id, LLUUID ownerid, LLVector3 position) | ||||
| 		{ | ||||
| 			if (message.Length > 0) | ||||
| 			{ | ||||
| 				_speechSynthesizer.SpeakAsync(message); | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | @ -0,0 +1,49 @@ | |||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Text; | ||||
| using libsecondlife; | ||||
| using libsecondlife.Packets; | ||||
| 
 | ||||
| namespace libsecondlife.TestClient | ||||
| { | ||||
|     public class WhisperCommand : Command | ||||
|     { | ||||
|         public WhisperCommand(TestClient testClient) | ||||
|         { | ||||
|             Name = "whisper"; | ||||
|             Description = "Whisper something."; | ||||
|         } | ||||
| 
 | ||||
|         public override string Execute(string[] args, LLUUID fromAgentID) | ||||
|         { | ||||
|             int channel = 0; | ||||
|             int startIndex = 0; | ||||
|             string message = String.Empty; | ||||
|             if (args.Length < 1) | ||||
|             { | ||||
|                 return "usage: whisper (optional channel) whatever"; | ||||
|             } | ||||
|             else if (args.Length > 1) | ||||
|             { | ||||
|                 try | ||||
|                 { | ||||
|                     channel = Convert.ToInt32(args[0]); | ||||
|                     startIndex = 1; | ||||
|                 } | ||||
|                 catch (FormatException) | ||||
|                 { | ||||
|                     channel = 0; | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             for (int i = startIndex; i < args.Length; i++) | ||||
|             { | ||||
|                 message += args[i] + " "; | ||||
|             } | ||||
| 
 | ||||
|             Client.Self.Chat(message, channel, MainAvatar.ChatType.Whisper); | ||||
| 
 | ||||
|             return "Whispered " + message; | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | @ -0,0 +1,26 @@ | |||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Text; | ||||
| using libsecondlife; | ||||
| using libsecondlife.Packets; | ||||
| 
 | ||||
| namespace libsecondlife.TestClient | ||||
| { | ||||
|     public class GoHomeCommand : Command | ||||
|     { | ||||
| 		public GoHomeCommand(TestClient testClient) | ||||
|         { | ||||
|             Name = "gohome"; | ||||
|             Description = "Teleports home"; | ||||
|         } | ||||
| 
 | ||||
|         public override string Execute(string[] args, LLUUID fromAgentID) | ||||
|         { | ||||
| 			if ( Client.Self.GoHome() ) { | ||||
| 				return "Teleport Home Succesful"; | ||||
| 			} else { | ||||
| 				return "Teleport Home Failed"; | ||||
| 			} | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | @ -0,0 +1,32 @@ | |||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Text; | ||||
| using libsecondlife; | ||||
| using libsecondlife.Packets; | ||||
| 
 | ||||
| namespace libsecondlife.TestClient | ||||
| { | ||||
|     public class GotoLandmarkCommand : Command | ||||
|     { | ||||
| 		public GotoLandmarkCommand(TestClient testClient) | ||||
|         { | ||||
|             Name = "goto_landmark"; | ||||
|             Description = "Teleports to a Landmark "; | ||||
|         } | ||||
| 
 | ||||
|         public override string Execute(string[] args, LLUUID fromAgentID) | ||||
|         { | ||||
| 			LLUUID landmark = new LLUUID(); | ||||
| 			if ( ! LLUUID.TryParse(args[0], out landmark) ) { | ||||
| 				return "Invalid LLUID"; | ||||
| 			} else { | ||||
| 				Console.WriteLine("Teleporting to " + landmark.ToString()); | ||||
| 			} | ||||
| 			if ( Client.Self.Teleport(landmark) ) { | ||||
| 				return "Teleport Succesful"; | ||||
| 			} else { | ||||
| 				return "Teleport Failed"; | ||||
| 			} | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | @ -0,0 +1,29 @@ | |||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Text; | ||||
| using libsecondlife; | ||||
| using libsecondlife.Packets; | ||||
| 
 | ||||
| namespace libsecondlife.TestClient | ||||
| { | ||||
|     public class AppearanceCommand : Command | ||||
|     { | ||||
|         Utilities.Assets.AssetManager Assets; | ||||
|         Utilities.Appearance.AppearanceManager Appearance; | ||||
| 
 | ||||
| 		public AppearanceCommand(TestClient testClient) | ||||
|         { | ||||
|             Name = "appearance"; | ||||
|             Description = "Set your current appearance to your last saved appearance"; | ||||
| 
 | ||||
|             Assets = new libsecondlife.Utilities.Assets.AssetManager(testClient); | ||||
|             Appearance = new libsecondlife.Utilities.Appearance.AppearanceManager(testClient, Assets); | ||||
|         } | ||||
| 
 | ||||
|         public override string Execute(string[] args, LLUUID fromAgentID) | ||||
|         { | ||||
|             Appearance.SetPreviousAppearance(); | ||||
|             return "Done."; | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | @ -0,0 +1,21 @@ | |||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using libsecondlife; | ||||
| using libsecondlife.Packets; | ||||
| 
 | ||||
| namespace libsecondlife.TestClient | ||||
| { | ||||
|     public class BalanceCommand: Command | ||||
|     { | ||||
|         public BalanceCommand(TestClient testClient) | ||||
| 		{ | ||||
| 			Name = "balance"; | ||||
| 			Description = "Shows the amount of L$."; | ||||
| 		} | ||||
| 
 | ||||
|         public override string Execute(string[] args, LLUUID fromAgentID) | ||||
| 		{ | ||||
| 			return Client.ToString() + " has L$: " + Client.Self.Balance; | ||||
| 		} | ||||
|     } | ||||
| } | ||||
|  | @ -0,0 +1,43 @@ | |||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.IO; | ||||
| using System.Text; | ||||
| using System.Threading; | ||||
| using System.Xml; | ||||
| using System.Xml.Serialization; | ||||
| 
 | ||||
| using libsecondlife; | ||||
| using libsecondlife.Packets; | ||||
| using libsecondlife.InventorySystem; | ||||
| 
 | ||||
| namespace libsecondlife.TestClient | ||||
| { | ||||
|     public class DeleteFolderCommand : Command | ||||
|     { | ||||
| 		public DeleteFolderCommand(TestClient testClient) | ||||
|         { | ||||
|             Name = "deleteFolder"; | ||||
|             Description = "Deletes a folder from inventory."; | ||||
|         } | ||||
| 
 | ||||
|         public override string Execute(string[] args, LLUUID fromAgentID) | ||||
|         { | ||||
|             return "Broken until someone fixes me"; | ||||
| 
 | ||||
|             //string target = String.Empty; | ||||
|             //for (int ct = 0; ct < args.Length; ct++) | ||||
|             //    target = target + args[ct] + " "; | ||||
|             //target = target.TrimEnd(); | ||||
| 
 | ||||
|             //Client.Inventory.DownloadInventory(); | ||||
|             //InventoryFolder folder = Client.Inventory.getFolder(target); | ||||
|             //if (folder != null) | ||||
|             //{ | ||||
|             //    folder.Delete(); | ||||
|             //    return "Folder " + target + " deleted."; | ||||
|             //} | ||||
| 
 | ||||
|             //return "Unable to find: " + target; | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | @ -0,0 +1,98 @@ | |||
| using System; | ||||
| using System.Text; | ||||
| using System.IO; | ||||
| using System.Collections.Generic; | ||||
| using libsecondlife; | ||||
| using libsecondlife.Utilities.Assets; | ||||
| using libsecondlife.Utilities.Appearance; | ||||
| 
 | ||||
| namespace libsecondlife.TestClient | ||||
| { | ||||
|     public class DumpOutfitCommand : Command | ||||
|     { | ||||
|         libsecondlife.Utilities.Assets.AssetManager Assets; | ||||
|         List<LLUUID> OutfitAssets = new List<LLUUID>(); | ||||
| 
 | ||||
|         public DumpOutfitCommand(TestClient testClient) | ||||
|         { | ||||
|             Name = "dumpoutfit"; | ||||
|             Description = "Dumps all of the textures from an avatars outfit to the hard drive. Usage: dumpoutfit [avatar-uuid]"; | ||||
| 
 | ||||
|             Assets = new AssetManager(testClient); | ||||
|             Assets.OnImageReceived += new AssetManager.ImageReceivedCallback(Assets_OnImageReceived); | ||||
|         } | ||||
| 
 | ||||
|         public override string Execute(string[] args, LLUUID fromAgentID) | ||||
|         { | ||||
|             if (args.Length != 1) | ||||
|                 return "Usage: dumpoutfit [avatar-uuid]"; | ||||
| 
 | ||||
|             LLUUID target; | ||||
| 
 | ||||
|             if (!LLUUID.TryParse(args[0], out target)) | ||||
|                 return "Usage: dumpoutfit [avatar-uuid]"; | ||||
| 
 | ||||
|             lock (Client.AvatarList) | ||||
|             { | ||||
|                 foreach (Avatar avatar in Client.AvatarList.Values) | ||||
|                 { | ||||
|                     if (avatar.ID == target) | ||||
|                     { | ||||
|                         StringBuilder output = new StringBuilder("Downloading "); | ||||
| 
 | ||||
|                         lock (OutfitAssets) OutfitAssets.Clear(); | ||||
| 
 | ||||
|                         foreach (KeyValuePair<uint, LLObject.TextureEntryFace> face in avatar.Textures.FaceTextures) | ||||
|                         { | ||||
|                             ImageType type = ImageType.Normal; | ||||
| 
 | ||||
|                             switch ((AppearanceManager.TextureIndex)face.Key) | ||||
|                             { | ||||
|                                 case AppearanceManager.TextureIndex.HeadBaked: | ||||
|                                 case AppearanceManager.TextureIndex.EyesBaked: | ||||
|                                 case AppearanceManager.TextureIndex.UpperBaked: | ||||
|                                 case AppearanceManager.TextureIndex.LowerBaked: | ||||
|                                 case AppearanceManager.TextureIndex.SkirtBaked: | ||||
|                                     type = ImageType.Baked; | ||||
|                                     break; | ||||
|                             } | ||||
| 
 | ||||
|                             Assets.RequestImage(face.Value.TextureID, type, 100000.0f, 0); | ||||
| 
 | ||||
|                             output.Append(((AppearanceManager.TextureIndex)face.Key).ToString()); | ||||
|                             output.Append(" "); | ||||
|                         } | ||||
| 
 | ||||
|                         return output.ToString(); | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             return "Couldn't find avatar " + target.ToStringHyphenated(); | ||||
|         } | ||||
| 
 | ||||
|         private void Assets_OnImageReceived(ImageDownload image) | ||||
|         { | ||||
|             if (image.Success) | ||||
|             { | ||||
|                 try | ||||
|                 { | ||||
|                     File.WriteAllBytes(image.ID.ToStringHyphenated() + ".jp2", image.AssetData); | ||||
|                     Console.WriteLine("Wrote JPEG2000 image " + image.ID.ToStringHyphenated() + ".jp2"); | ||||
| 
 | ||||
|                     byte[] tgaFile = OpenJPEGNet.OpenJPEG.DecodeToTGA(image.AssetData); | ||||
|                     File.WriteAllBytes(image.ID.ToStringHyphenated() + ".tga", tgaFile); | ||||
|                     Console.WriteLine("Wrote TGA image " + image.ID.ToStringHyphenated() + ".tga"); | ||||
|                 } | ||||
|                 catch (Exception e) | ||||
|                 { | ||||
|                     Console.WriteLine(e.ToString()); | ||||
|                 } | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 Console.WriteLine("Failed to download image " + image.ID.ToStringHyphenated()); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | @ -0,0 +1,66 @@ | |||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.IO; | ||||
| using System.Xml; | ||||
| using libsecondlife; | ||||
| using libsecondlife.Packets; | ||||
| 
 | ||||
| namespace libsecondlife.TestClient | ||||
| { | ||||
|     public class ExportOutfitCommand : Command | ||||
|     { | ||||
|         public ExportOutfitCommand(TestClient testClient) | ||||
|         { | ||||
|             Name = "exportoutfit"; | ||||
|             Description = "Exports an avatars outfit to an xml file. Usage: exportoutfit avataruuid outputfile.xml"; | ||||
|         } | ||||
| 
 | ||||
|         public override string Execute(string[] args, LLUUID fromAgentID) | ||||
|         { | ||||
|             if (args.Length != 2) | ||||
|                 return "Usage: exportoutfit avataruuid outputfile.xml"; | ||||
| 
 | ||||
|             LLUUID id; | ||||
| 
 | ||||
|             try | ||||
|             { | ||||
|                 id = new LLUUID(args[0]); | ||||
|             } | ||||
|             catch (Exception) | ||||
|             { | ||||
|                 return "Usage: exportoutfit avataruuid outputfile.xml"; | ||||
|             } | ||||
| 
 | ||||
|             lock (Client.Appearances) | ||||
|             { | ||||
|                 if (Client.Appearances.ContainsKey(id)) | ||||
|                 { | ||||
|                     try | ||||
|                     { | ||||
| 						XmlWriterSettings settings = new XmlWriterSettings(); | ||||
| 						settings.Indent = true; | ||||
| 						XmlWriter writer = XmlWriter.Create(args[1], settings); | ||||
| 						try | ||||
| 						{ | ||||
| 							Client.Appearances[id].ToXml(writer); | ||||
| 						} | ||||
| 						finally | ||||
| 						{ | ||||
| 							writer.Close(); | ||||
| 						} | ||||
|                     } | ||||
|                     catch (Exception e) | ||||
|                     { | ||||
|                         return e.ToString(); | ||||
|                     } | ||||
| 
 | ||||
|                     return "Exported appearance for avatar " + id.ToString() + " to " + args[1]; | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     return "Couldn't find an appearance for avatar " + id.ToString(); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | @ -0,0 +1,27 @@ | |||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Text; | ||||
| using libsecondlife; | ||||
| using libsecondlife.Packets; | ||||
| 
 | ||||
| namespace libsecondlife.TestClient | ||||
| { | ||||
|     public class GiveAllCommand: Command | ||||
|     { | ||||
| 		public GiveAllCommand(TestClient testClient) | ||||
| 		{ | ||||
| 			Name = "giveAll"; | ||||
| 			Description = "Gives you all it's money."; | ||||
| 		} | ||||
| 
 | ||||
|         public override string Execute(string[] args, LLUUID fromAgentID) | ||||
| 		{ | ||||
| 			if (fromAgentID == null) | ||||
| 				return "Unable to send money to console.  This command only works when IMed."; | ||||
| 
 | ||||
| 		    int amount = Client.Self.Balance; | ||||
| 		    Client.Self.GiveMoney(fromAgentID, Client.Self.Balance, String.Empty); | ||||
| 		    return "Gave $" + amount + " to " + fromAgentID; | ||||
| 		} | ||||
|     } | ||||
| } | ||||
|  | @ -0,0 +1,66 @@ | |||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.IO; | ||||
| using System.Xml; | ||||
| using System.Xml.Serialization; | ||||
| using libsecondlife; | ||||
| using libsecondlife.Packets; | ||||
| 
 | ||||
| namespace libsecondlife.TestClient | ||||
| { | ||||
|     public class ImportOutfitCommand : Command | ||||
|     { | ||||
|         private uint SerialNum = 1; | ||||
| 
 | ||||
|         public ImportOutfitCommand(TestClient testClient) | ||||
|         { | ||||
|             Name = "importoutfit"; | ||||
|             Description = "Imports an appearance from an xml file. Usage: importoutfit inputfile.xml"; | ||||
|         } | ||||
| 
 | ||||
|         public override string Execute(string[] args, LLUUID fromAgentID) | ||||
|         { | ||||
|             if (args.Length != 1) | ||||
|                 return "Usage: importoutfit inputfile.xml"; | ||||
| 
 | ||||
|             try | ||||
|             { | ||||
|                 XmlReader reader = XmlReader.Create(args[0]); | ||||
|                 XmlSerializer serializer = new XmlSerializer(typeof(Packet)); | ||||
|                 AvatarAppearancePacket appearance = (AvatarAppearancePacket)serializer.Deserialize(reader); | ||||
|                 reader.Close(); | ||||
| 
 | ||||
|                 AgentSetAppearancePacket set = new AgentSetAppearancePacket(); | ||||
| 
 | ||||
|                 set.AgentData.AgentID = Client.Network.AgentID; | ||||
|                 set.AgentData.SessionID = Client.Network.SessionID; | ||||
|                 set.AgentData.SerialNum = SerialNum++; | ||||
| 
 | ||||
|                 float AV_Height_Range = 2.025506f - 1.50856f; | ||||
|                 float AV_Height = 1.50856f + (((float)appearance.VisualParam[25].ParamValue / 255.0f) * AV_Height_Range); | ||||
|                 set.AgentData.Size = new LLVector3(0.45f, 0.6f, AV_Height); | ||||
| 
 | ||||
|                 set.ObjectData.TextureEntry = appearance.ObjectData.TextureEntry; | ||||
|                 set.VisualParam = new AgentSetAppearancePacket.VisualParamBlock[appearance.VisualParam.Length]; | ||||
| 
 | ||||
|                 int i = 0; | ||||
|                 foreach (AvatarAppearancePacket.VisualParamBlock block in appearance.VisualParam) | ||||
|                 { | ||||
|                     set.VisualParam[i] = new AgentSetAppearancePacket.VisualParamBlock(); | ||||
|                     set.VisualParam[i].ParamValue = block.ParamValue; | ||||
|                     i++; | ||||
|                 } | ||||
| 
 | ||||
|                 set.WearableData = new AgentSetAppearancePacket.WearableDataBlock[0]; | ||||
| 
 | ||||
|                 Client.Network.SendPacket(set); | ||||
|             } | ||||
|             catch (Exception) | ||||
|             { | ||||
|                 return "Failed to import the appearance XML file, maybe it doesn't exist or is in the wrong format?"; | ||||
|             } | ||||
| 
 | ||||
|             return "Imported " + args[0] + " and sent an AgentSetAppearance packet"; | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | @ -0,0 +1,62 @@ | |||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.IO; | ||||
| using System.Text; | ||||
| using System.Threading; | ||||
| using System.Xml; | ||||
| using System.Xml.Serialization; | ||||
| 
 | ||||
| using libsecondlife; | ||||
| using libsecondlife.Packets; | ||||
| using libsecondlife.InventorySystem; | ||||
| 
 | ||||
| namespace libsecondlife.TestClient | ||||
| { | ||||
|     public class InventoryCommand : Command | ||||
|     { | ||||
| 		public InventoryCommand(TestClient testClient) | ||||
|         { | ||||
|             Name = "i"; | ||||
|             Description = "Prints out inventory."; | ||||
|         } | ||||
| 
 | ||||
|         public override string Execute(string[] args, LLUUID fromAgentID) | ||||
|         { | ||||
|             return "Broken until someone fixes me"; | ||||
| 
 | ||||
|             //Client.Inventory.DownloadInventory(); | ||||
|             //StringBuilder result = new StringBuilder(); | ||||
|             //PrintFolder(Client.Inventory.GetRootFolder(), result, 0); | ||||
|             //return result.ToString(); | ||||
|         } | ||||
| 
 | ||||
|         //void PrintFolder(InventoryFolder folder, StringBuilder output, int indenting) | ||||
|         //{ | ||||
|         //    Indent(output, indenting); | ||||
|         //    output.Append(folder.Name); | ||||
|         //    output.Append("\n"); | ||||
|         //    foreach (InventoryBase b in folder.GetContents()) | ||||
|         //    { | ||||
|         //        InventoryItem item = b as InventoryItem; | ||||
|         //        if (item != null) | ||||
|         //        { | ||||
|         //            Indent(output, indenting + 1); | ||||
|         //            output.Append(item.Name); | ||||
|         //            output.Append("\n"); | ||||
|         //            continue; | ||||
|         //        } | ||||
|         //        InventoryFolder subFolder = b as InventoryFolder; | ||||
|         //        if (subFolder != null) | ||||
|         //            PrintFolder(subFolder, output, indenting + 1); | ||||
|         //    } | ||||
|         //} | ||||
| 
 | ||||
|         //void Indent(StringBuilder output, int indenting) | ||||
|         //{ | ||||
|         //    for (int count = 0; count < indenting; count++) | ||||
|         //    { | ||||
|         //        output.Append("  "); | ||||
|         //    } | ||||
|         //} | ||||
| 	} | ||||
| } | ||||
|  | @ -0,0 +1,43 @@ | |||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.IO; | ||||
| using System.Text; | ||||
| using System.Threading; | ||||
| using System.Xml; | ||||
| using System.Xml.Serialization; | ||||
| 
 | ||||
| using libsecondlife; | ||||
| using libsecondlife.Packets; | ||||
| using libsecondlife.InventorySystem; | ||||
| 
 | ||||
| namespace libsecondlife.TestClient | ||||
| { | ||||
|     public class WearCommand : Command | ||||
|     { | ||||
| 		    public WearCommand(TestClient testClient) | ||||
|         { | ||||
|             Name = "wear"; | ||||
|             Description = "Wear an outfit folder from inventory. Usage: wear [outfit name]"; | ||||
|         } | ||||
| 
 | ||||
|         public override string Execute(string[] args, LLUUID fromAgentID) | ||||
|         { | ||||
|             string target = String.Empty; | ||||
| 
 | ||||
|             for (int ct = 0; ct < args.Length; ct++) | ||||
|                 target = target + args[ct] + " "; | ||||
|              | ||||
|             target = target.TrimEnd(); | ||||
| 
 | ||||
|             InventoryFolder folder = Client.Inventory.getFolder(target); | ||||
|              | ||||
|             if (folder != null) | ||||
|             { | ||||
|                 Client.Appearance.WearOutfit(folder); | ||||
|                 return "Outfit " + target + " worn."; | ||||
|             } | ||||
| 
 | ||||
|             return "Unable to find: " + target; | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | @ -0,0 +1,43 @@ | |||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Text; | ||||
| using libsecondlife; | ||||
| using libsecondlife.Packets; | ||||
| 
 | ||||
| namespace libsecondlife.TestClient | ||||
| { | ||||
|     public class FindSimCommand : Command | ||||
|     { | ||||
|         public FindSimCommand(TestClient testClient) | ||||
|         { | ||||
|             Name = "findsim"; | ||||
|             Description = "Searches for a simulator and returns information about it. Usage: findsim [Simulator Name]"; | ||||
|         } | ||||
| 
 | ||||
|         public override string Execute(string[] args, LLUUID fromAgentID) | ||||
|         { | ||||
|             if (args.Length < 1) | ||||
|                 return "Usage: findsim [Simulator Name]"; | ||||
| 
 | ||||
|             // Build the simulator name from the args list | ||||
|             string simName = string.Empty; | ||||
|             for (int i = 0; i < args.Length; i++) | ||||
|                 simName += args[i] + " "; | ||||
|             simName = simName.TrimEnd().ToLower(); | ||||
| 
 | ||||
|             //if (!GridDataCached[Client]) | ||||
|             //{ | ||||
|             //    Client.Grid.RequestAllSims(GridManager.MapLayerType.Objects); | ||||
|             //    System.Threading.Thread.Sleep(5000); | ||||
|             //    GridDataCached[Client] = true; | ||||
|             //} | ||||
| 
 | ||||
|             GridRegion region; | ||||
| 
 | ||||
|             if (Client.Grid.GetGridRegion(simName, out region)) | ||||
|                 return String.Format("{0}: handle={1} ({2},{3})", region.Name, region.RegionHandle, region.X, region.Y); | ||||
|             else | ||||
|                 return "Lookup of " + simName + " failed"; | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | @ -0,0 +1,62 @@ | |||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Threading; | ||||
| using libsecondlife; | ||||
| using libsecondlife.Utilities; | ||||
| 
 | ||||
| namespace libsecondlife.TestClient | ||||
| { | ||||
|     public class ParcelInfoCommand : Command | ||||
|     { | ||||
|         private ParcelDownloader ParcelDownloader; | ||||
|         private ManualResetEvent ParcelsDownloaded = new ManualResetEvent(false); | ||||
|         private int ParcelCount = 0; | ||||
| 
 | ||||
|         public ParcelInfoCommand(TestClient testClient) | ||||
| 		{ | ||||
| 			Name = "parcelinfo"; | ||||
| 			Description = "Prints out info about all the parcels in this simulator"; | ||||
| 
 | ||||
|             ParcelDownloader = new ParcelDownloader(testClient); | ||||
|             ParcelDownloader.OnParcelsDownloaded += new ParcelDownloader.ParcelsDownloadedCallback(Parcels_OnParcelsDownloaded); | ||||
|             testClient.Network.OnDisconnected += new NetworkManager.DisconnectedCallback(Network_OnDisconnected); | ||||
| 		} | ||||
| 
 | ||||
|         public override string Execute(string[] args, LLUUID fromAgentID) | ||||
|         { | ||||
|             ParcelDownloader.DownloadSimParcels(Client.Network.CurrentSim); | ||||
| 
 | ||||
|             ParcelsDownloaded.Reset(); | ||||
|             ParcelsDownloaded.WaitOne(20000, false); | ||||
| 
 | ||||
|             if (Client.Network.CurrentSim != null) | ||||
|                 return "Downloaded information for " + ParcelCount + " parcels in " + Client.Network.CurrentSim.Name; | ||||
|             else | ||||
|                 return String.Empty; | ||||
|         } | ||||
| 
 | ||||
|         void Parcels_OnParcelsDownloaded(Simulator simulator, Dictionary<int, Parcel> Parcels, int[,] map) | ||||
|         { | ||||
|             foreach (KeyValuePair<int, Parcel> parcel in Parcels) | ||||
|             { | ||||
|                 WaterType type = ParcelDownloader.GetWaterType(map, parcel.Value.LocalID); | ||||
|                 float delta = ParcelDownloader.GetHeightRange(map, parcel.Value.LocalID); | ||||
|                 int deviation = ParcelDownloader.GetRectangularDeviation(parcel.Value.AABBMin, parcel.Value.AABBMax,  | ||||
|                     parcel.Value.Area); | ||||
| 
 | ||||
|                 Console.WriteLine("Parcels[{0}]: Name: \"{1}\", Description: \"{2}\" ACL Count: {3}, " + | ||||
|                     "Location: {4}, Height Range: {5}, Shape Deviation: {6}", parcel.Key, parcel.Value.Name,  | ||||
|                     parcel.Value.Desc, parcel.Value.AccessList.Count, type.ToString(), delta, deviation); | ||||
|             } | ||||
| 
 | ||||
|             ParcelCount = Parcels.Count; | ||||
| 
 | ||||
|             ParcelsDownloaded.Set(); | ||||
|         } | ||||
| 
 | ||||
|         void Network_OnDisconnected(NetworkManager.DisconnectType reason, string message) | ||||
|         { | ||||
|             ParcelsDownloaded.Set(); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | @ -0,0 +1,90 @@ | |||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Text; | ||||
| using libsecondlife; | ||||
| using libsecondlife.Packets; | ||||
| 
 | ||||
| namespace libsecondlife.TestClient | ||||
| { | ||||
|     public class FollowCommand: Command | ||||
|     { | ||||
| 		public FollowCommand(TestClient testClient) | ||||
| 		{ | ||||
| 			Name = "follow"; | ||||
| 			Description = "Follow another avatar. (usage: follow [FirstName LastName])  If no target is set then will follow master."; | ||||
| 		} | ||||
| 
 | ||||
|         public override string Execute(string[] args, LLUUID fromAgentID) | ||||
| 		{ | ||||
| 			string target = String.Empty; | ||||
| 			for (int ct = 0; ct < args.Length; ct++) | ||||
| 				target = target + args[ct] + " "; | ||||
| 			target = target.TrimEnd(); | ||||
| 
 | ||||
|             if (target.Length > 0) | ||||
|             { | ||||
|                 if (Follow(target)) | ||||
|                     return "Following " + target; | ||||
|                 else | ||||
|                     return "Unable to follow " + target + ".  Client may not be able to see that avatar."; | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 if (Follow(Client.MasterKey)) | ||||
|                     return "Following " + Client.MasterKey; | ||||
|                 else | ||||
|                     return "No target specified and no master not found. usage: follow [FirstName LastName])"; | ||||
|             } | ||||
| 		} | ||||
| 
 | ||||
|         const float DISTANCE_BUFFER = 3.0f; | ||||
| 		Avatar followAvatar; | ||||
| 
 | ||||
|         bool Follow(string name) | ||||
|         { | ||||
|             foreach (Avatar av in Client.AvatarList.Values) | ||||
|             { | ||||
|                 if (av.Name == name) | ||||
| 				{ | ||||
| 					followAvatar = av; | ||||
| 					Active = true; | ||||
| 	                return true; | ||||
| 				} | ||||
|             } | ||||
|             return false; | ||||
|         } | ||||
| 
 | ||||
|         bool Follow(LLUUID id) | ||||
|         { | ||||
|             foreach (Avatar av in Client.AvatarList.Values) | ||||
|             { | ||||
|                 if (av.ID == id) | ||||
|                 { | ||||
|                     followAvatar = av; | ||||
|                     Active = true; | ||||
|                     return true; | ||||
|                 } | ||||
|             } | ||||
|             return false; | ||||
|         } | ||||
| 
 | ||||
| 		public override void Think() | ||||
| 		{ | ||||
|             if (Helpers.VecDist(followAvatar.Position, Client.Self.Position) > DISTANCE_BUFFER) | ||||
|             { | ||||
|                 //move toward target | ||||
|            		LLVector3 avPos = followAvatar.Position;  | ||||
| 				Client.Self.AutoPilot((ulong)avPos.X + (ulong)Client.regionX, (ulong)avPos.Y + (ulong)Client.regionY, avPos.Z); | ||||
| 			} | ||||
| 			//else | ||||
| 			//{ | ||||
| 			//    //stop at current position | ||||
| 			//    LLVector3 myPos = client.Self.Position; | ||||
| 			//    client.Self.AutoPilot((ulong)myPos.x, (ulong)myPos.y, myPos.Z); | ||||
| 			//} | ||||
| 
 | ||||
| 			base.Think(); | ||||
| 		} | ||||
| 
 | ||||
|     } | ||||
| } | ||||
|  | @ -0,0 +1,53 @@ | |||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Text; | ||||
| using libsecondlife; | ||||
| using libsecondlife.Packets; | ||||
| 
 | ||||
| namespace libsecondlife.TestClient | ||||
| { | ||||
|     public class GotoCommand: Command | ||||
|     { | ||||
|         public GotoCommand(TestClient testClient) | ||||
| 		{ | ||||
| 			Name = "goto"; | ||||
| 			Description = "Teleport to a location (e.g. \"goto Hooper/100/100/30\")"; | ||||
| 		} | ||||
| 
 | ||||
|         public override string Execute(string[] args, LLUUID fromAgentID) | ||||
| 		{ | ||||
| 			if (args.Length < 1) | ||||
|                 return "usage: Destination should be specified as sim/x/y/z"; | ||||
| 
 | ||||
|             string destination = String.Empty; | ||||
| 
 | ||||
|             // Handle multi-word sim names by combining the arguments | ||||
|             foreach (string arg in args) | ||||
|             { | ||||
|                 destination += arg + " "; | ||||
|             } | ||||
|             destination = destination.Trim(); | ||||
| 
 | ||||
|             string[] tokens = destination.Split(new char[] { '/' }); | ||||
|             if (tokens.Length != 4) | ||||
|                 return "usage: Destination should be specified as sim/x/y/z"; | ||||
| 
 | ||||
|             string sim = tokens[0]; | ||||
| 			float x = Client.Self.Position.X; | ||||
| 			float y = Client.Self.Position.Y; | ||||
| 			float z = Client.Self.Position.Z; | ||||
|             float.TryParse(tokens[1], out x); | ||||
|             float.TryParse(tokens[2], out y); | ||||
|             float.TryParse(tokens[3], out z); | ||||
| 
 | ||||
|             if (Client.Self.Teleport(sim, new LLVector3(x, y, z))) | ||||
|             { | ||||
|                 return "Teleported to " + Client.Network.CurrentSim; | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 return "Teleport failed: " + Client.Self.TeleportMessage; | ||||
|             } | ||||
| 		} | ||||
|     } | ||||
| } | ||||
|  | @ -0,0 +1,34 @@ | |||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Text; | ||||
| using libsecondlife; | ||||
| using libsecondlife.Packets; | ||||
| 
 | ||||
| namespace libsecondlife.TestClient | ||||
| { | ||||
|     public class JumpCommand: Command | ||||
|     { | ||||
|         public JumpCommand(TestClient testClient) | ||||
| 		{ | ||||
| 			Name = "jump"; | ||||
| 			Description = "Teleports to the specified height. (e.g. \"jump 1000\")"; | ||||
| 		} | ||||
| 
 | ||||
|         public override string Execute(string[] args, LLUUID fromAgentID) | ||||
| 		{ | ||||
| 			if (args.Length != 1) | ||||
|                 return "usage: jump 1000"; | ||||
| 
 | ||||
| 			float height = 0; | ||||
| 			float.TryParse(args[0], out height); | ||||
| 
 | ||||
| 			Client.Self.Teleport | ||||
| 			( | ||||
| 				Client.Network.CurrentSim.Name, | ||||
| 				new LLVector3(Client.Self.Position.X, Client.Self.Position.Y, Client.Self.Position.Z + height) | ||||
| 			); | ||||
| 
 | ||||
|             return "Jumped " + height; | ||||
| 		} | ||||
|     } | ||||
| } | ||||
|  | @ -0,0 +1,23 @@ | |||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Text; | ||||
| using libsecondlife; | ||||
| using libsecondlife.Packets; | ||||
| 
 | ||||
| namespace libsecondlife.TestClient | ||||
| { | ||||
|     public class LocationCommand: Command | ||||
|     { | ||||
|         public LocationCommand(TestClient testClient) | ||||
| 		{ | ||||
| 			Name = "location"; | ||||
| 			Description = "Show the location."; | ||||
| 		} | ||||
| 
 | ||||
| 		public override string Execute(string[] args, LLUUID fromAgentID) | ||||
| 		{ | ||||
|             return "CurrentSim: '" + Client.Network.CurrentSim.ToString() + "' Position: " +  | ||||
|                 Client.Self.Position.ToString(); | ||||
| 		} | ||||
|     } | ||||
| } | ||||
|  | @ -0,0 +1,24 @@ | |||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Text; | ||||
| 
 | ||||
| namespace libsecondlife.TestClient.Commands.Movement { | ||||
|     class MovetoCommand : Command { | ||||
|         public MovetoCommand(TestClient client) { | ||||
|             Name = "moveto"; | ||||
|             Description = "Moves the avatar to the specified global position using simulator autopilot."; | ||||
|         } | ||||
|         public override string Execute(string[] args, LLUUID fromAgentID) { | ||||
|             if (args.Length != 3) | ||||
|                 return "usage: moveto x y z"; | ||||
|             float x = Client.Self.Position.X + Client.regionX; | ||||
|             float y = Client.Self.Position.Y + Client.regionY; | ||||
|             float z = Client.Self.Position.Z; | ||||
|             float.TryParse(args[0], out x); | ||||
|             float.TryParse(args[1], out y); | ||||
|             float.TryParse(args[2], out z); | ||||
|             Client.Self.AutoPilot((ulong)x, (ulong)y, z); | ||||
|             return "Attempting to move to <" + x + ", " + y + ", " + z + ">"; | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | @ -0,0 +1,23 @@ | |||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Text; | ||||
| using libsecondlife; | ||||
| using libsecondlife.Packets; | ||||
| 
 | ||||
| namespace libsecondlife.TestClient | ||||
| { | ||||
|     public class SetHomeCommand : Command | ||||
|     { | ||||
| 		public SetHomeCommand(TestClient testClient) | ||||
|         { | ||||
|             Name = "sethome"; | ||||
|             Description = "Sets home to the current location."; | ||||
|         } | ||||
| 
 | ||||
|         public override string Execute(string[] args, LLUUID fromAgentID) | ||||
|         { | ||||
| 			Client.Self.SetHome(); | ||||
|             return "Home Set"; | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | @ -0,0 +1,52 @@ | |||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Text; | ||||
| using libsecondlife; | ||||
| using libsecondlife.Packets; | ||||
| 
 | ||||
| namespace libsecondlife.TestClient | ||||
| { | ||||
|     public class SitCommand: Command | ||||
|     { | ||||
|         public SitCommand(TestClient testClient) | ||||
| 		{ | ||||
| 			Name = "sit"; | ||||
| 			Description = "Attempt to sit on the closest prim"; | ||||
| 		} | ||||
| 			 | ||||
|         public override string Execute(string[] args, LLUUID fromAgentID) | ||||
| 		{ | ||||
|             Primitive closest = null; | ||||
| 		    double closestDistance = Double.MaxValue; | ||||
| 
 | ||||
| 		    lock (Client.SimPrims) | ||||
| 		    { | ||||
|                 if (Client.SimPrims.ContainsKey(Client.Network.CurrentSim)) | ||||
|                 { | ||||
|                     foreach (Primitive p in Client.SimPrims[Client.Network.CurrentSim].Values) | ||||
|                     { | ||||
|                         float distance = Helpers.VecDist(Client.Self.Position, p.Position); | ||||
| 
 | ||||
|                         if (closest == null || distance < closestDistance) | ||||
|                         { | ||||
|                             closest = p; | ||||
|                             closestDistance = distance; | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
| 		    } | ||||
| 
 | ||||
|             if (closest != null) | ||||
|             { | ||||
|                 Client.Self.RequestSit(closest.ID, LLVector3.Zero); | ||||
|                 Client.Self.Sit(); | ||||
| 
 | ||||
|                 return "Sat on " + closest.ID + ". Distance: " + closestDistance; | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 return "Couldn't find a nearby prim to sit on"; | ||||
|             } | ||||
| 		} | ||||
|     } | ||||
| } | ||||
|  | @ -0,0 +1,54 @@ | |||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Text; | ||||
| using libsecondlife; | ||||
| using libsecondlife.Packets; | ||||
| 
 | ||||
| namespace libsecondlife.TestClient | ||||
| { | ||||
|     public class SitOnCommand: Command | ||||
|     { | ||||
|         public SitOnCommand(TestClient testClient) | ||||
| 		{ | ||||
| 			Name = "siton"; | ||||
| 			Description = "Attempt to sit on a particular prim, with specified UUID"; | ||||
| 		} | ||||
| 			 | ||||
|         public override string Execute(string[] args, LLUUID fromAgentID) | ||||
| 		{ | ||||
| 		    LLObject targetSeat = null; | ||||
| 
 | ||||
| 		    lock (Client.SimPrims) | ||||
| 		    { | ||||
|                 if (Client.SimPrims.ContainsKey(Client.Network.CurrentSim)) | ||||
|                 { | ||||
|                     foreach (LLObject p in Client.SimPrims[Client.Network.CurrentSim].Values) | ||||
|                    { | ||||
|                        try | ||||
|                        { | ||||
|                            if (p.ID == args[0]) | ||||
|                                targetSeat = p; | ||||
|                        } | ||||
|                        catch | ||||
|                        { | ||||
|                            // handle exception | ||||
|                            return "Sorry, I don't think " + args[0] + " is a valid UUID.  I'm unable to sit there."; | ||||
|                        } | ||||
|                    } | ||||
|                 } | ||||
| 		    } | ||||
| 
 | ||||
|             if (targetSeat != null) | ||||
|             { | ||||
|                 Client.Self.RequestSit(targetSeat.ID, LLVector3.Zero); | ||||
|                 Client.Self.Sit(); | ||||
| 
 | ||||
|                 return "Sat on prim " + targetSeat.ID + "."; | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 return "Couldn't find specified prim to sit on"; | ||||
|             } | ||||
| 		} | ||||
|     } | ||||
| } | ||||
|  | @ -0,0 +1,47 @@ | |||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Text; | ||||
| using libsecondlife; | ||||
| using libsecondlife.Packets; | ||||
| 
 | ||||
| namespace libsecondlife.TestClient | ||||
| { | ||||
|     public class StandCommand: Command | ||||
|     { | ||||
|         public StandCommand(TestClient testClient) | ||||
| 	{ | ||||
| 		Name = "stand"; | ||||
| 		Description = "Stand"; | ||||
| 	} | ||||
| 	 | ||||
|         public override string Execute(string[] args, LLUUID fromAgentID) | ||||
| 	{ | ||||
| 		Client.Self.Status.StandUp = true; | ||||
| 		stand(Client); | ||||
| 		return "Standing up.";   | ||||
| 	} | ||||
| 
 | ||||
|         void stand(SecondLife client) | ||||
|         { | ||||
|             SendAgentUpdate(client, (uint)MainAvatar.ControlFlags.AGENT_CONTROL_STAND_UP); | ||||
|         } | ||||
| 
 | ||||
|         const float DRAW_DISTANCE = 96.0f; | ||||
|         void SendAgentUpdate(SecondLife client, uint ControlID) | ||||
|         { | ||||
|             AgentUpdatePacket p = new AgentUpdatePacket(); | ||||
|             p.AgentData.Far = DRAW_DISTANCE; | ||||
|             //LLVector3 myPos = client.Self.Position; | ||||
|             p.AgentData.CameraCenter = new LLVector3(0, 0, 0); | ||||
|             p.AgentData.CameraAtAxis = new LLVector3(0, 0, 0); | ||||
|             p.AgentData.CameraLeftAxis = new LLVector3(0, 0, 0); | ||||
|             p.AgentData.CameraUpAxis = new LLVector3(0, 0, 0); | ||||
|             p.AgentData.HeadRotation = new LLQuaternion(0, 0, 0, 1); ; | ||||
|             p.AgentData.BodyRotation = new LLQuaternion(0, 0, 0, 1); ; | ||||
|             p.AgentData.AgentID = client.Network.AgentID; | ||||
|             p.AgentData.SessionID = client.Network.SessionID; | ||||
|             p.AgentData.ControlFlags = ControlID; | ||||
|             client.Network.SendPacket(p); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | @ -0,0 +1,209 @@ | |||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.IO; | ||||
| using System.Xml; | ||||
| using System.Text; | ||||
| using System.Threading; | ||||
| using libsecondlife; | ||||
| using libsecondlife.Packets; | ||||
| 
 | ||||
| namespace libsecondlife.TestClient | ||||
| { | ||||
|     public class ExportCommand : Command | ||||
|     { | ||||
|         AutoResetEvent GotPermissionsEvent = new AutoResetEvent(false); | ||||
|         LLObject.ObjectPropertiesFamily Properties; | ||||
|         bool GotPermissions = false; | ||||
|         LLUUID SelectedObject = LLUUID.Zero; | ||||
| 
 | ||||
|         Dictionary<LLUUID, Primitive> PrimsWaiting = new Dictionary<LLUUID, Primitive>(); | ||||
|         AutoResetEvent AllPropertiesReceived = new AutoResetEvent(false); | ||||
| 
 | ||||
|         public ExportCommand(TestClient 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 && !(args.Length == 1 && SelectedObject != LLUUID.Zero)) | ||||
|                 return "Usage: export uuid outputfile.xml"; | ||||
| 
 | ||||
|             LLUUID id; | ||||
|             uint localid = 0; | ||||
|             int count = 0; | ||||
|             string file; | ||||
| 
 | ||||
|             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) | ||||
|             { | ||||
|                 if (Client.SimPrims.ContainsKey(Client.Network.CurrentSim)) | ||||
|                 { | ||||
|                     foreach (Primitive prim in Client.SimPrims[Client.Network.CurrentSim].Values) | ||||
|                     { | ||||
|                         if (prim.ID == id) | ||||
|                         { | ||||
|                             if (prim.ParentID != 0) | ||||
|                                 localid = prim.ParentID; | ||||
|                             else | ||||
|                                 localid = prim.LocalID; | ||||
| 
 | ||||
|                             break; | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|              | ||||
|             if (localid != 0) | ||||
|             { | ||||
|                 // Check for export permission first | ||||
|                 Client.Objects.RequestObjectPropertiesFamily(Client.Network.CurrentSim, id); | ||||
|                 GotPermissionsEvent.WaitOne(8000, false); | ||||
| 
 | ||||
|                 if (!GotPermissions) | ||||
|                 { | ||||
|                     return "Couldn't fetch permissions for the requested object, try again"; | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     GotPermissions = false; | ||||
|                     if (Properties.OwnerID != Client.Network.AgentID &&  | ||||
|                         Properties.OwnerID != Client.MasterKey &&  | ||||
|                         Client.Network.AgentID != Client.Self.ID) | ||||
|                     { | ||||
|                         return "That object is owned by " + Properties.OwnerID + ", we don't have permission " + | ||||
|                             "to export it"; | ||||
|                     } | ||||
|                 } | ||||
| 
 | ||||
|                 try | ||||
|                 { | ||||
| 					XmlWriterSettings settings = new XmlWriterSettings(); | ||||
| 					settings.Indent = true; | ||||
|                     XmlWriter writer = XmlWriter.Create(file, settings); | ||||
| 
 | ||||
| 					try | ||||
| 					{ | ||||
|                         List<Primitive> prims = new List<Primitive>(); | ||||
| 
 | ||||
| 						lock (Client.SimPrims) | ||||
| 						{ | ||||
| 							if (Client.SimPrims.ContainsKey(Client.Network.CurrentSim)) | ||||
| 							{ | ||||
|                                 foreach (Primitive prim in Client.SimPrims[Client.Network.CurrentSim].Values) | ||||
| 								{ | ||||
| 									if (prim.LocalID == localid || prim.ParentID == localid) | ||||
| 									{ | ||||
| 										prims.Add(prim); | ||||
| 										count++; | ||||
| 									} | ||||
| 								} | ||||
| 							} | ||||
| 						} | ||||
| 
 | ||||
|                         bool complete = RequestObjectProperties(prims, 250); | ||||
| 						 | ||||
|                         //Serialize it! | ||||
| 						Helpers.PrimListToXml(prims, writer); | ||||
| 
 | ||||
|                         if (!complete) { | ||||
|                             Console.WriteLine("Warning: Unable to retrieve full properties for:"); | ||||
|                             foreach (LLUUID uuid in PrimsWaiting.Keys) | ||||
|                                 Console.WriteLine(uuid); | ||||
|                         } | ||||
| 					} | ||||
| 					finally | ||||
| 					{ | ||||
| 						writer.Close(); | ||||
| 					} | ||||
|                 } | ||||
|                 catch (Exception e) | ||||
|                 { | ||||
|                     string ret = "Failed to write to " + file + ":" + e.ToString(); | ||||
|                     if (ret.Length > 1000) | ||||
|                     { | ||||
|                         ret = ret.Remove(1000); | ||||
|                     } | ||||
|                     return ret; | ||||
|                 } | ||||
|                 return "Exported " + count + " prims to " + file; | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 return "Couldn't find UUID " + id.ToString() + " in the " +  | ||||
|                     Client.SimPrims[Client.Network.CurrentSim].Count +  | ||||
|                     "objects currently indexed in the current simulator"; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         private bool RequestObjectProperties(List<Primitive> objects, int msPerRequest) | ||||
|         { | ||||
|             // Create an array of the local IDs of all the prims we are requesting properties for | ||||
|             uint[] localids = new uint[objects.Count]; | ||||
|              | ||||
|             lock (PrimsWaiting) | ||||
|             { | ||||
|                 PrimsWaiting.Clear(); | ||||
| 
 | ||||
|                 for (int i = 0; i < objects.Count; ++i) | ||||
|                 { | ||||
|                     localids[i] = objects[i].LocalID; | ||||
|                     PrimsWaiting.Add(objects[i].ID, objects[i]); | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             Client.Objects.SelectObjects(Client.Network.CurrentSim, localids); | ||||
| 
 | ||||
|             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; | ||||
|             GotPermissions = true; | ||||
|             GotPermissionsEvent.Set(); | ||||
|         } | ||||
| 
 | ||||
|         void Objects_OnObjectProperties(Simulator simulator, LLObject.ObjectProperties properties) | ||||
|         { | ||||
|             lock (PrimsWaiting) | ||||
|             { | ||||
|                 Primitive prim; | ||||
|                 if (PrimsWaiting.TryGetValue(properties.ObjectID, out prim)) | ||||
|                 { | ||||
|                     prim.Properties = properties; | ||||
|                 } | ||||
|                 PrimsWaiting.Remove(properties.ObjectID); | ||||
| 
 | ||||
|                 if (PrimsWaiting.Count == 0) | ||||
|                     AllPropertiesReceived.Set(); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | @ -0,0 +1,119 @@ | |||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.IO; | ||||
| using System.Text; | ||||
| using libsecondlife; | ||||
| 
 | ||||
| namespace libsecondlife.TestClient | ||||
| { | ||||
|     public class ExportParticlesCommand : Command | ||||
|     { | ||||
|         public ExportParticlesCommand(TestClient testClient) | ||||
|         { | ||||
|             Name = "exportparticles"; | ||||
|             Description = "Reverse engineers a prim with a particle system to an LSL script. Usage: exportscript [prim-uuid]"; | ||||
|         } | ||||
| 
 | ||||
|         public override string Execute(string[] args, LLUUID fromAgentID) | ||||
|         { | ||||
|             if (args.Length != 1) | ||||
|                 return "Usage: exportparticles [prim-uuid]"; | ||||
| 
 | ||||
|             LLUUID id; | ||||
|             if (!LLUUID.TryParse(args[0], out id)) | ||||
|                 return "Usage: exportparticles [prim-uuid]"; | ||||
| 
 | ||||
|             lock (Client.SimPrims) | ||||
|             { | ||||
|                 if (Client.SimPrims.ContainsKey(Client.Network.CurrentSim)) | ||||
|                 { | ||||
|                     foreach (Primitive prim in Client.SimPrims[Client.Network.CurrentSim].Values) | ||||
|                     { | ||||
|                         if (prim.ID == id) | ||||
|                         { | ||||
|                             if (prim.ParticleSys.CRC != 0) | ||||
|                             { | ||||
|                                 StringBuilder lsl = new StringBuilder(); | ||||
| 
 | ||||
|                                 lsl.Append("default" + Environment.NewLine); | ||||
|                                 lsl.Append("{" + Environment.NewLine); | ||||
|                                 lsl.Append("    state_entry()" + Environment.NewLine); | ||||
|                                 lsl.Append("    {" + Environment.NewLine); | ||||
|                                 lsl.Append("         llParticleSystem([" + Environment.NewLine); | ||||
| 
 | ||||
|                                 lsl.Append("         PSYS_PART_FLAGS, 0"); | ||||
| 
 | ||||
|                                 if ((prim.ParticleSys.PartDataFlags & Primitive.ParticleSystem.ParticleDataFlags.InterpColor) != 0) | ||||
|                                     lsl.Append(" | PSYS_PART_INTERP_COLOR_MASK"); | ||||
|                                 if ((prim.ParticleSys.PartDataFlags & Primitive.ParticleSystem.ParticleDataFlags.InterpScale) != 0) | ||||
|                                     lsl.Append(" | PSYS_PART_INTERP_SCALE_MASK"); | ||||
|                                 if ((prim.ParticleSys.PartDataFlags & Primitive.ParticleSystem.ParticleDataFlags.Bounce) != 0) | ||||
|                                     lsl.Append(" | PSYS_PART_BOUNCE_MASK"); | ||||
|                                 if ((prim.ParticleSys.PartDataFlags & Primitive.ParticleSystem.ParticleDataFlags.Wind) != 0) | ||||
|                                     lsl.Append(" | PSYS_PART_WIND_MASK"); | ||||
|                                 if ((prim.ParticleSys.PartDataFlags & Primitive.ParticleSystem.ParticleDataFlags.FollowSrc) != 0) | ||||
|                                     lsl.Append(" | PSYS_PART_FOLLOW_SRC_MASK"); | ||||
|                                 if ((prim.ParticleSys.PartDataFlags & Primitive.ParticleSystem.ParticleDataFlags.FollowVelocity) != 0) | ||||
|                                     lsl.Append(" | PSYS_PART_FOLLOW_VELOCITY_MASK"); | ||||
|                                 if ((prim.ParticleSys.PartDataFlags & Primitive.ParticleSystem.ParticleDataFlags.TargetPos) != 0) | ||||
|                                     lsl.Append(" | PSYS_PART_TARGET_POS_MASK"); | ||||
|                                 if ((prim.ParticleSys.PartDataFlags & Primitive.ParticleSystem.ParticleDataFlags.TargetLinear) != 0) | ||||
|                                     lsl.Append(" | PSYS_PART_TARGET_LINEAR_MASK"); | ||||
|                                 if ((prim.ParticleSys.PartDataFlags & Primitive.ParticleSystem.ParticleDataFlags.Emissive) != 0) | ||||
|                                     lsl.Append(" | PSYS_PART_EMISSIVE_MASK"); | ||||
| 
 | ||||
|                                 lsl.Append(","); lsl.Append(Environment.NewLine); | ||||
|                                 lsl.Append("         PSYS_SRC_PATTERN, 0"); | ||||
| 
 | ||||
|                                 if ((prim.ParticleSys.Pattern & Primitive.ParticleSystem.SourcePattern.Drop) != 0) | ||||
|                                     lsl.Append(" | PSYS_SRC_PATTERN_DROP"); | ||||
|                                 if ((prim.ParticleSys.Pattern & Primitive.ParticleSystem.SourcePattern.Explode) != 0) | ||||
|                                     lsl.Append(" | PSYS_SRC_PATTERN_EXPLODE"); | ||||
|                                 if ((prim.ParticleSys.Pattern & Primitive.ParticleSystem.SourcePattern.Angle) != 0) | ||||
|                                     lsl.Append(" | PSYS_SRC_PATTERN_ANGLE"); | ||||
|                                 if ((prim.ParticleSys.Pattern & Primitive.ParticleSystem.SourcePattern.AngleCone) != 0) | ||||
|                                     lsl.Append(" | PSYS_SRC_PATTERN_ANGLE_CONE"); | ||||
|                                 if ((prim.ParticleSys.Pattern & Primitive.ParticleSystem.SourcePattern.AngleConeEmpty) != 0) | ||||
|                                     lsl.Append(" | PSYS_SRC_PATTERN_ANGLE_CONE_EMPTY"); | ||||
| 
 | ||||
|                                 lsl.Append("," + Environment.NewLine); | ||||
| 
 | ||||
|                                 lsl.Append("         PSYS_PART_START_ALPHA, " + String.Format("{0:0.00000}", prim.ParticleSys.PartStartColor.A) + "," + Environment.NewLine); | ||||
|                                 lsl.Append("         PSYS_PART_END_ALPHA, " + String.Format("{0:0.00000}", prim.ParticleSys.PartEndColor.A) + "," + Environment.NewLine); | ||||
|                                 lsl.Append("         PSYS_PART_START_COLOR, " + prim.ParticleSys.PartStartColor.ToStringRGB() + "," + Environment.NewLine); | ||||
|                                 lsl.Append("         PSYS_PART_END_COLOR, " + prim.ParticleSys.PartEndColor.ToStringRGB() + "," + Environment.NewLine); | ||||
|                                 lsl.Append("         PSYS_PART_START_SCALE, <" + String.Format("{0:0.00000}", prim.ParticleSys.PartStartScaleX) + ", " + String.Format("{0:0.00000}", prim.ParticleSys.PartStartScaleY) + ", 0>, " + Environment.NewLine); | ||||
|                                 lsl.Append("         PSYS_PART_END_SCALE, <" + String.Format("{0:0.00000}", prim.ParticleSys.PartEndScaleX) + ", " + String.Format("{0:0.00000}", prim.ParticleSys.PartEndScaleY) + ", 0>, " + Environment.NewLine); | ||||
|                                 lsl.Append("         PSYS_PART_MAX_AGE, " + String.Format("{0:0.00000}", prim.ParticleSys.PartMaxAge) + "," + Environment.NewLine); | ||||
|                                 lsl.Append("         PSYS_SRC_MAX_AGE, " + String.Format("{0:0.00000}", prim.ParticleSys.MaxAge) + "," + Environment.NewLine); | ||||
|                                 lsl.Append("         PSYS_SRC_ACCEL, " + prim.ParticleSys.PartAcceleration.ToString() + "," + Environment.NewLine); | ||||
|                                 lsl.Append("         PSYS_SRC_BURST_PART_COUNT, " + String.Format("{0:0}", prim.ParticleSys.BurstPartCount) + "," + Environment.NewLine); | ||||
|                                 lsl.Append("         PSYS_SRC_BURST_RADIUS, " + String.Format("{0:0.00000}", prim.ParticleSys.BurstRadius) + "," + Environment.NewLine); | ||||
|                                 lsl.Append("         PSYS_SRC_BURST_RATE, " + String.Format("{0:0.00000}", prim.ParticleSys.BurstRate) + "," + Environment.NewLine); | ||||
|                                 lsl.Append("         PSYS_SRC_BURST_SPEED_MIN, " + String.Format("{0:0.00000}", prim.ParticleSys.BurstSpeedMin) + "," + Environment.NewLine); | ||||
|                                 lsl.Append("         PSYS_SRC_BURST_SPEED_MAX, " + String.Format("{0:0.00000}", prim.ParticleSys.BurstSpeedMax) + "," + Environment.NewLine); | ||||
|                                 lsl.Append("         PSYS_SRC_INNERANGLE, " + String.Format("{0:0.00000}", prim.ParticleSys.InnerAngle) + "," + Environment.NewLine); | ||||
|                                 lsl.Append("         PSYS_SRC_OUTERANGLE, " + String.Format("{0:0.00000}", prim.ParticleSys.OuterAngle) + "," + Environment.NewLine); | ||||
|                                 lsl.Append("         PSYS_SRC_OMEGA, " + prim.ParticleSys.AngularVelocity.ToString() + "," + Environment.NewLine); | ||||
|                                 lsl.Append("         PSYS_SRC_TEXTURE, (key)\"" + prim.ParticleSys.Texture.ToStringHyphenated() + "\"," + Environment.NewLine); | ||||
|                                 lsl.Append("         PSYS_SRC_TARGET_KEY, (key)\"" + prim.ParticleSys.Target.ToStringHyphenated() + "\"" + Environment.NewLine); | ||||
|                                  | ||||
|                                 lsl.Append("         ]);" + Environment.NewLine); | ||||
|                                 lsl.Append("    }" + Environment.NewLine); | ||||
|                                 lsl.Append("}" + Environment.NewLine); | ||||
| 
 | ||||
|                                 return lsl.ToString(); | ||||
|                             } | ||||
|                             else | ||||
|                             { | ||||
|                                 return "Prim " + prim.LocalID + " does not have a particle system"; | ||||
|                             } | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             return "Couldn't find prim " + id.ToStringHyphenated(); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | @ -0,0 +1,246 @@ | |||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Xml; | ||||
| using System.Xml.Serialization; | ||||
| using System.Threading; | ||||
| using System.IO; | ||||
| using libsecondlife; | ||||
| 
 | ||||
| namespace libsecondlife.TestClient | ||||
| { | ||||
|     enum ImporterState | ||||
|     { | ||||
|         RezzingParent, | ||||
|         RezzingChildren, | ||||
|         Linking, | ||||
|         Idle | ||||
|     } | ||||
| 
 | ||||
|     public class Linkset | ||||
|     { | ||||
|         public Primitive RootPrim; | ||||
|         public List<Primitive> Children = new List<Primitive>(); | ||||
| 
 | ||||
|         public Linkset() | ||||
|         { | ||||
|             RootPrim = new Primitive(); | ||||
|         } | ||||
| 
 | ||||
|         public Linkset(Primitive rootPrim) | ||||
|         { | ||||
|             RootPrim = rootPrim; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     public class ImportCommand : Command | ||||
|     { | ||||
|         Primitive currentPrim; | ||||
|         LLVector3 currentPosition; | ||||
|         SecondLife currentClient; | ||||
|         AutoResetEvent primDone; | ||||
|         List<Primitive> primsCreated; | ||||
|         List<uint> linkQueue; | ||||
|         uint rootLocalID = 0; | ||||
|         bool registeredCreateEvent = false; | ||||
| 
 | ||||
|         ImporterState state = ImporterState.Idle; | ||||
| 
 | ||||
|         public ImportCommand(TestClient testClient) | ||||
|         { | ||||
|             Name = "import"; | ||||
|             Description = "Import prims from an exported xml file. Usage: import inputfile.xml"; | ||||
|             primDone = new AutoResetEvent(false); | ||||
|             registeredCreateEvent = false; | ||||
|         } | ||||
| 
 | ||||
|         public override string Execute(string[] args, LLUUID fromAgentID) | ||||
|         { | ||||
|             if (args.Length != 1) | ||||
|                 return "Usage: import inputfile.xml"; | ||||
| 
 | ||||
|             string filename = args[0]; | ||||
|             Dictionary<uint, Primitive> prims; | ||||
| 
 | ||||
|             currentClient = Client; | ||||
| 
 | ||||
|             try | ||||
|             { | ||||
|                 XmlReader reader = XmlReader.Create(filename); | ||||
|                 List<Primitive> listprims = Helpers.PrimListFromXml(reader); | ||||
|                 reader.Close(); | ||||
| 
 | ||||
|                 // Create a dictionary indexed by the old local ID of the prims | ||||
|                 prims = new Dictionary<uint, Primitive>(); | ||||
|                 foreach (Primitive prim in listprims) | ||||
|                 { | ||||
|                     prims.Add(prim.LocalID, prim); | ||||
|                 } | ||||
|             } | ||||
|             catch (Exception) | ||||
|             { | ||||
|                 return "Failed to import the object XML file, maybe it doesn't exist or is in the wrong format?"; | ||||
|             } | ||||
| 
 | ||||
|             if (!registeredCreateEvent) | ||||
|             { | ||||
|                 Client.OnPrimCreated += new TestClient.PrimCreatedCallback(TestClient_OnPrimCreated); | ||||
|                 registeredCreateEvent = true; | ||||
|             } | ||||
| 
 | ||||
|             // Build an organized structure from the imported prims | ||||
|             Dictionary<uint, Linkset> linksets = new Dictionary<uint, Linkset>(); | ||||
|             foreach (Primitive prim in prims.Values) | ||||
|             { | ||||
|                 if (prim.ParentID == 0) | ||||
|                 { | ||||
|                     if (linksets.ContainsKey(prim.LocalID)) | ||||
|                         linksets[prim.LocalID].RootPrim = prim; | ||||
|                     else | ||||
|                         linksets[prim.LocalID] = new Linkset(prim); | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     if (!linksets.ContainsKey(prim.ParentID)) | ||||
|                         linksets[prim.ParentID] = new Linkset(); | ||||
| 
 | ||||
|                     linksets[prim.ParentID].Children.Add(prim); | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             primsCreated = new List<Primitive>(); | ||||
|             Console.WriteLine("Importing " + linksets.Count + " structures."); | ||||
| 
 | ||||
|             foreach (Linkset linkset in linksets.Values) | ||||
|             { | ||||
|                 if (linkset.RootPrim.LocalID != 0) | ||||
|                 { | ||||
|                     state = ImporterState.RezzingParent; | ||||
|                     currentPrim = linkset.RootPrim; | ||||
|                     // HACK: Offset the root prim position so it's not lying on top of the original | ||||
|                     // We need a more elaborate solution for importing with relative or absolute offsets | ||||
|                     linkset.RootPrim.Position = Client.Self.Position; | ||||
|                     linkset.RootPrim.Position.Z += 3.0f; | ||||
|                     currentPosition = linkset.RootPrim.Position; | ||||
|                     // A better solution would move the bot to the desired position. | ||||
|                     // or to check if we are within a certain distance of the desired position. | ||||
| 
 | ||||
|                     // Rez the root prim with no rotation | ||||
|                     LLQuaternion rootRotation = linkset.RootPrim.Rotation; | ||||
|                     linkset.RootPrim.Rotation = LLQuaternion.Identity; | ||||
| 
 | ||||
|                     Client.Objects.AddPrim(Client.Network.CurrentSim, linkset.RootPrim.Data, LLUUID.Zero, | ||||
|                         linkset.RootPrim.Position, linkset.RootPrim.Scale, linkset.RootPrim.Rotation); | ||||
| 
 | ||||
|                     if (!primDone.WaitOne(10000, false)) | ||||
|                         return "Rez failed, timed out while creating the root prim."; | ||||
| 
 | ||||
|                     state = ImporterState.RezzingChildren; | ||||
| 
 | ||||
|                     // Rez the child prims | ||||
|                     foreach (Primitive prim in linkset.Children) | ||||
|                     { | ||||
|                         currentPrim = prim; | ||||
|                         currentPosition = prim.Position + linkset.RootPrim.Position; | ||||
| 
 | ||||
|                         Client.Objects.AddPrim(Client.Network.CurrentSim, prim.Data, LLUUID.Zero, currentPosition, | ||||
|                             prim.Scale, prim.Rotation); | ||||
| 
 | ||||
|                         if (!primDone.WaitOne(10000, false)) | ||||
|                             return "Rez failed, timed out while creating child prim."; | ||||
|                     } | ||||
| 
 | ||||
|                     if (linkset.Children.Count != 0) | ||||
|                     { | ||||
|                         // Create a list of the local IDs of the newly created prims | ||||
|                         List<uint> primIDs = new List<uint>(primsCreated.Count); | ||||
|                         primIDs.Add(rootLocalID); // Root prim is first in list. | ||||
|                         foreach (Primitive prim in primsCreated) | ||||
|                         { | ||||
|                             if (prim.LocalID != rootLocalID) | ||||
|                                 primIDs.Add(prim.LocalID); | ||||
|                         } | ||||
|                         linkQueue = new List<uint>(primIDs.Count); | ||||
|                         linkQueue.AddRange(primIDs); | ||||
| 
 | ||||
|                         // Link and set the permissions + rotation | ||||
|                         state = ImporterState.Linking; | ||||
|                         Client.Objects.LinkPrims(Client.Network.CurrentSim, linkQueue); | ||||
|                         if (primDone.WaitOne(100000 * linkset.Children.Count, false)) | ||||
|                         { | ||||
|                             Client.Objects.SetPermissions(Client.Network.CurrentSim, primIDs, | ||||
|                                 Helpers.PermissionWho.Everyone | Helpers.PermissionWho.Group | Helpers.PermissionWho.NextOwner, | ||||
|                                 Helpers.PermissionType.Copy | Helpers.PermissionType.Modify | Helpers.PermissionType.Move | | ||||
|                                 Helpers.PermissionType.Transfer, true); | ||||
| 
 | ||||
|                             Client.Objects.SetRotation(Client.Network.CurrentSim, rootLocalID, rootRotation); | ||||
|                         } | ||||
|                         else | ||||
|                         { | ||||
|                             Console.WriteLine("Warning: Failed to link {0} prims", linkQueue.Count); | ||||
|                         } | ||||
|                     } | ||||
|                     else | ||||
|                     { | ||||
|                         Client.Objects.SetRotation(Client.Network.CurrentSim, rootLocalID, rootRotation); | ||||
|                     } | ||||
|                     state = ImporterState.Idle; | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     // Skip linksets with a missing root prim | ||||
|                     Console.WriteLine("WARNING: Skipping a linkset with a missing root prim"); | ||||
|                 } | ||||
| 
 | ||||
|                 // Reset everything for the next linkset | ||||
|                 primsCreated.Clear(); | ||||
|             } | ||||
| 
 | ||||
|             return "Import complete."; | ||||
|         } | ||||
| 
 | ||||
|         void TestClient_OnPrimCreated(Simulator simulator, Primitive prim) | ||||
|         { | ||||
|             if ((prim.Flags & LLObject.ObjectFlags.CreateSelected) == 0) | ||||
|                 return; // We received an update for an object we didn't create | ||||
| 
 | ||||
|             switch (state) | ||||
|             { | ||||
|                 case ImporterState.RezzingParent: | ||||
|                     rootLocalID = prim.LocalID; | ||||
|                     goto case ImporterState.RezzingChildren; | ||||
|                 case ImporterState.RezzingChildren: | ||||
|                     if (!primsCreated.Contains(prim)) | ||||
|                     { | ||||
|                         Console.WriteLine("Setting properties for " + prim.LocalID); | ||||
|                         // TODO: Is there a way to set all of this at once, and update more ObjectProperties stuff? | ||||
|                         currentClient.Objects.SetPosition(simulator, prim.LocalID, currentPosition); | ||||
|                         currentClient.Objects.SetTextures(simulator, prim.LocalID, currentPrim.Textures); | ||||
|                         currentClient.Objects.SetLight(simulator, prim.LocalID, currentPrim.Light); | ||||
|                         currentClient.Objects.SetFlexible(simulator, prim.LocalID, currentPrim.Flexible); | ||||
| 
 | ||||
|                         if (!String.IsNullOrEmpty(currentPrim.Properties.Name)) | ||||
|                             currentClient.Objects.SetName(simulator, prim.LocalID, currentPrim.Properties.Name); | ||||
|                         if (!String.IsNullOrEmpty(currentPrim.Properties.Description)) | ||||
|                             currentClient.Objects.SetDescription(simulator, prim.LocalID,  | ||||
|                                 currentPrim.Properties.Description); | ||||
| 
 | ||||
|                         primsCreated.Add(prim); | ||||
|                         primDone.Set(); | ||||
|                     } | ||||
|                     break; | ||||
|                 case ImporterState.Linking: | ||||
|                     lock (linkQueue) | ||||
|                     { | ||||
|                         int index = linkQueue.IndexOf(prim.LocalID); | ||||
|                         if (index != -1) | ||||
|                         { | ||||
|                             linkQueue.RemoveAt(index); | ||||
|                             if (linkQueue.Count == 0) | ||||
|                                 primDone.Set(); | ||||
|                         } | ||||
|                     } | ||||
|                     break; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | @ -0,0 +1,32 @@ | |||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Text; | ||||
| using libsecondlife; | ||||
| using libsecondlife.Packets; | ||||
| 
 | ||||
| namespace libsecondlife.TestClient | ||||
| { | ||||
|     public class PrimCountCommand: Command | ||||
|     { | ||||
|         public PrimCountCommand(TestClient testClient) | ||||
| 		{ | ||||
| 			Name = "primcount"; | ||||
| 			Description = "Shows the number of prims that have been received."; | ||||
| 		} | ||||
| 
 | ||||
|         public override string Execute(string[] args, LLUUID fromAgentID) | ||||
| 		{ | ||||
|             int count = 0; | ||||
| 
 | ||||
|             lock (Client.SimPrims) | ||||
|             { | ||||
|                 foreach (Dictionary<uint, Primitive> prims in Client.SimPrims.Values) | ||||
|                 { | ||||
|                     count += prims.Count; | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
| 			return count.ToString(); | ||||
| 		} | ||||
|     } | ||||
| } | ||||
|  | @ -0,0 +1,22 @@ | |||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Text; | ||||
| using libsecondlife; | ||||
| using libsecondlife.Packets; | ||||
| 
 | ||||
| namespace libsecondlife.TestClient | ||||
| { | ||||
|     public class DilationCommand : Command | ||||
|     { | ||||
| 		public DilationCommand(TestClient testClient) | ||||
|         { | ||||
|             Name = "dilation"; | ||||
|             Description = "Shows time dilation for current sim."; | ||||
|         } | ||||
| 
 | ||||
|         public override string Execute(string[] args, LLUUID fromAgentID) | ||||
|         { | ||||
|             return "Dilation is " + Client.Network.CurrentSim.Dilation.ToString(); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | @ -0,0 +1,45 @@ | |||
| using System; | ||||
| using System.Text; | ||||
| using libsecondlife; | ||||
| 
 | ||||
| namespace libsecondlife.TestClient | ||||
| { | ||||
|     public class RegionInfoCommand : Command | ||||
|     { | ||||
|         public RegionInfoCommand(TestClient testClient) | ||||
| 		{ | ||||
| 			Name = "regioninfo"; | ||||
| 			Description = "Prints out info about all the current region"; | ||||
| 		} | ||||
| 
 | ||||
|         public override string Execute(string[] args, LLUUID fromAgentID) | ||||
|         { | ||||
|             StringBuilder output = new StringBuilder(); | ||||
|             output.AppendLine(Client.Network.CurrentSim.ToString()); | ||||
|             output.Append("Access: "); | ||||
|             output.AppendLine(Client.Network.CurrentSim.Access.ToString()); | ||||
|             output.Append("Flags: "); | ||||
|             output.AppendLine(Client.Network.CurrentSim.Flags.ToString()); | ||||
|             output.Append("TerrainBase0: "); | ||||
|             output.AppendLine(Client.Network.CurrentSim.TerrainBase0.ToStringHyphenated()); | ||||
|             output.Append("TerrainBase1: "); | ||||
|             output.AppendLine(Client.Network.CurrentSim.TerrainBase1.ToStringHyphenated()); | ||||
|             output.Append("TerrainBase2: "); | ||||
|             output.AppendLine(Client.Network.CurrentSim.TerrainBase2.ToStringHyphenated()); | ||||
|             output.Append("TerrainBase3: "); | ||||
|             output.AppendLine(Client.Network.CurrentSim.TerrainBase3.ToStringHyphenated()); | ||||
|             output.Append("TerrainDetail0: "); | ||||
|             output.AppendLine(Client.Network.CurrentSim.TerrainDetail0.ToStringHyphenated()); | ||||
|             output.Append("TerrainDetail1: "); | ||||
|             output.AppendLine(Client.Network.CurrentSim.TerrainDetail1.ToStringHyphenated()); | ||||
|             output.Append("TerrainDetail2: "); | ||||
|             output.AppendLine(Client.Network.CurrentSim.TerrainDetail2.ToStringHyphenated()); | ||||
|             output.Append("TerrainDetail3: "); | ||||
|             output.AppendLine(Client.Network.CurrentSim.TerrainDetail3.ToStringHyphenated()); | ||||
|             output.Append("Water Height: "); | ||||
|             output.AppendLine(Client.Network.CurrentSim.WaterHeight.ToString()); | ||||
| 
 | ||||
|             return output.ToString(); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | @ -0,0 +1,44 @@ | |||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Text; | ||||
| using libsecondlife; | ||||
| using libsecondlife.Packets; | ||||
| 
 | ||||
| namespace libsecondlife.TestClient | ||||
| { | ||||
|     public class StatsCommand : Command | ||||
|     { | ||||
|         public StatsCommand(TestClient testClient) | ||||
|         { | ||||
|             Name = "stats"; | ||||
|             Description = "Provide connection figures and statistics"; | ||||
|         } | ||||
| 
 | ||||
|         public override string Execute(string[] args, LLUUID fromAgentID) | ||||
|         { | ||||
|             StringBuilder output = new StringBuilder(); | ||||
| 
 | ||||
|             lock (Client.Network.Simulators) | ||||
|             { | ||||
|                 for (int i = 0; i < Client.Network.Simulators.Count; i++) | ||||
|                 { | ||||
|                     Simulator sim = Client.Network.Simulators[i]; | ||||
| 
 | ||||
|                     output.AppendLine(String.Format( | ||||
|                         "[{0}] Dilation: {1} InBPS: {2} OutBPS: {3} ResentOut: {4}  ResentIn: {5}", | ||||
|                         sim.ToString(), sim.Dilation, sim.IncomingBPS, sim.OutgoingBPS, sim.ResentPackets,  | ||||
|                         sim.ReceivedResends)); | ||||
|                 } | ||||
|             } | ||||
|             output.Append("Packets in the queue: " + Client.Network.InboxCount); | ||||
| 			output.AppendLine(String.Format("FPS : {0} PhysicsFPS : {1} AgentUpdates : {2} Objects : {3} Scripted Objects : {4}", | ||||
| 				Client.Network.CurrentSim.FPS, Client.Network.CurrentSim.PhysicsFPS, Client.Network.CurrentSim.AgentUpdates, Client.Network.CurrentSim.Objects, Client.Network.CurrentSim.ScriptedObjects)); | ||||
| 			output.AppendLine(String.Format("Frame Time : {0} Net Time : {1} Image Time : {2} Physics Time : {3} Script Time : {4} Other Time : {5}", | ||||
| 				Client.Network.CurrentSim.FrameTime, Client.Network.CurrentSim.NetTime, Client.Network.CurrentSim.ImageTime, Client.Network.CurrentSim.PhysicsTime, Client.Network.CurrentSim.ScriptTime, Client.Network.CurrentSim.OtherTime)); | ||||
| 			output.AppendLine(String.Format("Agents : {0} Child Agents : {1} Active Scripts : {2}", | ||||
| 				Client.Network.CurrentSim.Agents, Client.Network.CurrentSim.ChildAgents, Client.Network.CurrentSim.ActiveScripts)); | ||||
| 
 | ||||
|             return output.ToString(); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | @ -0,0 +1,25 @@ | |||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Text; | ||||
| using libsecondlife; | ||||
| using libsecondlife.Packets; | ||||
| 
 | ||||
| namespace libsecondlife.TestClient | ||||
| { | ||||
|     public class UptimeCommand : Command | ||||
|     { | ||||
|         public DateTime Created = DateTime.Now; | ||||
| 
 | ||||
|         public UptimeCommand(TestClient testClient) | ||||
|         { | ||||
|             Name = "uptime"; | ||||
|             Description = "Shows the login name, login time and length of time logged on."; | ||||
|         } | ||||
| 
 | ||||
|         public override string Execute(string[] args, LLUUID fromAgentID) | ||||
|         { | ||||
|             string name = Client.ToString(); | ||||
|             return "I am " + name + ", Up Since: " + Created + " (" + (DateTime.Now - Created) + ")"; | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | @ -0,0 +1,37 @@ | |||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using libsecondlife; | ||||
| using libsecondlife.Packets; | ||||
| 
 | ||||
| namespace libsecondlife.TestClient | ||||
| { | ||||
|     public class DebugCommand : Command | ||||
|     { | ||||
|         public DebugCommand(TestClient testClient) | ||||
|         { | ||||
|             Name = "debug"; | ||||
|             Description = "Turn debug messages on or off. Usage: debug [on/off]"; | ||||
|         } | ||||
| 
 | ||||
|         public override string Execute(string[] args, LLUUID fromAgentID) | ||||
|         { | ||||
|             if (args.Length != 1) | ||||
|                 return "Usage: debug [on/off]"; | ||||
| 
 | ||||
|             if (args[0].ToLower() == "on") | ||||
|             { | ||||
|                 Client.Settings.DEBUG = true; | ||||
|                 return "Debug logging is on"; | ||||
|             } | ||||
|             else if (args[0].ToLower() == "off") | ||||
|             { | ||||
|                 Client.Settings.DEBUG = false; | ||||
|                 return "Debug logging is off"; | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 return "Usage: debug [on/off]"; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | @ -0,0 +1,29 @@ | |||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Text; | ||||
| using libsecondlife; | ||||
| using libsecondlife.Packets; | ||||
| 
 | ||||
| namespace libsecondlife.TestClient | ||||
| { | ||||
|     public class HelpCommand: Command | ||||
|     { | ||||
|         public HelpCommand(TestClient testClient) | ||||
| 		{ | ||||
| 			Name = "help"; | ||||
| 			Description = "Lists available commands."; | ||||
| 		} | ||||
| 
 | ||||
|         public override string Execute(string[] args, LLUUID fromAgentID) | ||||
| 		{ | ||||
| 			StringBuilder result = new StringBuilder(); | ||||
| 			result.AppendFormat("\n\nHELP\nClient accept teleport lures from master and group members.\n"); | ||||
| 			foreach (Command c in Client.Commands.Values) | ||||
| 			{ | ||||
| 				result.AppendFormat(" * {0} - {1}\n", c.Name, c.Description); | ||||
| 			} | ||||
| 
 | ||||
|             return result.ToString(); | ||||
| 		} | ||||
|     } | ||||
| } | ||||
|  | @ -0,0 +1,28 @@ | |||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Text; | ||||
| using System.Reflection; | ||||
| using libsecondlife; | ||||
| using libsecondlife.Packets; | ||||
| 
 | ||||
| namespace libsecondlife.TestClient | ||||
| { | ||||
|     public class LoadCommand: Command | ||||
|     { | ||||
|         public LoadCommand(TestClient testClient) | ||||
| 		{ | ||||
| 			Name = "load"; | ||||
| 			Description = "Loads commands from a dll. (Usage: load AssemblyNameWithoutExtension)"; | ||||
| 		} | ||||
| 
 | ||||
| 		public override string Execute(string[] args, LLUUID fromAgentID) | ||||
| 		{ | ||||
| 			if (args.Length < 1) | ||||
| 				return "Usage: load AssemblyNameWithoutExtension"; | ||||
| 
 | ||||
| 			string filename = AppDomain.CurrentDomain.BaseDirectory + args[0] + ".dll"; | ||||
| 			Client.RegisterAllCommands(Assembly.LoadFile(filename)); | ||||
|             return "Assembly " + filename + " loaded."; | ||||
| 		} | ||||
|     } | ||||
| } | ||||
|  | @ -0,0 +1,34 @@ | |||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Reflection; | ||||
| using libsecondlife; | ||||
| using libsecondlife.Packets; | ||||
| 
 | ||||
| namespace libsecondlife.TestClient | ||||
| { | ||||
|     public class LoginCommand : Command | ||||
|     { | ||||
|         public LoginCommand(TestClient testClient) | ||||
|         { | ||||
|             Name = "login"; | ||||
|             Description = "Logs in another avatar"; | ||||
|         } | ||||
| 
 | ||||
|         public override string Execute(string[] args, LLUUID fromAgentID) | ||||
|         { | ||||
|             if (args.Length != 3 && args.Length != 4) | ||||
|                 return "usage: login firstname lastname password [simname]"; | ||||
| 
 | ||||
|             SecondLife newClient = Client.ClientManager.Login(args); | ||||
| 
 | ||||
|             if (newClient.Network.Connected) | ||||
|             { | ||||
|                 return "Logged in " + newClient.ToString(); | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 return "Failed to login: " + newClient.Network.LoginMessage; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | @ -0,0 +1,24 @@ | |||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Text; | ||||
| using libsecondlife; | ||||
| using libsecondlife.Packets; | ||||
| 
 | ||||
| namespace libsecondlife.TestClient | ||||
| { | ||||
|     public class LogoutCommand : Command | ||||
|     { | ||||
|         public LogoutCommand(TestClient testClient) | ||||
|         { | ||||
|             Name = "logout"; | ||||
|             Description = "Log this avatar out"; | ||||
|         } | ||||
| 
 | ||||
|         public override string Execute(string[] args, LLUUID fromAgentID) | ||||
|         { | ||||
|             string name = Client.ToString(); | ||||
| 			Client.ClientManager.Logout(Client); | ||||
|             return "Logged " + name + " out"; | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | @ -0,0 +1,22 @@ | |||
| using System; | ||||
| using libsecondlife; | ||||
| 
 | ||||
| namespace libsecondlife.TestClient | ||||
| { | ||||
|     public class MD5Command : Command | ||||
|     { | ||||
|         public MD5Command(TestClient testClient) | ||||
|         { | ||||
|             Name = "md5"; | ||||
|             Description = "Creates an MD5 hash from a given password. Usage: md5 [password]"; | ||||
|         } | ||||
| 
 | ||||
|         public override string Execute(string[] args, LLUUID fromAgentID) | ||||
|         { | ||||
|             if (args.Length == 1) | ||||
|                 return Helpers.MD5(args[0]); | ||||
|             else | ||||
|                 return "Usage: md5 [password]"; | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | @ -0,0 +1,84 @@ | |||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Xml; | ||||
| using libsecondlife; | ||||
| using libsecondlife.Packets; | ||||
| 
 | ||||
| namespace libsecondlife.TestClient | ||||
| { | ||||
|     public class PacketLogCommand : Command | ||||
|     { | ||||
|         List<Packet> Packets = new List<Packet>(); | ||||
|         bool Done = false; | ||||
|         int Count = 0; | ||||
|         int Total = 0; | ||||
| 
 | ||||
|         public PacketLogCommand(TestClient testClient) | ||||
|         { | ||||
|             Name = "packetlog"; | ||||
|             Description = "Logs a given number of packets to an xml file. Usage: packetlog 10 tenpackets.xml"; | ||||
|         } | ||||
| 
 | ||||
|         public override string Execute(string[] args, LLUUID fromAgentID) | ||||
|         { | ||||
|             if (args.Length != 2) | ||||
|                 return "Usage: packetlog 10 tenpackets.xml"; | ||||
| 
 | ||||
|             XmlWriter writer; | ||||
|             NetworkManager.PacketCallback callback = new NetworkManager.PacketCallback(OnPacket); | ||||
| 
 | ||||
|             Packets.Clear(); | ||||
|             Done = false; | ||||
|             Count = 0; | ||||
| 
 | ||||
|             try | ||||
|             { | ||||
|                 Total = Int32.Parse(args[0]); | ||||
|                 writer = XmlWriter.Create(args[1]); | ||||
| 
 | ||||
|                 Client.Network.RegisterCallback(PacketType.Default, callback); | ||||
|             } | ||||
|             catch (Exception e) | ||||
|             { | ||||
|                 return "Usage: packetlog 10 tenpackets.xml (" + e + ")"; | ||||
|             } | ||||
| 
 | ||||
|             while (!Done) | ||||
|             { | ||||
|                 System.Threading.Thread.Sleep(100); | ||||
|             } | ||||
| 
 | ||||
|             Client.Network.UnregisterCallback(PacketType.Default, callback); | ||||
| 
 | ||||
|             try | ||||
|             { | ||||
|                 Helpers.PacketListToXml(Packets, writer); | ||||
|             } | ||||
|             catch (Exception e) | ||||
|             { | ||||
|                 return "Serialization failed: " + e.ToString(); | ||||
|             } | ||||
| 
 | ||||
|             writer.Close(); | ||||
|             Packets.Clear(); | ||||
| 
 | ||||
|             return "Exported " + Count + " packets to " + args[1]; | ||||
|         } | ||||
| 
 | ||||
|         private void OnPacket(Packet packet, Simulator simulator) | ||||
|         { | ||||
|             lock (Packets) | ||||
|             { | ||||
|                 if (Count >= Total) | ||||
|                 { | ||||
|                     Done = true; | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     Packets.Add(packet); | ||||
|                     Count++; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | @ -0,0 +1,24 @@ | |||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Text; | ||||
| using libsecondlife; | ||||
| using libsecondlife.Packets; | ||||
| 
 | ||||
| namespace libsecondlife.TestClient | ||||
| { | ||||
|     public class QuitCommand: Command | ||||
|     { | ||||
|         public QuitCommand(TestClient testClient) | ||||
| 		{ | ||||
| 			Name = "quit"; | ||||
| 			Description = "Log all avatars out and shut down"; | ||||
| 		} | ||||
| 
 | ||||
|         public override string Execute(string[] args, LLUUID fromAgentID) | ||||
| 		{ | ||||
| 			Client.ClientManager.LogoutAll(); | ||||
|             Client.ClientManager.Running = false; | ||||
|             return "All avatars logged out"; | ||||
| 		} | ||||
|     } | ||||
| } | ||||
|  | @ -0,0 +1,73 @@ | |||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Text; | ||||
| using System.Threading; | ||||
| using libsecondlife; | ||||
| using libsecondlife.Packets; | ||||
| 
 | ||||
| namespace libsecondlife.TestClient | ||||
| { | ||||
|     public class SetMasterCommand: Command | ||||
|     { | ||||
| 		public DateTime Created = DateTime.Now; | ||||
|         private LLUUID resolvedMasterKey = LLUUID.Zero; | ||||
|         private ManualResetEvent keyResolution = new ManualResetEvent(false); | ||||
|         private LLUUID query = LLUUID.Zero; | ||||
| 
 | ||||
|         public SetMasterCommand(TestClient testClient) | ||||
| 		{ | ||||
| 			Name = "setMaster"; | ||||
| 			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) | ||||
| 		{ | ||||
| 			string masterName = String.Empty; | ||||
| 			for (int ct = 0; ct < args.Length;ct++) | ||||
| 				masterName = masterName + args[ct] + " "; | ||||
|             masterName = masterName.TrimEnd(); | ||||
| 
 | ||||
|             if (masterName.Length == 0) | ||||
|                 return "Usage setMaster name"; | ||||
| 
 | ||||
|             DirectoryManager.DirPeopleReplyCallback callback = new DirectoryManager.DirPeopleReplyCallback(KeyResolvHandler); | ||||
|             Client.Directory.OnDirPeopleReply += callback; | ||||
|             query = Client.Directory.StartPeopleSearch(DirectoryManager.DirFindFlags.People, masterName, 0); | ||||
|             if (keyResolution.WaitOne(TimeSpan.FromMinutes(1), false)) | ||||
|             { | ||||
|                 Client.MasterKey = resolvedMasterKey; | ||||
|                 keyResolution.Reset(); | ||||
|                 Client.Directory.OnDirPeopleReply -= callback; | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 keyResolution.Reset(); | ||||
|                 Client.Directory.OnDirPeopleReply -= callback; | ||||
|                 return "Unable to obtain UUID for \"" + masterName + "\". Master unchanged."; | ||||
|             } | ||||
|              | ||||
| 
 | ||||
| 			foreach (Avatar av in Client.AvatarList.Values) | ||||
| 			{ | ||||
| 			    if (av.ID == Client.MasterKey) | ||||
| 			    { | ||||
| 			        Client.Self.InstantMessage(av.ID, "You are now my master.  IM me with \"help\" for a command list."); | ||||
| 			        break; | ||||
| 			    } | ||||
| 			} | ||||
| 
 | ||||
|             return "Master set to " + masterName + " (" + Client.MasterKey.ToStringHyphenated() + ")"; | ||||
| 		} | ||||
| 
 | ||||
|         private void KeyResolvHandler(LLUUID queryid, List<DirectoryManager.AgentSearchData> matches) | ||||
|         { | ||||
|             if (query != queryid) | ||||
|                 return; | ||||
|             // We can't handle ambiguities here as nicely as we can in ClientManager. | ||||
|             resolvedMasterKey = matches[0].AgentID; | ||||
|             keyResolution.Set(); | ||||
|             query = LLUUID.Zero; | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | @ -0,0 +1,35 @@ | |||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Text; | ||||
| using libsecondlife; | ||||
| using libsecondlife.Packets; | ||||
| 
 | ||||
| namespace libsecondlife.TestClient | ||||
| { | ||||
|     public class SetMasterKeyCommand : Command | ||||
|     { | ||||
|         public DateTime Created = DateTime.Now; | ||||
| 
 | ||||
|         public SetMasterKeyCommand(TestClient testClient) | ||||
|         { | ||||
|             Name = "setMasterKey"; | ||||
|             Description = "Sets the key of the master user.  The master user can IM to run commands."; | ||||
|         } | ||||
| 
 | ||||
|         public override string Execute(string[] args, LLUUID fromAgentID) | ||||
|         { | ||||
|             Client.MasterKey = LLUUID.Parse(args[0]); | ||||
| 
 | ||||
|             foreach (Avatar av in Client.AvatarList.Values) | ||||
|             { | ||||
|                 if (av.ID == Client.MasterKey) | ||||
|                 { | ||||
|                     Client.Self.InstantMessage(av.ID, "You are now my master.  IM me with \"help\" for a command list."); | ||||
|                     break; | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             return "Master set to " + Client.MasterKey; | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | @ -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()); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | @ -0,0 +1,55 @@ | |||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Text; | ||||
| using libsecondlife; | ||||
| using libsecondlife.Packets; | ||||
| 
 | ||||
| namespace libsecondlife.TestClient | ||||
| { | ||||
|     public class TouchCommand: Command | ||||
|     { | ||||
|         public TouchCommand(TestClient testClient) | ||||
| 		{ | ||||
| 			Name = "touch"; | ||||
| 			Description = "Attempt to touch a prim with specified UUID"; | ||||
| 		} | ||||
| 		 | ||||
|         public override string Execute(string[] args, LLUUID fromAgentID) | ||||
| 		{ | ||||
| 		    Primitive target = null; | ||||
| 
 | ||||
| 		    lock (Client.SimPrims) | ||||
| 		    { | ||||
|                 if (Client.SimPrims.ContainsKey(Client.Network.CurrentSim)) | ||||
|                 { | ||||
|                     foreach (Primitive p in Client.SimPrims[Client.Network.CurrentSim].Values) | ||||
|                     { | ||||
|                         if (args.Length == 0) | ||||
|                             return "You must specify a UUID of the prim."; | ||||
| 
 | ||||
|                         try | ||||
|                         { | ||||
|                             if (p.ID == args[0]) | ||||
|                                 target = p; | ||||
|                         } | ||||
|                         catch | ||||
|                         { | ||||
|                             // handle exception | ||||
|                             return "Sorry, I don't think " + args[0] + " is a valid UUID.  I'm unable to touch it."; | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
| 		    } | ||||
| 
 | ||||
|             if (target != null) | ||||
|             { | ||||
|                 Client.Self.Touch(target.LocalID); | ||||
|                 return "Touched prim " + target.ID + "."; | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 return "Couldn't find that prim."; | ||||
|             } | ||||
| 		} | ||||
|     } | ||||
| } | ||||
|  | @ -0,0 +1,51 @@ | |||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Text; | ||||
| using libsecondlife; | ||||
| using libsecondlife.Packets; | ||||
| 
 | ||||
| namespace libsecondlife.TestClient | ||||
| { | ||||
|     public class TreeCommand: Command | ||||
|     { | ||||
|         public TreeCommand(TestClient testClient) | ||||
| 		{ | ||||
| 			Name = "tree"; | ||||
| 			Description = "Rez a tree."; | ||||
| 		} | ||||
| 
 | ||||
|         public override string Execute(string[] args, LLUUID fromAgentID) | ||||
| 		{ | ||||
| 		    if (args.Length == 1) | ||||
| 		    { | ||||
| 		        try | ||||
| 		        { | ||||
| 		            string treeName = args[0].Trim(new char[] { ' ' }); | ||||
| 		            ObjectManager.Tree tree = (ObjectManager.Tree)Enum.Parse(typeof(ObjectManager.Tree), treeName); | ||||
| 
 | ||||
| 		            LLVector3 treePosition = new LLVector3(Client.Self.Position.X, Client.Self.Position.Y, | ||||
| 		                Client.Self.Position.Z); | ||||
| 		            treePosition.Z += 3.0f; | ||||
| 
 | ||||
| 		            Client.Objects.AddTree(Client.Network.CurrentSim, new LLVector3(0.5f, 0.5f, 0.5f), | ||||
| 		                LLQuaternion.Identity, treePosition, tree, Client.GroupID, false); | ||||
| 
 | ||||
| 		            return "Attempted to rez a " + treeName + " tree"; | ||||
| 		        } | ||||
| 		        catch (Exception) | ||||
| 		        { | ||||
| 		            return "Type !tree for usage"; | ||||
| 		        } | ||||
| 		    } | ||||
| 
 | ||||
| 		    string usage = "Usage: !tree ["; | ||||
| 		    foreach (string value in Enum.GetNames(typeof(ObjectManager.Tree))) | ||||
| 		    { | ||||
| 		        usage += value + ","; | ||||
| 		    } | ||||
| 		    usage = usage.TrimEnd(new char[] { ',' }); | ||||
| 		    usage += "]"; | ||||
| 		    return usage; | ||||
| 		} | ||||
|     } | ||||
| } | ||||
|  | @ -0,0 +1,29 @@ | |||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Text; | ||||
| using libsecondlife; | ||||
| using libsecondlife.Packets; | ||||
| 
 | ||||
| namespace libsecondlife.TestClient | ||||
| { | ||||
|     public class WhoCommand: Command | ||||
|     { | ||||
|         public WhoCommand(TestClient testClient) | ||||
| 		{ | ||||
| 			Name = "who"; | ||||
| 			Description = "Lists seen avatars."; | ||||
| 		} | ||||
| 
 | ||||
|         public override string Execute(string[] args, LLUUID fromAgentID) | ||||
| 		{ | ||||
| 			StringBuilder result = new StringBuilder(); | ||||
| 			foreach (Avatar av in Client.AvatarList.Values) | ||||
| 			{ | ||||
| 				result.AppendFormat("\n{0} {1} {2}/{3} ID: {4}", av.Name, av.GroupName,  | ||||
|                     (av.CurrentSim != null ? av.CurrentSim.Name : String.Empty), av.Position, av.ID); | ||||
| 			} | ||||
| 
 | ||||
|             return result.ToString(); | ||||
| 		} | ||||
|     } | ||||
| } | ||||
|  | @ -0,0 +1,121 @@ | |||
| <Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> | ||||
|   <PropertyGroup> | ||||
|     <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> | ||||
|     <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> | ||||
|     <ProductVersion>8.0.50727</ProductVersion> | ||||
|     <SchemaVersion>2.0</SchemaVersion> | ||||
|     <ProjectGuid>{B87682F6-B2D7-4C4D-A529-400C24FD4880}</ProjectGuid> | ||||
|     <OutputType>Exe</OutputType> | ||||
|     <AppDesignerFolder>Properties</AppDesignerFolder> | ||||
|     <RootNamespace>libsecondlife.MassTestClient</RootNamespace> | ||||
|     <AssemblyName>MassTestClient</AssemblyName> | ||||
|   </PropertyGroup> | ||||
|   <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> | ||||
|     <DebugSymbols>true</DebugSymbols> | ||||
|     <DebugType>full</DebugType> | ||||
|     <Optimize>false</Optimize> | ||||
|     <OutputPath>..\..\..\bin\</OutputPath> | ||||
|     <DefineConstants>DEBUG;TRACE</DefineConstants> | ||||
|     <ErrorReport>prompt</ErrorReport> | ||||
|     <WarningLevel>4</WarningLevel> | ||||
|   </PropertyGroup> | ||||
|   <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> | ||||
|     <DebugType>pdbonly</DebugType> | ||||
|     <Optimize>true</Optimize> | ||||
|     <OutputPath>bin\</OutputPath> | ||||
|     <DefineConstants>TRACE</DefineConstants> | ||||
|     <ErrorReport>prompt</ErrorReport> | ||||
|     <WarningLevel>4</WarningLevel> | ||||
|   </PropertyGroup> | ||||
|   <ItemGroup> | ||||
|     <Reference Include="libsecondlife, Version=0.9.0.0, Culture=neutral, processorArchitecture=MSIL"> | ||||
|       <SpecificVersion>False</SpecificVersion> | ||||
|       <HintPath>bin\libsecondlife.dll</HintPath> | ||||
|     </Reference> | ||||
|     <Reference Include="libsecondlife.Utilities, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL"> | ||||
|       <SpecificVersion>False</SpecificVersion> | ||||
|       <HintPath>bin\libsecondlife.Utilities.dll</HintPath> | ||||
|     </Reference> | ||||
|     <Reference Include="openjpegnet, Version=0.0.0.0, Culture=neutral, processorArchitecture=MSIL"> | ||||
|       <SpecificVersion>False</SpecificVersion> | ||||
|       <HintPath>bin\openjpegnet.dll</HintPath> | ||||
|     </Reference> | ||||
|     <Reference Include="System" /> | ||||
|     <Reference Include="System.Data" /> | ||||
|     <Reference Include="System.Xml" /> | ||||
|   </ItemGroup> | ||||
|   <ItemGroup> | ||||
|     <Compile Include="Arguments.cs" /> | ||||
|     <Compile Include="Command.cs" /> | ||||
|     <Compile Include="Commands\Inventory\AppearanceCommand.cs" /> | ||||
|     <Compile Include="Commands\CloneProfileCommand.cs" /> | ||||
|     <Compile Include="Commands\System\DebugCommand.cs" /> | ||||
|     <Compile Include="Commands\Inventory\DumpOutfitCommand.cs" /> | ||||
|     <Compile Include="Commands\Prims\ExportParticlesCommand.cs" /> | ||||
|     <Compile Include="Commands\Inventory\BalanceCommand.cs" /> | ||||
|     <Compile Include="Commands\Inventory\DeleteFolderCommand.cs" /> | ||||
|     <Compile Include="Commands\Inventory\GiveAllCommand.cs" /> | ||||
|     <Compile Include="Commands\Inventory\WearCommand.cs" /> | ||||
|     <Compile Include="Commands\Inventory\InventoryCommand.cs" /> | ||||
|     <Compile Include="Commands\Inventory\ExportOutfitCommand.cs" /> | ||||
|     <Compile Include="Commands\Land\FindSimCommand.cs" /> | ||||
|     <Compile Include="Commands\Inventory\ImportOutfitCommand.cs" /> | ||||
|     <Compile Include="Commands\System\LoginCommand.cs"> | ||||
|       <SubType>Code</SubType> | ||||
|     </Compile> | ||||
|     <Compile Include="Commands\System\LogoutCommand.cs"> | ||||
|       <SubType>Code</SubType> | ||||
|     </Compile> | ||||
|     <Compile Include="Commands\Communication\EchoMasterCommand.cs" /> | ||||
|     <Compile Include="Commands\Communication\IMCommand.cs" /> | ||||
|     <Compile Include="Commands\Communication\SayCommand.cs" /> | ||||
|     <Compile Include="Commands\Communication\ShoutCommand.cs" /> | ||||
|     <Compile Include="Commands\Communication\WhisperCommand.cs" /> | ||||
|     <Compile Include="Commands\System\MD5Command.cs" /> | ||||
|     <Compile Include="Commands\Movement\FollowCommand.cs" /> | ||||
|     <Compile Include="Commands\Movement\GotoCommand.cs" /> | ||||
|     <Compile Include="Commands\Movement\JumpCommand.cs" /> | ||||
|     <Compile Include="Commands\Movement\LocationCommand.cs" /> | ||||
|     <Compile Include="Commands\Movement\SitCommand.cs" /> | ||||
|     <Compile Include="Commands\System\PacketLogCommand.cs" /> | ||||
|     <Compile Include="Commands\Land\ParcelInfoCommand.cs" /> | ||||
|     <Compile Include="Commands\System\QuitCommand.cs"> | ||||
|       <SubType>Code</SubType> | ||||
|     </Compile> | ||||
|     <Compile Include="Commands\Stats\RegionInfoCommand.cs" /> | ||||
|     <Compile Include="Commands\System\SetMasterCommand.cs"> | ||||
|       <SubType>Code</SubType> | ||||
|     </Compile> | ||||
|     <Compile Include="Commands\Prims\ExportCommand.cs" /> | ||||
|     <Compile Include="Commands\Prims\ImportCommand.cs" /> | ||||
|     <Compile Include="Commands\System\LoadCommand.cs" /> | ||||
|     <Compile Include="Commands\Prims\PrimCountCommand.cs" /> | ||||
|     <Compile Include="Commands\System\SetMasterKeyCommand.cs" /> | ||||
|     <Compile Include="Commands\System\ShowEffectsCommand.cs" /> | ||||
|     <Compile Include="Commands\Stats\StatsCommand.cs" /> | ||||
|     <Compile Include="Commands\TouchCommand.cs" /> | ||||
|     <Compile Include="Commands\TreeCommand.cs" /> | ||||
|     <Compile Include="Commands\Stats\UptimeCommand.cs" /> | ||||
|     <Compile Include="Commands\System\HelpCommand.cs" /> | ||||
|     <Compile Include="ClientManager.cs" /> | ||||
|     <Compile Include="Commands\WhoCommand.cs"> | ||||
|       <SubType>Code</SubType> | ||||
|     </Compile> | ||||
|     <Compile Include="Parsing.cs" /> | ||||
|     <Compile Include="Program.cs" /> | ||||
|     <Compile Include="TestClient.cs" /> | ||||
|     <Compile Include="Properties\AssemblyInfo.cs" /> | ||||
|   </ItemGroup> | ||||
|   <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" /> | ||||
|   <!-- To modify your build process, add your task inside one of the targets below and uncomment it.  | ||||
|        Other similar extension points exist, see Microsoft.Common.targets. | ||||
|   <Target Name="BeforeBuild"> | ||||
|   </Target> | ||||
|   <Target Name="AfterBuild"> | ||||
|   </Target> | ||||
|   --> | ||||
|   <PropertyGroup> | ||||
|     <PreBuildEvent> | ||||
|     </PreBuildEvent> | ||||
|   </PropertyGroup> | ||||
| </Project> | ||||
|  | @ -0,0 +1,10 @@ | |||
| <Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> | ||||
|   <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> | ||||
|     <StartArguments> | ||||
|     </StartArguments> | ||||
|   </PropertyGroup> | ||||
|   <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> | ||||
|     <StartArguments> | ||||
|     </StartArguments> | ||||
|   </PropertyGroup> | ||||
| </Project> | ||||
|  | @ -0,0 +1,20 @@ | |||
|  | ||||
| Microsoft Visual Studio Solution File, Format Version 9.00 | ||||
| # Visual C# Express 2005 | ||||
| Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MassTestClient", "MassTestClient.csproj", "{B87682F6-B2D7-4C4D-A529-400C24FD4880}" | ||||
| EndProject | ||||
| Global | ||||
| 	GlobalSection(SolutionConfigurationPlatforms) = preSolution | ||||
| 		Debug|Any CPU = Debug|Any CPU | ||||
| 		Release|Any CPU = Release|Any CPU | ||||
| 	EndGlobalSection | ||||
| 	GlobalSection(ProjectConfigurationPlatforms) = postSolution | ||||
| 		{B87682F6-B2D7-4C4D-A529-400C24FD4880}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | ||||
| 		{B87682F6-B2D7-4C4D-A529-400C24FD4880}.Debug|Any CPU.Build.0 = Debug|Any CPU | ||||
| 		{B87682F6-B2D7-4C4D-A529-400C24FD4880}.Release|Any CPU.ActiveCfg = Release|Any CPU | ||||
| 		{B87682F6-B2D7-4C4D-A529-400C24FD4880}.Release|Any CPU.Build.0 = Release|Any CPU | ||||
| 	EndGlobalSection | ||||
| 	GlobalSection(SolutionProperties) = preSolution | ||||
| 		HideSolutionNode = FALSE | ||||
| 	EndGlobalSection | ||||
| EndGlobal | ||||
										
											Binary file not shown.
										
									
								
							|  | @ -0,0 +1,61 @@ | |||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Text; | ||||
| 
 | ||||
| namespace libsecondlife.TestClient { | ||||
|     class Parsing { | ||||
|         public static string[] ParseArguments(string str) { | ||||
|             List<string> list = new List<string>(); | ||||
|             string current = ""; | ||||
|             string trimmed = null; | ||||
|             bool withinQuote = false; | ||||
|             bool escaped = false; | ||||
|             foreach (char c in str) { | ||||
|                 if (c == '"') { | ||||
|                     if (escaped) { | ||||
|                         current += '"'; | ||||
|                         escaped = false; | ||||
|                     } else { | ||||
|                         current += '"'; | ||||
|                         withinQuote = !withinQuote; | ||||
|                     } | ||||
|                 } else if (c == ' ' || c == '\t') { | ||||
|                     if (escaped || withinQuote) { | ||||
|                         current += c; | ||||
|                         escaped = false; | ||||
|                     } else { | ||||
|                         trimmed = current.Trim(); | ||||
|                         if (trimmed.StartsWith("\"") && trimmed.EndsWith("\"")) { | ||||
|                             trimmed = trimmed.Remove(0, 1); | ||||
|                             trimmed = trimmed.Remove(trimmed.Length - 1); | ||||
|                             trimmed = trimmed.Trim(); | ||||
|                         } | ||||
|                         if (trimmed.Length > 0) | ||||
|                             list.Add(trimmed); | ||||
|                         current = ""; | ||||
|                     } | ||||
|                 } else if (c == '\\') { | ||||
|                     if (escaped) { | ||||
|                         current += '\\'; | ||||
|                         escaped = false; | ||||
|                     } else { | ||||
|                         escaped = true; | ||||
|                     } | ||||
|                 } else { | ||||
|                     if (escaped) | ||||
|                         throw new FormatException(c.ToString() + " is not an escapable character."); | ||||
|                     current += c; | ||||
|                 } | ||||
|             } | ||||
|             trimmed = current.Trim(); | ||||
|             if (trimmed.StartsWith("\"") && trimmed.EndsWith("\"")) { | ||||
|                 trimmed = trimmed.Remove(0, 1); | ||||
|                 trimmed = trimmed.Remove(trimmed.Length - 1); | ||||
|                 trimmed = trimmed.Trim(); | ||||
|             } | ||||
|             if (trimmed.Length > 0) | ||||
|                 list.Add(trimmed); | ||||
|             return list.ToArray(); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | @ -0,0 +1,218 @@ | |||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.IO; | ||||
| using CommandLine.Utility; | ||||
| 
 | ||||
| namespace libsecondlife.TestClient | ||||
| { | ||||
|     public class CommandLineArgumentsException : Exception | ||||
|     { | ||||
|     } | ||||
|      | ||||
|     public class Program | ||||
|     { | ||||
| 
 | ||||
|         private static void Usage() | ||||
|         { | ||||
|             Console.WriteLine("Usage: " + Environment.NewLine + | ||||
|                     "MassTestClient.exe --first \"firstname\" --last \"lastname\" --pass \"password\" --contact \"youremail\" [--startpos \"sim/x/y/z\"] [--master \"master name\"] [--masterkey \"master uuid\"] [--loginuri \"loginuri\"] [--masscommandfile \"filename\"]" + | ||||
|                     Environment.NewLine + Environment.NewLine + "MassTestClient.exe --loginfile \"filename\" --contact \"youremail\" [--master \"master name\"] [--masterkey \"master uuid\"] [--loginuri \"loginuri\"] [--masscommandfile \"filename\"]"); | ||||
|             Console.ReadLine(); | ||||
|         } | ||||
| 
 | ||||
|         private static List<string> getMassTestCommands() | ||||
|         { | ||||
|             List<string> givenCommands = new List<string>(); | ||||
|             Console.WriteLine("Please enter mass test commands to run in an infinite loop. Press enter to end the current command. Entering a blank command represents that you are done."); | ||||
|             Console.WriteLine(""); | ||||
| 
 | ||||
|             int curCommand = 0; | ||||
|             string lastCommand = "NULL"; | ||||
|             while (lastCommand.Length > 0) | ||||
|             { | ||||
|                 Console.Write("Command #" + curCommand + ">"); | ||||
|                 lastCommand = Console.ReadLine().Trim(); | ||||
|                 if (lastCommand.Length > 0) | ||||
|                 { | ||||
|                     givenCommands.Add(lastCommand); | ||||
|                     curCommand++; | ||||
|                 } | ||||
|             } | ||||
|              | ||||
|             return givenCommands; | ||||
|         } | ||||
| 
 | ||||
|         static void Main(string[] args) | ||||
|         { | ||||
|             Arguments arguments = new Arguments(args); | ||||
| 
 | ||||
|             ClientManager manager; | ||||
|             List<LoginDetails> accounts = new List<LoginDetails>(); | ||||
|             LoginDetails account; | ||||
|             string masterName = String.Empty; | ||||
|             LLUUID masterKey = LLUUID.Zero; | ||||
|             string file = String.Empty; | ||||
| 			string contact = String.Empty; | ||||
|             string loginURI = "https://login.agni.lindenlab.com/cgi-bin/login.cgi"; | ||||
|             try | ||||
|             { | ||||
|                 if (arguments["masterkey"] != null) | ||||
|                 { | ||||
|                     masterKey = LLUUID.Parse(arguments["masterkey"]); | ||||
|                 } | ||||
| 
 | ||||
|                 if (arguments["master"] != null) | ||||
|                 { | ||||
|                     masterName = arguments["master"]; | ||||
|                 } | ||||
| 
 | ||||
|                 if (arguments["contact"] == null) | ||||
|                     throw new CommandLineArgumentsException(); | ||||
| 
 | ||||
|                 contact = arguments["contact"]; | ||||
| 
 | ||||
|                 if (arguments["file"] != null) | ||||
|                 { | ||||
|                     file = arguments["file"]; | ||||
| 
 | ||||
|                     // Loading names from a file | ||||
|                     try | ||||
|                     { | ||||
|                         using (StreamReader reader = new StreamReader(file)) | ||||
|                         { | ||||
|                             string line; | ||||
|                             int lineNumber = 0; | ||||
| 
 | ||||
|                             while ((line = reader.ReadLine()) != null) | ||||
|                             { | ||||
|                                 lineNumber++; | ||||
|                                 string[] tokens = line.Trim().Split(new char[] { ' ', ',' }); | ||||
| 
 | ||||
|                                 if (tokens.Length >= 3) | ||||
|                                 { | ||||
|                                     account = new LoginDetails(); | ||||
|                                     account.FirstName = tokens[0]; | ||||
|                                     account.LastName = tokens[1]; | ||||
|                                     account.Password = tokens[2]; | ||||
| 
 | ||||
|                                     accounts.Add(account); | ||||
| 
 | ||||
|                                     // Leaving this out until we have per-account masters (if that | ||||
|                                     // is desirable). For now the command-line option can  | ||||
|                                     // specify the single master that TestClient supports | ||||
| 
 | ||||
|                                     //if (tokens.Length == 5) | ||||
|                                     //{ | ||||
|                                     //    master = tokens[3] + " " + tokens[4]; | ||||
|                                     //} | ||||
|                                 } | ||||
|                                 else | ||||
|                                 { | ||||
|                                     Console.WriteLine("Invalid data on line " + lineNumber + | ||||
|                                         ", must be in the format of: FirstName LastName Password"); | ||||
|                                 } | ||||
|                             } | ||||
|                         } | ||||
|                     } | ||||
|                     catch (Exception e) | ||||
|                     { | ||||
|                         Console.WriteLine("Error reading from " + args[1]); | ||||
|                         Console.WriteLine(e.ToString()); | ||||
|                         Console.ReadLine(); | ||||
|                         return; | ||||
|                     } | ||||
|                 } | ||||
|                 else if (arguments["first"] != null && arguments["last"] != null && arguments["pass"] != null) | ||||
|                 { | ||||
|                     // Taking a single login off the command-line | ||||
|                     account = new LoginDetails(); | ||||
|                     account.FirstName = arguments["first"]; | ||||
|                     account.LastName = arguments["last"]; | ||||
|                     account.Password = arguments["pass"]; | ||||
| 
 | ||||
|                     accounts.Add(account); | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     throw new CommandLineArgumentsException(); | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             catch (CommandLineArgumentsException) | ||||
|             { | ||||
|                 Usage(); | ||||
|                 return; | ||||
|             } | ||||
| 
 | ||||
|             if(arguments["loginuri"] != null) | ||||
|             { | ||||
|                 loginURI = arguments["loginuri"]; | ||||
|             } | ||||
| 
 | ||||
|             List<string> massTestCommands = new List<string>(); | ||||
|             if(arguments["masscommandfile"] != null) | ||||
|             { | ||||
|                 string massCommandFile = arguments["masscommandfile"]; | ||||
|                 try | ||||
|                 { | ||||
|                     using (StreamReader reader = new StreamReader(massCommandFile)) | ||||
|                     { | ||||
|                         string line; | ||||
| 
 | ||||
|                         while ((line = reader.ReadLine()) != null) | ||||
|                         { | ||||
|                                | ||||
|                             line = line.Trim(); | ||||
|                             if(line.Length > 0) | ||||
|                             { | ||||
|                                 massTestCommands.Add(line); | ||||
|                             } | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|                 catch (Exception e) | ||||
|                 { | ||||
|                     Console.WriteLine("Error reading from " + args[1]); | ||||
|                     Console.WriteLine(e.ToString()); | ||||
|                     Console.ReadLine(); | ||||
|                     return; | ||||
|                 } | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 Console.Clear(); | ||||
|                 massTestCommands = getMassTestCommands(); | ||||
|             } | ||||
|              | ||||
|             Console.Clear(); | ||||
|             if (massTestCommands.Count == 0) | ||||
|             { | ||||
|                 Console.WriteLine("No mass commands entered; Normal 'TestClient' operation will be used"); | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 Console.WriteLine("Detected " + massTestCommands.Count + " mass commands; MassTestClient operation will be used"); | ||||
|             } | ||||
| 
 | ||||
|             foreach (LoginDetails a in accounts) | ||||
|             { | ||||
|                 a.MasterName = masterName; | ||||
|                 a.MasterKey = masterKey; | ||||
|                 a.LoginURI = loginURI; | ||||
|             } | ||||
| 
 | ||||
|             // Login the accounts and run the input loop | ||||
|             if (arguments["startpos"] != null) | ||||
|             { | ||||
|                 manager = new ClientManager(accounts, contact, arguments["startpos"]); | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 manager = new ClientManager(accounts, contact); | ||||
|             } | ||||
| 
 | ||||
| 
 | ||||
|             manager.Run(massTestCommands); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | @ -0,0 +1,33 @@ | |||
| using System.Reflection; | ||||
| using System.Runtime.CompilerServices; | ||||
| using System.Runtime.InteropServices; | ||||
| 
 | ||||
| // General Information about an assembly is controlled through the following  | ||||
| // set of attributes. Change these attribute values to modify the information | ||||
| // associated with an assembly. | ||||
| [assembly: AssemblyTitle("MassTestClient")] | ||||
| [assembly: AssemblyDescription("")] | ||||
| [assembly: AssemblyConfiguration("")] | ||||
| [assembly: AssemblyCompany("")] | ||||
| [assembly: AssemblyProduct("MassTestClient")] | ||||
| [assembly: AssemblyCopyright("Copyright ©  2007")] | ||||
| [assembly: AssemblyTrademark("")] | ||||
| [assembly: AssemblyCulture("")] | ||||
| 
 | ||||
| // Setting ComVisible to false makes the types in this assembly not visible  | ||||
| // to COM components.  If you need to access a type in this assembly from  | ||||
| // COM, set the ComVisible attribute to true on that type. | ||||
| [assembly: ComVisible(false)] | ||||
| 
 | ||||
| // The following GUID is for the ID of the typelib if this project is exposed to COM | ||||
| [assembly: Guid("0563f706-7fa9-42f6-bf23-c6acd1175964")] | ||||
| 
 | ||||
| // Version information for an assembly consists of the following four values: | ||||
| // | ||||
| //      Major Version | ||||
| //      Minor Version  | ||||
| //      Build Number | ||||
| //      Revision | ||||
| // | ||||
| [assembly: AssemblyVersion("1.0.0.0")] | ||||
| [assembly: AssemblyFileVersion("1.0.0.0")] | ||||
|  | @ -0,0 +1,125 @@ | |||
| <?xml version="1.0"?> | ||||
| 
 | ||||
| <project | ||||
|   name="libsecondlife" | ||||
|   default="build"> | ||||
| 
 | ||||
|   <!-- global framework settings --> | ||||
|   <property | ||||
|     name="target.framework" | ||||
|     value="${framework::get-target-framework()}" /> | ||||
|   <property | ||||
|     name="assembly.dir" | ||||
|     value="${framework::get-assembly-directory(target.framework)}" /> | ||||
| 
 | ||||
|   <!-- global project settings --> | ||||
|   <xmlpeek | ||||
|     file="../../../libsecondlife.build" | ||||
|     xpath="/project/property[@name = 'project.version']/@value" | ||||
|     property="project.version" /> | ||||
|   <property | ||||
|      name="build.number" | ||||
|      value="${math::abs(math::floor(timespan::get-total-days(datetime::now() | ||||
|      - datetime::parse('01/01/2002'))))}" /> | ||||
|   <property | ||||
|     name="assembly" | ||||
|     value="TestClient"/> | ||||
|   <property | ||||
|     name="bin_dir" | ||||
|     value="../../../bin" /> | ||||
| 
 | ||||
|   <!-- default configuration --> | ||||
|   <property | ||||
|     name="project.config" | ||||
|     value="debug" /> <!-- debug|release --> | ||||
| 
 | ||||
|   <!-- named configurations --> | ||||
|   <target | ||||
|     name="init" | ||||
|     description="Initializes build properties"> | ||||
|     <call target="${project.config}" /> | ||||
|   </target> | ||||
| 
 | ||||
|   <target | ||||
|     name="debug" | ||||
|     description="configures a debug build"> | ||||
|     <property | ||||
|       name="build.debug" | ||||
|       value="true" /> | ||||
|     <property | ||||
|       name="package.name" | ||||
|       value="${project::get-name()}-${project.version}-${project.config}" /> | ||||
|     <property | ||||
|       name="assembly.configuration" | ||||
|       value="${framework::get-target-framework()}.${platform::get-name()} [${project.config}]" /> | ||||
|   </target> | ||||
| 
 | ||||
|   <target | ||||
|     name="release" | ||||
|     description="configures a release build"> | ||||
|     <property | ||||
|       name="project.config" | ||||
|       value="release" /> | ||||
|     <property | ||||
|       name="build.debug" | ||||
|       value="false" /> | ||||
|     <property | ||||
|       name="package.name" | ||||
|       value="${project::get-name()}-${project.version}" /> | ||||
|     <property | ||||
|       name="assembly.configuration" | ||||
|       value="${framework::get-target-framework()}.${platform::get-name()}" /> | ||||
|   </target> | ||||
| 
 | ||||
|   <!-- build tasks --> | ||||
|   <target | ||||
|     name="build" | ||||
|     depends="init" | ||||
|     description="Builds the binaries for the current configuration"> | ||||
|     <echo message="Build Directory is ${bin_dir}/" /> | ||||
|     <mkdir | ||||
|       dir="${bin_dir}" | ||||
|       failonerror="false" /> | ||||
|     <csc | ||||
|       target="exe" | ||||
|       debug="${build.debug}" | ||||
|       output="${bin_dir}/${assembly}.exe"> | ||||
|       <sources failonempty="true"> | ||||
| 	      <include name="*.cs" /> | ||||
| 	      <include name="Commands/**.cs" /> | ||||
| 	      <exclude name="Commands/Communication/TtsCommand.cs" /> | ||||
|       </sources> | ||||
|       <references basedir="${bin_dir}/"> | ||||
|         <include name="libsecondlife.dll"/> | ||||
|         <include name="openjpegnet.dll"/> | ||||
|       </references> | ||||
|     </csc> | ||||
|   </target> | ||||
| 
 | ||||
|   <target | ||||
|     name="build-dll" | ||||
|     description="Builds libsecondlife dll"> | ||||
|     <nant | ||||
|       buildfile="../../libsecondlife-cs/libsecondlife.build" | ||||
|       target="${project.config} build"/> | ||||
|   </target> | ||||
| 
 | ||||
|   <target | ||||
|     name="clean" | ||||
|     depends="init" | ||||
|     description="Deletes the current configuration"> | ||||
|     <delete failonerror="false"> | ||||
|       <fileset basedir="${bin_dir}/"> | ||||
|         <include name="${assembly}.exe" /> | ||||
|         <include name="${assembly}.pdb" /> | ||||
|         <include name="**/${assembly}.*.resources" /> | ||||
|       </fileset> | ||||
|     </delete> | ||||
|   </target> | ||||
| 
 | ||||
|   <target | ||||
|     name="*" | ||||
|     description="Handles unknown targets"> | ||||
|     <echo message="skip" /> | ||||
|   </target> | ||||
| </project> | ||||
|  | @ -0,0 +1,324 @@ | |||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Reflection; | ||||
| using System.Xml; | ||||
| using libsecondlife; | ||||
| using libsecondlife.Packets; | ||||
| using libsecondlife.AssetSystem; | ||||
| 
 | ||||
| namespace libsecondlife.TestClient | ||||
| { | ||||
|     public class TestClient : SecondLife | ||||
|     { | ||||
|         public delegate void PrimCreatedCallback(Simulator simulator, Primitive prim); | ||||
| 
 | ||||
|         public event PrimCreatedCallback OnPrimCreated; | ||||
| 
 | ||||
|         public Dictionary<Simulator, Dictionary<uint, Primitive>> SimPrims; | ||||
|         public LLUUID GroupID = LLUUID.Zero; | ||||
|         public Dictionary<LLUUID, GroupMember> GroupMembers; | ||||
|         public Dictionary<uint, Avatar> AvatarList = new Dictionary<uint,Avatar>(); | ||||
| 		public Dictionary<LLUUID, AvatarAppearancePacket> Appearances = new Dictionary<LLUUID, AvatarAppearancePacket>(); | ||||
| 		public Dictionary<string, Command> Commands = new Dictionary<string,Command>(); | ||||
| 		public bool Running = true; | ||||
|         public string MasterName = String.Empty; | ||||
|         public LLUUID MasterKey = LLUUID.Zero; | ||||
| 		public ClientManager ClientManager; | ||||
|         public int regionX; | ||||
|         public int regionY; | ||||
| 
 | ||||
|         //internal libsecondlife.InventorySystem.InventoryFolder currentDirectory; | ||||
| 
 | ||||
|         private System.Timers.Timer updateTimer; | ||||
|          | ||||
| 
 | ||||
|         /// <summary> | ||||
|         ///  | ||||
|         /// </summary> | ||||
|         public TestClient(ClientManager manager) | ||||
|         { | ||||
| 			ClientManager = manager; | ||||
| 
 | ||||
|             updateTimer = new System.Timers.Timer(1000); | ||||
|             updateTimer.Elapsed += new System.Timers.ElapsedEventHandler(updateTimer_Elapsed); | ||||
| 
 | ||||
|             RegisterAllCommands(Assembly.GetExecutingAssembly()); | ||||
| 
 | ||||
|             Settings.DEBUG = true; | ||||
|             Settings.STORE_LAND_PATCHES = true; | ||||
|             Settings.ALWAYS_REQUEST_OBJECTS = true; | ||||
| 
 | ||||
|             Network.RegisterCallback(PacketType.AgentDataUpdate, new NetworkManager.PacketCallback(AgentDataUpdateHandler)); | ||||
| 
 | ||||
|             Objects.OnNewPrim += new ObjectManager.NewPrimCallback(Objects_OnNewPrim); | ||||
|             Objects.OnObjectUpdated += new ObjectManager.ObjectUpdatedCallback(Objects_OnObjectUpdated); | ||||
|             Objects.OnObjectKilled += new ObjectManager.KillObjectCallback(Objects_OnObjectKilled); | ||||
| 			Objects.OnNewAvatar += new ObjectManager.NewAvatarCallback(Objects_OnNewAvatar); | ||||
|             Self.OnInstantMessage += new MainAvatar.InstantMessageCallback(Self_OnInstantMessage); | ||||
|             Groups.OnGroupMembers += new GroupManager.GroupMembersCallback(GroupMembersHandler); | ||||
|             this.OnLogMessage += new LogCallback(TestClient_OnLogMessage); | ||||
| 
 | ||||
|             Network.RegisterCallback(PacketType.AvatarAppearance, new NetworkManager.PacketCallback(AvatarAppearanceHandler)); | ||||
| 
 | ||||
|             updateTimer.Start(); | ||||
|         } | ||||
| 
 | ||||
|         public void RegisterAllCommands(Assembly assembly) | ||||
|         { | ||||
|             foreach (Type t in assembly.GetTypes()) | ||||
|             { | ||||
|                 try | ||||
|                 { | ||||
|                     if (t.IsSubclassOf(typeof(Command))) | ||||
|                     { | ||||
|                         ConstructorInfo info = t.GetConstructor(new Type[] { typeof(TestClient) }); | ||||
|                         Command command = (Command)info.Invoke(new object[] { this }); | ||||
|                         RegisterCommand(command); | ||||
|                     } | ||||
|                 } | ||||
|                 catch (Exception e) | ||||
|                 { | ||||
|                     Console.WriteLine(e.ToString()); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         public void RegisterCommand(Command command) | ||||
|         { | ||||
| 			command.Client = this; | ||||
| 			if (!Commands.ContainsKey(command.Name.ToLower())) | ||||
| 			{ | ||||
| 				Commands.Add(command.Name.ToLower(), command); | ||||
| 			} | ||||
|         } | ||||
| 
 | ||||
|         //breaks up large responses to deal with the max IM size | ||||
|         private void SendResponseIM(SecondLife client, LLUUID fromAgentID, string data, LLUUID imSessionID) | ||||
|         { | ||||
|             for ( int i = 0 ; i < data.Length ; i += 1024 ) { | ||||
|                 int y; | ||||
|                 if ((i + 1023) > data.Length) | ||||
|                 { | ||||
|                     y = data.Length - i; | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     y = 1023; | ||||
|                 } | ||||
|                 string message = data.Substring(i, y); | ||||
|                 client.Self.InstantMessage(fromAgentID, message, imSessionID); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
| 		public void DoCommand(string cmd, LLUUID fromAgentID, LLUUID imSessionID) | ||||
|         { | ||||
| 			string[] tokens = Parsing.ParseArguments(cmd); | ||||
| 
 | ||||
|             if (tokens.Length == 0) | ||||
|                 return; | ||||
| 				 | ||||
| 			string firstToken = tokens[0].ToLower(); | ||||
| 
 | ||||
|             // "all balance" will send the balance command to all currently logged in bots | ||||
| 			if (firstToken == "all" && tokens.Length > 1) | ||||
| 			{ | ||||
| 			    cmd = String.Empty; | ||||
| 
 | ||||
| 			    // Reserialize all of the arguments except for "all" | ||||
| 			    for (int i = 1; i < tokens.Length; i++) | ||||
| 			    { | ||||
| 			        cmd += tokens[i] + " "; | ||||
| 			    } | ||||
| 
 | ||||
| 			    ClientManager.DoCommandAll(cmd, fromAgentID, imSessionID); | ||||
| 
 | ||||
| 			    return; | ||||
| 			} | ||||
| 
 | ||||
|             if (Commands.ContainsKey(firstToken)) | ||||
|             { | ||||
|                 string[] args = new string[tokens.Length - 1]; | ||||
|                 Array.Copy(tokens, 1, args, 0, args.Length); | ||||
|                 string response = Commands[firstToken].Execute(args, fromAgentID); | ||||
| 
 | ||||
|                 if (response.Length > 0) | ||||
|                 { | ||||
|                     Console.WriteLine(response); | ||||
| 
 | ||||
|                     if (fromAgentID != null && Network.Connected) | ||||
|                     { | ||||
|                         // IMs don't like \r\n line endings, clean them up first | ||||
|                         response = response.Replace("\r", ""); | ||||
|                         SendResponseIM(this, fromAgentID, response, imSessionID); | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         private void updateTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) | ||||
|         { | ||||
|             foreach (Command c in Commands.Values) | ||||
|                 if (c.Active) | ||||
|                     c.Think(); | ||||
|         } | ||||
| 
 | ||||
|         private void AgentDataUpdateHandler(Packet packet, Simulator sim) | ||||
|         { | ||||
|             AgentDataUpdatePacket p = (AgentDataUpdatePacket)packet; | ||||
|             if (p.AgentData.AgentID == sim.Client.Network.AgentID) | ||||
|             { | ||||
|                 Console.WriteLine("Got the group ID for " + sim.Client.ToString() + ", requesting group members..."); | ||||
|                 GroupID = p.AgentData.ActiveGroupID; | ||||
| 
 | ||||
|                 sim.Client.Groups.BeginGetGroupMembers(GroupID); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         private void TestClient_OnLogMessage(string message, Helpers.LogLevel level) | ||||
|         { | ||||
|             Console.WriteLine("<" + this.ToString() + "> " + level.ToString() + ": " + message); | ||||
|         } | ||||
| 
 | ||||
|         private void GroupMembersHandler(Dictionary<LLUUID, GroupMember> members) | ||||
|         { | ||||
|             Console.WriteLine("Got " + members.Count + " group members."); | ||||
|             GroupMembers = members; | ||||
|         } | ||||
| 
 | ||||
|         private void Objects_OnObjectKilled(Simulator simulator, uint objectID) | ||||
|         { | ||||
|             lock (SimPrims) | ||||
|             { | ||||
|                 if (SimPrims.ContainsKey(simulator) && SimPrims[simulator].ContainsKey(objectID)) | ||||
|                     SimPrims[simulator].Remove(objectID); | ||||
|             } | ||||
| 
 | ||||
| 			lock (AvatarList) | ||||
| 			{ | ||||
| 			    if (AvatarList.ContainsKey(objectID)) | ||||
| 			        AvatarList.Remove(objectID); | ||||
| 			} | ||||
|         } | ||||
| 
 | ||||
|         private void Objects_OnObjectUpdated(Simulator simulator, ObjectUpdate update, ulong regionHandle, ushort timeDilation) | ||||
|         { | ||||
|             regionX = (int)(regionHandle >> 32); | ||||
|             regionY = (int)(regionHandle & 0xFFFFFFFF); | ||||
| 
 | ||||
|             if (update.Avatar) | ||||
|             { | ||||
|                 lock (AvatarList) | ||||
|                 { | ||||
|                     // TODO: We really need a solid avatar and object tracker in Utilities to use here | ||||
|                     if (AvatarList.ContainsKey(update.LocalID)) | ||||
|                     { | ||||
|                         AvatarList[update.LocalID].CollisionPlane = update.CollisionPlane; | ||||
|                         AvatarList[update.LocalID].Position = update.Position; | ||||
|                         AvatarList[update.LocalID].Velocity = update.Velocity; | ||||
|                         AvatarList[update.LocalID].Acceleration = update.Acceleration; | ||||
|                         AvatarList[update.LocalID].Rotation = update.Rotation; | ||||
|                         AvatarList[update.LocalID].AngularVelocity = update.AngularVelocity; | ||||
|                         AvatarList[update.LocalID].Textures = update.Textures; | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 lock (SimPrims) | ||||
|                 { | ||||
|                     if (SimPrims.ContainsKey(simulator) && SimPrims[simulator].ContainsKey(update.LocalID)) | ||||
|                     { | ||||
|                         SimPrims[simulator][update.LocalID].Position = update.Position; | ||||
|                         SimPrims[simulator][update.LocalID].Velocity = update.Velocity; | ||||
|                         SimPrims[simulator][update.LocalID].Acceleration = update.Acceleration; | ||||
|                         SimPrims[simulator][update.LocalID].Rotation = update.Rotation; | ||||
|                         SimPrims[simulator][update.LocalID].AngularVelocity = update.AngularVelocity; | ||||
|                         SimPrims[simulator][update.LocalID].Textures = update.Textures; | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         private void Objects_OnNewPrim(Simulator simulator, Primitive prim, ulong regionHandle, ushort timeDilation) | ||||
|         { | ||||
|             lock (SimPrims) | ||||
|             { | ||||
|                 if (!SimPrims.ContainsKey(simulator)) | ||||
|                 { | ||||
|                     SimPrims[simulator] = new Dictionary<uint, Primitive>(10000); | ||||
|                 } | ||||
| 
 | ||||
|                 SimPrims[simulator][prim.LocalID] = prim; | ||||
|             } | ||||
| 
 | ||||
|             if ((prim.Flags & LLObject.ObjectFlags.CreateSelected) != 0 && OnPrimCreated != null) | ||||
|             { | ||||
|                 OnPrimCreated(simulator, prim); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
| 		private void Objects_OnNewAvatar(Simulator simulator, Avatar avatar, ulong regionHandle, ushort timeDilation) | ||||
| 		{ | ||||
| 		    lock (AvatarList) | ||||
| 		    { | ||||
| 		        AvatarList[avatar.LocalID] = avatar; | ||||
| 		    } | ||||
| 		} | ||||
| 
 | ||||
|         private void AvatarAppearanceHandler(Packet packet, Simulator simulator) | ||||
|         { | ||||
|             AvatarAppearancePacket appearance = (AvatarAppearancePacket)packet; | ||||
| 
 | ||||
|             lock (Appearances) Appearances[appearance.Sender.ID] = appearance; | ||||
|         } | ||||
| 
 | ||||
|         private void Self_OnInstantMessage(LLUUID fromAgentID, string fromAgentName, LLUUID toAgentID,  | ||||
|             uint parentEstateID, LLUUID regionID, LLVector3 position, MainAvatar.InstantMessageDialog dialog,  | ||||
|             bool groupIM, LLUUID imSessionID, DateTime timestamp, string message,  | ||||
|             MainAvatar.InstantMessageOnline offline, byte[] binaryBucket) | ||||
|         { | ||||
|             if (MasterKey != LLUUID.Zero) | ||||
|             { | ||||
|                 if (fromAgentID != MasterKey) | ||||
|                 { | ||||
|                     // Received an IM from someone that is not the bot's master, ignore | ||||
|                     Console.WriteLine("<IM>" + fromAgentName + " (not master): " + message + "@"  + regionID.ToString() + ":" + position.ToString() ); | ||||
|                     return; | ||||
|                 } | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 if (GroupMembers != null && !GroupMembers.ContainsKey(fromAgentID)) | ||||
|                 { | ||||
|                     // Received an IM from someone outside the bot's group, ignore | ||||
|                     Console.WriteLine("<IM>" + fromAgentName + " (not in group): " + message + "@" + regionID.ToString() + ":" + position.ToString()); | ||||
|                     return; | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             Console.WriteLine("<IM>" + fromAgentName + ": " + message); | ||||
| 
 | ||||
|             if (dialog == MainAvatar.InstantMessageDialog.RequestTeleport) | ||||
|             { | ||||
|                 Console.WriteLine("Accepting teleport lure."); | ||||
|                 Self.TeleportLureRespond(fromAgentID, true); | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 if (dialog == MainAvatar.InstantMessageDialog.InventoryOffered) | ||||
|                 { | ||||
|                     Console.WriteLine("Accepting inventory offer."); | ||||
| 
 | ||||
|                     Self.InstantMessage(Self.FirstName + " " + Self.LastName, fromAgentID, String.Empty, | ||||
|                         imSessionID, MainAvatar.InstantMessageDialog.InventoryAccepted, | ||||
|                         MainAvatar.InstantMessageOnline.Offline, Self.Position, LLUUID.Zero, | ||||
|                         Self.InventoryRootFolderUUID.GetBytes()); | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     DoCommand(message, fromAgentID, imSessionID); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| 	} | ||||
| } | ||||
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							
		Loading…
	
		Reference in New Issue
	
	 Adam Frisby
						Adam Frisby