diff options
Diffstat (limited to 'ExportBot')
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 @@ | |||
1 | using System; | ||
2 | using System.Collections.Specialized; | ||
3 | using System.Text.RegularExpressions; | ||
4 | |||
5 | namespace 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 @@ | |||
1 | using System; | ||
2 | using System.Collections.Generic; | ||
3 | using System.Reflection; | ||
4 | using System.Xml; | ||
5 | using System.Threading; | ||
6 | using libsecondlife; | ||
7 | using libsecondlife.Packets; | ||
8 | using libsecondlife.AssetSystem; | ||
9 | |||
10 | namespace 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 @@ | |||
1 | using System; | ||
2 | using System.Collections.Generic; | ||
3 | using System.Text; | ||
4 | using libsecondlife; | ||
5 | using libsecondlife.Packets; | ||
6 | |||
7 | namespace 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 @@ | |||
1 | using System; | ||
2 | using System.Collections.Generic; | ||
3 | using System.Text; | ||
4 | using libsecondlife; | ||
5 | using libsecondlife.Packets; | ||
6 | |||
7 | namespace 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 @@ | |||
1 | using System; | ||
2 | using System.Collections.Generic; | ||
3 | using System.Threading; | ||
4 | using libsecondlife; | ||
5 | using libsecondlife.Packets; | ||
6 | |||
7 | namespace 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 @@ | |||
1 | using System; | ||
2 | using System.Collections.Generic; | ||
3 | using System.Text; | ||
4 | using libsecondlife; | ||
5 | using libsecondlife.Packets; | ||
6 | |||
7 | namespace 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 @@ | |||
1 | using System; | ||
2 | using System.Collections.Generic; | ||
3 | using System.Threading; | ||
4 | using libsecondlife; | ||
5 | using libsecondlife.Packets; | ||
6 | |||
7 | namespace 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 @@ | |||
1 | using System; | ||
2 | using System.Collections.Generic; | ||
3 | using System.Text; | ||
4 | using libsecondlife; | ||
5 | |||
6 | namespace 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 @@ | |||
1 | using System; | ||
2 | using System.Collections.Generic; | ||
3 | using System.Text; | ||
4 | using libsecondlife; | ||
5 | using libsecondlife.Packets; | ||
6 | |||
7 | namespace 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 @@ | |||
1 | using System; | ||
2 | using System.Collections.Generic; | ||
3 | using System.Text; | ||
4 | using System.Speech.Synthesis; | ||
5 | using libsecondlife; | ||
6 | using libsecondlife.Packets; | ||
7 | using 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 | |||
13 | namespace 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 @@ | |||
1 | using System; | ||
2 | using System.Collections.Generic; | ||
3 | using System.Text; | ||
4 | using libsecondlife; | ||
5 | using libsecondlife.Packets; | ||
6 | |||
7 | namespace 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 @@ | |||
1 | using System; | ||
2 | using System.Collections.Generic; | ||
3 | using libsecondlife; | ||
4 | using libsecondlife.Packets; | ||
5 | |||
6 | namespace 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 @@ | |||
1 | using System; | ||
2 | using System.Collections.Generic; | ||
3 | using System.Text; | ||
4 | using libsecondlife; | ||
5 | using libsecondlife.Packets; | ||
6 | |||
7 | namespace 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 @@ | |||
1 | using System; | ||
2 | using System.Text; | ||
3 | using System.IO; | ||
4 | using System.Collections.Generic; | ||
5 | using libsecondlife; | ||
6 | using libsecondlife.Utilities.Assets; | ||
7 | using libsecondlife.Utilities.Appearance; | ||
8 | |||
9 | namespace 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 @@ | |||
1 | using System; | ||
2 | using System.Collections.Generic; | ||
3 | using System.IO; | ||
4 | using System.Xml; | ||
5 | using System.Text; | ||
6 | using System.Threading; | ||
7 | using libsecondlife; | ||
8 | using libsecondlife.Packets; | ||
9 | |||
10 | namespace 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 @@ | |||
1 | using System; | ||
2 | using System.Collections.Generic; | ||
3 | using System.IO; | ||
4 | using System.Xml; | ||
5 | using libsecondlife; | ||
6 | using libsecondlife.Packets; | ||
7 | |||
8 | namespace 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 @@ | |||
1 | using System; | ||
2 | using System.Collections.Generic; | ||
3 | using System.IO; | ||
4 | using System.Text; | ||
5 | using libsecondlife; | ||
6 | |||
7 | namespace 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 @@ | |||
1 | using System; | ||
2 | using System.Collections.Generic; | ||
3 | using System.Text; | ||
4 | using libsecondlife; | ||
5 | using libsecondlife.Packets; | ||
6 | |||
7 | namespace 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 @@ | |||
1 | using System; | ||
2 | using System.Collections.Generic; | ||
3 | using System.Text; | ||
4 | using libsecondlife; | ||
5 | using libsecondlife.Packets; | ||
6 | |||
7 | namespace 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 @@ | |||
1 | using System; | ||
2 | using System.Collections.Generic; | ||
3 | using System.Xml; | ||
4 | using System.Xml.Serialization; | ||
5 | using System.Threading; | ||
6 | using System.IO; | ||
7 | using libsecondlife; | ||
8 | |||
9 | namespace 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 @@ | |||
1 | using System; | ||
2 | using System.Collections.Generic; | ||
3 | using System.IO; | ||
4 | using System.Xml; | ||
5 | using System.Xml.Serialization; | ||
6 | using libsecondlife; | ||
7 | using libsecondlife.Packets; | ||
8 | |||
9 | namespace 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 @@ | |||
1 | using System; | ||
2 | using System.Collections.Generic; | ||
3 | using libsecondlife; | ||
4 | using libsecondlife.Packets; | ||
5 | |||
6 | namespace 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 @@ | |||
1 | using System; | ||
2 | using System.Collections.Generic; | ||
3 | using System.IO; | ||
4 | using System.Text; | ||
5 | using System.Threading; | ||
6 | using System.Xml; | ||
7 | using System.Xml.Serialization; | ||
8 | |||
9 | using libsecondlife; | ||
10 | using libsecondlife.Packets; | ||
11 | using libsecondlife.InventorySystem; | ||
12 | |||
13 | namespace 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 @@ | |||
1 | using System; | ||
2 | using System.Collections.Generic; | ||
3 | using System.Text; | ||
4 | using libsecondlife; | ||
5 | using libsecondlife.Packets; | ||
6 | |||
7 | namespace 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 @@ | |||
1 | using System; | ||
2 | using System.Collections.Generic; | ||
3 | using System.IO; | ||
4 | using System.Text; | ||
5 | using System.Threading; | ||
6 | using System.Xml; | ||
7 | using System.Xml.Serialization; | ||
8 | |||
9 | using libsecondlife; | ||
10 | using libsecondlife.Packets; | ||
11 | using libsecondlife.InventorySystem; | ||
12 | |||
13 | namespace 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 @@ | |||
1 | using System; | ||
2 | using System.Collections.Generic; | ||
3 | using System.IO; | ||
4 | using System.Text; | ||
5 | using System.Threading; | ||
6 | using System.Xml; | ||
7 | using System.Xml.Serialization; | ||
8 | |||
9 | using libsecondlife; | ||
10 | using libsecondlife.Packets; | ||
11 | using libsecondlife.InventorySystem; | ||
12 | |||
13 | namespace 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 @@ | |||
1 | using System; | ||
2 | using System.Collections.Generic; | ||
3 | using System.Text; | ||
4 | using System.Reflection; | ||
5 | using libsecondlife; | ||
6 | using libsecondlife.Packets; | ||
7 | |||
8 | namespace 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 @@ | |||
1 | using System; | ||
2 | using System.Collections.Generic; | ||
3 | using System.Reflection; | ||
4 | using libsecondlife; | ||
5 | using libsecondlife.Packets; | ||
6 | |||
7 | namespace 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 @@ | |||
1 | using System; | ||
2 | using System.Collections.Generic; | ||
3 | using System.Text; | ||
4 | using libsecondlife; | ||
5 | using libsecondlife.Packets; | ||
6 | |||
7 | namespace 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 @@ | |||
1 | using System; | ||
2 | using libsecondlife; | ||
3 | |||
4 | namespace 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 @@ | |||
1 | using System; | ||
2 | using System.Collections.Generic; | ||
3 | using System.Text; | ||
4 | using libsecondlife; | ||
5 | using libsecondlife.Packets; | ||
6 | |||
7 | namespace 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 @@ | |||
1 | using System; | ||
2 | using System.Collections.Generic; | ||
3 | using System.Text; | ||
4 | using libsecondlife; | ||
5 | using libsecondlife.Packets; | ||
6 | |||
7 | namespace 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 @@ | |||
1 | using System; | ||
2 | using System.Collections.Generic; | ||
3 | using System.Text; | ||
4 | using libsecondlife; | ||
5 | using libsecondlife.Packets; | ||
6 | |||
7 | namespace 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 @@ | |||
1 | using System; | ||
2 | using System.Collections.Generic; | ||
3 | using System.Text; | ||
4 | using libsecondlife; | ||
5 | using libsecondlife.Packets; | ||
6 | |||
7 | namespace 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 @@ | |||
1 | using System; | ||
2 | using System.Collections.Generic; | ||
3 | using System.Text; | ||
4 | |||
5 | namespace 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 @@ | |||
1 | using System; | ||
2 | using System.Collections.Generic; | ||
3 | using System.Text; | ||
4 | using libsecondlife; | ||
5 | using libsecondlife.Packets; | ||
6 | |||
7 | namespace 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 @@ | |||
1 | using System; | ||
2 | using System.Collections.Generic; | ||
3 | using System.Text; | ||
4 | using libsecondlife; | ||
5 | using libsecondlife.Packets; | ||
6 | |||
7 | namespace 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 @@ | |||
1 | using System; | ||
2 | using System.Collections.Generic; | ||
3 | using System.Text; | ||
4 | using libsecondlife; | ||
5 | using libsecondlife.Packets; | ||
6 | |||
7 | namespace 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 @@ | |||
1 | using System; | ||
2 | using System.Collections.Generic; | ||
3 | using System.Xml; | ||
4 | using libsecondlife; | ||
5 | using libsecondlife.Packets; | ||
6 | |||
7 | namespace 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 @@ | |||
1 | using System; | ||
2 | using System.Collections.Generic; | ||
3 | using System.Threading; | ||
4 | using libsecondlife; | ||
5 | using libsecondlife.Utilities; | ||
6 | |||
7 | namespace 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 @@ | |||
1 | using System; | ||
2 | using System.Collections.Generic; | ||
3 | using System.Text; | ||
4 | using libsecondlife; | ||
5 | using libsecondlife.Packets; | ||
6 | |||
7 | namespace 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 @@ | |||
1 | using System; | ||
2 | using System.Collections.Generic; | ||
3 | using System.Text; | ||
4 | using libsecondlife; | ||
5 | using libsecondlife.Packets; | ||
6 | |||
7 | namespace 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 @@ | |||
1 | using System; | ||
2 | using System.Text; | ||
3 | using libsecondlife; | ||
4 | |||
5 | namespace 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 @@ | |||
1 | using System; | ||
2 | using System.Collections.Generic; | ||
3 | using System.Text; | ||
4 | using System.Threading; | ||
5 | using libsecondlife; | ||
6 | using libsecondlife.Packets; | ||
7 | |||
8 | namespace 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 @@ | |||
1 | using System; | ||
2 | using System.Collections.Generic; | ||
3 | using System.Text; | ||
4 | using libsecondlife; | ||
5 | using libsecondlife.Packets; | ||
6 | |||
7 | namespace 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 @@ | |||
1 | using System; | ||
2 | using libsecondlife; | ||
3 | |||
4 | namespace 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 @@ | |||
1 | using System; | ||
2 | using System.Collections.Generic; | ||
3 | using System.Text; | ||
4 | using libsecondlife; | ||
5 | using libsecondlife.Packets; | ||
6 | |||
7 | namespace 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 @@ | |||
1 | using System; | ||
2 | using System.Collections.Generic; | ||
3 | using System.Text; | ||
4 | using libsecondlife; | ||
5 | using libsecondlife.Packets; | ||
6 | |||
7 | namespace 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 @@ | |||
1 | using System; | ||
2 | using System.Collections.Generic; | ||
3 | using System.Text; | ||
4 | using libsecondlife; | ||
5 | using libsecondlife.Packets; | ||
6 | |||
7 | namespace 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 @@ | |||
1 | using System; | ||
2 | using System.Collections.Generic; | ||
3 | using System.Text; | ||
4 | using libsecondlife; | ||
5 | using libsecondlife.Packets; | ||
6 | |||
7 | namespace 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 @@ | |||
1 | using System; | ||
2 | using System.Collections.Generic; | ||
3 | using System.Text; | ||
4 | using libsecondlife; | ||
5 | using libsecondlife.Packets; | ||
6 | |||
7 | namespace 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 @@ | |||
1 | using System; | ||
2 | using System.Collections.Generic; | ||
3 | using System.Text; | ||
4 | |||
5 | namespace 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 @@ | |||
1 | using System; | ||
2 | using System.Collections.Generic; | ||
3 | using System.IO; | ||
4 | using CommandLine.Utility; | ||
5 | |||
6 | namespace 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 @@ | |||
1 | using System.Reflection; | ||
2 | using System.Runtime.CompilerServices; | ||
3 | using 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 @@ | |||
1 | This 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 | |||
3 | It'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 | |||
5 | THE 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 @@ | |||
1 | using System; | ||
2 | using System.Collections.Generic; | ||
3 | using System.Reflection; | ||
4 | using System.Xml; | ||
5 | using libsecondlife; | ||
6 | using libsecondlife.Packets; | ||
7 | using libsecondlife.AssetSystem; | ||
8 | |||
9 | namespace 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 | ||