diff options
author | Justin Clark-Casey (justincc) | 2011-11-03 22:39:06 +0000 |
---|---|---|
committer | Justin Clark-Casey (justincc) | 2011-11-03 22:39:06 +0000 |
commit | f26fdbd8da89ee35a23886defc13b44bc63b1349 (patch) | |
tree | b788fcc4948ab1fc4d3c20d309b5361d3b2c809b /OpenSim/Tools/pCampBot/Bot.cs | |
parent | Move one of the old physics sleeps out into the main bot loop, so leaving out... (diff) | |
download | opensim-SC_OLD-f26fdbd8da89ee35a23886defc13b44bc63b1349.zip opensim-SC_OLD-f26fdbd8da89ee35a23886defc13b44bc63b1349.tar.gz opensim-SC_OLD-f26fdbd8da89ee35a23886defc13b44bc63b1349.tar.bz2 opensim-SC_OLD-f26fdbd8da89ee35a23886defc13b44bc63b1349.tar.xz |
Rename PhysicsBot => Bot since it doesn't just exercise physics anymore
Diffstat (limited to 'OpenSim/Tools/pCampBot/Bot.cs')
-rw-r--r-- | OpenSim/Tools/pCampBot/Bot.cs | 495 |
1 files changed, 495 insertions, 0 deletions
diff --git a/OpenSim/Tools/pCampBot/Bot.cs b/OpenSim/Tools/pCampBot/Bot.cs new file mode 100644 index 0000000..bf01065 --- /dev/null +++ b/OpenSim/Tools/pCampBot/Bot.cs | |||
@@ -0,0 +1,495 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.Text; | ||
31 | using System.IO; | ||
32 | using System.Reflection; | ||
33 | using System.Threading; | ||
34 | using System.Timers; | ||
35 | using log4net; | ||
36 | using OpenMetaverse; | ||
37 | using OpenMetaverse.Assets; | ||
38 | using Nini.Config; | ||
39 | using OpenSim.Framework; | ||
40 | using OpenSim.Framework.Console; | ||
41 | using pCampBot.Interfaces; | ||
42 | using Timer = System.Timers.Timer; | ||
43 | |||
44 | namespace pCampBot | ||
45 | { | ||
46 | public class Bot | ||
47 | { | ||
48 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
49 | |||
50 | public delegate void AnEvent(Bot callbot, EventType someevent); // event delegate for bot events | ||
51 | |||
52 | public BotManager BotManager { get; private set; } | ||
53 | private IConfig startupConfig; // bot config, passed from BotManager | ||
54 | |||
55 | /// <summary> | ||
56 | /// Behaviours implemented by this bot. | ||
57 | /// </summary> | ||
58 | /// <remarks> | ||
59 | /// Lock this list before manipulating it. | ||
60 | /// </remarks> | ||
61 | public List<IBehaviour> Behaviours { get; private set; } | ||
62 | |||
63 | /// <summary> | ||
64 | /// Objects that the bot has discovered. | ||
65 | /// </summary> | ||
66 | /// <remarks> | ||
67 | /// Returns a list copy. Inserting new objects manually will have no effect. | ||
68 | /// </remarks> | ||
69 | public Dictionary<UUID, Primitive> Objects | ||
70 | { | ||
71 | get | ||
72 | { | ||
73 | lock (m_objects) | ||
74 | return new Dictionary<UUID, Primitive>(m_objects); | ||
75 | } | ||
76 | } | ||
77 | private Dictionary<UUID, Primitive> m_objects = new Dictionary<UUID, Primitive>(); | ||
78 | |||
79 | /// <summary> | ||
80 | /// Is this bot connected to the grid? | ||
81 | /// </summary> | ||
82 | public bool IsConnected { get; private set; } | ||
83 | |||
84 | public string FirstName { get; private set; } | ||
85 | public string LastName { get; private set; } | ||
86 | public string Name { get; private set; } | ||
87 | public string Password { get; private set; } | ||
88 | public string LoginUri { get; private set; } | ||
89 | public string saveDir; | ||
90 | public string wear; | ||
91 | |||
92 | public event AnEvent OnConnected; | ||
93 | public event AnEvent OnDisconnected; | ||
94 | |||
95 | /// <summary> | ||
96 | /// Keep a track of the continuously acting thread so that we can abort it. | ||
97 | /// </summary> | ||
98 | private Thread m_actionThread; | ||
99 | |||
100 | protected List<uint> objectIDs = new List<uint>(); | ||
101 | |||
102 | /// <summary> | ||
103 | /// Random number generator. | ||
104 | /// </summary> | ||
105 | public Random Random { get; private set; } | ||
106 | |||
107 | /// <summary> | ||
108 | /// New instance of a SecondLife client | ||
109 | /// </summary> | ||
110 | public GridClient Client { get; private set; } | ||
111 | |||
112 | /// <summary> | ||
113 | /// Constructor | ||
114 | /// </summary> | ||
115 | /// <param name="bm"></param> | ||
116 | /// <param name="behaviours">Behaviours for this bot to perform</param> | ||
117 | /// <param name="firstName"></param> | ||
118 | /// <param name="lastName"></param> | ||
119 | /// <param name="password"></param> | ||
120 | /// <param name="loginUri"></param> | ||
121 | /// <param name="behaviours"></param> | ||
122 | public Bot( | ||
123 | BotManager bm, List<IBehaviour> behaviours, | ||
124 | string firstName, string lastName, string password, string loginUri) | ||
125 | { | ||
126 | Client = new GridClient(); | ||
127 | |||
128 | Random = new Random(Environment.TickCount);// We do stuff randomly here | ||
129 | FirstName = firstName; | ||
130 | LastName = lastName; | ||
131 | Name = string.Format("{0} {1}", FirstName, LastName); | ||
132 | Password = password; | ||
133 | LoginUri = loginUri; | ||
134 | |||
135 | BotManager = bm; | ||
136 | startupConfig = bm.Config; | ||
137 | readconfig(); | ||
138 | |||
139 | Behaviours = behaviours; | ||
140 | } | ||
141 | |||
142 | //We do our actions here. This is where one would | ||
143 | //add additional steps and/or things the bot should do | ||
144 | private void Action() | ||
145 | { | ||
146 | while (true) | ||
147 | lock (Behaviours) | ||
148 | Behaviours.ForEach( | ||
149 | b => | ||
150 | { | ||
151 | // m_log.DebugFormat("[pCAMPBOT]: For {0} performing action {1}", Name, b.GetType()); | ||
152 | b.Action(this); | ||
153 | |||
154 | Thread.Sleep(Random.Next(1000, 10000)); | ||
155 | } | ||
156 | ); | ||
157 | } | ||
158 | |||
159 | /// <summary> | ||
160 | /// Read the Nini config and initialize | ||
161 | /// </summary> | ||
162 | public void readconfig() | ||
163 | { | ||
164 | wear = startupConfig.GetString("wear", "no"); | ||
165 | } | ||
166 | |||
167 | /// <summary> | ||
168 | /// Tells LibSecondLife to logout and disconnect. Raises the disconnect events once it finishes. | ||
169 | /// </summary> | ||
170 | public void shutdown() | ||
171 | { | ||
172 | if (m_actionThread != null) | ||
173 | m_actionThread.Abort(); | ||
174 | |||
175 | Client.Network.Logout(); | ||
176 | } | ||
177 | |||
178 | /// <summary> | ||
179 | /// This is the bot startup loop. | ||
180 | /// </summary> | ||
181 | public void startup() | ||
182 | { | ||
183 | Client.Settings.LOGIN_SERVER = LoginUri; | ||
184 | Client.Settings.ALWAYS_DECODE_OBJECTS = false; | ||
185 | Client.Settings.AVATAR_TRACKING = false; | ||
186 | Client.Settings.OBJECT_TRACKING = false; | ||
187 | Client.Settings.SEND_AGENT_THROTTLE = true; | ||
188 | Client.Settings.SEND_PINGS = true; | ||
189 | Client.Settings.STORE_LAND_PATCHES = false; | ||
190 | Client.Settings.USE_ASSET_CACHE = false; | ||
191 | Client.Settings.MULTIPLE_SIMS = true; | ||
192 | Client.Throttle.Asset = 100000; | ||
193 | Client.Throttle.Land = 100000; | ||
194 | Client.Throttle.Task = 100000; | ||
195 | Client.Throttle.Texture = 100000; | ||
196 | Client.Throttle.Wind = 100000; | ||
197 | Client.Throttle.Total = 400000; | ||
198 | Client.Network.LoginProgress += this.Network_LoginProgress; | ||
199 | Client.Network.SimConnected += this.Network_SimConnected; | ||
200 | Client.Network.Disconnected += this.Network_OnDisconnected; | ||
201 | Client.Objects.ObjectUpdate += Objects_NewPrim; | ||
202 | |||
203 | if (Client.Network.Login(FirstName, LastName, Password, "pCampBot", "Your name")) | ||
204 | { | ||
205 | IsConnected = true; | ||
206 | |||
207 | Thread.Sleep(Random.Next(1000, 10000)); | ||
208 | m_actionThread = new Thread(Action); | ||
209 | m_actionThread.Start(); | ||
210 | |||
211 | // OnConnected(this, EventType.CONNECTED); | ||
212 | if (wear == "save") | ||
213 | { | ||
214 | Client.Appearance.SetPreviousAppearance(); | ||
215 | SaveDefaultAppearance(); | ||
216 | } | ||
217 | else if (wear != "no") | ||
218 | { | ||
219 | MakeDefaultAppearance(wear); | ||
220 | } | ||
221 | Client.Self.Jump(true); | ||
222 | } | ||
223 | else | ||
224 | { | ||
225 | MainConsole.Instance.OutputFormat( | ||
226 | "{0} {1} cannot login: {2}", FirstName, LastName, Client.Network.LoginMessage); | ||
227 | |||
228 | if (OnDisconnected != null) | ||
229 | { | ||
230 | OnDisconnected(this, EventType.DISCONNECTED); | ||
231 | } | ||
232 | } | ||
233 | } | ||
234 | |||
235 | public void SaveDefaultAppearance() | ||
236 | { | ||
237 | saveDir = "MyAppearance/" + FirstName + "_" + LastName; | ||
238 | if (!Directory.Exists(saveDir)) | ||
239 | { | ||
240 | Directory.CreateDirectory(saveDir); | ||
241 | } | ||
242 | |||
243 | Array wtypes = Enum.GetValues(typeof(WearableType)); | ||
244 | foreach (WearableType wtype in wtypes) | ||
245 | { | ||
246 | UUID wearable = Client.Appearance.GetWearableAsset(wtype); | ||
247 | if (wearable != UUID.Zero) | ||
248 | { | ||
249 | Client.Assets.RequestAsset(wearable, AssetType.Clothing, false, Asset_ReceivedCallback); | ||
250 | Client.Assets.RequestAsset(wearable, AssetType.Bodypart, false, Asset_ReceivedCallback); | ||
251 | } | ||
252 | } | ||
253 | } | ||
254 | |||
255 | public void SaveAsset(AssetWearable asset) | ||
256 | { | ||
257 | if (asset != null) | ||
258 | { | ||
259 | try | ||
260 | { | ||
261 | if (asset.Decode()) | ||
262 | { | ||
263 | File.WriteAllBytes(Path.Combine(saveDir, String.Format("{1}.{0}", | ||
264 | asset.AssetType.ToString().ToLower(), | ||
265 | asset.WearableType)), asset.AssetData); | ||
266 | } | ||
267 | else | ||
268 | { | ||
269 | MainConsole.Instance.Output(String.Format("Failed to decode {0} asset {1}", asset.AssetType, asset.AssetID)); | ||
270 | } | ||
271 | } | ||
272 | catch (Exception e) | ||
273 | { | ||
274 | MainConsole.Instance.Output(String.Format("Exception: {0}",e.ToString())); | ||
275 | } | ||
276 | } | ||
277 | } | ||
278 | |||
279 | public WearableType GetWearableType(string path) | ||
280 | { | ||
281 | string type = ((((path.Split('/'))[2]).Split('.'))[0]).Trim(); | ||
282 | switch (type) | ||
283 | { | ||
284 | case "Eyes": | ||
285 | return WearableType.Eyes; | ||
286 | case "Hair": | ||
287 | return WearableType.Hair; | ||
288 | case "Pants": | ||
289 | return WearableType.Pants; | ||
290 | case "Shape": | ||
291 | return WearableType.Shape; | ||
292 | case "Shirt": | ||
293 | return WearableType.Shirt; | ||
294 | case "Skin": | ||
295 | return WearableType.Skin; | ||
296 | default: | ||
297 | return WearableType.Shape; | ||
298 | } | ||
299 | } | ||
300 | |||
301 | public void MakeDefaultAppearance(string wear) | ||
302 | { | ||
303 | try | ||
304 | { | ||
305 | if (wear == "yes") | ||
306 | { | ||
307 | //TODO: Implement random outfit picking | ||
308 | MainConsole.Instance.Output("Picks a random outfit. Not yet implemented."); | ||
309 | } | ||
310 | else if (wear != "save") | ||
311 | saveDir = "MyAppearance/" + wear; | ||
312 | saveDir = saveDir + "/"; | ||
313 | |||
314 | string[] clothing = Directory.GetFiles(saveDir, "*.clothing", SearchOption.TopDirectoryOnly); | ||
315 | string[] bodyparts = Directory.GetFiles(saveDir, "*.bodypart", SearchOption.TopDirectoryOnly); | ||
316 | InventoryFolder clothfolder = FindClothingFolder(); | ||
317 | UUID transid = UUID.Random(); | ||
318 | List<InventoryBase> listwearables = new List<InventoryBase>(); | ||
319 | |||
320 | for (int i = 0; i < clothing.Length; i++) | ||
321 | { | ||
322 | UUID assetID = UUID.Random(); | ||
323 | AssetClothing asset = new AssetClothing(assetID, File.ReadAllBytes(clothing[i])); | ||
324 | asset.Decode(); | ||
325 | asset.Owner = Client.Self.AgentID; | ||
326 | asset.WearableType = GetWearableType(clothing[i]); | ||
327 | asset.Encode(); | ||
328 | transid = Client.Assets.RequestUpload(asset,true); | ||
329 | Client.Inventory.RequestCreateItem(clothfolder.UUID, "MyClothing" + i.ToString(), "MyClothing", AssetType.Clothing, | ||
330 | transid, InventoryType.Wearable, asset.WearableType, PermissionMask.All, delegate(bool success, InventoryItem item) | ||
331 | { | ||
332 | if (success) | ||
333 | { | ||
334 | listwearables.Add(item); | ||
335 | } | ||
336 | else | ||
337 | MainConsole.Instance.Output(String.Format("Failed to create item {0}",item.Name)); | ||
338 | } | ||
339 | ); | ||
340 | } | ||
341 | |||
342 | for (int i = 0; i < bodyparts.Length; i++) | ||
343 | { | ||
344 | UUID assetID = UUID.Random(); | ||
345 | AssetBodypart asset = new AssetBodypart(assetID, File.ReadAllBytes(bodyparts[i])); | ||
346 | asset.Decode(); | ||
347 | asset.Owner = Client.Self.AgentID; | ||
348 | asset.WearableType = GetWearableType(bodyparts[i]); | ||
349 | asset.Encode(); | ||
350 | transid = Client.Assets.RequestUpload(asset,true); | ||
351 | Client.Inventory.RequestCreateItem(clothfolder.UUID, "MyBodyPart" + i.ToString(), "MyBodyPart", AssetType.Bodypart, | ||
352 | transid, InventoryType.Wearable, asset.WearableType, PermissionMask.All, delegate(bool success, InventoryItem item) | ||
353 | { | ||
354 | if (success) | ||
355 | { | ||
356 | listwearables.Add(item); | ||
357 | } | ||
358 | else | ||
359 | MainConsole.Instance.Output(String.Format("Failed to create item {0}",item.Name)); | ||
360 | } | ||
361 | ); | ||
362 | } | ||
363 | |||
364 | Thread.Sleep(1000); | ||
365 | |||
366 | if (listwearables == null || listwearables.Count == 0) | ||
367 | MainConsole.Instance.Output("Nothing to send on this folder!"); | ||
368 | else | ||
369 | { | ||
370 | MainConsole.Instance.Output(String.Format("Sending {0} wearables...",listwearables.Count)); | ||
371 | Client.Appearance.WearOutfit(listwearables, false); | ||
372 | } | ||
373 | } | ||
374 | catch (Exception ex) | ||
375 | { | ||
376 | Console.WriteLine(ex.ToString()); | ||
377 | } | ||
378 | } | ||
379 | |||
380 | public InventoryFolder FindClothingFolder() | ||
381 | { | ||
382 | UUID rootfolder = Client.Inventory.Store.RootFolder.UUID; | ||
383 | List<InventoryBase> listfolders = Client.Inventory.Store.GetContents(rootfolder); | ||
384 | InventoryFolder clothfolder = new InventoryFolder(UUID.Random()); | ||
385 | foreach (InventoryBase folder in listfolders) | ||
386 | { | ||
387 | if (folder.Name == "Clothing") | ||
388 | { | ||
389 | clothfolder = (InventoryFolder)folder; | ||
390 | break; | ||
391 | } | ||
392 | } | ||
393 | return clothfolder; | ||
394 | } | ||
395 | |||
396 | public void Network_LoginProgress(object sender, LoginProgressEventArgs args) | ||
397 | { | ||
398 | if (args.Status == LoginStatus.Success) | ||
399 | { | ||
400 | if (OnConnected != null) | ||
401 | { | ||
402 | OnConnected(this, EventType.CONNECTED); | ||
403 | } | ||
404 | } | ||
405 | } | ||
406 | |||
407 | public void Network_SimConnected(object sender, SimConnectedEventArgs args) | ||
408 | { | ||
409 | } | ||
410 | |||
411 | public void Network_OnDisconnected(object sender, DisconnectedEventArgs args) | ||
412 | { | ||
413 | // m_log.ErrorFormat("Fired Network_OnDisconnected"); | ||
414 | |||
415 | // if ( | ||
416 | // (args.Reason == NetworkManager.DisconnectType.SimShutdown | ||
417 | // || args.Reason == NetworkManager.DisconnectType.NetworkTimeout) | ||
418 | // && OnDisconnected != null) | ||
419 | |||
420 | if ( | ||
421 | (args.Reason == NetworkManager.DisconnectType.ClientInitiated | ||
422 | || args.Reason == NetworkManager.DisconnectType.ServerInitiated | ||
423 | || args.Reason == NetworkManager.DisconnectType.NetworkTimeout) | ||
424 | && OnDisconnected != null) | ||
425 | // if (OnDisconnected != null) | ||
426 | { | ||
427 | IsConnected = false; | ||
428 | OnDisconnected(this, EventType.DISCONNECTED); | ||
429 | } | ||
430 | } | ||
431 | |||
432 | public void Objects_NewPrim(object sender, PrimEventArgs args) | ||
433 | { | ||
434 | Primitive prim = args.Prim; | ||
435 | |||
436 | if (prim != null) | ||
437 | { | ||
438 | lock (m_objects) | ||
439 | m_objects[prim.ID] = prim; | ||
440 | |||
441 | if (prim.Textures != null) | ||
442 | { | ||
443 | if (prim.Textures.DefaultTexture.TextureID != UUID.Zero) | ||
444 | { | ||
445 | GetTexture(prim.Textures.DefaultTexture.TextureID); | ||
446 | } | ||
447 | |||
448 | for (int i = 0; i < prim.Textures.FaceTextures.Length; i++) | ||
449 | { | ||
450 | UUID textureID = prim.Textures.FaceTextures[i].TextureID; | ||
451 | |||
452 | if (textureID != null && textureID != UUID.Zero) | ||
453 | { | ||
454 | GetTexture(textureID); | ||
455 | } | ||
456 | } | ||
457 | } | ||
458 | |||
459 | if (prim.Sculpt.SculptTexture != UUID.Zero) | ||
460 | { | ||
461 | GetTexture(prim.Sculpt.SculptTexture); | ||
462 | } | ||
463 | } | ||
464 | } | ||
465 | |||
466 | private void GetTexture(UUID textureID) | ||
467 | { | ||
468 | lock (BotManager.AssetsReceived) | ||
469 | { | ||
470 | // Don't request assets more than once. | ||
471 | if (BotManager.AssetsReceived.ContainsKey(textureID)) | ||
472 | return; | ||
473 | |||
474 | BotManager.AssetsReceived[textureID] = false; | ||
475 | Client.Assets.RequestImage(textureID, ImageType.Normal, Asset_TextureCallback_Texture); | ||
476 | } | ||
477 | } | ||
478 | |||
479 | public void Asset_TextureCallback_Texture(TextureRequestState state, AssetTexture assetTexture) | ||
480 | { | ||
481 | //TODO: Implement texture saving and applying | ||
482 | } | ||
483 | |||
484 | public void Asset_ReceivedCallback(AssetDownload transfer, Asset asset) | ||
485 | { | ||
486 | lock (BotManager.AssetsReceived) | ||
487 | BotManager.AssetsReceived[asset.AssetID] = true; | ||
488 | |||
489 | // if (wear == "save") | ||
490 | // { | ||
491 | // SaveAsset((AssetWearable) asset); | ||
492 | // } | ||
493 | } | ||
494 | } | ||
495 | } | ||