OpenSim
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros
BotManager.cs
Go to the documentation of this file.
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.Linq;
31 using System.Reflection;
32 using System.Threading;
33 using OpenMetaverse;
34 using log4net;
35 using log4net.Appender;
36 using log4net.Core;
37 using log4net.Repository;
38 using Nini.Config;
39 using OpenSim.Framework;
40 using OpenSim.Framework.Console;
41 using OpenSim.Framework.Monitoring;
42 using pCampBot.Interfaces;
43 
44 namespace pCampBot
45 {
47  {
49  Ready,
50  Connecting,
52  }
53 
57  public class BotManager
58  {
59  private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
60 
61  public const int DefaultLoginDelay = 5000;
62 
66  public BotManagerBotConnectingState BotConnectingState { get; private set; }
67 
71  private object BotConnectingStateChangeObject = new object();
72 
77  public int LoginDelay { get; set; }
78 
83 
87  public bool InitBotSendAgentUpdates { get; set; }
88 
92  public bool InitBotRequestObjectTextures { get; set; }
93 
97  protected List<Bot> m_bots;
98 
102  public Random Rng { get; private set; }
103 
107  public Dictionary<UUID, bool> AssetsReceived { get; private set; }
108 
112  public Dictionary<ulong, GridRegion> RegionsKnown { get; private set; }
113 
117  private string m_firstName;
118 
122  private string m_lastNameStem;
123 
127  private string m_password;
128 
132  private string m_loginUri;
133 
137  private string m_startUri;
138 
142  private int m_fromBotNumber;
143 
147  private string m_wearSetting;
148 
152  private HashSet<string> m_defaultBehaviourSwitches = new HashSet<string>();
153 
157  private ServerStatsCollector m_serverStatsCollector;
158 
162  public BotManager()
163  {
164  // We set this to avoid issues with bots running out of HTTP connections if many are run from a single machine
165  // to multiple regions.
166  Settings.MAX_HTTP_CONNECTIONS = int.MaxValue;
167 
168 // System.Threading.ThreadPool.SetMaxThreads(600, 240);
169 //
170 // int workerThreads, iocpThreads;
171 // System.Threading.ThreadPool.GetMaxThreads(out workerThreads, out iocpThreads);
172 // Console.WriteLine("ThreadPool.GetMaxThreads {0} {1}", workerThreads, iocpThreads);
173 
176 
178 
179  Rng = new Random(Environment.TickCount);
180  AssetsReceived = new Dictionary<UUID, bool>();
181  RegionsKnown = new Dictionary<ulong, GridRegion>();
182 
184  MainConsole.Instance = m_console;
185 
186  // Make log4net see the console
187  //
188  ILoggerRepository repository = LogManager.GetRepository();
189  IAppender[] appenders = repository.GetAppenders();
190  OpenSimAppender consoleAppender = null;
191 
192  foreach (IAppender appender in appenders)
193  {
194  if (appender.Name == "Console")
195  {
196  consoleAppender = (OpenSimAppender)appender;
197  consoleAppender.Console = m_console;
198  break;
199  }
200  }
201 
202  m_console.Commands.AddCommand(
203  "Bots", false, "shutdown", "shutdown", "Shutdown bots and exit", HandleShutdown);
204 
205  m_console.Commands.AddCommand(
206  "Bots", false, "quit", "quit", "Shutdown bots and exit", HandleShutdown);
207 
208  m_console.Commands.AddCommand(
209  "Bots", false, "connect", "connect [<n>]", "Connect bots",
210  "If an <n> is given, then the first <n> disconnected bots by postfix number are connected.\n"
211  + "If no <n> is given, then all currently disconnected bots are connected.",
212  HandleConnect);
213 
214  m_console.Commands.AddCommand(
215  "Bots", false, "disconnect", "disconnect [<n>]", "Disconnect bots",
216  "Disconnecting bots will interupt any bot connection process, including connection on startup.\n"
217  + "If an <n> is given, then the last <n> connected bots by postfix number are disconnected.\n"
218  + "If no <n> is given, then all currently connected bots are disconnected.",
219  HandleDisconnect);
220 
221  m_console.Commands.AddCommand(
222  "Bots", false, "add behaviour", "add behaviour <abbreviated-name> [<bot-number>]",
223  "Add a behaviour to a bot",
224  "If no bot number is specified then behaviour is added to all bots.\n"
225  + "Can be performed on connected or disconnected bots.",
226  HandleAddBehaviour);
227 
228  m_console.Commands.AddCommand(
229  "Bots", false, "remove behaviour", "remove behaviour <abbreviated-name> [<bot-number>]",
230  "Remove a behaviour from a bot",
231  "If no bot number is specified then behaviour is added to all bots.\n"
232  + "Can be performed on connected or disconnected bots.",
233  HandleRemoveBehaviour);
234 
235  m_console.Commands.AddCommand(
236  "Bots", false, "sit", "sit", "Sit all bots on the ground.",
237  HandleSit);
238 
239  m_console.Commands.AddCommand(
240  "Bots", false, "stand", "stand", "Stand all bots.",
241  HandleStand);
242 
243  m_console.Commands.AddCommand(
244  "Bots", false, "set bots", "set bots <key> <value>", "Set a setting for all bots.", HandleSetBots);
245 
246  m_console.Commands.AddCommand(
247  "Bots", false, "show regions", "show regions", "Show regions known to bots", HandleShowRegions);
248 
249  m_console.Commands.AddCommand(
250  "Bots", false, "show bots", "show bots", "Shows the status of all bots.", HandleShowBotsStatus);
251 
252  m_console.Commands.AddCommand(
253  "Bots", false, "show bot", "show bot <bot-number>",
254  "Shows the detailed status and settings of a particular bot.", HandleShowBotStatus);
255 
256  m_console.Commands.AddCommand(
257  "Debug",
258  false,
259  "debug lludp packet",
260  "debug lludp packet <level> <avatar-first-name> <avatar-last-name>",
261  "Turn on received packet logging.",
262  "If level > 0 then all received packets that are not duplicates are logged.\n"
263  + "If level <= 0 then no received packets are logged.",
264  HandleDebugLludpPacketCommand);
265 
266  m_console.Commands.AddCommand(
267  "Bots", false, "show status", "show status", "Shows pCampbot status.", HandleShowStatus);
268 
269  m_bots = new List<Bot>();
270 
271  Watchdog.Enabled = true;
272  StatsManager.RegisterConsoleCommands(m_console);
273 
274  m_serverStatsCollector = new ServerStatsCollector();
275  m_serverStatsCollector.Initialise(null);
276  m_serverStatsCollector.Enabled = true;
277  m_serverStatsCollector.Start();
278 
279  BotConnectingState = BotManagerBotConnectingState.Ready;
280  }
281 
287  public void CreateBots(int botcount, IConfig startupConfig)
288  {
289  m_firstName = startupConfig.GetString("firstname");
290  m_lastNameStem = startupConfig.GetString("lastname");
291  m_password = startupConfig.GetString("password");
292  m_loginUri = startupConfig.GetString("loginuri");
293  m_fromBotNumber = startupConfig.GetInt("from", 0);
294  m_wearSetting = startupConfig.GetString("wear", "no");
295 
296  m_startUri = ParseInputStartLocationToUri(startupConfig.GetString("start", "last"));
297 
298  Array.ForEach<string>(
299  startupConfig.GetString("behaviours", "p").Split(new char[] { ',' }), b => m_defaultBehaviourSwitches.Add(b));
300 
301  for (int i = 0; i < botcount; i++)
302  {
303  lock (m_bots)
304  {
305  string lastName = string.Format("{0}_{1}", m_lastNameStem, i + m_fromBotNumber);
306 
307  CreateBot(
308  this,
309  CreateBehavioursFromAbbreviatedNames(m_defaultBehaviourSwitches),
310  m_firstName, lastName, m_password, m_loginUri, m_startUri, m_wearSetting);
311  }
312  }
313  }
314 
315  private List<IBehaviour> CreateBehavioursFromAbbreviatedNames(HashSet<string> abbreviatedNames)
316  {
317  // We must give each bot its own list of instantiated behaviours since they store state.
318  List<IBehaviour> behaviours = new List<IBehaviour>();
319 
320  // Hard-coded for now
321  foreach (string abName in abbreviatedNames)
322  {
323  IBehaviour newBehaviour = null;
324 
325  if (abName == "c")
326  newBehaviour = new CrossBehaviour();
327 
328  if (abName == "g")
329  newBehaviour = new GrabbingBehaviour();
330 
331  if (abName == "n")
332  newBehaviour = new NoneBehaviour();
333 
334  if (abName == "p")
335  newBehaviour = new PhysicsBehaviour();
336 
337  if (abName == "t")
338  newBehaviour = new TeleportBehaviour();
339 
340  if (abName == "tw")
341  newBehaviour = new TwitchyBehaviour();
342 
343  if (abName == "ph2")
344  newBehaviour = new PhysicsBehaviour2();
345 
346  if (abName == "inv")
347  newBehaviour = new InventoryDownloadBehaviour();
348 
349  if (newBehaviour != null)
350  {
351  behaviours.Add(newBehaviour);
352  }
353  else
354  {
355  MainConsole.Instance.OutputFormat("No behaviour with abbreviated name {0} found", abName);
356  }
357  }
358 
359  return behaviours;
360  }
361 
362  public void ConnectBots(int botcount)
363  {
364  lock (BotConnectingStateChangeObject)
365  {
367  {
368  MainConsole.Instance.OutputFormat(
369  "Bot connecting status is {0}. Please wait for previous process to complete.", BotConnectingState);
370  return;
371  }
372 
373  BotConnectingState = BotManagerBotConnectingState.Connecting;
374  }
375 
376  Thread connectBotThread = new Thread(o => ConnectBotsInternal(botcount));
377 
378  connectBotThread.Name = "Bots connection thread";
379  connectBotThread.Start();
380  }
381 
382  private void ConnectBotsInternal(int botCount)
383  {
384  m_log.InfoFormat(
385  "[BOT MANAGER]: Starting {0} bots connecting to {1}, location {2}, named {3} {4}_<n>",
386  botCount,
387  m_loginUri,
388  m_startUri,
389  m_firstName,
390  m_lastNameStem);
391 
392  m_log.DebugFormat("[BOT MANAGER]: Delay between logins is {0}ms", LoginDelay);
393  m_log.DebugFormat("[BOT MANAGER]: BotsSendAgentUpdates is {0}", InitBotSendAgentUpdates);
394  m_log.DebugFormat("[BOT MANAGER]: InitBotRequestObjectTextures is {0}", InitBotRequestObjectTextures);
395 
396  List<Bot> botsToConnect = new List<Bot>();
397 
398  lock (m_bots)
399  {
400  foreach (Bot bot in m_bots)
401  {
402  if (bot.ConnectionState == ConnectionState.Disconnected)
403  botsToConnect.Add(bot);
404 
405  if (botsToConnect.Count >= botCount)
406  break;
407  }
408  }
409 
410  foreach (Bot bot in botsToConnect)
411  {
412  lock (BotConnectingStateChangeObject)
413  {
415  {
416  MainConsole.Instance.Output(
417  "[BOT MANAGER]: Aborting bot connection due to user-initiated disconnection");
418  return;
419  }
420  }
421 
422  bot.Connect();
423 
424  // Stagger logins
425  Thread.Sleep(LoginDelay);
426  }
427 
428  lock (BotConnectingStateChangeObject)
429  {
431  BotConnectingState = BotManagerBotConnectingState.Ready;
432  }
433  }
434 
444  private string ParseInputStartLocationToUri(string startLocation)
445  {
446  if (startLocation == "home" || startLocation == "last")
447  return startLocation;
448 
449  string regionName;
450 
451  // Just a region name or only one (!) extra component. Like a viewer, we will stick 128/128/0 on the end
452  Vector3 startPos = new Vector3(128, 128, 0);
453 
454  string[] startLocationComponents = startLocation.Split('/');
455 
456  regionName = startLocationComponents[0];
457 
458  if (startLocationComponents.Length >= 2)
459  {
460  float.TryParse(startLocationComponents[1], out startPos.X);
461 
462  if (startLocationComponents.Length >= 3)
463  {
464  float.TryParse(startLocationComponents[2], out startPos.Y);
465 
466  if (startLocationComponents.Length >= 4)
467  float.TryParse(startLocationComponents[3], out startPos.Z);
468  }
469  }
470 
471  return string.Format("uri:{0}&{1}&{2}&{3}", regionName, startPos.X, startPos.Y, startPos.Z);
472  }
473 
485  public void CreateBot(
486  BotManager bm, List<IBehaviour> behaviours,
487  string firstName, string lastName, string password, string loginUri, string startLocation, string wearSetting)
488  {
489  MainConsole.Instance.OutputFormat(
490  "[BOT MANAGER]: Creating bot {0} {1}, behaviours are {2}",
491  firstName, lastName, string.Join(",", behaviours.ConvertAll<string>(b => b.Name).ToArray()));
492 
493  Bot pb = new Bot(bm, behaviours, firstName, lastName, password, startLocation, loginUri);
494  pb.wear = wearSetting;
495  pb.Client.Settings.SEND_AGENT_UPDATES = InitBotSendAgentUpdates;
496  pb.RequestObjectTextures = InitBotRequestObjectTextures;
497 
498  pb.OnConnected += handlebotEvent;
499  pb.OnDisconnected += handlebotEvent;
500 
501  m_bots.Add(pb);
502  }
503 
509  private void handlebotEvent(Bot callbot, EventType eventt)
510  {
511  switch (eventt)
512  {
513  case EventType.CONNECTED:
514  {
515  m_log.Info("[" + callbot.FirstName + " " + callbot.LastName + "]: Connected");
516  break;
517  }
518 
519  case EventType.DISCONNECTED:
520  {
521  m_log.Info("[" + callbot.FirstName + " " + callbot.LastName + "]: Disconnected");
522  break;
523  }
524  }
525  }
526 
532  {
533  return new LocalConsole("pCampbot");
534  }
535 
536  private void HandleConnect(string module, string[] cmd)
537  {
538  lock (m_bots)
539  {
540  int botsToConnect;
541  int disconnectedBots = m_bots.Count(b => b.ConnectionState == ConnectionState.Disconnected);
542 
543  if (cmd.Length == 1)
544  {
545  botsToConnect = disconnectedBots;
546  }
547  else
548  {
549  if (!ConsoleUtil.TryParseConsoleNaturalInt(MainConsole.Instance, cmd[1], out botsToConnect))
550  return;
551 
552  botsToConnect = Math.Min(botsToConnect, disconnectedBots);
553  }
554 
555  MainConsole.Instance.OutputFormat("Connecting {0} bots", botsToConnect);
556 
557  ConnectBots(botsToConnect);
558  }
559  }
560 
561  private void HandleAddBehaviour(string module, string[] cmd)
562  {
563  if (cmd.Length < 3 || cmd.Length > 4)
564  {
565  MainConsole.Instance.OutputFormat("Usage: add behaviour <abbreviated-behaviour> [<bot-number>]");
566  return;
567  }
568 
569  string rawBehaviours = cmd[2];
570 
571  List<Bot> botsToEffect = new List<Bot>();
572 
573  if (cmd.Length == 3)
574  {
575  lock (m_bots)
576  botsToEffect.AddRange(m_bots);
577  }
578  else
579  {
580  int botNumber;
581  if (!ConsoleUtil.TryParseConsoleNaturalInt(MainConsole.Instance, cmd[3], out botNumber))
582  return;
583 
584  Bot bot = GetBotFromNumber(botNumber);
585 
586  if (bot == null)
587  {
588  MainConsole.Instance.OutputFormat("Error: No bot found with number {0}", botNumber);
589  return;
590  }
591 
592  botsToEffect.Add(bot);
593  }
594 
595 
596  HashSet<string> rawAbbreviatedSwitchesToAdd = new HashSet<string>();
597  Array.ForEach<string>(rawBehaviours.Split(new char[] { ',' }), b => rawAbbreviatedSwitchesToAdd.Add(b));
598 
599  foreach (Bot bot in botsToEffect)
600  {
601  List<IBehaviour> behavioursAdded = new List<IBehaviour>();
602 
603  foreach (IBehaviour behaviour in CreateBehavioursFromAbbreviatedNames(rawAbbreviatedSwitchesToAdd))
604  {
605  if (bot.AddBehaviour(behaviour))
606  behavioursAdded.Add(behaviour);
607  }
608 
609  MainConsole.Instance.OutputFormat(
610  "Added behaviours {0} to bot {1}",
611  string.Join(", ", behavioursAdded.ConvertAll<string>(b => b.Name).ToArray()), bot.Name);
612  }
613  }
614 
615  private void HandleRemoveBehaviour(string module, string[] cmd)
616  {
617  if (cmd.Length < 3 || cmd.Length > 4)
618  {
619  MainConsole.Instance.OutputFormat("Usage: remove behaviour <abbreviated-behaviour> [<bot-number>]");
620  return;
621  }
622 
623  string rawBehaviours = cmd[2];
624 
625  List<Bot> botsToEffect = new List<Bot>();
626 
627  if (cmd.Length == 3)
628  {
629  lock (m_bots)
630  botsToEffect.AddRange(m_bots);
631  }
632  else
633  {
634  int botNumber;
635  if (!ConsoleUtil.TryParseConsoleNaturalInt(MainConsole.Instance, cmd[3], out botNumber))
636  return;
637 
638  Bot bot = GetBotFromNumber(botNumber);
639 
640  if (bot == null)
641  {
642  MainConsole.Instance.OutputFormat("Error: No bot found with number {0}", botNumber);
643  return;
644  }
645 
646  botsToEffect.Add(bot);
647  }
648 
649  HashSet<string> abbreviatedBehavioursToRemove = new HashSet<string>();
650  Array.ForEach<string>(rawBehaviours.Split(new char[] { ',' }), b => abbreviatedBehavioursToRemove.Add(b));
651 
652  foreach (Bot bot in botsToEffect)
653  {
654  List<IBehaviour> behavioursRemoved = new List<IBehaviour>();
655 
656  foreach (string b in abbreviatedBehavioursToRemove)
657  {
658  IBehaviour behaviour;
659 
660  if (bot.TryGetBehaviour(b, out behaviour))
661  {
662  bot.RemoveBehaviour(b);
663  behavioursRemoved.Add(behaviour);
664  }
665  }
666 
667  MainConsole.Instance.OutputFormat(
668  "Removed behaviours {0} from bot {1}",
669  string.Join(", ", behavioursRemoved.ConvertAll<string>(b => b.Name).ToArray()), bot.Name);
670  }
671  }
672 
673  private void HandleDisconnect(string module, string[] cmd)
674  {
675  List<Bot> connectedBots;
676  int botsToDisconnectCount;
677 
678  lock (m_bots)
679  connectedBots = m_bots.FindAll(b => b.ConnectionState == ConnectionState.Connected);
680 
681  if (cmd.Length == 1)
682  {
683  botsToDisconnectCount = connectedBots.Count;
684  }
685  else
686  {
687  if (!ConsoleUtil.TryParseConsoleNaturalInt(MainConsole.Instance, cmd[1], out botsToDisconnectCount))
688  return;
689 
690  botsToDisconnectCount = Math.Min(botsToDisconnectCount, connectedBots.Count);
691  }
692 
693  lock (BotConnectingStateChangeObject)
695 
696  Thread disconnectBotThread = new Thread(o => DisconnectBotsInternal(connectedBots, botsToDisconnectCount));
697 
698  disconnectBotThread.Name = "Bots disconnection thread";
699  disconnectBotThread.Start();
700  }
701 
702  private void DisconnectBotsInternal(List<Bot> connectedBots, int disconnectCount)
703  {
704  MainConsole.Instance.OutputFormat("Disconnecting {0} bots", disconnectCount);
705 
706  int disconnectedBots = 0;
707 
708  for (int i = connectedBots.Count - 1; i >= 0; i--)
709  {
710  if (disconnectedBots >= disconnectCount)
711  break;
712 
713  Bot thisBot = connectedBots[i];
714 
715  if (thisBot.ConnectionState == ConnectionState.Connected)
716  {
717  ThreadPool.QueueUserWorkItem(o => thisBot.Disconnect());
718  disconnectedBots++;
719  }
720  }
721 
722  lock (BotConnectingStateChangeObject)
724  }
725 
726  private void HandleSit(string module, string[] cmd)
727  {
728  lock (m_bots)
729  {
730  foreach (Bot bot in m_bots)
731  {
732  if (bot.ConnectionState == ConnectionState.Connected)
733  {
734  MainConsole.Instance.OutputFormat("Sitting bot {0} on ground.", bot.Name);
735  bot.SitOnGround();
736  }
737  }
738  }
739  }
740 
741  private void HandleStand(string module, string[] cmd)
742  {
743  lock (m_bots)
744  {
745  foreach (Bot bot in m_bots)
746  {
747  if (bot.ConnectionState == ConnectionState.Connected)
748  {
749  MainConsole.Instance.OutputFormat("Standing bot {0} from ground.", bot.Name);
750  bot.Stand();
751  }
752  }
753  }
754  }
755 
756  private void HandleShutdown(string module, string[] cmd)
757  {
758  lock (m_bots)
759  {
760  int connectedBots = m_bots.Count(b => b.ConnectionState == ConnectionState.Connected);
761 
762  if (connectedBots > 0)
763  {
764  MainConsole.Instance.OutputFormat("Please disconnect {0} connected bots first", connectedBots);
765  return;
766  }
767  }
768 
769  MainConsole.Instance.Output("Shutting down");
770 
771  m_serverStatsCollector.Close();
772 
773  Environment.Exit(0);
774  }
775 
776  private void HandleSetBots(string module, string[] cmd)
777  {
778  string key = cmd[2];
779  string rawValue = cmd[3];
780 
781  if (key == "SEND_AGENT_UPDATES")
782  {
783  bool newSendAgentUpdatesSetting;
784 
785  if (!ConsoleUtil.TryParseConsoleBool(MainConsole.Instance, rawValue, out newSendAgentUpdatesSetting))
786  return;
787 
788  MainConsole.Instance.OutputFormat(
789  "Setting SEND_AGENT_UPDATES to {0} for all bots", newSendAgentUpdatesSetting);
790 
791  lock (m_bots)
792  m_bots.ForEach(b => b.Client.Settings.SEND_AGENT_UPDATES = newSendAgentUpdatesSetting);
793  }
794  else
795  {
796  MainConsole.Instance.Output("Error: Only setting currently available is SEND_AGENT_UPDATES");
797  }
798  }
799 
800  private void HandleDebugLludpPacketCommand(string module, string[] args)
801  {
802  if (args.Length != 6)
803  {
804  MainConsole.Instance.OutputFormat("Usage: debug lludp packet <level> <bot-first-name> <bot-last-name>");
805  return;
806  }
807 
808  int level;
809 
810  if (!ConsoleUtil.TryParseConsoleInt(MainConsole.Instance, args[3], out level))
811  return;
812 
813  string botFirstName = args[4];
814  string botLastName = args[5];
815 
816  Bot bot;
817 
818  lock (m_bots)
819  bot = m_bots.FirstOrDefault(b => b.FirstName == botFirstName && b.LastName == botLastName);
820 
821  if (bot == null)
822  {
823  MainConsole.Instance.OutputFormat("No bot named {0} {1}", botFirstName, botLastName);
824  return;
825  }
826 
827  bot.PacketDebugLevel = level;
828 
829  MainConsole.Instance.OutputFormat("Set debug level of {0} to {1}", bot.Name, bot.PacketDebugLevel);
830  }
831 
832  private void HandleShowRegions(string module, string[] cmd)
833  {
834  string outputFormat = "{0,-30} {1, -20} {2, -5} {3, -5}";
835  MainConsole.Instance.OutputFormat(outputFormat, "Name", "Handle", "X", "Y");
836 
837  lock (RegionsKnown)
838  {
839  foreach (GridRegion region in RegionsKnown.Values)
840  {
841  MainConsole.Instance.OutputFormat(
842  outputFormat, region.Name, region.RegionHandle, region.X, region.Y);
843  }
844  }
845  }
846 
847  private void HandleShowStatus(string module, string[] cmd)
848  {
850  cdl.AddRow("Bot connecting state", BotConnectingState);
851 
852  MainConsole.Instance.Output(cdl.ToString());
853  }
854 
855  private void HandleShowBotsStatus(string module, string[] cmd)
856  {
858  cdt.AddColumn("Name", 24);
859  cdt.AddColumn("Region", 24);
860  cdt.AddColumn("Status", 13);
861  cdt.AddColumn("Conns", 5);
862  cdt.AddColumn("Behaviours", 20);
863 
864  Dictionary<ConnectionState, int> totals = new Dictionary<ConnectionState, int>();
865  foreach (object o in Enum.GetValues(typeof(ConnectionState)))
866  totals[(ConnectionState)o] = 0;
867 
868  lock (m_bots)
869  {
870  foreach (Bot bot in m_bots)
871  {
872  Simulator currentSim = bot.Client.Network.CurrentSim;
873  totals[bot.ConnectionState]++;
874 
875  cdt.AddRow(
876  bot.Name,
877  currentSim != null ? currentSim.Name : "(none)",
879  bot.SimulatorsCount,
880  string.Join(",", bot.Behaviours.Keys.ToArray()));
881  }
882  }
883 
884  MainConsole.Instance.Output(cdt.ToString());
885 
887 
888  foreach (KeyValuePair<ConnectionState, int> kvp in totals)
889  cdl.AddRow(kvp.Key, kvp.Value);
890 
891  MainConsole.Instance.Output(cdl.ToString());
892  }
893 
894  private void HandleShowBotStatus(string module, string[] cmd)
895  {
896  if (cmd.Length != 3)
897  {
898  MainConsole.Instance.Output("Usage: show bot <n>");
899  return;
900  }
901 
902  int botNumber;
903 
904  if (!ConsoleUtil.TryParseConsoleInt(MainConsole.Instance, cmd[2], out botNumber))
905  return;
906 
907  Bot bot = GetBotFromNumber(botNumber);
908 
909  if (bot == null)
910  {
911  MainConsole.Instance.OutputFormat("Error: No bot found with number {0}", botNumber);
912  return;
913  }
914 
916  cdl.AddRow("Name", bot.Name);
917  cdl.AddRow("Status", bot.ConnectionState);
918 
919  Simulator currentSim = bot.Client.Network.CurrentSim;
920  cdl.AddRow("Region", currentSim != null ? currentSim.Name : "(none)");
921 
922  List<Simulator> connectedSimulators = bot.Simulators;
923  List<string> simulatorNames = connectedSimulators.ConvertAll<string>(cs => cs.Name);
924  cdl.AddRow("Connections", string.Join(", ", simulatorNames.ToArray()));
925 
926  MainConsole.Instance.Output(cdl.ToString());
927 
928  MainConsole.Instance.Output("Settings");
929 
930  ConsoleDisplayList statusCdl = new ConsoleDisplayList();
931 
932  statusCdl.AddRow(
933  "Behaviours",
934  string.Join(", ", bot.Behaviours.Values.ToList().ConvertAll<string>(b => b.Name).ToArray()));
935 
936  GridClient botClient = bot.Client;
937  statusCdl.AddRow("SEND_AGENT_UPDATES", botClient.Settings.SEND_AGENT_UPDATES);
938 
939  MainConsole.Instance.Output(statusCdl.ToString());
940  }
941 
947  private Bot GetBotFromNumber(int botNumber)
948  {
949  string name = GenerateBotNameFromNumber(botNumber);
950 
951  Bot bot;
952 
953  lock (m_bots)
954  bot = m_bots.Find(b => b.Name == name);
955 
956  return bot;
957  }
958 
959  private string GenerateBotNameFromNumber(int botNumber)
960  {
961  return string.Format("{0} {1}_{2}", m_firstName, m_lastNameStem, botNumber);
962  }
963 
964  internal void Grid_GridRegion(object o, GridRegionEventArgs args)
965  {
966  lock (RegionsKnown)
967  {
968  GridRegion newRegion = args.Region;
969 
970  if (RegionsKnown.ContainsKey(newRegion.RegionHandle))
971  {
972  return;
973  }
974  else
975  {
976  m_log.DebugFormat(
977  "[BOT MANAGER]: Adding {0} {1} to known regions", newRegion.Name, newRegion.RegionHandle);
978  RegionsKnown[newRegion.RegionHandle] = newRegion;
979  }
980  }
981  }
982  }
983 }
Used to generated a formatted table for the console.
List< Bot > m_bots
Created bots, whether active or inactive.
Definition: BotManager.cs:97
static bool TryParseConsoleInt(ICommandConsole console, string rawConsoleInt, out int i)
Convert a console input to an int, automatically complaining if a console is given.
Definition: ConsoleUtil.cs:185
Used to generated a formatted table for the console.
void ConnectBots(int botcount)
Definition: BotManager.cs:362
EventType
Event Types from the BOT. Add new events here
Definition: pCampBot.cs:43
Teleport to a random region on the grid.
int LoginDelay
Delay between logins of multiple bots.
Definition: BotManager.cs:77
static bool TryParseConsoleBool(ICommandConsole console, string rawConsoleString, out bool b)
Convert a console input to a bool, automatically complaining if a console is given.
Definition: ConsoleUtil.cs:165
OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString key
Definition: ICM_Api.cs:31
void CreateBots(int botcount, IConfig startupConfig)
Startup number of bots specified in the starting arguments
Definition: BotManager.cs:287
Thread/Bot manager for the application
Definition: BotManager.cs:57
Stress physics by moving and bouncing around bots a whole lot.
Random Rng
Random number generator.
Definition: BotManager.cs:102
Writes log information out onto the console
bool InitBotRequestObjectTextures
Controls whether bots request textures for the object information they receive
Definition: BotManager.cs:92
ConnectionState ConnectionState
Is this bot connected to the grid?
Definition: Bot.cs:121
This behavior is for the systematic study of some performance improvements made for OSCC'13...
static ICommandConsole Instance
Definition: MainConsole.cs:35
This behavior is for the systematic study of some performance improvements made for OSCC'13...
CommandConsole m_console
Command console
Definition: BotManager.cs:82
Get the bot to make a region crossing.
void CreateBot(BotManager bm, List< IBehaviour > behaviours, string firstName, string lastName, string password, string loginUri, string startLocation, string wearSetting)
This creates a bot but does not start it.
Definition: BotManager.cs:485
static bool TryParseConsoleNaturalInt(ICommandConsole console, string rawConsoleInt, out int i)
Convert a console integer to a natural int, automatically complaining if a console is given...
Definition: ConsoleUtil.cs:245
Dictionary< ulong, GridRegion > RegionsKnown
The regions that we know about.
Definition: BotManager.cs:112
const int DefaultLoginDelay
Definition: BotManager.cs:61
BotManagerBotConnectingState
Definition: BotManager.cs:46
BotManager()
Constructor Creates MainConsole.Instance to take commands and provide the place to write data ...
Definition: BotManager.cs:162
CommandConsole CreateConsole()
Standard CreateConsole routine
Definition: BotManager.cs:531
OpenSim.Services.Interfaces.GridRegion GridRegion
BotManagerBotConnectingState BotConnectingState
Is pCampbot ready to connect or currently in the process of connecting or disconnecting bots...
Definition: BotManager.cs:66
bool InitBotSendAgentUpdates
Controls whether bots start out sending agent updates on connection.
Definition: BotManager.cs:87
A console that uses cursor control and color
Definition: LocalConsole.cs:44
ConnectionState
Definition: Bot.cs:48
Click (grab) on random objects in the scene.
A console that processes commands internally
Dictionary< UUID, bool > AssetsReceived
Track the assets we have and have not received so we don't endlessly repeat requests.
Definition: BotManager.cs:107