aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/ExportBot
diff options
context:
space:
mode:
Diffstat (limited to 'ExportBot')
-rw-r--r--ExportBot/Arguments.cs111
-rw-r--r--ExportBot/ClientManager.cs307
-rw-r--r--ExportBot/Command.cs29
-rw-r--r--ExportBot/Commands/AppearanceCommand.cs29
-rw-r--r--ExportBot/Commands/CloneProfileCommand.cs131
-rw-r--r--ExportBot/Commands/Communication/EchoMasterCommand.cs42
-rw-r--r--ExportBot/Commands/Communication/IMCommand.cs71
-rw-r--r--ExportBot/Commands/Communication/SayCommand.cs44
-rw-r--r--ExportBot/Commands/Communication/ShoutCommand.cs49
-rw-r--r--ExportBot/Commands/Communication/TtsCommand.cs51
-rw-r--r--ExportBot/Commands/Communication/WhisperCommand.cs49
-rw-r--r--ExportBot/Commands/DebugCommand.cs37
-rw-r--r--ExportBot/Commands/DilationCommand.cs22
-rw-r--r--ExportBot/Commands/DumpOutfitCommand.cs98
-rw-r--r--ExportBot/Commands/ExportCommand.cs209
-rw-r--r--ExportBot/Commands/ExportOutfitCommand.cs66
-rw-r--r--ExportBot/Commands/ExportParticlesCommand.cs119
-rw-r--r--ExportBot/Commands/FindSimCommand.cs43
-rw-r--r--ExportBot/Commands/HelpCommand.cs29
-rw-r--r--ExportBot/Commands/ImportCommand.cs246
-rw-r--r--ExportBot/Commands/ImportOutfitCommand.cs66
-rw-r--r--ExportBot/Commands/Inventory/BalanceCommand.cs21
-rw-r--r--ExportBot/Commands/Inventory/DeleteFolderCommand.cs43
-rw-r--r--ExportBot/Commands/Inventory/GiveAllCommand.cs27
-rw-r--r--ExportBot/Commands/Inventory/InventoryCommand.cs62
-rw-r--r--ExportBot/Commands/Inventory/WearCommand.cs43
-rw-r--r--ExportBot/Commands/LoadCommand.cs28
-rw-r--r--ExportBot/Commands/LoginCommand.cs34
-rw-r--r--ExportBot/Commands/LogoutCommand.cs24
-rw-r--r--ExportBot/Commands/MD5Command.cs22
-rw-r--r--ExportBot/Commands/Movement/FollowCommand.cs90
-rw-r--r--ExportBot/Commands/Movement/GotoCommand.cs53
-rw-r--r--ExportBot/Commands/Movement/JumpCommand.cs34
-rw-r--r--ExportBot/Commands/Movement/LocationCommand.cs23
-rw-r--r--ExportBot/Commands/Movement/MoveToCommand.cs24
-rw-r--r--ExportBot/Commands/Movement/SitCommand.cs52
-rw-r--r--ExportBot/Commands/Movement/SitOnCommand.cs54
-rw-r--r--ExportBot/Commands/Movement/StandCommand.cs47
-rw-r--r--ExportBot/Commands/PacketLogCommand.cs84
-rw-r--r--ExportBot/Commands/ParcelInfoCommand.cs62
-rw-r--r--ExportBot/Commands/PrimCountCommand.cs32
-rw-r--r--ExportBot/Commands/QuitCommand.cs24
-rw-r--r--ExportBot/Commands/RegionInfoCommand.cs45
-rw-r--r--ExportBot/Commands/SetMasterCommand.cs73
-rw-r--r--ExportBot/Commands/SetMasterKeyCommand.cs35
-rw-r--r--ExportBot/Commands/ShowEffectsCommand.cs76
-rw-r--r--ExportBot/Commands/StatsCommand.cs39
-rw-r--r--ExportBot/Commands/TouchCommand.cs55
-rw-r--r--ExportBot/Commands/TreeCommand.cs51
-rw-r--r--ExportBot/Commands/UptimeCommand.cs25
-rw-r--r--ExportBot/Commands/WhoCommand.cs29
-rw-r--r--ExportBot/Parsing.cs61
-rw-r--r--ExportBot/Program.cs127
-rw-r--r--ExportBot/Properties/AssemblyInfo.cs33
-rw-r--r--ExportBot/README5
-rw-r--r--ExportBot/TestClient.build125
-rw-r--r--ExportBot/TestClient.cs328
-rw-r--r--ExportBot/TestClient.csproj120
58 files changed, 3958 insertions, 0 deletions
diff --git a/ExportBot/Arguments.cs b/ExportBot/Arguments.cs
new file mode 100644
index 0000000..01d852d
--- /dev/null
+++ b/ExportBot/Arguments.cs
@@ -0,0 +1,111 @@
1using System;
2using System.Collections.Specialized;
3using System.Text.RegularExpressions;
4
5namespace CommandLine.Utility
6{
7 /// <summary>
8 /// Arguments class
9 /// </summary>
10 public class Arguments
11 {
12 // Variables
13 private StringDictionary Parameters;
14
15 // Constructor
16 public Arguments(string[] Args)
17 {
18 Parameters = new StringDictionary();
19 Regex Splitter = new Regex(@"^-{1,2}|=|:",
20 RegexOptions.IgnoreCase | RegexOptions.Compiled);
21
22 Regex Remover = new Regex(@"^['""]?(.*?)['""]?$",
23 RegexOptions.IgnoreCase | RegexOptions.Compiled);
24
25 string Parameter = null;
26 string[] Parts;
27
28 // Valid parameters forms:
29 // {-,/,--}param{ ,=,:}((",')value(",'))
30 // Examples:
31 // -param1 value1 --param2 /param3:"Test-:-work"
32 // /param4=happy -param5 '--=nice=--'
33 foreach (string Txt in Args)
34 {
35 // Look for new parameters (-,/ or --) and a
36 // possible enclosed value (=,:)
37 Parts = Splitter.Split(Txt, 3);
38
39 switch (Parts.Length)
40 {
41 // Found a value (for the last parameter
42 // found (space separator))
43 case 1:
44 if (Parameter != null)
45 {
46 if (!Parameters.ContainsKey(Parameter))
47 {
48 Parts[0] =
49 Remover.Replace(Parts[0], "$1");
50
51 Parameters.Add(Parameter, Parts[0]);
52 }
53 Parameter = null;
54 }
55 // else Error: no parameter waiting for a value (skipped)
56 break;
57
58 // Found just a parameter
59 case 2:
60 // The last parameter is still waiting.
61 // With no value, set it to true.
62 if (Parameter != null)
63 {
64 if (!Parameters.ContainsKey(Parameter))
65 Parameters.Add(Parameter, "true");
66 }
67 Parameter = Parts[1];
68 break;
69
70 // Parameter with enclosed value
71 case 3:
72 // The last parameter is still waiting.
73 // With no value, set it to true.
74 if (Parameter != null)
75 {
76 if (!Parameters.ContainsKey(Parameter))
77 Parameters.Add(Parameter, "true");
78 }
79
80 Parameter = Parts[1];
81
82 // Remove possible enclosing characters (",')
83 if (!Parameters.ContainsKey(Parameter))
84 {
85 Parts[2] = Remover.Replace(Parts[2], "$1");
86 Parameters.Add(Parameter, Parts[2]);
87 }
88
89 Parameter = null;
90 break;
91 }
92 }
93 // In case a parameter is still waiting
94 if (Parameter != null)
95 {
96 if (!Parameters.ContainsKey(Parameter))
97 Parameters.Add(Parameter, "true");
98 }
99 }
100
101 // Retrieve a parameter value if it exists
102 // (overriding C# indexer property)
103 public string this[string Param]
104 {
105 get
106 {
107 return (Parameters[Param]);
108 }
109 }
110 }
111}
diff --git a/ExportBot/ClientManager.cs b/ExportBot/ClientManager.cs
new file mode 100644
index 0000000..0e43142
--- /dev/null
+++ b/ExportBot/ClientManager.cs
@@ -0,0 +1,307 @@
1using System;
2using System.Collections.Generic;
3using System.Reflection;
4using System.Xml;
5using System.Threading;
6using libsecondlife;
7using libsecondlife.Packets;
8using libsecondlife.AssetSystem;
9
10namespace libsecondlife.TestClient
11{
12 public class LoginDetails
13 {
14 public string FirstName;
15 public string LastName;
16 public string Password;
17 public string StartLocation;
18 public string MasterName;
19 public LLUUID MasterKey;
20 }
21
22 public class StartPosition
23 {
24 public string sim;
25 public int x;
26 public int y;
27 public int z;
28
29 public StartPosition()
30 {
31 this.sim = null;
32 this.x = 0;
33 this.y = 0;
34 this.z = 0;
35 }
36 }
37
38 public class ClientManager
39 {
40 public Dictionary<LLUUID, SecondLife> Clients = new Dictionary<LLUUID, SecondLife>();
41 public Dictionary<Simulator, Dictionary<uint, Primitive>> SimPrims = new Dictionary<Simulator, Dictionary<uint, Primitive>>();
42
43 public bool Running = true;
44
45 string contactPerson = String.Empty;
46 private LLUUID resolvedMasterKey = LLUUID.Zero;
47 private ManualResetEvent keyResolution = new ManualResetEvent(false);
48
49 /// <summary>
50 ///
51 /// </summary>
52 /// <param name="accounts"></param>
53 public ClientManager(List<LoginDetails> accounts, string c)
54 {
55 this.contactPerson = c;
56 foreach (LoginDetails account in accounts)
57 Login(account);
58 }
59
60 public ClientManager(List<LoginDetails> accounts, string c, string s)
61 {
62 this.contactPerson = c;
63 char sep = '/';
64 string[] startbits = s.Split(sep);
65
66 foreach (LoginDetails account in accounts)
67 {
68 account.StartLocation = NetworkManager.StartLocation(startbits[0], Int32.Parse(startbits[1]),
69 Int32.Parse(startbits[2]), Int32.Parse(startbits[3]));
70 Login(account);
71 }
72 }
73 /// <summary>
74 ///
75 /// </summary>
76 /// <param name="account"></param>
77 /// <returns></returns>
78 public TestClient Login(LoginDetails account)
79 {
80 // Check if this client is already logged in
81 foreach (TestClient c in Clients.Values)
82 {
83 if (c.Self.FirstName == account.FirstName && c.Self.LastName == account.LastName)
84 {
85 Logout(c);
86 break;
87 }
88 }
89
90 TestClient client = new TestClient(this);
91
92 // Optimize the throttle
93 client.Throttle.Wind = 0;
94 client.Throttle.Cloud = 0;
95 client.Throttle.Land = 1000000;
96 client.Throttle.Task = 1000000;
97
98 client.SimPrims = SimPrims;
99 client.MasterName = account.MasterName;
100 client.MasterKey = account.MasterKey;
101
102 if (!String.IsNullOrEmpty(account.StartLocation))
103 {
104 if (!client.Network.Login(account.FirstName, account.LastName, account.Password, "TestClient",
105 account.StartLocation, contactPerson))
106 {
107 Console.WriteLine("Failed to login " + account.FirstName + " " + account.LastName + ": " +
108 client.Network.LoginMessage);
109 }
110 }
111 else
112 {
113 if (!client.Network.Login(account.FirstName, account.LastName, account.Password, "TestClient",
114 contactPerson))
115 {
116 Console.WriteLine("Failed to login " + account.FirstName + " " + account.LastName + ": " +
117 client.Network.LoginStatusMessage);
118 }
119 }
120
121 if (client.Network.Connected)
122 {
123 if (account.MasterKey == LLUUID.Zero && !String.IsNullOrEmpty(account.MasterName))
124 {
125 Console.WriteLine("Resolving {0}'s UUID", account.MasterName);
126 // Find master's key from name
127 DirectoryManager.DirPeopleReplyCallback callback = new DirectoryManager.DirPeopleReplyCallback(KeyResolvHandler);
128 client.Directory.OnDirPeopleReply += callback;
129 client.Directory.StartPeopleSearch(DirectoryManager.DirFindFlags.People, account.MasterName);
130 if (keyResolution.WaitOne(TimeSpan.FromMinutes(1), false))
131 {
132 account.MasterKey = resolvedMasterKey;
133 Console.WriteLine("\"{0}\" resolved to {1}", account.MasterName, account.MasterKey);
134 }
135 else
136 {
137 Console.WriteLine("Unable to obtain UUID for \"{0}\". No master will be used. Try specifying a key with --masterkey.", account.MasterName);
138 }
139 client.Directory.OnDirPeopleReply -= callback;
140 keyResolution.Reset();
141 }
142
143 client.MasterKey = account.MasterKey;
144
145 Clients[client.Network.AgentID] = client;
146
147 Console.WriteLine("Logged in " + client.ToString());
148 }
149
150 return client;
151 }
152
153 private void KeyResolvHandler(LLUUID queryid, List<DirectoryManager.AgentSearchData> matches)
154 {
155 LLUUID master = matches[0].AgentID;
156 if (matches.Count > 1)
157 {
158 Console.WriteLine("Possible masters:");
159 for (int i = 0; i < matches.Count; ++i)
160 {
161 Console.WriteLine("{0}: {1}", i, matches[i].FirstName + " " + matches[i].LastName);
162 }
163 Console.Write("Ambiguous master, choose one:");
164 string read = Console.ReadLine();
165 while (read != null)
166 {
167 int choice = 0;
168 if (int.TryParse(read, out choice))
169 {
170 master = matches[choice].AgentID;
171 break;
172 }
173 else
174 {
175 Console.WriteLine("Responce misunderstood.");
176 Console.Write("Type the corresponding number:");
177 }
178 read = Console.ReadLine();
179 }
180 }
181 resolvedMasterKey = master;
182 keyResolution.Set();
183 }
184
185 /// <summary>
186 ///
187 /// </summary>
188 /// <param name="args"></param>
189 /// <returns></returns>
190 public TestClient Login(string[] args)
191 {
192 LoginDetails account = new LoginDetails();
193 account.FirstName = args[0];
194 account.LastName = args[1];
195 account.Password = args[2];
196
197 if (args.Length == 4)
198 {
199 account.StartLocation = NetworkManager.StartLocation(args[3], 128, 128, 40);
200 }
201
202 return Login(account);
203 }
204
205 /// <summary>
206 ///
207 /// </summary>
208 public void Run()
209 {
210 Console.WriteLine("Type quit to exit. Type help for a command list.");
211
212 while (Running)
213 {
214 PrintPrompt();
215 string input = Console.ReadLine();
216 DoCommandAll(input, null, null);
217 }
218
219 foreach (SecondLife client in Clients.Values)
220 {
221 if (client.Network.Connected)
222 client.Network.Logout();
223 }
224 }
225
226 private void PrintPrompt()
227 {
228 int online = 0;
229
230 foreach (SecondLife client in Clients.Values)
231 {
232 if (client.Network.Connected) online++;
233 }
234
235 Console.Write(online + " avatars online> ");
236 }
237
238 /// <summary>
239 ///
240 /// </summary>
241 /// <param name="cmd"></param>
242 /// <param name="fromAgentID"></param>
243 /// <param name="imSessionID"></param>
244 public void DoCommandAll(string cmd, LLUUID fromAgentID, LLUUID imSessionID)
245 {
246 string[] tokens = cmd.Trim().Split(new char[] { ' ', '\t' });
247 string firstToken = tokens[0].ToLower();
248
249 if (tokens.Length == 0)
250 return;
251
252 if (firstToken == "login")
253 {
254 // Special login case: Only call it once, and allow it with
255 // no logged in avatars
256 string[] args = new string[tokens.Length - 1];
257 Array.Copy(tokens, 1, args, 0, args.Length);
258 Login(args);
259 }
260 else if (firstToken == "quit")
261 {
262 Quit();
263 Console.WriteLine("All clients logged out and program finished running.");
264 }
265 else
266 {
267 // make a copy of the clients list so that it can be iterated without fear of being changed during iteration
268 Dictionary<LLUUID, SecondLife> clientsCopy = new Dictionary<LLUUID, SecondLife>(Clients);
269
270 foreach (TestClient client in clientsCopy.Values)
271 client.DoCommand(cmd, fromAgentID, imSessionID);
272 }
273 }
274
275 /// <summary>
276 ///
277 /// </summary>
278 /// <param name="client"></param>
279 public void Logout(TestClient client)
280 {
281 Clients.Remove(client.Network.AgentID);
282 client.Network.Logout();
283 }
284
285 /// <summary>
286 ///
287 /// </summary>
288 public void LogoutAll()
289 {
290 // make a copy of the clients list so that it can be iterated without fear of being changed during iteration
291 Dictionary<LLUUID, SecondLife> clientsCopy = new Dictionary<LLUUID, SecondLife>(Clients);
292
293 foreach (TestClient client in clientsCopy.Values)
294 Logout(client);
295 }
296
297 /// <summary>
298 ///
299 /// </summary>
300 public void Quit()
301 {
302 LogoutAll();
303 Running = false;
304 // TODO: It would be really nice if we could figure out a way to abort the ReadLine here in so that Run() will exit.
305 }
306 }
307}
diff --git a/ExportBot/Command.cs b/ExportBot/Command.cs
new file mode 100644
index 0000000..5f92f32
--- /dev/null
+++ b/ExportBot/Command.cs
@@ -0,0 +1,29 @@
1using System;
2using System.Collections.Generic;
3using System.Text;
4using libsecondlife;
5using libsecondlife.Packets;
6
7namespace libsecondlife.TestClient
8{
9 public abstract class Command
10 {
11 public string Name;
12 public string Description;
13 public TestClient Client;
14
15 public abstract string Execute(string[] args, LLUUID fromAgentID);
16
17 /// <summary>
18 /// When set to true, think will be called.
19 /// </summary>
20 public bool Active;
21
22 /// <summary>
23 /// Called twice per second, when Command.Active is set to true.
24 /// </summary>
25 public virtual void Think()
26 {
27 }
28 }
29}
diff --git a/ExportBot/Commands/AppearanceCommand.cs b/ExportBot/Commands/AppearanceCommand.cs
new file mode 100644
index 0000000..6f003a7
--- /dev/null
+++ b/ExportBot/Commands/AppearanceCommand.cs
@@ -0,0 +1,29 @@
1using System;
2using System.Collections.Generic;
3using System.Text;
4using libsecondlife;
5using libsecondlife.Packets;
6
7namespace libsecondlife.TestClient
8{
9 public class AppearanceCommand : Command
10 {
11 Utilities.Assets.AssetManager Assets;
12 Utilities.Appearance.AppearanceManager Appearance;
13
14 public AppearanceCommand(TestClient testClient)
15 {
16 Name = "appearance";
17 Description = "Set your current appearance to your last saved appearance";
18
19 Assets = new libsecondlife.Utilities.Assets.AssetManager(testClient);
20 Appearance = new libsecondlife.Utilities.Appearance.AppearanceManager(testClient, Assets);
21 }
22
23 public override string Execute(string[] args, LLUUID fromAgentID)
24 {
25 Appearance.SetPreviousAppearance();
26 return "Done.";
27 }
28 }
29}
diff --git a/ExportBot/Commands/CloneProfileCommand.cs b/ExportBot/Commands/CloneProfileCommand.cs
new file mode 100644
index 0000000..d7fb5fc
--- /dev/null
+++ b/ExportBot/Commands/CloneProfileCommand.cs
@@ -0,0 +1,131 @@
1using System;
2using System.Collections.Generic;
3using System.Threading;
4using libsecondlife;
5using libsecondlife.Packets;
6
7namespace libsecondlife.TestClient
8{
9 public class CloneProfileCommand : Command
10 {
11 Avatar.AvatarProperties Properties;
12 Avatar.Interests Interests;
13 List<LLUUID> Groups = new List<LLUUID>();
14 bool ReceivedProperties = false;
15 bool ReceivedInterests = false;
16 bool ReceivedGroups = false;
17 ManualResetEvent ReceivedProfileEvent = new ManualResetEvent(false);
18
19 public CloneProfileCommand(TestClient testClient)
20 {
21 testClient.Avatars.OnAvatarInterests += new AvatarManager.AvatarInterestsCallback(Avatars_OnAvatarInterests);
22 testClient.Avatars.OnAvatarProperties += new AvatarManager.AvatarPropertiesCallback(Avatars_OnAvatarProperties);
23 testClient.Avatars.OnAvatarGroups += new AvatarManager.AvatarGroupsCallback(Avatars_OnAvatarGroups);
24 testClient.Self.OnJoinGroup += new MainAvatar.JoinGroupCallback(Self_OnJoinGroup);
25
26 Name = "cloneprofile";
27 Description = "Clones another avatars profile as closely as possible. WARNING: This command will " +
28 "destroy your existing profile! Usage: cloneprofile [targetuuid]";
29 }
30
31 public override string Execute(string[] args, LLUUID fromAgentID)
32 {
33 if (args.Length != 1)
34 return Description;
35
36 LLUUID targetID;
37 ReceivedProperties = false;
38 ReceivedInterests = false;
39 ReceivedGroups = false;
40
41 try
42 {
43 targetID = new LLUUID(args[0]);
44 }
45 catch (Exception)
46 {
47 return Description;
48 }
49
50 // Request all of the packets that make up an avatar profile
51 Client.Avatars.RequestAvatarProperties(targetID);
52
53 // Wait for all the packets to arrive
54 ReceivedProfileEvent.Reset();
55 ReceivedProfileEvent.WaitOne(5000, false);
56
57 // Check if everything showed up
58 if (!ReceivedInterests || !ReceivedProperties || !ReceivedGroups)
59 return "Failed to retrieve a complete profile for that UUID";
60
61 // Synchronize our profile
62 Client.Self.ProfileInterests = Interests;
63 Client.Self.ProfileProperties = Properties;
64 Client.Self.SetAvatarInformation();
65
66 // TODO: Leave all the groups we're currently a member of? This could
67 // break TestClient connectivity that might be relying on group authentication
68
69 // Attempt to join all the groups
70 foreach (LLUUID groupID in Groups)
71 {
72 Client.Self.RequestJoinGroup(groupID);
73 }
74
75 return "Synchronized our profile to the profile of " + targetID.ToStringHyphenated();
76 }
77
78 void Avatars_OnAvatarProperties(LLUUID avatarID, Avatar.AvatarProperties properties)
79 {
80 lock (ReceivedProfileEvent)
81 {
82 Properties = properties;
83 ReceivedProperties = true;
84
85 if (ReceivedInterests && ReceivedProperties && ReceivedGroups)
86 ReceivedProfileEvent.Set();
87 }
88 }
89
90 void Avatars_OnAvatarInterests(LLUUID avatarID, Avatar.Interests interests)
91 {
92 lock (ReceivedProfileEvent)
93 {
94 Interests = interests;
95 ReceivedInterests = true;
96
97 if (ReceivedInterests && ReceivedProperties && ReceivedGroups)
98 ReceivedProfileEvent.Set();
99 }
100 }
101
102 void Avatars_OnAvatarGroups(LLUUID avatarID, AvatarGroupsReplyPacket.GroupDataBlock[] groups)
103 {
104 lock (ReceivedProfileEvent)
105 {
106 foreach (AvatarGroupsReplyPacket.GroupDataBlock block in groups)
107 {
108 Groups.Add(block.GroupID);
109 }
110
111 ReceivedGroups = true;
112
113 if (ReceivedInterests && ReceivedProperties && ReceivedGroups)
114 ReceivedProfileEvent.Set();
115 }
116 }
117
118 void Self_OnJoinGroup(LLUUID groupID, bool success)
119 {
120 Console.WriteLine(Client.ToString() + (success ? " joined " : " failed to join ") +
121 groupID.ToStringHyphenated());
122
123 if (success)
124 {
125 Console.WriteLine(Client.ToString() + " setting " + groupID.ToStringHyphenated() +
126 " as the active group");
127 Client.Self.ActivateGroup(groupID);
128 }
129 }
130 }
131}
diff --git a/ExportBot/Commands/Communication/EchoMasterCommand.cs b/ExportBot/Commands/Communication/EchoMasterCommand.cs
new file mode 100644
index 0000000..2e426a8
--- /dev/null
+++ b/ExportBot/Commands/Communication/EchoMasterCommand.cs
@@ -0,0 +1,42 @@
1using System;
2using System.Collections.Generic;
3using System.Text;
4using libsecondlife;
5using libsecondlife.Packets;
6
7namespace libsecondlife.TestClient
8{
9 public class EchoMasterCommand: Command
10 {
11 public EchoMasterCommand(TestClient testClient)
12 {
13 Name = "echoMaster";
14 Description = "Repeat everything that master says.";
15 }
16
17 public override string Execute(string[] args, LLUUID fromAgentID)
18 {
19 if (!Active)
20 {
21 Active = true;
22 Client.Self.OnChat += new MainAvatar.ChatCallback(Self_OnChat);
23 return "Echoing is now on.";
24 }
25 else
26 {
27 Active = false;
28 Client.Self.OnChat -= new MainAvatar.ChatCallback(Self_OnChat);
29 return "Echoing is now off.";
30 }
31 }
32
33 void Self_OnChat(string message, MainAvatar.ChatAudibleLevel audible, MainAvatar.ChatType type,
34 MainAvatar.ChatSourceType sourcetype, string fromName, LLUUID id, LLUUID ownerid, LLVector3 position)
35 {
36 if (message.Length > 0 && Client.MasterKey == id)
37 {
38 Client.Self.Chat(message, 0, MainAvatar.ChatType.Normal);
39 }
40 }
41 }
42}
diff --git a/ExportBot/Commands/Communication/IMCommand.cs b/ExportBot/Commands/Communication/IMCommand.cs
new file mode 100644
index 0000000..32d7fff
--- /dev/null
+++ b/ExportBot/Commands/Communication/IMCommand.cs
@@ -0,0 +1,71 @@
1using System;
2using System.Collections.Generic;
3using System.Threading;
4using libsecondlife;
5using libsecondlife.Packets;
6
7namespace libsecondlife.TestClient
8{
9 public class ImCommand : Command
10 {
11 string ToAvatarName = String.Empty;
12 ManualResetEvent NameSearchEvent = new ManualResetEvent(false);
13 Dictionary<string, LLUUID> Name2Key = new Dictionary<string, LLUUID>();
14
15 public ImCommand(TestClient testClient)
16 {
17 testClient.Avatars.OnAvatarNameSearch += new AvatarManager.AvatarNameSearchCallback(Avatars_OnAvatarNameSearch);
18
19 Name = "im";
20 Description = "Instant message someone. Usage: im [firstname] [lastname] [message]";
21 }
22
23 public override string Execute(string[] args, LLUUID fromAgentID)
24 {
25 if (args.Length < 3)
26 return "Usage: im [firstname] [lastname] [message]";
27
28 ToAvatarName = args[0] + " " + args[1];
29
30 // Build the message
31 string message = String.Empty;
32 for (int ct = 2; ct < args.Length; ct++)
33 message += args[ct] + " ";
34 message = message.TrimEnd();
35 if (message.Length > 1023) message = message.Remove(1023);
36
37 if (!Name2Key.ContainsKey(ToAvatarName.ToLower()))
38 {
39 // Send the Query
40 Client.Avatars.RequestAvatarNameSearch(ToAvatarName, LLUUID.Random());
41
42 NameSearchEvent.WaitOne(6000, false);
43 }
44
45 if (Name2Key.ContainsKey(ToAvatarName.ToLower()))
46 {
47 LLUUID id = Name2Key[ToAvatarName.ToLower()];
48
49 Client.Self.InstantMessage(id, message, id);
50 return "Instant Messaged " + id.ToStringHyphenated() + " with message: " + message;
51 }
52 else
53 {
54 return "Name lookup for " + ToAvatarName + " failed";
55 }
56 }
57
58 void Avatars_OnAvatarNameSearch(LLUUID queryID, Dictionary<LLUUID, string> avatars)
59 {
60 foreach (KeyValuePair<LLUUID, string> kvp in avatars)
61 {
62 if (kvp.Value.ToLower() == ToAvatarName.ToLower())
63 {
64 Name2Key[ToAvatarName.ToLower()] = kvp.Key;
65 NameSearchEvent.Set();
66 return;
67 }
68 }
69 }
70 }
71}
diff --git a/ExportBot/Commands/Communication/SayCommand.cs b/ExportBot/Commands/Communication/SayCommand.cs
new file mode 100644
index 0000000..d5717a6
--- /dev/null
+++ b/ExportBot/Commands/Communication/SayCommand.cs
@@ -0,0 +1,44 @@
1using System;
2using System.Collections.Generic;
3using System.Text;
4using libsecondlife;
5
6namespace libsecondlife.TestClient
7{
8 public class SayCommand: Command
9 {
10 public SayCommand(TestClient testClient)
11 {
12 Name = "say";
13 Description = "Say something. (usage: say (optional channel) whatever)";
14 }
15
16 public override string Execute(string[] args, LLUUID fromAgentID)
17 {
18 int channel = 0;
19 int startIndex = 0;
20
21 if (args.Length < 1)
22 {
23 return "usage: say (optional channel) whatever";
24 }
25 else if (args.Length > 1)
26 {
27 if (Int32.TryParse(args[0], out channel))
28 startIndex = 1;
29 }
30
31 StringBuilder message = new StringBuilder();
32
33 for (int i = startIndex; i < args.Length; i++)
34 {
35 message.Append(args[i]);
36 if (i != args.Length - 1) message.Append(" ");
37 }
38
39 Client.Self.Chat(message.ToString(), channel, MainAvatar.ChatType.Normal);
40
41 return "Said " + message.ToString();
42 }
43 }
44}
diff --git a/ExportBot/Commands/Communication/ShoutCommand.cs b/ExportBot/Commands/Communication/ShoutCommand.cs
new file mode 100644
index 0000000..cf4b6c5
--- /dev/null
+++ b/ExportBot/Commands/Communication/ShoutCommand.cs
@@ -0,0 +1,49 @@
1using System;
2using System.Collections.Generic;
3using System.Text;
4using libsecondlife;
5using libsecondlife.Packets;
6
7namespace libsecondlife.TestClient
8{
9 public class ShoutCommand : Command
10 {
11 public ShoutCommand(TestClient testClient)
12 {
13 Name = "shout";
14 Description = "Shout something.";
15 }
16
17 public override string Execute(string[] args, LLUUID fromAgentID)
18 {
19 int channel = 0;
20 int startIndex = 0;
21 string message = String.Empty;
22 if (args.Length < 1)
23 {
24 return "usage: shout (optional channel) whatever";
25 }
26 else if (args.Length > 1)
27 {
28 try
29 {
30 channel = Convert.ToInt32(args[0]);
31 startIndex = 1;
32 }
33 catch (FormatException)
34 {
35 channel = 0;
36 }
37 }
38
39 for (int i = startIndex; i < args.Length; i++)
40 {
41 message += args[i] + " ";
42 }
43
44 Client.Self.Chat(message, channel, MainAvatar.ChatType.Shout);
45
46 return "Shouted " + message;
47 }
48 }
49}
diff --git a/ExportBot/Commands/Communication/TtsCommand.cs b/ExportBot/Commands/Communication/TtsCommand.cs
new file mode 100644
index 0000000..e8bd122
--- /dev/null
+++ b/ExportBot/Commands/Communication/TtsCommand.cs
@@ -0,0 +1,51 @@
1using System;
2using System.Collections.Generic;
3using System.Text;
4using System.Speech.Synthesis;
5using libsecondlife;
6using libsecondlife.Packets;
7using libsecondlife.AssetSystem;
8
9
10// Since this requires .Net 3.0 I've left it out of the project by default.
11// To use this: include it in the project and add a reference to the System.Speech.dll
12
13namespace libsecondlife.TestClient
14{
15 public class TtsCommand : Command
16 {
17 SpeechSynthesizer _speechSynthesizer;
18
19 public TtsCommand(TestClient testClient)
20 {
21 Name = "tts";
22 Description = "Text To Speech. When activated, client will echo all recieved chat messages out thru the computer's speakers.";
23 }
24
25 public override string Execute(string[] args, LLUUID fromAgentID)
26 {
27 if (!Active)
28 {
29 if (_speechSynthesizer == null)
30 _speechSynthesizer = new SpeechSynthesizer();
31 Active = true;
32 Client.Self.OnChat += new MainAvatar.ChatCallback(Self_OnChat);
33 return "TTS is now on.";
34 }
35 else
36 {
37 Active = false;
38 Client.Self.OnChat -= new MainAvatar.ChatCallback(Self_OnChat);
39 return "TTS is now off.";
40 }
41 }
42
43 void Self_OnChat(string message, byte audible, byte type, byte sourcetype, string fromName, LLUUID id, LLUUID ownerid, LLVector3 position)
44 {
45 if (message.Length > 0)
46 {
47 _speechSynthesizer.SpeakAsync(message);
48 }
49 }
50 }
51} \ No newline at end of file
diff --git a/ExportBot/Commands/Communication/WhisperCommand.cs b/ExportBot/Commands/Communication/WhisperCommand.cs
new file mode 100644
index 0000000..89ba0f3
--- /dev/null
+++ b/ExportBot/Commands/Communication/WhisperCommand.cs
@@ -0,0 +1,49 @@
1using System;
2using System.Collections.Generic;
3using System.Text;
4using libsecondlife;
5using libsecondlife.Packets;
6
7namespace libsecondlife.TestClient
8{
9 public class WhisperCommand : Command
10 {
11 public WhisperCommand(TestClient testClient)
12 {
13 Name = "whisper";
14 Description = "Whisper something.";
15 }
16
17 public override string Execute(string[] args, LLUUID fromAgentID)
18 {
19 int channel = 0;
20 int startIndex = 0;
21 string message = String.Empty;
22 if (args.Length < 1)
23 {
24 return "usage: whisper (optional channel) whatever";
25 }
26 else if (args.Length > 1)
27 {
28 try
29 {
30 channel = Convert.ToInt32(args[0]);
31 startIndex = 1;
32 }
33 catch (FormatException)
34 {
35 channel = 0;
36 }
37 }
38
39 for (int i = startIndex; i < args.Length; i++)
40 {
41 message += args[i] + " ";
42 }
43
44 Client.Self.Chat(message, channel, MainAvatar.ChatType.Whisper);
45
46 return "Whispered " + message;
47 }
48 }
49}
diff --git a/ExportBot/Commands/DebugCommand.cs b/ExportBot/Commands/DebugCommand.cs
new file mode 100644
index 0000000..fbfde7c
--- /dev/null
+++ b/ExportBot/Commands/DebugCommand.cs
@@ -0,0 +1,37 @@
1using System;
2using System.Collections.Generic;
3using libsecondlife;
4using libsecondlife.Packets;
5
6namespace libsecondlife.TestClient
7{
8 public class DebugCommand : Command
9 {
10 public DebugCommand(TestClient testClient)
11 {
12 Name = "debug";
13 Description = "Turn debug messages on or off. Usage: debug [on/off]";
14 }
15
16 public override string Execute(string[] args, LLUUID fromAgentID)
17 {
18 if (args.Length != 1)
19 return "Usage: debug [on/off]";
20
21 if (args[0].ToLower() == "on")
22 {
23 Client.Settings.DEBUG = true;
24 return "Debug logging is on";
25 }
26 else if (args[0].ToLower() == "off")
27 {
28 Client.Settings.DEBUG = false;
29 return "Debug logging is off";
30 }
31 else
32 {
33 return "Usage: debug [on/off]";
34 }
35 }
36 }
37}
diff --git a/ExportBot/Commands/DilationCommand.cs b/ExportBot/Commands/DilationCommand.cs
new file mode 100644
index 0000000..c1d3c04
--- /dev/null
+++ b/ExportBot/Commands/DilationCommand.cs
@@ -0,0 +1,22 @@
1using System;
2using System.Collections.Generic;
3using System.Text;
4using libsecondlife;
5using libsecondlife.Packets;
6
7namespace libsecondlife.TestClient
8{
9 public class DilationCommand : Command
10 {
11 public DilationCommand(TestClient testClient)
12 {
13 Name = "dilation";
14 Description = "Shows time dilation for current sim.";
15 }
16
17 public override string Execute(string[] args, LLUUID fromAgentID)
18 {
19 return "Dilation is " + Client.Network.CurrentSim.Dilation.ToString();
20 }
21 }
22} \ No newline at end of file
diff --git a/ExportBot/Commands/DumpOutfitCommand.cs b/ExportBot/Commands/DumpOutfitCommand.cs
new file mode 100644
index 0000000..2d3d0d8
--- /dev/null
+++ b/ExportBot/Commands/DumpOutfitCommand.cs
@@ -0,0 +1,98 @@
1using System;
2using System.Text;
3using System.IO;
4using System.Collections.Generic;
5using libsecondlife;
6using libsecondlife.Utilities.Assets;
7using libsecondlife.Utilities.Appearance;
8
9namespace libsecondlife.TestClient
10{
11 public class DumpOutfitCommand : Command
12 {
13 libsecondlife.Utilities.Assets.AssetManager Assets;
14 List<LLUUID> OutfitAssets = new List<LLUUID>();
15
16 public DumpOutfitCommand(TestClient testClient)
17 {
18 Name = "dumpoutfit";
19 Description = "Dumps all of the textures from an avatars outfit to the hard drive. Usage: dumpoutfit [avatar-uuid]";
20
21 Assets = new AssetManager(testClient);
22 Assets.OnImageReceived += new AssetManager.ImageReceivedCallback(Assets_OnImageReceived);
23 }
24
25 public override string Execute(string[] args, LLUUID fromAgentID)
26 {
27 if (args.Length != 1)
28 return "Usage: dumpoutfit [avatar-uuid]";
29
30 LLUUID target;
31
32 if (!LLUUID.TryParse(args[0], out target))
33 return "Usage: dumpoutfit [avatar-uuid]";
34
35 lock (Client.AvatarList)
36 {
37 foreach (Avatar avatar in Client.AvatarList.Values)
38 {
39 if (avatar.ID == target)
40 {
41 StringBuilder output = new StringBuilder("Downloading ");
42
43 lock (OutfitAssets) OutfitAssets.Clear();
44
45 foreach (KeyValuePair<uint, LLObject.TextureEntryFace> face in avatar.Textures.FaceTextures)
46 {
47 ImageType type = ImageType.Normal;
48
49 switch ((AppearanceManager.TextureIndex)face.Key)
50 {
51 case AppearanceManager.TextureIndex.HeadBaked:
52 case AppearanceManager.TextureIndex.EyesBaked:
53 case AppearanceManager.TextureIndex.UpperBaked:
54 case AppearanceManager.TextureIndex.LowerBaked:
55 case AppearanceManager.TextureIndex.SkirtBaked:
56 type = ImageType.Baked;
57 break;
58 }
59
60 Assets.RequestImage(face.Value.TextureID, type, 100000.0f, 0);
61
62 output.Append(((AppearanceManager.TextureIndex)face.Key).ToString());
63 output.Append(" ");
64 }
65
66 return output.ToString();
67 }
68 }
69 }
70
71 return "Couldn't find avatar " + target.ToStringHyphenated();
72 }
73
74 private void Assets_OnImageReceived(ImageDownload image)
75 {
76 if (image.Success)
77 {
78 try
79 {
80 File.WriteAllBytes(image.ID.ToStringHyphenated() + ".jp2", image.AssetData);
81 Console.WriteLine("Wrote JPEG2000 image " + image.ID.ToStringHyphenated() + ".jp2");
82
83 byte[] tgaFile = OpenJPEGNet.OpenJPEG.DecodeToTGA(image.AssetData);
84 File.WriteAllBytes(image.ID.ToStringHyphenated() + ".tga", tgaFile);
85 Console.WriteLine("Wrote TGA image " + image.ID.ToStringHyphenated() + ".tga");
86 }
87 catch (Exception e)
88 {
89 Console.WriteLine(e.ToString());
90 }
91 }
92 else
93 {
94 Console.WriteLine("Failed to download image " + image.ID.ToStringHyphenated());
95 }
96 }
97 }
98}
diff --git a/ExportBot/Commands/ExportCommand.cs b/ExportBot/Commands/ExportCommand.cs
new file mode 100644
index 0000000..2baac1a
--- /dev/null
+++ b/ExportBot/Commands/ExportCommand.cs
@@ -0,0 +1,209 @@
1using System;
2using System.Collections.Generic;
3using System.IO;
4using System.Xml;
5using System.Text;
6using System.Threading;
7using libsecondlife;
8using libsecondlife.Packets;
9
10namespace libsecondlife.TestClient
11{
12 public class ExportCommand : Command
13 {
14 AutoResetEvent GotPermissionsEvent = new AutoResetEvent(false);
15 LLObject.ObjectPropertiesFamily Properties;
16 bool GotPermissions = false;
17 LLUUID SelectedObject = LLUUID.Zero;
18
19 Dictionary<LLUUID, Primitive> PrimsWaiting = new Dictionary<LLUUID, Primitive>();
20 AutoResetEvent AllPropertiesReceived = new AutoResetEvent(false);
21
22 public ExportCommand(TestClient testClient)
23 {
24 testClient.Objects.OnObjectPropertiesFamily += new ObjectManager.ObjectPropertiesFamilyCallback(Objects_OnObjectPropertiesFamily);
25 testClient.Objects.OnObjectProperties += new ObjectManager.ObjectPropertiesCallback(Objects_OnObjectProperties);
26 testClient.Avatars.OnPointAt += new AvatarManager.PointAtCallback(Avatars_OnPointAt);
27
28 Name = "export";
29 Description = "Exports an object to an xml file. Usage: export uuid outputfile.xml";
30 }
31
32 public override string Execute(string[] args, LLUUID fromAgentID)
33 {
34 if (args.Length != 2 && !(args.Length == 1 && SelectedObject != LLUUID.Zero))
35 return "Usage: export uuid outputfile.xml";
36
37 LLUUID id;
38 uint localid = 0;
39 int count = 0;
40 string file;
41
42 if (args.Length == 2)
43 {
44 file = args[1];
45 if (!LLUUID.TryParse(args[0], out id))
46 return "Usage: export uuid outputfile.xml";
47 }
48 else
49 {
50 file = args[0];
51 id = SelectedObject;
52 }
53
54 lock (Client.SimPrims)
55 {
56 if (Client.SimPrims.ContainsKey(Client.Network.CurrentSim))
57 {
58 foreach (Primitive prim in Client.SimPrims[Client.Network.CurrentSim].Values)
59 {
60 if (prim.ID == id)
61 {
62 if (prim.ParentID != 0)
63 localid = prim.ParentID;
64 else
65 localid = prim.LocalID;
66
67 break;
68 }
69 }
70 }
71 }
72
73 if (localid != 0)
74 {
75 // Check for export permission first
76 Client.Objects.RequestObjectPropertiesFamily(Client.Network.CurrentSim, id);
77 GotPermissionsEvent.WaitOne(8000, false);
78
79 if (!GotPermissions)
80 {
81 return "Couldn't fetch permissions for the requested object, try again";
82 }
83 else
84 {
85 GotPermissions = false;
86 if (Properties.OwnerID != Client.Network.AgentID &&
87 Properties.OwnerID != Client.MasterKey &&
88 Client.Network.AgentID != Client.Self.ID)
89 {
90 return "That object is owned by " + Properties.OwnerID + ", we don't have permission " +
91 "to export it";
92 }
93 }
94
95 try
96 {
97 XmlWriterSettings settings = new XmlWriterSettings();
98 settings.Indent = true;
99 XmlWriter writer = XmlWriter.Create(file, settings);
100
101 try
102 {
103 List<Primitive> prims = new List<Primitive>();
104
105 lock (Client.SimPrims)
106 {
107 if (Client.SimPrims.ContainsKey(Client.Network.CurrentSim))
108 {
109 foreach (Primitive prim in Client.SimPrims[Client.Network.CurrentSim].Values)
110 {
111 if (prim.LocalID == localid || prim.ParentID == localid)
112 {
113 prims.Add(prim);
114 count++;
115 }
116 }
117 }
118 }
119
120 bool complete = RequestObjectProperties(prims, 250);
121
122 //Serialize it!
123 Helpers.PrimListToXml(prims, writer);
124
125 if (!complete) {
126 Console.WriteLine("Warning: Unable to retrieve full properties for:");
127 foreach (LLUUID uuid in PrimsWaiting.Keys)
128 Console.WriteLine(uuid);
129 }
130 }
131 finally
132 {
133 writer.Close();
134 }
135 }
136 catch (Exception e)
137 {
138 string ret = "Failed to write to " + file + ":" + e.ToString();
139 if (ret.Length > 1000)
140 {
141 ret = ret.Remove(1000);
142 }
143 return ret;
144 }
145 return "Exported " + count + " prims to " + file;
146 }
147 else
148 {
149 return "Couldn't find UUID " + id.ToString() + " in the " +
150 Client.SimPrims[Client.Network.CurrentSim].Count +
151 "objects currently indexed in the current simulator";
152 }
153 }
154
155 private bool RequestObjectProperties(List<Primitive> objects, int msPerRequest)
156 {
157 // Create an array of the local IDs of all the prims we are requesting properties for
158 uint[] localids = new uint[objects.Count];
159
160 lock (PrimsWaiting)
161 {
162 PrimsWaiting.Clear();
163
164 for (int i = 0; i < objects.Count; ++i)
165 {
166 localids[i] = objects[i].LocalID;
167 PrimsWaiting.Add(objects[i].ID, objects[i]);
168 }
169 }
170
171 Client.Objects.SelectObjects(Client.Network.CurrentSim, localids);
172
173 return AllPropertiesReceived.WaitOne(2000 + msPerRequest * objects.Count, false);
174 }
175
176 void Avatars_OnPointAt(LLUUID sourceID, LLUUID targetID, LLVector3d targetPos,
177 MainAvatar.PointAtType pointType, float duration, LLUUID id)
178 {
179 if (sourceID == Client.MasterKey)
180 {
181 //Client.DebugLog("Master is now selecting " + targetID.ToStringHyphenated());
182 SelectedObject = targetID;
183 }
184 }
185
186 void Objects_OnObjectPropertiesFamily(Simulator simulator, LLObject.ObjectPropertiesFamily properties)
187 {
188 Properties = properties;
189 GotPermissions = true;
190 GotPermissionsEvent.Set();
191 }
192
193 void Objects_OnObjectProperties(Simulator simulator, LLObject.ObjectProperties properties)
194 {
195 lock (PrimsWaiting)
196 {
197 Primitive prim;
198 if (PrimsWaiting.TryGetValue(properties.ObjectID, out prim))
199 {
200 prim.Properties = properties;
201 }
202 PrimsWaiting.Remove(properties.ObjectID);
203
204 if (PrimsWaiting.Count == 0)
205 AllPropertiesReceived.Set();
206 }
207 }
208 }
209}
diff --git a/ExportBot/Commands/ExportOutfitCommand.cs b/ExportBot/Commands/ExportOutfitCommand.cs
new file mode 100644
index 0000000..6ec2776
--- /dev/null
+++ b/ExportBot/Commands/ExportOutfitCommand.cs
@@ -0,0 +1,66 @@
1using System;
2using System.Collections.Generic;
3using System.IO;
4using System.Xml;
5using libsecondlife;
6using libsecondlife.Packets;
7
8namespace libsecondlife.TestClient
9{
10 public class ExportOutfitCommand : Command
11 {
12 public ExportOutfitCommand(TestClient testClient)
13 {
14 Name = "exportoutfit";
15 Description = "Exports an avatars outfit to an xml file. Usage: exportoutfit avataruuid outputfile.xml";
16 }
17
18 public override string Execute(string[] args, LLUUID fromAgentID)
19 {
20 if (args.Length != 2)
21 return "Usage: exportoutfit avataruuid outputfile.xml";
22
23 LLUUID id;
24
25 try
26 {
27 id = new LLUUID(args[0]);
28 }
29 catch (Exception)
30 {
31 return "Usage: exportoutfit avataruuid outputfile.xml";
32 }
33
34 lock (Client.Appearances)
35 {
36 if (Client.Appearances.ContainsKey(id))
37 {
38 try
39 {
40 XmlWriterSettings settings = new XmlWriterSettings();
41 settings.Indent = true;
42 XmlWriter writer = XmlWriter.Create(args[1], settings);
43 try
44 {
45 Client.Appearances[id].ToXml(writer);
46 }
47 finally
48 {
49 writer.Close();
50 }
51 }
52 catch (Exception e)
53 {
54 return e.ToString();
55 }
56
57 return "Exported appearance for avatar " + id.ToString() + " to " + args[1];
58 }
59 else
60 {
61 return "Couldn't find an appearance for avatar " + id.ToString();
62 }
63 }
64 }
65 }
66} \ No newline at end of file
diff --git a/ExportBot/Commands/ExportParticlesCommand.cs b/ExportBot/Commands/ExportParticlesCommand.cs
new file mode 100644
index 0000000..4b2c322
--- /dev/null
+++ b/ExportBot/Commands/ExportParticlesCommand.cs
@@ -0,0 +1,119 @@
1using System;
2using System.Collections.Generic;
3using System.IO;
4using System.Text;
5using libsecondlife;
6
7namespace libsecondlife.TestClient
8{
9 public class ExportParticlesCommand : Command
10 {
11 public ExportParticlesCommand(TestClient testClient)
12 {
13 Name = "exportparticles";
14 Description = "Reverse engineers a prim with a particle system to an LSL script. Usage: exportscript [prim-uuid]";
15 }
16
17 public override string Execute(string[] args, LLUUID fromAgentID)
18 {
19 if (args.Length != 1)
20 return "Usage: exportparticles [prim-uuid]";
21
22 LLUUID id;
23 if (!LLUUID.TryParse(args[0], out id))
24 return "Usage: exportparticles [prim-uuid]";
25
26 lock (Client.SimPrims)
27 {
28 if (Client.SimPrims.ContainsKey(Client.Network.CurrentSim))
29 {
30 foreach (Primitive prim in Client.SimPrims[Client.Network.CurrentSim].Values)
31 {
32 if (prim.ID == id)
33 {
34 if (prim.ParticleSys.CRC != 0)
35 {
36 StringBuilder lsl = new StringBuilder();
37
38 lsl.Append("default" + Environment.NewLine);
39 lsl.Append("{" + Environment.NewLine);
40 lsl.Append(" state_entry()" + Environment.NewLine);
41 lsl.Append(" {" + Environment.NewLine);
42 lsl.Append(" llParticleSystem([" + Environment.NewLine);
43
44 lsl.Append(" PSYS_PART_FLAGS, 0");
45
46 if ((prim.ParticleSys.PartDataFlags & Primitive.ParticleSystem.ParticleDataFlags.InterpColor) != 0)
47 lsl.Append(" | PSYS_PART_INTERP_COLOR_MASK");
48 if ((prim.ParticleSys.PartDataFlags & Primitive.ParticleSystem.ParticleDataFlags.InterpScale) != 0)
49 lsl.Append(" | PSYS_PART_INTERP_SCALE_MASK");
50 if ((prim.ParticleSys.PartDataFlags & Primitive.ParticleSystem.ParticleDataFlags.Bounce) != 0)
51 lsl.Append(" | PSYS_PART_BOUNCE_MASK");
52 if ((prim.ParticleSys.PartDataFlags & Primitive.ParticleSystem.ParticleDataFlags.Wind) != 0)
53 lsl.Append(" | PSYS_PART_WIND_MASK");
54 if ((prim.ParticleSys.PartDataFlags & Primitive.ParticleSystem.ParticleDataFlags.FollowSrc) != 0)
55 lsl.Append(" | PSYS_PART_FOLLOW_SRC_MASK");
56 if ((prim.ParticleSys.PartDataFlags & Primitive.ParticleSystem.ParticleDataFlags.FollowVelocity) != 0)
57 lsl.Append(" | PSYS_PART_FOLLOW_VELOCITY_MASK");
58 if ((prim.ParticleSys.PartDataFlags & Primitive.ParticleSystem.ParticleDataFlags.TargetPos) != 0)
59 lsl.Append(" | PSYS_PART_TARGET_POS_MASK");
60 if ((prim.ParticleSys.PartDataFlags & Primitive.ParticleSystem.ParticleDataFlags.TargetLinear) != 0)
61 lsl.Append(" | PSYS_PART_TARGET_LINEAR_MASK");
62 if ((prim.ParticleSys.PartDataFlags & Primitive.ParticleSystem.ParticleDataFlags.Emissive) != 0)
63 lsl.Append(" | PSYS_PART_EMISSIVE_MASK");
64
65 lsl.Append(","); lsl.Append(Environment.NewLine);
66 lsl.Append(" PSYS_SRC_PATTERN, 0");
67
68 if ((prim.ParticleSys.Pattern & Primitive.ParticleSystem.SourcePattern.Drop) != 0)
69 lsl.Append(" | PSYS_SRC_PATTERN_DROP");
70 if ((prim.ParticleSys.Pattern & Primitive.ParticleSystem.SourcePattern.Explode) != 0)
71 lsl.Append(" | PSYS_SRC_PATTERN_EXPLODE");
72 if ((prim.ParticleSys.Pattern & Primitive.ParticleSystem.SourcePattern.Angle) != 0)
73 lsl.Append(" | PSYS_SRC_PATTERN_ANGLE");
74 if ((prim.ParticleSys.Pattern & Primitive.ParticleSystem.SourcePattern.AngleCone) != 0)
75 lsl.Append(" | PSYS_SRC_PATTERN_ANGLE_CONE");
76 if ((prim.ParticleSys.Pattern & Primitive.ParticleSystem.SourcePattern.AngleConeEmpty) != 0)
77 lsl.Append(" | PSYS_SRC_PATTERN_ANGLE_CONE_EMPTY");
78
79 lsl.Append("," + Environment.NewLine);
80
81 lsl.Append(" PSYS_PART_START_ALPHA, " + String.Format("{0:0.00000}", prim.ParticleSys.PartStartColor.A) + "," + Environment.NewLine);
82 lsl.Append(" PSYS_PART_END_ALPHA, " + String.Format("{0:0.00000}", prim.ParticleSys.PartEndColor.A) + "," + Environment.NewLine);
83 lsl.Append(" PSYS_PART_START_COLOR, " + prim.ParticleSys.PartStartColor.ToStringRGB() + "," + Environment.NewLine);
84 lsl.Append(" PSYS_PART_END_COLOR, " + prim.ParticleSys.PartEndColor.ToStringRGB() + "," + Environment.NewLine);
85 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);
86 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);
87 lsl.Append(" PSYS_PART_MAX_AGE, " + String.Format("{0:0.00000}", prim.ParticleSys.PartMaxAge) + "," + Environment.NewLine);
88 lsl.Append(" PSYS_SRC_MAX_AGE, " + String.Format("{0:0.00000}", prim.ParticleSys.MaxAge) + "," + Environment.NewLine);
89 lsl.Append(" PSYS_SRC_ACCEL, " + prim.ParticleSys.PartAcceleration.ToString() + "," + Environment.NewLine);
90 lsl.Append(" PSYS_SRC_BURST_PART_COUNT, " + String.Format("{0:0}", prim.ParticleSys.BurstPartCount) + "," + Environment.NewLine);
91 lsl.Append(" PSYS_SRC_BURST_RADIUS, " + String.Format("{0:0.00000}", prim.ParticleSys.BurstRadius) + "," + Environment.NewLine);
92 lsl.Append(" PSYS_SRC_BURST_RATE, " + String.Format("{0:0.00000}", prim.ParticleSys.BurstRate) + "," + Environment.NewLine);
93 lsl.Append(" PSYS_SRC_BURST_SPEED_MIN, " + String.Format("{0:0.00000}", prim.ParticleSys.BurstSpeedMin) + "," + Environment.NewLine);
94 lsl.Append(" PSYS_SRC_BURST_SPEED_MAX, " + String.Format("{0:0.00000}", prim.ParticleSys.BurstSpeedMax) + "," + Environment.NewLine);
95 lsl.Append(" PSYS_SRC_INNERANGLE, " + String.Format("{0:0.00000}", prim.ParticleSys.InnerAngle) + "," + Environment.NewLine);
96 lsl.Append(" PSYS_SRC_OUTERANGLE, " + String.Format("{0:0.00000}", prim.ParticleSys.OuterAngle) + "," + Environment.NewLine);
97 lsl.Append(" PSYS_SRC_OMEGA, " + prim.ParticleSys.AngularVelocity.ToString() + "," + Environment.NewLine);
98 lsl.Append(" PSYS_SRC_TEXTURE, (key)\"" + prim.ParticleSys.Texture.ToStringHyphenated() + "\"," + Environment.NewLine);
99 lsl.Append(" PSYS_SRC_TARGET_KEY, (key)\"" + prim.ParticleSys.Target.ToStringHyphenated() + "\"" + Environment.NewLine);
100
101 lsl.Append(" ]);" + Environment.NewLine);
102 lsl.Append(" }" + Environment.NewLine);
103 lsl.Append("}" + Environment.NewLine);
104
105 return lsl.ToString();
106 }
107 else
108 {
109 return "Prim " + prim.LocalID + " does not have a particle system";
110 }
111 }
112 }
113 }
114 }
115
116 return "Couldn't find prim " + id.ToStringHyphenated();
117 }
118 }
119}
diff --git a/ExportBot/Commands/FindSimCommand.cs b/ExportBot/Commands/FindSimCommand.cs
new file mode 100644
index 0000000..c6cc9c4
--- /dev/null
+++ b/ExportBot/Commands/FindSimCommand.cs
@@ -0,0 +1,43 @@
1using System;
2using System.Collections.Generic;
3using System.Text;
4using libsecondlife;
5using libsecondlife.Packets;
6
7namespace libsecondlife.TestClient
8{
9 public class FindSimCommand : Command
10 {
11 public FindSimCommand(TestClient testClient)
12 {
13 Name = "findsim";
14 Description = "Searches for a simulator and returns information about it. Usage: findsim [Simulator Name]";
15 }
16
17 public override string Execute(string[] args, LLUUID fromAgentID)
18 {
19 if (args.Length < 1)
20 return "Usage: findsim [Simulator Name]";
21
22 // Build the simulator name from the args list
23 string simName = string.Empty;
24 for (int i = 0; i < args.Length; i++)
25 simName += args[i] + " ";
26 simName = simName.TrimEnd().ToLower();
27
28 //if (!GridDataCached[Client])
29 //{
30 // Client.Grid.RequestAllSims(GridManager.MapLayerType.Objects);
31 // System.Threading.Thread.Sleep(5000);
32 // GridDataCached[Client] = true;
33 //}
34
35 GridRegion region;
36
37 if (Client.Grid.GetGridRegion(simName, out region))
38 return String.Format("{0}: handle={1} ({2},{3})", region.Name, region.RegionHandle, region.X, region.Y);
39 else
40 return "Lookup of " + simName + " failed";
41 }
42 }
43}
diff --git a/ExportBot/Commands/HelpCommand.cs b/ExportBot/Commands/HelpCommand.cs
new file mode 100644
index 0000000..5cbdcb2
--- /dev/null
+++ b/ExportBot/Commands/HelpCommand.cs
@@ -0,0 +1,29 @@
1using System;
2using System.Collections.Generic;
3using System.Text;
4using libsecondlife;
5using libsecondlife.Packets;
6
7namespace libsecondlife.TestClient
8{
9 public class HelpCommand: Command
10 {
11 public HelpCommand(TestClient testClient)
12 {
13 Name = "help";
14 Description = "Lists available commands.";
15 }
16
17 public override string Execute(string[] args, LLUUID fromAgentID)
18 {
19 StringBuilder result = new StringBuilder();
20 result.AppendFormat("\n\nHELP\nClient accept teleport lures from master and group members.\n");
21 foreach (Command c in Client.Commands.Values)
22 {
23 result.AppendFormat(" * {0} - {1}\n", c.Name, c.Description);
24 }
25
26 return result.ToString();
27 }
28 }
29}
diff --git a/ExportBot/Commands/ImportCommand.cs b/ExportBot/Commands/ImportCommand.cs
new file mode 100644
index 0000000..4cdcaee
--- /dev/null
+++ b/ExportBot/Commands/ImportCommand.cs
@@ -0,0 +1,246 @@
1using System;
2using System.Collections.Generic;
3using System.Xml;
4using System.Xml.Serialization;
5using System.Threading;
6using System.IO;
7using libsecondlife;
8
9namespace libsecondlife.TestClient
10{
11 enum ImporterState
12 {
13 RezzingParent,
14 RezzingChildren,
15 Linking,
16 Idle
17 }
18
19 public class Linkset
20 {
21 public Primitive RootPrim;
22 public List<Primitive> Children = new List<Primitive>();
23
24 public Linkset()
25 {
26 RootPrim = new Primitive();
27 }
28
29 public Linkset(Primitive rootPrim)
30 {
31 RootPrim = rootPrim;
32 }
33 }
34
35 public class ImportCommand : Command
36 {
37 Primitive currentPrim;
38 LLVector3 currentPosition;
39 SecondLife currentClient;
40 AutoResetEvent primDone;
41 List<Primitive> primsCreated;
42 List<uint> linkQueue;
43 uint rootLocalID = 0;
44 bool registeredCreateEvent = false;
45
46 ImporterState state = ImporterState.Idle;
47
48 public ImportCommand(TestClient testClient)
49 {
50 Name = "import";
51 Description = "Import prims from an exported xml file. Usage: import inputfile.xml";
52 primDone = new AutoResetEvent(false);
53 registeredCreateEvent = false;
54 }
55
56 public override string Execute(string[] args, LLUUID fromAgentID)
57 {
58 if (args.Length != 1)
59 return "Usage: import inputfile.xml";
60
61 string filename = args[0];
62 Dictionary<uint, Primitive> prims;
63
64 currentClient = Client;
65
66 try
67 {
68 XmlReader reader = XmlReader.Create(filename);
69 List<Primitive> listprims = Helpers.PrimListFromXml(reader);
70 reader.Close();
71
72 // Create a dictionary indexed by the old local ID of the prims
73 prims = new Dictionary<uint, Primitive>();
74 foreach (Primitive prim in listprims)
75 {
76 prims.Add(prim.LocalID, prim);
77 }
78 }
79 catch (Exception)
80 {
81 return "Failed to import the object XML file, maybe it doesn't exist or is in the wrong format?";
82 }
83
84 if (!registeredCreateEvent)
85 {
86 Client.OnPrimCreated += new TestClient.PrimCreatedCallback(TestClient_OnPrimCreated);
87 registeredCreateEvent = true;
88 }
89
90 // Build an organized structure from the imported prims
91 Dictionary<uint, Linkset> linksets = new Dictionary<uint, Linkset>();
92 foreach (Primitive prim in prims.Values)
93 {
94 if (prim.ParentID == 0)
95 {
96 if (linksets.ContainsKey(prim.LocalID))
97 linksets[prim.LocalID].RootPrim = prim;
98 else
99 linksets[prim.LocalID] = new Linkset(prim);
100 }
101 else
102 {
103 if (!linksets.ContainsKey(prim.ParentID))
104 linksets[prim.ParentID] = new Linkset();
105
106 linksets[prim.ParentID].Children.Add(prim);
107 }
108 }
109
110 primsCreated = new List<Primitive>();
111 Console.WriteLine("Importing " + linksets.Count + " structures.");
112
113 foreach (Linkset linkset in linksets.Values)
114 {
115 if (linkset.RootPrim.LocalID != 0)
116 {
117 state = ImporterState.RezzingParent;
118 currentPrim = linkset.RootPrim;
119 // HACK: Offset the root prim position so it's not lying on top of the original
120 // We need a more elaborate solution for importing with relative or absolute offsets
121 linkset.RootPrim.Position = Client.Self.Position;
122 linkset.RootPrim.Position.Z += 3.0f;
123 currentPosition = linkset.RootPrim.Position;
124 // A better solution would move the bot to the desired position.
125 // or to check if we are within a certain distance of the desired position.
126
127 // Rez the root prim with no rotation
128 LLQuaternion rootRotation = linkset.RootPrim.Rotation;
129 linkset.RootPrim.Rotation = LLQuaternion.Identity;
130
131 Client.Objects.AddPrim(Client.Network.CurrentSim, linkset.RootPrim.Data, LLUUID.Zero,
132 linkset.RootPrim.Position, linkset.RootPrim.Scale, linkset.RootPrim.Rotation);
133
134 if (!primDone.WaitOne(10000, false))
135 return "Rez failed, timed out while creating the root prim.";
136
137 state = ImporterState.RezzingChildren;
138
139 // Rez the child prims
140 foreach (Primitive prim in linkset.Children)
141 {
142 currentPrim = prim;
143 currentPosition = prim.Position + linkset.RootPrim.Position;
144
145 Client.Objects.AddPrim(Client.Network.CurrentSim, prim.Data, LLUUID.Zero, currentPosition,
146 prim.Scale, prim.Rotation);
147
148 if (!primDone.WaitOne(10000, false))
149 return "Rez failed, timed out while creating child prim.";
150 }
151
152 if (linkset.Children.Count != 0)
153 {
154 // Create a list of the local IDs of the newly created prims
155 List<uint> primIDs = new List<uint>(primsCreated.Count);
156 primIDs.Add(rootLocalID); // Root prim is first in list.
157 foreach (Primitive prim in primsCreated)
158 {
159 if (prim.LocalID != rootLocalID)
160 primIDs.Add(prim.LocalID);
161 }
162 linkQueue = new List<uint>(primIDs.Count);
163 linkQueue.AddRange(primIDs);
164
165 // Link and set the permissions + rotation
166 state = ImporterState.Linking;
167 Client.Objects.LinkPrims(Client.Network.CurrentSim, linkQueue);
168 if (primDone.WaitOne(100000 * linkset.Children.Count, false))
169 {
170 Client.Objects.SetPermissions(Client.Network.CurrentSim, primIDs,
171 Helpers.PermissionWho.Everyone | Helpers.PermissionWho.Group | Helpers.PermissionWho.NextOwner,
172 Helpers.PermissionType.Copy | Helpers.PermissionType.Modify | Helpers.PermissionType.Move |
173 Helpers.PermissionType.Transfer, true);
174
175 Client.Objects.SetRotation(Client.Network.CurrentSim, rootLocalID, rootRotation);
176 }
177 else
178 {
179 Console.WriteLine("Warning: Failed to link {0} prims", linkQueue.Count);
180 }
181 }
182 else
183 {
184 Client.Objects.SetRotation(Client.Network.CurrentSim, rootLocalID, rootRotation);
185 }
186 state = ImporterState.Idle;
187 }
188 else
189 {
190 // Skip linksets with a missing root prim
191 Console.WriteLine("WARNING: Skipping a linkset with a missing root prim");
192 }
193
194 // Reset everything for the next linkset
195 primsCreated.Clear();
196 }
197
198 return "Import complete.";
199 }
200
201 void TestClient_OnPrimCreated(Simulator simulator, Primitive prim)
202 {
203 if ((prim.Flags & LLObject.ObjectFlags.CreateSelected) == 0)
204 return; // We received an update for an object we didn't create
205
206 switch (state)
207 {
208 case ImporterState.RezzingParent:
209 rootLocalID = prim.LocalID;
210 goto case ImporterState.RezzingChildren;
211 case ImporterState.RezzingChildren:
212 if (!primsCreated.Contains(prim))
213 {
214 Console.WriteLine("Setting properties for " + prim.LocalID);
215 // TODO: Is there a way to set all of this at once, and update more ObjectProperties stuff?
216 currentClient.Objects.SetPosition(simulator, prim.LocalID, currentPosition);
217 currentClient.Objects.SetTextures(simulator, prim.LocalID, currentPrim.Textures);
218 currentClient.Objects.SetLight(simulator, prim.LocalID, currentPrim.Light);
219 currentClient.Objects.SetFlexible(simulator, prim.LocalID, currentPrim.Flexible);
220
221 if (!String.IsNullOrEmpty(currentPrim.Properties.Name))
222 currentClient.Objects.SetName(simulator, prim.LocalID, currentPrim.Properties.Name);
223 if (!String.IsNullOrEmpty(currentPrim.Properties.Description))
224 currentClient.Objects.SetDescription(simulator, prim.LocalID,
225 currentPrim.Properties.Description);
226
227 primsCreated.Add(prim);
228 primDone.Set();
229 }
230 break;
231 case ImporterState.Linking:
232 lock (linkQueue)
233 {
234 int index = linkQueue.IndexOf(prim.LocalID);
235 if (index != -1)
236 {
237 linkQueue.RemoveAt(index);
238 if (linkQueue.Count == 0)
239 primDone.Set();
240 }
241 }
242 break;
243 }
244 }
245 }
246}
diff --git a/ExportBot/Commands/ImportOutfitCommand.cs b/ExportBot/Commands/ImportOutfitCommand.cs
new file mode 100644
index 0000000..5ac7b8a
--- /dev/null
+++ b/ExportBot/Commands/ImportOutfitCommand.cs
@@ -0,0 +1,66 @@
1using System;
2using System.Collections.Generic;
3using System.IO;
4using System.Xml;
5using System.Xml.Serialization;
6using libsecondlife;
7using libsecondlife.Packets;
8
9namespace libsecondlife.TestClient
10{
11 public class ImportOutfitCommand : Command
12 {
13 private uint SerialNum = 1;
14
15 public ImportOutfitCommand(TestClient testClient)
16 {
17 Name = "importoutfit";
18 Description = "Imports an appearance from an xml file. Usage: importoutfit inputfile.xml";
19 }
20
21 public override string Execute(string[] args, LLUUID fromAgentID)
22 {
23 if (args.Length != 1)
24 return "Usage: importoutfit inputfile.xml";
25
26 try
27 {
28 XmlReader reader = XmlReader.Create(args[0]);
29 XmlSerializer serializer = new XmlSerializer(typeof(Packet));
30 AvatarAppearancePacket appearance = (AvatarAppearancePacket)serializer.Deserialize(reader);
31 reader.Close();
32
33 AgentSetAppearancePacket set = new AgentSetAppearancePacket();
34
35 set.AgentData.AgentID = Client.Network.AgentID;
36 set.AgentData.SessionID = Client.Network.SessionID;
37 set.AgentData.SerialNum = SerialNum++;
38
39 float AV_Height_Range = 2.025506f - 1.50856f;
40 float AV_Height = 1.50856f + (((float)appearance.VisualParam[25].ParamValue / 255.0f) * AV_Height_Range);
41 set.AgentData.Size = new LLVector3(0.45f, 0.6f, AV_Height);
42
43 set.ObjectData.TextureEntry = appearance.ObjectData.TextureEntry;
44 set.VisualParam = new AgentSetAppearancePacket.VisualParamBlock[appearance.VisualParam.Length];
45
46 int i = 0;
47 foreach (AvatarAppearancePacket.VisualParamBlock block in appearance.VisualParam)
48 {
49 set.VisualParam[i] = new AgentSetAppearancePacket.VisualParamBlock();
50 set.VisualParam[i].ParamValue = block.ParamValue;
51 i++;
52 }
53
54 set.WearableData = new AgentSetAppearancePacket.WearableDataBlock[0];
55
56 Client.Network.SendPacket(set);
57 }
58 catch (Exception)
59 {
60 return "Failed to import the appearance XML file, maybe it doesn't exist or is in the wrong format?";
61 }
62
63 return "Imported " + args[0] + " and sent an AgentSetAppearance packet";
64 }
65 }
66}
diff --git a/ExportBot/Commands/Inventory/BalanceCommand.cs b/ExportBot/Commands/Inventory/BalanceCommand.cs
new file mode 100644
index 0000000..92e9b39
--- /dev/null
+++ b/ExportBot/Commands/Inventory/BalanceCommand.cs
@@ -0,0 +1,21 @@
1using System;
2using System.Collections.Generic;
3using libsecondlife;
4using libsecondlife.Packets;
5
6namespace libsecondlife.TestClient
7{
8 public class BalanceCommand: Command
9 {
10 public BalanceCommand(TestClient testClient)
11 {
12 Name = "balance";
13 Description = "Shows the amount of L$.";
14 }
15
16 public override string Execute(string[] args, LLUUID fromAgentID)
17 {
18 return Client.ToString() + " has L$: " + Client.Self.Balance;
19 }
20 }
21}
diff --git a/ExportBot/Commands/Inventory/DeleteFolderCommand.cs b/ExportBot/Commands/Inventory/DeleteFolderCommand.cs
new file mode 100644
index 0000000..ddbb86c
--- /dev/null
+++ b/ExportBot/Commands/Inventory/DeleteFolderCommand.cs
@@ -0,0 +1,43 @@
1using System;
2using System.Collections.Generic;
3using System.IO;
4using System.Text;
5using System.Threading;
6using System.Xml;
7using System.Xml.Serialization;
8
9using libsecondlife;
10using libsecondlife.Packets;
11using libsecondlife.InventorySystem;
12
13namespace libsecondlife.TestClient
14{
15 public class DeleteFolderCommand : Command
16 {
17 public DeleteFolderCommand(TestClient testClient)
18 {
19 Name = "deleteFolder";
20 Description = "Deletes a folder from inventory.";
21 }
22
23 public override string Execute(string[] args, LLUUID fromAgentID)
24 {
25 return "Broken until someone fixes me";
26
27 //string target = String.Empty;
28 //for (int ct = 0; ct < args.Length; ct++)
29 // target = target + args[ct] + " ";
30 //target = target.TrimEnd();
31
32 //Client.Inventory.DownloadInventory();
33 //InventoryFolder folder = Client.Inventory.getFolder(target);
34 //if (folder != null)
35 //{
36 // folder.Delete();
37 // return "Folder " + target + " deleted.";
38 //}
39
40 //return "Unable to find: " + target;
41 }
42 }
43} \ No newline at end of file
diff --git a/ExportBot/Commands/Inventory/GiveAllCommand.cs b/ExportBot/Commands/Inventory/GiveAllCommand.cs
new file mode 100644
index 0000000..fe42fce
--- /dev/null
+++ b/ExportBot/Commands/Inventory/GiveAllCommand.cs
@@ -0,0 +1,27 @@
1using System;
2using System.Collections.Generic;
3using System.Text;
4using libsecondlife;
5using libsecondlife.Packets;
6
7namespace libsecondlife.TestClient
8{
9 public class GiveAllCommand: Command
10 {
11 public GiveAllCommand(TestClient testClient)
12 {
13 Name = "giveAll";
14 Description = "Gives you all it's money.";
15 }
16
17 public override string Execute(string[] args, LLUUID fromAgentID)
18 {
19 if (fromAgentID == null)
20 return "Unable to send money to console. This command only works when IMed.";
21
22 int amount = Client.Self.Balance;
23 Client.Self.GiveMoney(fromAgentID, Client.Self.Balance, String.Empty);
24 return "Gave $" + amount + " to " + fromAgentID;
25 }
26 }
27}
diff --git a/ExportBot/Commands/Inventory/InventoryCommand.cs b/ExportBot/Commands/Inventory/InventoryCommand.cs
new file mode 100644
index 0000000..7b01bb1
--- /dev/null
+++ b/ExportBot/Commands/Inventory/InventoryCommand.cs
@@ -0,0 +1,62 @@
1using System;
2using System.Collections.Generic;
3using System.IO;
4using System.Text;
5using System.Threading;
6using System.Xml;
7using System.Xml.Serialization;
8
9using libsecondlife;
10using libsecondlife.Packets;
11using libsecondlife.InventorySystem;
12
13namespace libsecondlife.TestClient
14{
15 public class InventoryCommand : Command
16 {
17 public InventoryCommand(TestClient testClient)
18 {
19 Name = "i";
20 Description = "Prints out inventory.";
21 }
22
23 public override string Execute(string[] args, LLUUID fromAgentID)
24 {
25 return "Broken until someone fixes me";
26
27 //Client.Inventory.DownloadInventory();
28 //StringBuilder result = new StringBuilder();
29 //PrintFolder(Client.Inventory.GetRootFolder(), result, 0);
30 //return result.ToString();
31 }
32
33 //void PrintFolder(InventoryFolder folder, StringBuilder output, int indenting)
34 //{
35 // Indent(output, indenting);
36 // output.Append(folder.Name);
37 // output.Append("\n");
38 // foreach (InventoryBase b in folder.GetContents())
39 // {
40 // InventoryItem item = b as InventoryItem;
41 // if (item != null)
42 // {
43 // Indent(output, indenting + 1);
44 // output.Append(item.Name);
45 // output.Append("\n");
46 // continue;
47 // }
48 // InventoryFolder subFolder = b as InventoryFolder;
49 // if (subFolder != null)
50 // PrintFolder(subFolder, output, indenting + 1);
51 // }
52 //}
53
54 //void Indent(StringBuilder output, int indenting)
55 //{
56 // for (int count = 0; count < indenting; count++)
57 // {
58 // output.Append(" ");
59 // }
60 //}
61 }
62} \ No newline at end of file
diff --git a/ExportBot/Commands/Inventory/WearCommand.cs b/ExportBot/Commands/Inventory/WearCommand.cs
new file mode 100644
index 0000000..d1bc32c
--- /dev/null
+++ b/ExportBot/Commands/Inventory/WearCommand.cs
@@ -0,0 +1,43 @@
1using System;
2using System.Collections.Generic;
3using System.IO;
4using System.Text;
5using System.Threading;
6using System.Xml;
7using System.Xml.Serialization;
8
9using libsecondlife;
10using libsecondlife.Packets;
11using libsecondlife.InventorySystem;
12
13namespace libsecondlife.TestClient
14{
15 public class WearCommand : Command
16 {
17 public WearCommand(TestClient testClient)
18 {
19 Name = "wear";
20 Description = "Wear an outfit folder from inventory.";
21 }
22
23 public override string Execute(string[] args, LLUUID fromAgentID)
24 {
25 return "Broken until someone fixes me";
26
27 //string target = String.Empty;
28 //for (int ct = 0; ct < args.Length; ct++)
29 // target = target + args[ct] + " ";
30 //target = target.TrimEnd();
31
32 //Client.Inventory.DownloadInventory();
33 //InventoryFolder folder = Client.Inventory.getFolder(target);
34 //if (folder != null)
35 //{
36 // Client.Appearance.WearOutfit(folder);
37 // return "Outfit " + target + " worn.";
38 //}
39
40 //return "Unable to find: " + target;
41 }
42 }
43} \ No newline at end of file
diff --git a/ExportBot/Commands/LoadCommand.cs b/ExportBot/Commands/LoadCommand.cs
new file mode 100644
index 0000000..70dada4
--- /dev/null
+++ b/ExportBot/Commands/LoadCommand.cs
@@ -0,0 +1,28 @@
1using System;
2using System.Collections.Generic;
3using System.Text;
4using System.Reflection;
5using libsecondlife;
6using libsecondlife.Packets;
7
8namespace libsecondlife.TestClient
9{
10 public class LoadCommand: Command
11 {
12 public LoadCommand(TestClient testClient)
13 {
14 Name = "load";
15 Description = "Loads commands from a dll. (Usage: load AssemblyNameWithoutExtension)";
16 }
17
18 public override string Execute(string[] args, LLUUID fromAgentID)
19 {
20 if (args.Length < 1)
21 return "Usage: load AssemblyNameWithoutExtension";
22
23 string filename = AppDomain.CurrentDomain.BaseDirectory + args[0] + ".dll";
24 Client.RegisterAllCommands(Assembly.LoadFile(filename));
25 return "Assembly " + filename + " loaded.";
26 }
27 }
28}
diff --git a/ExportBot/Commands/LoginCommand.cs b/ExportBot/Commands/LoginCommand.cs
new file mode 100644
index 0000000..64675f5
--- /dev/null
+++ b/ExportBot/Commands/LoginCommand.cs
@@ -0,0 +1,34 @@
1using System;
2using System.Collections.Generic;
3using System.Reflection;
4using libsecondlife;
5using libsecondlife.Packets;
6
7namespace libsecondlife.TestClient
8{
9 public class LoginCommand : Command
10 {
11 public LoginCommand(TestClient testClient)
12 {
13 Name = "login";
14 Description = "Logs in another avatar";
15 }
16
17 public override string Execute(string[] args, LLUUID fromAgentID)
18 {
19 if (args.Length != 3 && args.Length != 4)
20 return "usage: login firstname lastname password [simname]";
21
22 SecondLife newClient = Client.ClientManager.Login(args);
23
24 if (newClient.Network.Connected)
25 {
26 return "Logged in " + newClient.ToString();
27 }
28 else
29 {
30 return "Failed to login: " + newClient.Network.LoginStatusMessage;
31 }
32 }
33 }
34}
diff --git a/ExportBot/Commands/LogoutCommand.cs b/ExportBot/Commands/LogoutCommand.cs
new file mode 100644
index 0000000..cdb5bde
--- /dev/null
+++ b/ExportBot/Commands/LogoutCommand.cs
@@ -0,0 +1,24 @@
1using System;
2using System.Collections.Generic;
3using System.Text;
4using libsecondlife;
5using libsecondlife.Packets;
6
7namespace libsecondlife.TestClient
8{
9 public class LogoutCommand : Command
10 {
11 public LogoutCommand(TestClient testClient)
12 {
13 Name = "logout";
14 Description = "Log this avatar out";
15 }
16
17 public override string Execute(string[] args, LLUUID fromAgentID)
18 {
19 string name = Client.ToString();
20 Client.ClientManager.Logout(Client);
21 return "Logged " + name + " out";
22 }
23 }
24}
diff --git a/ExportBot/Commands/MD5Command.cs b/ExportBot/Commands/MD5Command.cs
new file mode 100644
index 0000000..0a2ee5d
--- /dev/null
+++ b/ExportBot/Commands/MD5Command.cs
@@ -0,0 +1,22 @@
1using System;
2using libsecondlife;
3
4namespace libsecondlife.TestClient
5{
6 public class MD5Command : Command
7 {
8 public MD5Command(TestClient testClient)
9 {
10 Name = "md5";
11 Description = "Creates an MD5 hash from a given password. Usage: md5 [password]";
12 }
13
14 public override string Execute(string[] args, LLUUID fromAgentID)
15 {
16 if (args.Length == 1)
17 return Helpers.MD5(args[0]);
18 else
19 return "Usage: md5 [password]";
20 }
21 }
22}
diff --git a/ExportBot/Commands/Movement/FollowCommand.cs b/ExportBot/Commands/Movement/FollowCommand.cs
new file mode 100644
index 0000000..f5074a3
--- /dev/null
+++ b/ExportBot/Commands/Movement/FollowCommand.cs
@@ -0,0 +1,90 @@
1using System;
2using System.Collections.Generic;
3using System.Text;
4using libsecondlife;
5using libsecondlife.Packets;
6
7namespace libsecondlife.TestClient
8{
9 public class FollowCommand: Command
10 {
11 public FollowCommand(TestClient testClient)
12 {
13 Name = "follow";
14 Description = "Follow another avatar. (usage: follow [FirstName LastName]) If no target is set then will follow master.";
15 }
16
17 public override string Execute(string[] args, LLUUID fromAgentID)
18 {
19 string target = String.Empty;
20 for (int ct = 0; ct < args.Length; ct++)
21 target = target + args[ct] + " ";
22 target = target.TrimEnd();
23
24 if (target.Length > 0)
25 {
26 if (Follow(target))
27 return "Following " + target;
28 else
29 return "Unable to follow " + target + ". Client may not be able to see that avatar.";
30 }
31 else
32 {
33 if (Follow(Client.MasterKey))
34 return "Following " + Client.MasterKey;
35 else
36 return "No target specified and no master not found. usage: follow [FirstName LastName])";
37 }
38 }
39
40 const float DISTANCE_BUFFER = 3.0f;
41 Avatar followAvatar;
42
43 bool Follow(string name)
44 {
45 foreach (Avatar av in Client.AvatarList.Values)
46 {
47 if (av.Name == name)
48 {
49 followAvatar = av;
50 Active = true;
51 return true;
52 }
53 }
54 return false;
55 }
56
57 bool Follow(LLUUID id)
58 {
59 foreach (Avatar av in Client.AvatarList.Values)
60 {
61 if (av.ID == id)
62 {
63 followAvatar = av;
64 Active = true;
65 return true;
66 }
67 }
68 return false;
69 }
70
71 public override void Think()
72 {
73 if (Helpers.VecDist(followAvatar.Position, Client.Self.Position) > DISTANCE_BUFFER)
74 {
75 //move toward target
76 LLVector3 avPos = followAvatar.Position;
77 Client.Self.AutoPilot((ulong)avPos.X + (ulong)Client.regionX, (ulong)avPos.Y + (ulong)Client.regionY, avPos.Z);
78 }
79 //else
80 //{
81 // //stop at current position
82 // LLVector3 myPos = client.Self.Position;
83 // client.Self.AutoPilot((ulong)myPos.x, (ulong)myPos.y, myPos.Z);
84 //}
85
86 base.Think();
87 }
88
89 }
90}
diff --git a/ExportBot/Commands/Movement/GotoCommand.cs b/ExportBot/Commands/Movement/GotoCommand.cs
new file mode 100644
index 0000000..df2b8a7
--- /dev/null
+++ b/ExportBot/Commands/Movement/GotoCommand.cs
@@ -0,0 +1,53 @@
1using System;
2using System.Collections.Generic;
3using System.Text;
4using libsecondlife;
5using libsecondlife.Packets;
6
7namespace libsecondlife.TestClient
8{
9 public class GotoCommand: Command
10 {
11 public GotoCommand(TestClient testClient)
12 {
13 Name = "goto";
14 Description = "Teleport to a location (e.g. \"goto Hooper/100/100/30\")";
15 }
16
17 public override string Execute(string[] args, LLUUID fromAgentID)
18 {
19 if (args.Length < 1)
20 return "usage: Destination should be specified as sim/x/y/z";
21
22 string destination = String.Empty;
23
24 // Handle multi-word sim names by combining the arguments
25 foreach (string arg in args)
26 {
27 destination += arg + " ";
28 }
29 destination = destination.Trim();
30
31 string[] tokens = destination.Split(new char[] { '/' });
32 if (tokens.Length != 4)
33 return "usage: Destination should be specified as sim/x/y/z";
34
35 string sim = tokens[0];
36 float x = Client.Self.Position.X;
37 float y = Client.Self.Position.Y;
38 float z = Client.Self.Position.Z;
39 float.TryParse(tokens[1], out x);
40 float.TryParse(tokens[2], out y);
41 float.TryParse(tokens[3], out z);
42
43 if (Client.Self.Teleport(sim, new LLVector3(x, y, z)))
44 {
45 return "Teleported to " + Client.Network.CurrentSim;
46 }
47 else
48 {
49 return "Teleport failed: " + Client.Self.TeleportMessage;
50 }
51 }
52 }
53}
diff --git a/ExportBot/Commands/Movement/JumpCommand.cs b/ExportBot/Commands/Movement/JumpCommand.cs
new file mode 100644
index 0000000..29b11a0
--- /dev/null
+++ b/ExportBot/Commands/Movement/JumpCommand.cs
@@ -0,0 +1,34 @@
1using System;
2using System.Collections.Generic;
3using System.Text;
4using libsecondlife;
5using libsecondlife.Packets;
6
7namespace libsecondlife.TestClient
8{
9 public class JumpCommand: Command
10 {
11 public JumpCommand(TestClient testClient)
12 {
13 Name = "jump";
14 Description = "Teleports to the specified height. (e.g. \"jump 1000\")";
15 }
16
17 public override string Execute(string[] args, LLUUID fromAgentID)
18 {
19 if (args.Length != 1)
20 return "usage: jump 1000";
21
22 float height = 0;
23 float.TryParse(args[0], out height);
24
25 Client.Self.Teleport
26 (
27 Client.Network.CurrentSim.Name,
28 new LLVector3(Client.Self.Position.X, Client.Self.Position.Y, Client.Self.Position.Z + height)
29 );
30
31 return "Jumped " + height;
32 }
33 }
34}
diff --git a/ExportBot/Commands/Movement/LocationCommand.cs b/ExportBot/Commands/Movement/LocationCommand.cs
new file mode 100644
index 0000000..2fd62bb
--- /dev/null
+++ b/ExportBot/Commands/Movement/LocationCommand.cs
@@ -0,0 +1,23 @@
1using System;
2using System.Collections.Generic;
3using System.Text;
4using libsecondlife;
5using libsecondlife.Packets;
6
7namespace libsecondlife.TestClient
8{
9 public class LocationCommand: Command
10 {
11 public LocationCommand(TestClient testClient)
12 {
13 Name = "location";
14 Description = "Show the location.";
15 }
16
17 public override string Execute(string[] args, LLUUID fromAgentID)
18 {
19 return "CurrentSim: '" + Client.Network.CurrentSim.ToString() + "' Position: " +
20 Client.Self.Position.ToString();
21 }
22 }
23}
diff --git a/ExportBot/Commands/Movement/MoveToCommand.cs b/ExportBot/Commands/Movement/MoveToCommand.cs
new file mode 100644
index 0000000..6d0a225
--- /dev/null
+++ b/ExportBot/Commands/Movement/MoveToCommand.cs
@@ -0,0 +1,24 @@
1using System;
2using System.Collections.Generic;
3using System.Text;
4
5namespace libsecondlife.TestClient.Commands.Movement {
6 class MovetoCommand : Command {
7 public MovetoCommand(TestClient client) {
8 Name = "moveto";
9 Description = "Moves the avatar to the specified global position using simulator autopilot.";
10 }
11 public override string Execute(string[] args, LLUUID fromAgentID) {
12 if (args.Length != 3)
13 return "usage: moveto x y z";
14 float x = Client.Self.Position.X + Client.regionX;
15 float y = Client.Self.Position.Y + Client.regionY;
16 float z = Client.Self.Position.Z;
17 float.TryParse(args[0], out x);
18 float.TryParse(args[1], out y);
19 float.TryParse(args[2], out z);
20 Client.Self.AutoPilot((ulong)x, (ulong)y, z);
21 return "Attempting to move to <" + x + ", " + y + ", " + z + ">";
22 }
23 }
24}
diff --git a/ExportBot/Commands/Movement/SitCommand.cs b/ExportBot/Commands/Movement/SitCommand.cs
new file mode 100644
index 0000000..b9ef6be
--- /dev/null
+++ b/ExportBot/Commands/Movement/SitCommand.cs
@@ -0,0 +1,52 @@
1using System;
2using System.Collections.Generic;
3using System.Text;
4using libsecondlife;
5using libsecondlife.Packets;
6
7namespace libsecondlife.TestClient
8{
9 public class SitCommand: Command
10 {
11 public SitCommand(TestClient testClient)
12 {
13 Name = "sit";
14 Description = "Attempt to sit on the closest prim";
15 }
16
17 public override string Execute(string[] args, LLUUID fromAgentID)
18 {
19 Primitive closest = null;
20 double closestDistance = Double.MaxValue;
21
22 lock (Client.SimPrims)
23 {
24 if (Client.SimPrims.ContainsKey(Client.Network.CurrentSim))
25 {
26 foreach (Primitive p in Client.SimPrims[Client.Network.CurrentSim].Values)
27 {
28 float distance = Helpers.VecDist(Client.Self.Position, p.Position);
29
30 if (closest == null || distance < closestDistance)
31 {
32 closest = p;
33 closestDistance = distance;
34 }
35 }
36 }
37 }
38
39 if (closest != null)
40 {
41 Client.Self.RequestSit(closest.ID, LLVector3.Zero);
42 Client.Self.Sit();
43
44 return "Sat on " + closest.ID + ". Distance: " + closestDistance;
45 }
46 else
47 {
48 return "Couldn't find a nearby prim to sit on";
49 }
50 }
51 }
52}
diff --git a/ExportBot/Commands/Movement/SitOnCommand.cs b/ExportBot/Commands/Movement/SitOnCommand.cs
new file mode 100644
index 0000000..ec9d201
--- /dev/null
+++ b/ExportBot/Commands/Movement/SitOnCommand.cs
@@ -0,0 +1,54 @@
1using System;
2using System.Collections.Generic;
3using System.Text;
4using libsecondlife;
5using libsecondlife.Packets;
6
7namespace libsecondlife.TestClient
8{
9 public class SitOnCommand: Command
10 {
11 public SitOnCommand(TestClient testClient)
12 {
13 Name = "siton";
14 Description = "Attempt to sit on a particular prim, with specified UUID";
15 }
16
17 public override string Execute(string[] args, LLUUID fromAgentID)
18 {
19 LLObject targetSeat = null;
20
21 lock (Client.SimPrims)
22 {
23 if (Client.SimPrims.ContainsKey(Client.Network.CurrentSim))
24 {
25 foreach (LLObject p in Client.SimPrims[Client.Network.CurrentSim].Values)
26 {
27 try
28 {
29 if (p.ID == args[0])
30 targetSeat = p;
31 }
32 catch
33 {
34 // handle exception
35 return "Sorry, I don't think " + args[0] + " is a valid UUID. I'm unable to sit there.";
36 }
37 }
38 }
39 }
40
41 if (targetSeat != null)
42 {
43 Client.Self.RequestSit(targetSeat.ID, LLVector3.Zero);
44 Client.Self.Sit();
45
46 return "Sat on prim " + targetSeat.ID + ".";
47 }
48 else
49 {
50 return "Couldn't find specified prim to sit on";
51 }
52 }
53 }
54} \ No newline at end of file
diff --git a/ExportBot/Commands/Movement/StandCommand.cs b/ExportBot/Commands/Movement/StandCommand.cs
new file mode 100644
index 0000000..8a00552
--- /dev/null
+++ b/ExportBot/Commands/Movement/StandCommand.cs
@@ -0,0 +1,47 @@
1using System;
2using System.Collections.Generic;
3using System.Text;
4using libsecondlife;
5using libsecondlife.Packets;
6
7namespace libsecondlife.TestClient
8{
9 public class StandCommand: Command
10 {
11 public StandCommand(TestClient testClient)
12 {
13 Name = "stand";
14 Description = "Stand";
15 }
16
17 public override string Execute(string[] args, LLUUID fromAgentID)
18 {
19 Client.Self.Status.StandUp = true;
20 stand(Client);
21 return "Standing up.";
22 }
23
24 void stand(SecondLife client)
25 {
26 SendAgentUpdate(client, (uint)MainAvatar.ControlFlags.AGENT_CONTROL_STAND_UP);
27 }
28
29 const float DRAW_DISTANCE = 96.0f;
30 void SendAgentUpdate(SecondLife client, uint ControlID)
31 {
32 AgentUpdatePacket p = new AgentUpdatePacket();
33 p.AgentData.Far = DRAW_DISTANCE;
34 //LLVector3 myPos = client.Self.Position;
35 p.AgentData.CameraCenter = new LLVector3(0, 0, 0);
36 p.AgentData.CameraAtAxis = new LLVector3(0, 0, 0);
37 p.AgentData.CameraLeftAxis = new LLVector3(0, 0, 0);
38 p.AgentData.CameraUpAxis = new LLVector3(0, 0, 0);
39 p.AgentData.HeadRotation = new LLQuaternion(0, 0, 0, 1); ;
40 p.AgentData.BodyRotation = new LLQuaternion(0, 0, 0, 1); ;
41 p.AgentData.AgentID = client.Network.AgentID;
42 p.AgentData.SessionID = client.Network.SessionID;
43 p.AgentData.ControlFlags = ControlID;
44 client.Network.SendPacket(p);
45 }
46 }
47}
diff --git a/ExportBot/Commands/PacketLogCommand.cs b/ExportBot/Commands/PacketLogCommand.cs
new file mode 100644
index 0000000..827b147
--- /dev/null
+++ b/ExportBot/Commands/PacketLogCommand.cs
@@ -0,0 +1,84 @@
1using System;
2using System.Collections.Generic;
3using System.Xml;
4using libsecondlife;
5using libsecondlife.Packets;
6
7namespace libsecondlife.TestClient
8{
9 public class PacketLogCommand : Command
10 {
11 List<Packet> Packets = new List<Packet>();
12 bool Done = false;
13 int Count = 0;
14 int Total = 0;
15
16 public PacketLogCommand(TestClient testClient)
17 {
18 Name = "packetlog";
19 Description = "Logs a given number of packets to an xml file. Usage: packetlog 10 tenpackets.xml";
20 }
21
22 public override string Execute(string[] args, LLUUID fromAgentID)
23 {
24 if (args.Length != 2)
25 return "Usage: packetlog 10 tenpackets.xml";
26
27 XmlWriter writer;
28 NetworkManager.PacketCallback callback = new NetworkManager.PacketCallback(OnPacket);
29
30 Packets.Clear();
31 Done = false;
32 Count = 0;
33
34 try
35 {
36 Total = Int32.Parse(args[0]);
37 writer = XmlWriter.Create(args[1]);
38
39 Client.Network.RegisterCallback(PacketType.Default, callback);
40 }
41 catch (Exception e)
42 {
43 return "Usage: packetlog 10 tenpackets.xml (" + e + ")";
44 }
45
46 while (!Done)
47 {
48 System.Threading.Thread.Sleep(100);
49 }
50
51 Client.Network.UnregisterCallback(PacketType.Default, callback);
52
53 try
54 {
55 Helpers.PacketListToXml(Packets, writer);
56 }
57 catch (Exception e)
58 {
59 return "Serialization failed: " + e.ToString();
60 }
61
62 writer.Close();
63 Packets.Clear();
64
65 return "Exported " + Count + " packets to " + args[1];
66 }
67
68 private void OnPacket(Packet packet, Simulator simulator)
69 {
70 lock (Packets)
71 {
72 if (Count >= Total)
73 {
74 Done = true;
75 }
76 else
77 {
78 Packets.Add(packet);
79 Count++;
80 }
81 }
82 }
83 }
84}
diff --git a/ExportBot/Commands/ParcelInfoCommand.cs b/ExportBot/Commands/ParcelInfoCommand.cs
new file mode 100644
index 0000000..e4108a9
--- /dev/null
+++ b/ExportBot/Commands/ParcelInfoCommand.cs
@@ -0,0 +1,62 @@
1using System;
2using System.Collections.Generic;
3using System.Threading;
4using libsecondlife;
5using libsecondlife.Utilities;
6
7namespace libsecondlife.TestClient
8{
9 public class ParcelInfoCommand : Command
10 {
11 private ParcelDownloader ParcelDownloader;
12 private ManualResetEvent ParcelsDownloaded = new ManualResetEvent(false);
13 private int ParcelCount = 0;
14
15 public ParcelInfoCommand(TestClient testClient)
16 {
17 Name = "parcelinfo";
18 Description = "Prints out info about all the parcels in this simulator";
19
20 ParcelDownloader = new ParcelDownloader(testClient);
21 ParcelDownloader.OnParcelsDownloaded += new ParcelDownloader.ParcelsDownloadedCallback(Parcels_OnParcelsDownloaded);
22 testClient.Network.OnDisconnected += new NetworkManager.DisconnectedCallback(Network_OnDisconnected);
23 }
24
25 public override string Execute(string[] args, LLUUID fromAgentID)
26 {
27 ParcelDownloader.DownloadSimParcels(Client.Network.CurrentSim);
28
29 ParcelsDownloaded.Reset();
30 ParcelsDownloaded.WaitOne(20000, false);
31
32 if (Client.Network.CurrentSim != null)
33 return "Downloaded information for " + ParcelCount + " parcels in " + Client.Network.CurrentSim.Name;
34 else
35 return String.Empty;
36 }
37
38 void Parcels_OnParcelsDownloaded(Simulator simulator, Dictionary<int, Parcel> Parcels, int[,] map)
39 {
40 foreach (KeyValuePair<int, Parcel> parcel in Parcels)
41 {
42 WaterType type = ParcelDownloader.GetWaterType(map, parcel.Value.LocalID);
43 float delta = ParcelDownloader.GetHeightRange(map, parcel.Value.LocalID);
44 int deviation = ParcelDownloader.GetRectangularDeviation(parcel.Value.AABBMin, parcel.Value.AABBMax,
45 parcel.Value.Area);
46
47 Console.WriteLine("Parcels[{0}]: Name: \"{1}\", Description: \"{2}\" ACL Count: {3}, " +
48 "Location: {4}, Height Range: {5}, Shape Deviation: {6}", parcel.Key, parcel.Value.Name,
49 parcel.Value.Desc, parcel.Value.AccessList.Count, type.ToString(), delta, deviation);
50 }
51
52 ParcelCount = Parcels.Count;
53
54 ParcelsDownloaded.Set();
55 }
56
57 void Network_OnDisconnected(NetworkManager.DisconnectType reason, string message)
58 {
59 ParcelsDownloaded.Set();
60 }
61 }
62}
diff --git a/ExportBot/Commands/PrimCountCommand.cs b/ExportBot/Commands/PrimCountCommand.cs
new file mode 100644
index 0000000..8adc563
--- /dev/null
+++ b/ExportBot/Commands/PrimCountCommand.cs
@@ -0,0 +1,32 @@
1using System;
2using System.Collections.Generic;
3using System.Text;
4using libsecondlife;
5using libsecondlife.Packets;
6
7namespace libsecondlife.TestClient
8{
9 public class PrimCountCommand: Command
10 {
11 public PrimCountCommand(TestClient testClient)
12 {
13 Name = "primcount";
14 Description = "Shows the number of prims that have been received.";
15 }
16
17 public override string Execute(string[] args, LLUUID fromAgentID)
18 {
19 int count = 0;
20
21 lock (Client.SimPrims)
22 {
23 foreach (Dictionary<uint, Primitive> prims in Client.SimPrims.Values)
24 {
25 count += prims.Count;
26 }
27 }
28
29 return count.ToString();
30 }
31 }
32}
diff --git a/ExportBot/Commands/QuitCommand.cs b/ExportBot/Commands/QuitCommand.cs
new file mode 100644
index 0000000..4cd7209
--- /dev/null
+++ b/ExportBot/Commands/QuitCommand.cs
@@ -0,0 +1,24 @@
1using System;
2using System.Collections.Generic;
3using System.Text;
4using libsecondlife;
5using libsecondlife.Packets;
6
7namespace libsecondlife.TestClient
8{
9 public class QuitCommand: Command
10 {
11 public QuitCommand(TestClient testClient)
12 {
13 Name = "quit";
14 Description = "Log all avatars out and shut down";
15 }
16
17 public override string Execute(string[] args, LLUUID fromAgentID)
18 {
19 Client.ClientManager.LogoutAll();
20 Client.ClientManager.Running = false;
21 return "All avatars logged out";
22 }
23 }
24}
diff --git a/ExportBot/Commands/RegionInfoCommand.cs b/ExportBot/Commands/RegionInfoCommand.cs
new file mode 100644
index 0000000..7581137
--- /dev/null
+++ b/ExportBot/Commands/RegionInfoCommand.cs
@@ -0,0 +1,45 @@
1using System;
2using System.Text;
3using libsecondlife;
4
5namespace libsecondlife.TestClient
6{
7 public class RegionInfoCommand : Command
8 {
9 public RegionInfoCommand(TestClient testClient)
10 {
11 Name = "regioninfo";
12 Description = "Prints out info about all the current region";
13 }
14
15 public override string Execute(string[] args, LLUUID fromAgentID)
16 {
17 StringBuilder output = new StringBuilder();
18 output.AppendLine(Client.Network.CurrentSim.ToString());
19 output.Append("Access: ");
20 output.AppendLine(Client.Network.CurrentSim.Access.ToString());
21 output.Append("Flags: ");
22 output.AppendLine(Client.Network.CurrentSim.Flags.ToString());
23 output.Append("TerrainBase0: ");
24 output.AppendLine(Client.Network.CurrentSim.TerrainBase0.ToStringHyphenated());
25 output.Append("TerrainBase1: ");
26 output.AppendLine(Client.Network.CurrentSim.TerrainBase1.ToStringHyphenated());
27 output.Append("TerrainBase2: ");
28 output.AppendLine(Client.Network.CurrentSim.TerrainBase2.ToStringHyphenated());
29 output.Append("TerrainBase3: ");
30 output.AppendLine(Client.Network.CurrentSim.TerrainBase3.ToStringHyphenated());
31 output.Append("TerrainDetail0: ");
32 output.AppendLine(Client.Network.CurrentSim.TerrainDetail0.ToStringHyphenated());
33 output.Append("TerrainDetail1: ");
34 output.AppendLine(Client.Network.CurrentSim.TerrainDetail1.ToStringHyphenated());
35 output.Append("TerrainDetail2: ");
36 output.AppendLine(Client.Network.CurrentSim.TerrainDetail2.ToStringHyphenated());
37 output.Append("TerrainDetail3: ");
38 output.AppendLine(Client.Network.CurrentSim.TerrainDetail3.ToStringHyphenated());
39 output.Append("Water Height: ");
40 output.AppendLine(Client.Network.CurrentSim.WaterHeight.ToString());
41
42 return output.ToString();
43 }
44 }
45}
diff --git a/ExportBot/Commands/SetMasterCommand.cs b/ExportBot/Commands/SetMasterCommand.cs
new file mode 100644
index 0000000..a6ecbdc
--- /dev/null
+++ b/ExportBot/Commands/SetMasterCommand.cs
@@ -0,0 +1,73 @@
1using System;
2using System.Collections.Generic;
3using System.Text;
4using System.Threading;
5using libsecondlife;
6using libsecondlife.Packets;
7
8namespace libsecondlife.TestClient
9{
10 public class SetMasterCommand: Command
11 {
12 public DateTime Created = DateTime.Now;
13 private LLUUID resolvedMasterKey = LLUUID.Zero;
14 private ManualResetEvent keyResolution = new ManualResetEvent(false);
15 private LLUUID query = LLUUID.Zero;
16
17 public SetMasterCommand(TestClient testClient)
18 {
19 Name = "setMaster";
20 Description = "Sets the user name of the master user. The master user can IM to run commands.";
21
22 }
23
24 public override string Execute(string[] args, LLUUID fromAgentID)
25 {
26 string masterName = String.Empty;
27 for (int ct = 0; ct < args.Length;ct++)
28 masterName = masterName + args[ct] + " ";
29 masterName = masterName.TrimEnd();
30
31 if (masterName.Length == 0)
32 return "Usage setMaster name";
33
34 DirectoryManager.DirPeopleReplyCallback callback = new DirectoryManager.DirPeopleReplyCallback(KeyResolvHandler);
35 Client.Directory.OnDirPeopleReply += callback;
36 query = Client.Directory.StartPeopleSearch(DirectoryManager.DirFindFlags.People, masterName);
37 if (keyResolution.WaitOne(TimeSpan.FromMinutes(1), false))
38 {
39 Client.MasterKey = resolvedMasterKey;
40 keyResolution.Reset();
41 Client.Directory.OnDirPeopleReply -= callback;
42 }
43 else
44 {
45 keyResolution.Reset();
46 Client.Directory.OnDirPeopleReply -= callback;
47 return "Unable to obtain UUID for \"" + masterName + "\". Master unchanged.";
48 }
49
50
51 foreach (Avatar av in Client.AvatarList.Values)
52 {
53 if (av.ID == Client.MasterKey)
54 {
55 Client.Self.InstantMessage(av.ID, "You are now my master. IM me with \"help\" for a command list.");
56 break;
57 }
58 }
59
60 return "Master set to " + masterName + " (" + Client.MasterKey.ToStringHyphenated() + ")";
61 }
62
63 private void KeyResolvHandler(LLUUID queryid, List<DirectoryManager.AgentSearchData> matches)
64 {
65 if (query != queryid)
66 return;
67 // We can't handle ambiguities here as nicely as we can in ClientManager.
68 resolvedMasterKey = matches[0].AgentID;
69 keyResolution.Set();
70 query = LLUUID.Zero;
71 }
72 }
73}
diff --git a/ExportBot/Commands/SetMasterKeyCommand.cs b/ExportBot/Commands/SetMasterKeyCommand.cs
new file mode 100644
index 0000000..0085f79
--- /dev/null
+++ b/ExportBot/Commands/SetMasterKeyCommand.cs
@@ -0,0 +1,35 @@
1using System;
2using System.Collections.Generic;
3using System.Text;
4using libsecondlife;
5using libsecondlife.Packets;
6
7namespace libsecondlife.TestClient
8{
9 public class SetMasterKeyCommand : Command
10 {
11 public DateTime Created = DateTime.Now;
12
13 public SetMasterKeyCommand(TestClient testClient)
14 {
15 Name = "setMasterKey";
16 Description = "Sets the key of the master user. The master user can IM to run commands.";
17 }
18
19 public override string Execute(string[] args, LLUUID fromAgentID)
20 {
21 Client.MasterKey = LLUUID.Parse(args[0]);
22
23 foreach (Avatar av in Client.AvatarList.Values)
24 {
25 if (av.ID == Client.MasterKey)
26 {
27 Client.Self.InstantMessage(av.ID, "You are now my master. IM me with \"help\" for a command list.");
28 break;
29 }
30 }
31
32 return "Master set to " + Client.MasterKey;
33 }
34 }
35}
diff --git a/ExportBot/Commands/ShowEffectsCommand.cs b/ExportBot/Commands/ShowEffectsCommand.cs
new file mode 100644
index 0000000..c0b20a7
--- /dev/null
+++ b/ExportBot/Commands/ShowEffectsCommand.cs
@@ -0,0 +1,76 @@
1using System;
2using libsecondlife;
3
4namespace libsecondlife.TestClient
5{
6 public class ShowEffectsCommand : Command
7 {
8 bool ShowEffects = false;
9
10 public ShowEffectsCommand(TestClient testClient)
11 {
12 Name = "showeffects";
13 Description = "Prints out information for every viewer effect that is received. Usage: showeffects [on/off]";
14
15 testClient.Avatars.OnEffect += new AvatarManager.EffectCallback(Avatars_OnEffect);
16 testClient.Avatars.OnLookAt += new AvatarManager.LookAtCallback(Avatars_OnLookAt);
17 testClient.Avatars.OnPointAt += new AvatarManager.PointAtCallback(Avatars_OnPointAt);
18 }
19
20 public override string Execute(string[] args, LLUUID fromAgentID)
21 {
22 if (args.Length == 0)
23 {
24 ShowEffects = true;
25 return "Viewer effects will be shown on the console";
26 }
27 else if (args.Length == 1)
28 {
29 if (args[0] == "on")
30 {
31 ShowEffects = true;
32 return "Viewer effects will be shown on the console";
33 }
34 else
35 {
36 ShowEffects = false;
37 return "Viewer effects will not be shown";
38 }
39 }
40 else
41 {
42 return "Usage: showeffects [on/off]";
43 }
44 }
45
46 private void Avatars_OnPointAt(LLUUID sourceID, LLUUID targetID, LLVector3d targetPos,
47 MainAvatar.PointAtType pointType, float duration, LLUUID id)
48 {
49 if (ShowEffects)
50 Console.WriteLine(
51 "ViewerEffect [PointAt]: SourceID: {0} TargetID: {1} TargetPos: {2} Type: {3} Duration: {4} ID: {5}",
52 sourceID.ToStringHyphenated(), targetID.ToStringHyphenated(), targetPos, pointType, duration,
53 id.ToStringHyphenated());
54 }
55
56 private void Avatars_OnLookAt(LLUUID sourceID, LLUUID targetID, LLVector3d targetPos,
57 MainAvatar.LookAtType lookType, float duration, LLUUID id)
58 {
59 if (ShowEffects)
60 Console.WriteLine(
61 "ViewerEffect [LookAt]: SourceID: {0} TargetID: {1} TargetPos: {2} Type: {3} Duration: {4} ID: {5}",
62 sourceID.ToStringHyphenated(), targetID.ToStringHyphenated(), targetPos, lookType, duration,
63 id.ToStringHyphenated());
64 }
65
66 private void Avatars_OnEffect(MainAvatar.EffectType type, LLUUID sourceID, LLUUID targetID,
67 LLVector3d targetPos, float duration, LLUUID id)
68 {
69 if (ShowEffects)
70 Console.WriteLine(
71 "ViewerEffect [{0}]: SourceID: {1} TargetID: {2} TargetPos: {3} Duration: {4} ID: {5}",
72 type, sourceID.ToStringHyphenated(), targetID.ToStringHyphenated(), targetPos, duration,
73 id.ToStringHyphenated());
74 }
75 }
76}
diff --git a/ExportBot/Commands/StatsCommand.cs b/ExportBot/Commands/StatsCommand.cs
new file mode 100644
index 0000000..7835ec8
--- /dev/null
+++ b/ExportBot/Commands/StatsCommand.cs
@@ -0,0 +1,39 @@
1using System;
2using System.Collections.Generic;
3using System.Text;
4using libsecondlife;
5using libsecondlife.Packets;
6
7namespace libsecondlife.TestClient
8{
9 public class StatsCommand : Command
10 {
11 public StatsCommand(TestClient testClient)
12 {
13 Name = "stats";
14 Description = "Provide connection figures and statistics";
15 }
16
17 public override string Execute(string[] args, LLUUID fromAgentID)
18 {
19 StringBuilder output = new StringBuilder();
20
21 lock (Client.Network.Simulators)
22 {
23 for (int i = 0; i < Client.Network.Simulators.Count; i++)
24 {
25 Simulator sim = Client.Network.Simulators[i];
26
27 output.AppendLine(String.Format(
28 "[{0}] Dilation: {1} InBPS: {2} OutBPS: {3} ResentOut: {4} ResentIn: {5}",
29 sim.ToString(), sim.Dilation, sim.IncomingBPS, sim.OutgoingBPS, sim.ResentPackets,
30 sim.ReceivedResends));
31 }
32 }
33
34 output.Append("Packets in the queue: " + Client.Network.InboxCount);
35
36 return output.ToString();
37 }
38 }
39}
diff --git a/ExportBot/Commands/TouchCommand.cs b/ExportBot/Commands/TouchCommand.cs
new file mode 100644
index 0000000..4103d21
--- /dev/null
+++ b/ExportBot/Commands/TouchCommand.cs
@@ -0,0 +1,55 @@
1using System;
2using System.Collections.Generic;
3using System.Text;
4using libsecondlife;
5using libsecondlife.Packets;
6
7namespace libsecondlife.TestClient
8{
9 public class TouchCommand: Command
10 {
11 public TouchCommand(TestClient testClient)
12 {
13 Name = "touch";
14 Description = "Attempt to touch a prim with specified UUID";
15 }
16
17 public override string Execute(string[] args, LLUUID fromAgentID)
18 {
19 Primitive target = null;
20
21 lock (Client.SimPrims)
22 {
23 if (Client.SimPrims.ContainsKey(Client.Network.CurrentSim))
24 {
25 foreach (Primitive p in Client.SimPrims[Client.Network.CurrentSim].Values)
26 {
27 if (args.Length == 0)
28 return "You must specify a UUID of the prim.";
29
30 try
31 {
32 if (p.ID == args[0])
33 target = p;
34 }
35 catch
36 {
37 // handle exception
38 return "Sorry, I don't think " + args[0] + " is a valid UUID. I'm unable to touch it.";
39 }
40 }
41 }
42 }
43
44 if (target != null)
45 {
46 Client.Self.Touch(target.LocalID);
47 return "Touched prim " + target.ID + ".";
48 }
49 else
50 {
51 return "Couldn't find that prim.";
52 }
53 }
54 }
55} \ No newline at end of file
diff --git a/ExportBot/Commands/TreeCommand.cs b/ExportBot/Commands/TreeCommand.cs
new file mode 100644
index 0000000..2029e37
--- /dev/null
+++ b/ExportBot/Commands/TreeCommand.cs
@@ -0,0 +1,51 @@
1using System;
2using System.Collections.Generic;
3using System.Text;
4using libsecondlife;
5using libsecondlife.Packets;
6
7namespace libsecondlife.TestClient
8{
9 public class TreeCommand: Command
10 {
11 public TreeCommand(TestClient testClient)
12 {
13 Name = "tree";
14 Description = "Rez a tree.";
15 }
16
17 public override string Execute(string[] args, LLUUID fromAgentID)
18 {
19 if (args.Length == 1)
20 {
21 try
22 {
23 string treeName = args[0].Trim(new char[] { ' ' });
24 ObjectManager.Tree tree = (ObjectManager.Tree)Enum.Parse(typeof(ObjectManager.Tree), treeName);
25
26 LLVector3 treePosition = new LLVector3(Client.Self.Position.X, Client.Self.Position.Y,
27 Client.Self.Position.Z);
28 treePosition.Z += 3.0f;
29
30 Client.Objects.AddTree(Client.Network.CurrentSim, new LLVector3(0.5f, 0.5f, 0.5f),
31 LLQuaternion.Identity, treePosition, tree, Client.GroupID, false);
32
33 return "Attempted to rez a " + treeName + " tree";
34 }
35 catch (Exception)
36 {
37 return "Type !tree for usage";
38 }
39 }
40
41 string usage = "Usage: !tree [";
42 foreach (string value in Enum.GetNames(typeof(ObjectManager.Tree)))
43 {
44 usage += value + ",";
45 }
46 usage = usage.TrimEnd(new char[] { ',' });
47 usage += "]";
48 return usage;
49 }
50 }
51}
diff --git a/ExportBot/Commands/UptimeCommand.cs b/ExportBot/Commands/UptimeCommand.cs
new file mode 100644
index 0000000..3edec73
--- /dev/null
+++ b/ExportBot/Commands/UptimeCommand.cs
@@ -0,0 +1,25 @@
1using System;
2using System.Collections.Generic;
3using System.Text;
4using libsecondlife;
5using libsecondlife.Packets;
6
7namespace libsecondlife.TestClient
8{
9 public class UptimeCommand : Command
10 {
11 public DateTime Created = DateTime.Now;
12
13 public UptimeCommand(TestClient testClient)
14 {
15 Name = "uptime";
16 Description = "Shows the login name, login time and length of time logged on.";
17 }
18
19 public override string Execute(string[] args, LLUUID fromAgentID)
20 {
21 string name = Client.ToString();
22 return "I am " + name + ", Up Since: " + Created + " (" + (DateTime.Now - Created) + ")";
23 }
24 }
25} \ No newline at end of file
diff --git a/ExportBot/Commands/WhoCommand.cs b/ExportBot/Commands/WhoCommand.cs
new file mode 100644
index 0000000..83d8610
--- /dev/null
+++ b/ExportBot/Commands/WhoCommand.cs
@@ -0,0 +1,29 @@
1using System;
2using System.Collections.Generic;
3using System.Text;
4using libsecondlife;
5using libsecondlife.Packets;
6
7namespace libsecondlife.TestClient
8{
9 public class WhoCommand: Command
10 {
11 public WhoCommand(TestClient testClient)
12 {
13 Name = "who";
14 Description = "Lists seen avatars.";
15 }
16
17 public override string Execute(string[] args, LLUUID fromAgentID)
18 {
19 StringBuilder result = new StringBuilder();
20 foreach (Avatar av in Client.AvatarList.Values)
21 {
22 result.AppendFormat("\n{0} {1} {2}/{3} ID: {4}", av.Name, av.GroupName,
23 (av.CurrentSim != null ? av.CurrentSim.Name : String.Empty), av.Position, av.ID);
24 }
25
26 return result.ToString();
27 }
28 }
29}
diff --git a/ExportBot/Parsing.cs b/ExportBot/Parsing.cs
new file mode 100644
index 0000000..1e081c1
--- /dev/null
+++ b/ExportBot/Parsing.cs
@@ -0,0 +1,61 @@
1using System;
2using System.Collections.Generic;
3using System.Text;
4
5namespace libsecondlife.TestClient {
6 class Parsing {
7 public static string[] ParseArguments(string str) {
8 List<string> list = new List<string>();
9 string current = "";
10 string trimmed = null;
11 bool withinQuote = false;
12 bool escaped = false;
13 foreach (char c in str) {
14 if (c == '"') {
15 if (escaped) {
16 current += '"';
17 escaped = false;
18 } else {
19 current += '"';
20 withinQuote = !withinQuote;
21 }
22 } else if (c == ' ' || c == '\t') {
23 if (escaped || withinQuote) {
24 current += c;
25 escaped = false;
26 } else {
27 trimmed = current.Trim();
28 if (trimmed.StartsWith("\"") && trimmed.EndsWith("\"")) {
29 trimmed = trimmed.Remove(0, 1);
30 trimmed = trimmed.Remove(trimmed.Length - 1);
31 trimmed = trimmed.Trim();
32 }
33 if (trimmed.Length > 0)
34 list.Add(trimmed);
35 current = "";
36 }
37 } else if (c == '\\') {
38 if (escaped) {
39 current += '\\';
40 escaped = false;
41 } else {
42 escaped = true;
43 }
44 } else {
45 if (escaped)
46 throw new FormatException(c.ToString() + " is not an escapable character.");
47 current += c;
48 }
49 }
50 trimmed = current.Trim();
51 if (trimmed.StartsWith("\"") && trimmed.EndsWith("\"")) {
52 trimmed = trimmed.Remove(0, 1);
53 trimmed = trimmed.Remove(trimmed.Length - 1);
54 trimmed = trimmed.Trim();
55 }
56 if (trimmed.Length > 0)
57 list.Add(trimmed);
58 return list.ToArray();
59 }
60 }
61}
diff --git a/ExportBot/Program.cs b/ExportBot/Program.cs
new file mode 100644
index 0000000..705cf90
--- /dev/null
+++ b/ExportBot/Program.cs
@@ -0,0 +1,127 @@
1using System;
2using System.Collections.Generic;
3using System.IO;
4using CommandLine.Utility;
5
6namespace libsecondlife.TestClient
7{
8 public class Program
9 {
10 private static void Usage()
11 {
12 Console.WriteLine("Usage: " + Environment.NewLine +
13 "TestClient.exe --first firstname --last lastname --pass password --contact \"youremail\" [--startpos \"sim/x/y/z\"] [--master \"master name\"] [--masterkey \"master uuid\"]" +
14 Environment.NewLine + "TestClient.exe --file filename --contact \"youremail\" [--master \"master name\"] [--masterkey \"master uuid\"]");
15 }
16
17 static void Main(string[] args)
18 {
19 Arguments arguments = new Arguments(args);
20
21 ClientManager manager;
22 List<LoginDetails> accounts = new List<LoginDetails>();
23 LoginDetails account;
24 string masterName = String.Empty;
25 LLUUID masterKey = LLUUID.Zero;
26 string file = String.Empty;
27 string contact = String.Empty;
28
29 if (arguments["masterkey"] != null)
30 {
31 masterKey = LLUUID.Parse(arguments["masterkey"]);
32 }
33 if (arguments["master"] != null)
34 {
35 masterName = arguments["master"];
36 }
37
38 if (arguments["contact"] != null)
39 {
40 contact = arguments["contact"];
41 if (arguments["file"] != null)
42 {
43 file = arguments["file"];
44
45 // Loading names from a file
46 try
47 {
48 using (StreamReader reader = new StreamReader(file))
49 {
50 string line;
51 int lineNumber = 0;
52
53 while ((line = reader.ReadLine()) != null)
54 {
55 lineNumber++;
56 string[] tokens = line.Trim().Split(new char[] { ' ', ',' });
57
58 if (tokens.Length >= 3)
59 {
60 account = new LoginDetails();
61 account.FirstName = tokens[0];
62 account.LastName = tokens[1];
63 account.Password = tokens[2];
64
65 accounts.Add(account);
66
67 // Leaving this out until we have per-account masters (if that
68 // is desirable). For now the command-line option can
69 // specify the single master that TestClient supports
70
71 //if (tokens.Length == 5)
72 //{
73 // master = tokens[3] + " " + tokens[4];
74 //}
75 }
76 else
77 {
78 Console.WriteLine("Invalid data on line " + lineNumber +
79 ", must be in the format of: FirstName LastName Password");
80 }
81 }
82 }
83 }
84 catch (Exception e)
85 {
86 Console.WriteLine("Error reading from " + args[1]);
87 Console.WriteLine(e.ToString());
88 return;
89 }
90 }
91 else
92 {
93 if (arguments["first"] != null && arguments["last"] != null && arguments["pass"] != null)
94 {
95 // Taking a single login off the command-line
96 account = new LoginDetails();
97 account.FirstName = arguments["first"];
98 account.LastName = arguments["last"];
99 account.Password = arguments["pass"];
100
101 accounts.Add(account);
102 }
103 }
104 }
105 else
106 {
107 Usage();
108 return;
109 }
110
111 foreach (LoginDetails a in accounts)
112 {
113 a.MasterName = masterName;
114 a.MasterKey = masterKey;
115 }
116
117 // Login the accounts and run the input loop
118 if ( arguments["start"] != null ) {
119 manager = new ClientManager(accounts, contact, arguments["start"]);
120 } else {
121 manager = new ClientManager(accounts, contact);
122 }
123 manager.Run();
124
125 }
126 }
127}
diff --git a/ExportBot/Properties/AssemblyInfo.cs b/ExportBot/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..471a306
--- /dev/null
+++ b/ExportBot/Properties/AssemblyInfo.cs
@@ -0,0 +1,33 @@
1using System.Reflection;
2using System.Runtime.CompilerServices;
3using System.Runtime.InteropServices;
4
5// General Information about an assembly is controlled through the following
6// set of attributes. Change these attribute values to modify the information
7// associated with an assembly.
8[assembly: AssemblyTitle("TestClient")]
9[assembly: AssemblyDescription("")]
10[assembly: AssemblyConfiguration("")]
11[assembly: AssemblyCompany("")]
12[assembly: AssemblyProduct("TestClient")]
13[assembly: AssemblyCopyright("Copyright © 2006")]
14[assembly: AssemblyTrademark("")]
15[assembly: AssemblyCulture("")]
16
17// Setting ComVisible to false makes the types in this assembly not visible
18// to COM components. If you need to access a type in this assembly from
19// COM, set the ComVisible attribute to true on that type.
20[assembly: ComVisible(false)]
21
22// The following GUID is for the ID of the typelib if this project is exposed to COM
23[assembly: Guid("0563f706-7fa9-42f6-bf23-c6acd1175964")]
24
25// Version information for an assembly consists of the following four values:
26//
27// Major Version
28// Minor Version
29// Build Number
30// Revision
31//
32[assembly: AssemblyVersion("1.0.0.0")]
33[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/ExportBot/README b/ExportBot/README
new file mode 100644
index 0000000..1de2db1
--- /dev/null
+++ b/ExportBot/README
@@ -0,0 +1,5 @@
1This is a fork of TestClient from the main libsl project, it is not built as a normal part of the opensim release and is designed to allow migration of avatars from the main LL grid to an OGS system.
2
3It's essentially a "good CopyBot" - before an avatar is copied consent is taken and the avatar data is exported out to the remote grid via a web service. The bot is designed to be evoked remotely via an LSL script in-world.
4
5THE AUTHOR ACCEPTS NO RESPONSIBILITY WHATSOEVER FOR ANY POTENTIALLY INFRINGING USES OF THIS CODE.
diff --git a/ExportBot/TestClient.build b/ExportBot/TestClient.build
new file mode 100644
index 0000000..803377b
--- /dev/null
+++ b/ExportBot/TestClient.build
@@ -0,0 +1,125 @@
1<?xml version="1.0"?>
2
3<project
4 name="libsecondlife"
5 default="build">
6
7 <!-- global framework settings -->
8 <property
9 name="target.framework"
10 value="${framework::get-target-framework()}" />
11 <property
12 name="assembly.dir"
13 value="${framework::get-assembly-directory(target.framework)}" />
14
15 <!-- global project settings -->
16 <xmlpeek
17 file="../../../libsecondlife.build"
18 xpath="/project/property[@name = 'project.version']/@value"
19 property="project.version" />
20 <property
21 name="build.number"
22 value="${math::abs(math::floor(timespan::get-total-days(datetime::now()
23 - datetime::parse('01/01/2002'))))}" />
24 <property
25 name="assembly"
26 value="TestClient"/>
27 <property
28 name="bin_dir"
29 value="../../../bin" />
30
31 <!-- default configuration -->
32 <property
33 name="project.config"
34 value="debug" /> <!-- debug|release -->
35
36 <!-- named configurations -->
37 <target
38 name="init"
39 description="Initializes build properties">
40 <call target="${project.config}" />
41 </target>
42
43 <target
44 name="debug"
45 description="configures a debug build">
46 <property
47 name="build.debug"
48 value="true" />
49 <property
50 name="package.name"
51 value="${project::get-name()}-${project.version}-${project.config}" />
52 <property
53 name="assembly.configuration"
54 value="${framework::get-target-framework()}.${platform::get-name()} [${project.config}]" />
55 </target>
56
57 <target
58 name="release"
59 description="configures a release build">
60 <property
61 name="project.config"
62 value="release" />
63 <property
64 name="build.debug"
65 value="false" />
66 <property
67 name="package.name"
68 value="${project::get-name()}-${project.version}" />
69 <property
70 name="assembly.configuration"
71 value="${framework::get-target-framework()}.${platform::get-name()}" />
72 </target>
73
74 <!-- build tasks -->
75 <target
76 name="build"
77 depends="init"
78 description="Builds the binaries for the current configuration">
79 <echo message="Build Directory is ${bin_dir}/" />
80 <mkdir
81 dir="${bin_dir}"
82 failonerror="false" />
83 <csc
84 target="exe"
85 debug="${build.debug}"
86 output="${bin_dir}/${assembly}.exe">
87 <sources failonempty="true">
88 <include name="*.cs" />
89 <include name="Commands/**.cs" />
90 <exclude name="Commands/Communication/TtsCommand.cs" />
91 </sources>
92 <references basedir="${bin_dir}/">
93 <include name="libsecondlife.dll"/>
94 <include name="openjpegnet.dll"/>
95 </references>
96 </csc>
97 </target>
98
99 <target
100 name="build-dll"
101 description="Builds libsecondlife dll">
102 <nant
103 buildfile="../../libsecondlife-cs/libsecondlife.build"
104 target="${project.config} build"/>
105 </target>
106
107 <target
108 name="clean"
109 depends="init"
110 description="Deletes the current configuration">
111 <delete failonerror="false">
112 <fileset basedir="${bin_dir}/">
113 <include name="${assembly}.exe" />
114 <include name="${assembly}.pdb" />
115 <include name="**/${assembly}.*.resources" />
116 </fileset>
117 </delete>
118 </target>
119
120 <target
121 name="*"
122 description="Handles unknown targets">
123 <echo message="skip" />
124 </target>
125</project>
diff --git a/ExportBot/TestClient.cs b/ExportBot/TestClient.cs
new file mode 100644
index 0000000..cf8783e
--- /dev/null
+++ b/ExportBot/TestClient.cs
@@ -0,0 +1,328 @@
1using System;
2using System.Collections.Generic;
3using System.Reflection;
4using System.Xml;
5using libsecondlife;
6using libsecondlife.Packets;
7using libsecondlife.AssetSystem;
8
9namespace libsecondlife.TestClient
10{
11 public class TestClient : SecondLife
12 {
13 public delegate void PrimCreatedCallback(Simulator simulator, Primitive prim);
14
15 public event PrimCreatedCallback OnPrimCreated;
16
17 public Dictionary<Simulator, Dictionary<uint, Primitive>> SimPrims;
18 public LLUUID GroupID = LLUUID.Zero;
19 public Dictionary<LLUUID, GroupMember> GroupMembers;
20 public Dictionary<uint, Avatar> AvatarList = new Dictionary<uint,Avatar>();
21 public Dictionary<LLUUID, AvatarAppearancePacket> Appearances = new Dictionary<LLUUID, AvatarAppearancePacket>();
22 public Dictionary<string, Command> Commands = new Dictionary<string,Command>();
23 public bool Running = true;
24 public string MasterName = String.Empty;
25 public LLUUID MasterKey = LLUUID.Zero;
26 public ClientManager ClientManager;
27 public int regionX;
28 public int regionY;
29
30 //internal libsecondlife.InventorySystem.InventoryFolder currentDirectory;
31
32 private LLQuaternion bodyRotation = LLQuaternion.Identity;
33 private LLVector3 forward = new LLVector3(0, 0.9999f, 0);
34 private LLVector3 left = new LLVector3(0.9999f, 0, 0);
35 private LLVector3 up = new LLVector3(0, 0, 0.9999f);
36 private System.Timers.Timer updateTimer;
37
38
39 /// <summary>
40 ///
41 /// </summary>
42 public TestClient(ClientManager manager)
43 {
44 ClientManager = manager;
45
46 updateTimer = new System.Timers.Timer(1000);
47 updateTimer.Elapsed += new System.Timers.ElapsedEventHandler(updateTimer_Elapsed);
48
49 RegisterAllCommands(Assembly.GetExecutingAssembly());
50
51 Settings.DEBUG = true;
52 Settings.STORE_LAND_PATCHES = true;
53 Settings.ALWAYS_REQUEST_OBJECTS = true;
54
55 Network.RegisterCallback(PacketType.AgentDataUpdate, new NetworkManager.PacketCallback(AgentDataUpdateHandler));
56
57 Objects.OnNewPrim += new ObjectManager.NewPrimCallback(Objects_OnNewPrim);
58 Objects.OnObjectUpdated += new ObjectManager.ObjectUpdatedCallback(Objects_OnObjectUpdated);
59 Objects.OnObjectKilled += new ObjectManager.KillObjectCallback(Objects_OnObjectKilled);
60 Objects.OnNewAvatar += new ObjectManager.NewAvatarCallback(Objects_OnNewAvatar);
61 Self.OnInstantMessage += new MainAvatar.InstantMessageCallback(Self_OnInstantMessage);
62 Groups.OnGroupMembers += new GroupManager.GroupMembersCallback(GroupMembersHandler);
63 this.OnLogMessage += new LogCallback(TestClient_OnLogMessage);
64
65 Network.RegisterCallback(PacketType.AvatarAppearance, new NetworkManager.PacketCallback(AvatarAppearanceHandler));
66
67 updateTimer.Start();
68 }
69
70 public void RegisterAllCommands(Assembly assembly)
71 {
72 foreach (Type t in assembly.GetTypes())
73 {
74 try
75 {
76 if (t.IsSubclassOf(typeof(Command)))
77 {
78 ConstructorInfo info = t.GetConstructor(new Type[] { typeof(TestClient) });
79 Command command = (Command)info.Invoke(new object[] { this });
80 RegisterCommand(command);
81 }
82 }
83 catch (Exception e)
84 {
85 Console.WriteLine(e.ToString());
86 }
87 }
88 }
89
90 public void RegisterCommand(Command command)
91 {
92 command.Client = this;
93 if (!Commands.ContainsKey(command.Name.ToLower()))
94 {
95 Commands.Add(command.Name.ToLower(), command);
96 }
97 }
98
99 //breaks up large responses to deal with the max IM size
100 private void SendResponseIM(SecondLife client, LLUUID fromAgentID, string data, LLUUID imSessionID)
101 {
102 for ( int i = 0 ; i < data.Length ; i += 1024 ) {
103 int y;
104 if ((i + 1023) > data.Length)
105 {
106 y = data.Length - i;
107 }
108 else
109 {
110 y = 1023;
111 }
112 string message = data.Substring(i, y);
113 client.Self.InstantMessage(fromAgentID, message, imSessionID);
114 }
115 }
116
117 public void DoCommand(string cmd, LLUUID fromAgentID, LLUUID imSessionID)
118 {
119 string[] tokens = Parsing.ParseArguments(cmd);
120
121 if (tokens.Length == 0)
122 return;
123
124 string firstToken = tokens[0].ToLower();
125
126 // "all balance" will send the balance command to all currently logged in bots
127 if (firstToken == "all" && tokens.Length > 1)
128 {
129 cmd = String.Empty;
130
131 // Reserialize all of the arguments except for "all"
132 for (int i = 1; i < tokens.Length; i++)
133 {
134 cmd += tokens[i] + " ";
135 }
136
137 ClientManager.DoCommandAll(cmd, fromAgentID, imSessionID);
138
139 return;
140 }
141
142 if (Commands.ContainsKey(firstToken))
143 {
144 string[] args = new string[tokens.Length - 1];
145 Array.Copy(tokens, 1, args, 0, args.Length);
146 string response = response = Commands[firstToken].Execute(args, fromAgentID);
147
148 if (response.Length > 0)
149 {
150 Console.WriteLine(response);
151
152 if (fromAgentID != null && Network.Connected)
153 {
154 // IMs don't like \r\n line endings, clean them up first
155 response = response.Replace("\r", "");
156 SendResponseIM(this, fromAgentID, response, imSessionID);
157 }
158 }
159 }
160 }
161
162 private void updateTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
163 {
164 foreach (Command c in Commands.Values)
165 if (c.Active)
166 c.Think();
167 }
168
169 private void AgentDataUpdateHandler(Packet packet, Simulator sim)
170 {
171 AgentDataUpdatePacket p = (AgentDataUpdatePacket)packet;
172 if (p.AgentData.AgentID == sim.Client.Network.AgentID)
173 {
174 Console.WriteLine("Got the group ID for " + sim.Client.ToString() + ", requesting group members...");
175 GroupID = p.AgentData.ActiveGroupID;
176
177 sim.Client.Groups.BeginGetGroupMembers(GroupID);
178 }
179 }
180
181 private void TestClient_OnLogMessage(string message, Helpers.LogLevel level)
182 {
183 Console.WriteLine("<" + this.ToString() + "> " + level.ToString() + ": " + message);
184 }
185
186 private void GroupMembersHandler(Dictionary<LLUUID, GroupMember> members)
187 {
188 Console.WriteLine("Got " + members.Count + " group members.");
189 GroupMembers = members;
190 }
191
192 private void Objects_OnObjectKilled(Simulator simulator, uint objectID)
193 {
194 lock (SimPrims)
195 {
196 if (SimPrims.ContainsKey(simulator) && SimPrims[simulator].ContainsKey(objectID))
197 SimPrims[simulator].Remove(objectID);
198 }
199
200 lock (AvatarList)
201 {
202 if (AvatarList.ContainsKey(objectID))
203 AvatarList.Remove(objectID);
204 }
205 }
206
207 private void Objects_OnObjectUpdated(Simulator simulator, ObjectUpdate update, ulong regionHandle, ushort timeDilation)
208 {
209 regionX = (int)(regionHandle >> 32);
210 regionY = (int)(regionHandle & 0xFFFFFFFF);
211
212 if (update.Avatar)
213 {
214 lock (AvatarList)
215 {
216 // TODO: We really need a solid avatar and object tracker in Utilities to use here
217 if (AvatarList.ContainsKey(update.LocalID))
218 {
219 AvatarList[update.LocalID].CollisionPlane = update.CollisionPlane;
220 AvatarList[update.LocalID].Position = update.Position;
221 AvatarList[update.LocalID].Velocity = update.Velocity;
222 AvatarList[update.LocalID].Acceleration = update.Acceleration;
223 AvatarList[update.LocalID].Rotation = update.Rotation;
224 AvatarList[update.LocalID].AngularVelocity = update.AngularVelocity;
225 AvatarList[update.LocalID].Textures = update.Textures;
226 }
227 }
228 }
229 else
230 {
231 lock (SimPrims)
232 {
233 if (SimPrims.ContainsKey(simulator) && SimPrims[simulator].ContainsKey(update.LocalID))
234 {
235 SimPrims[simulator][update.LocalID].Position = update.Position;
236 SimPrims[simulator][update.LocalID].Velocity = update.Velocity;
237 SimPrims[simulator][update.LocalID].Acceleration = update.Acceleration;
238 SimPrims[simulator][update.LocalID].Rotation = update.Rotation;
239 SimPrims[simulator][update.LocalID].AngularVelocity = update.AngularVelocity;
240 SimPrims[simulator][update.LocalID].Textures = update.Textures;
241 }
242 }
243 }
244 }
245
246 private void Objects_OnNewPrim(Simulator simulator, Primitive prim, ulong regionHandle, ushort timeDilation)
247 {
248 lock (SimPrims)
249 {
250 if (!SimPrims.ContainsKey(simulator))
251 {
252 SimPrims[simulator] = new Dictionary<uint, Primitive>(10000);
253 }
254
255 SimPrims[simulator][prim.LocalID] = prim;
256 }
257
258 if ((prim.Flags & LLObject.ObjectFlags.CreateSelected) != 0 && OnPrimCreated != null)
259 {
260 OnPrimCreated(simulator, prim);
261 }
262 }
263
264 private void Objects_OnNewAvatar(Simulator simulator, Avatar avatar, ulong regionHandle, ushort timeDilation)
265 {
266 lock (AvatarList)
267 {
268 AvatarList[avatar.LocalID] = avatar;
269 }
270 }
271
272 private void AvatarAppearanceHandler(Packet packet, Simulator simulator)
273 {
274 AvatarAppearancePacket appearance = (AvatarAppearancePacket)packet;
275
276 lock (Appearances) Appearances[appearance.Sender.ID] = appearance;
277 }
278
279 private void Self_OnInstantMessage(LLUUID fromAgentID, string fromAgentName, LLUUID toAgentID,
280 uint parentEstateID, LLUUID regionID, LLVector3 position, MainAvatar.InstantMessageDialog dialog,
281 bool groupIM, LLUUID imSessionID, DateTime timestamp, string message,
282 MainAvatar.InstantMessageOnline offline, byte[] binaryBucket)
283 {
284 if (MasterKey != LLUUID.Zero)
285 {
286 if (fromAgentID != MasterKey)
287 {
288 // Received an IM from someone that is not the bot's master, ignore
289 Console.WriteLine("<IM>" + fromAgentName + " (not master): " + message + "@" + regionID.ToString() + ":" + position.ToString() );
290 return;
291 }
292 }
293 else
294 {
295 if (GroupMembers != null && !GroupMembers.ContainsKey(fromAgentID))
296 {
297 // Received an IM from someone outside the bot's group, ignore
298 Console.WriteLine("<IM>" + fromAgentName + " (not in group): " + message + "@" + regionID.ToString() + ":" + position.ToString());
299 return;
300 }
301 }
302
303 Console.WriteLine("<IM>" + fromAgentName + ": " + message);
304
305 if (dialog == MainAvatar.InstantMessageDialog.RequestTeleport)
306 {
307 Console.WriteLine("Accepting teleport lure.");
308 Self.TeleportLureRespond(fromAgentID, true);
309 }
310 else
311 {
312 if (dialog == MainAvatar.InstantMessageDialog.InventoryOffered)
313 {
314 Console.WriteLine("Accepting inventory offer.");
315
316 Self.InstantMessage(Self.FirstName + " " + Self.LastName, fromAgentID, String.Empty,
317 imSessionID, MainAvatar.InstantMessageDialog.InventoryAccepted,
318 MainAvatar.InstantMessageOnline.Offline, Self.Position, LLUUID.Zero,
319 Self.InventoryRootFolderUUID.GetBytes());
320 }
321 else
322 {
323 DoCommand(message, fromAgentID, imSessionID);
324 }
325 }
326 }
327 }
328}
diff --git a/ExportBot/TestClient.csproj b/ExportBot/TestClient.csproj
new file mode 100644
index 0000000..16d4afe
--- /dev/null
+++ b/ExportBot/TestClient.csproj
@@ -0,0 +1,120 @@
1<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
2 <PropertyGroup>
3 <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
4 <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
5 <ProductVersion>8.0.50727</ProductVersion>
6 <SchemaVersion>2.0</SchemaVersion>
7 <ProjectGuid>{B87682F6-B2D7-4C4D-A529-400C24FD4880}</ProjectGuid>
8 <OutputType>Exe</OutputType>
9 <AppDesignerFolder>Properties</AppDesignerFolder>
10 <RootNamespace>libsecondlife.TestClient</RootNamespace>
11 <AssemblyName>TestClient</AssemblyName>
12 </PropertyGroup>
13 <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
14 <DebugSymbols>true</DebugSymbols>
15 <DebugType>full</DebugType>
16 <Optimize>false</Optimize>
17 <OutputPath>..\..\..\bin\</OutputPath>
18 <DefineConstants>DEBUG;TRACE</DefineConstants>
19 <ErrorReport>prompt</ErrorReport>
20 <WarningLevel>4</WarningLevel>
21 </PropertyGroup>
22 <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
23 <DebugType>pdbonly</DebugType>
24 <Optimize>true</Optimize>
25 <OutputPath>..\..\bin\</OutputPath>
26 <DefineConstants>TRACE</DefineConstants>
27 <ErrorReport>prompt</ErrorReport>
28 <WarningLevel>4</WarningLevel>
29 </PropertyGroup>
30 <ItemGroup>
31 <Reference Include="System" />
32 <Reference Include="System.Data" />
33 <Reference Include="System.Speech, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL" />
34 <Reference Include="System.Xml" />
35 </ItemGroup>
36 <ItemGroup>
37 <Compile Include="Arguments.cs" />
38 <Compile Include="Command.cs" />
39 <Compile Include="Commands\AppearanceCommand.cs" />
40 <Compile Include="Commands\CloneProfileCommand.cs" />
41 <Compile Include="Commands\DebugCommand.cs" />
42 <Compile Include="Commands\DumpOutfitCommand.cs" />
43 <Compile Include="Commands\ExportParticlesCommand.cs" />
44 <Compile Include="Commands\Inventory\BalanceCommand.cs" />
45 <Compile Include="Commands\Inventory\DeleteFolderCommand.cs" />
46 <Compile Include="Commands\Inventory\GiveAllCommand.cs" />
47 <Compile Include="Commands\Inventory\WearCommand.cs" />
48 <Compile Include="Commands\Inventory\InventoryCommand.cs" />
49 <Compile Include="Commands\ExportOutfitCommand.cs" />
50 <Compile Include="Commands\FindSimCommand.cs" />
51 <Compile Include="Commands\ImportOutfitCommand.cs" />
52 <Compile Include="Commands\LoginCommand.cs">
53 <SubType>Code</SubType>
54 </Compile>
55 <Compile Include="Commands\LogoutCommand.cs">
56 <SubType>Code</SubType>
57 </Compile>
58 <Compile Include="Commands\Communication\EchoMasterCommand.cs" />
59 <Compile Include="Commands\Communication\IMCommand.cs" />
60 <Compile Include="Commands\Communication\SayCommand.cs" />
61 <Compile Include="Commands\Communication\ShoutCommand.cs" />
62 <Compile Include="Commands\Communication\WhisperCommand.cs" />
63 <Compile Include="Commands\MD5Command.cs" />
64 <Compile Include="Commands\Movement\FollowCommand.cs" />
65 <Compile Include="Commands\Movement\GotoCommand.cs" />
66 <Compile Include="Commands\Movement\JumpCommand.cs" />
67 <Compile Include="Commands\Movement\LocationCommand.cs" />
68 <Compile Include="Commands\Movement\SitCommand.cs" />
69 <Compile Include="Commands\PacketLogCommand.cs" />
70 <Compile Include="Commands\ParcelInfoCommand.cs" />
71 <Compile Include="Commands\QuitCommand.cs">
72 <SubType>Code</SubType>
73 </Compile>
74 <Compile Include="Commands\RegionInfoCommand.cs" />
75 <Compile Include="Commands\SetMasterCommand.cs">
76 <SubType>Code</SubType>
77 </Compile>
78 <Compile Include="Commands\ExportCommand.cs" />
79 <Compile Include="Commands\ImportCommand.cs" />
80 <Compile Include="Commands\LoadCommand.cs" />
81 <Compile Include="Commands\PrimCountCommand.cs" />
82 <Compile Include="Commands\SetMasterKeyCommand.cs" />
83 <Compile Include="Commands\ShowEffectsCommand.cs" />
84 <Compile Include="Commands\StatsCommand.cs" />
85 <Compile Include="Commands\TouchCommand.cs" />
86 <Compile Include="Commands\TreeCommand.cs" />
87 <Compile Include="Commands\UptimeCommand.cs" />
88 <Compile Include="Commands\HelpCommand.cs" />
89 <Compile Include="ClientManager.cs" />
90 <Compile Include="Commands\WhoCommand.cs">
91 <SubType>Code</SubType>
92 </Compile>
93 <Compile Include="Parsing.cs" />
94 <Compile Include="Program.cs" />
95 <Compile Include="TestClient.cs" />
96 <Compile Include="Properties\AssemblyInfo.cs" />
97 </ItemGroup>
98 <ItemGroup>
99 <ProjectReference Include="..\..\..\openjpegnet\openjpegnet.csproj">
100 <Project>{D0DCFDCB-71FA-4343-A8D1-24D4665A94A4}</Project>
101 <Name>openjpegnet</Name>
102 </ProjectReference>
103 <ProjectReference Include="..\..\libsecondlife.csproj">
104 <Project>{D9CDEDFB-8169-4B03-B57F-0DF638F044EC}</Project>
105 <Name>libsecondlife</Name>
106 </ProjectReference>
107 <ProjectReference Include="..\..\libsecondlife.Utilities\libsecondlife.Utilities.csproj">
108 <Project>{CE5E06C2-2428-416B-ADC1-F1FE16A0FB27}</Project>
109 <Name>libsecondlife.Utilities</Name>
110 </ProjectReference>
111 </ItemGroup>
112 <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
113 <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
114 Other similar extension points exist, see Microsoft.Common.targets.
115 <Target Name="BeforeBuild">
116 </Target>
117 <Target Name="AfterBuild">
118 </Target>
119 -->
120</Project> \ No newline at end of file