aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Tools/pCampBot/Bot.cs
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Tools/pCampBot/Bot.cs')
-rw-r--r--OpenSim/Tools/pCampBot/Bot.cs495
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
28using System;
29using System.Collections.Generic;
30using System.Text;
31using System.IO;
32using System.Reflection;
33using System.Threading;
34using System.Timers;
35using log4net;
36using OpenMetaverse;
37using OpenMetaverse.Assets;
38using Nini.Config;
39using OpenSim.Framework;
40using OpenSim.Framework.Console;
41using pCampBot.Interfaces;
42using Timer = System.Timers.Timer;
43
44namespace 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}