From 134f86e8d5c414409631b25b8c6f0ee45fbd8631 Mon Sep 17 00:00:00 2001
From: David Walter Seikel
Date: Thu, 3 Nov 2016 21:44:39 +1000
Subject: Initial update to OpenSim 0.8.2.1 source code.
---
OpenSim/Tools/pCampBot/BotManager.cs | 903 +++++++++++++++++++++++++++++------
1 file changed, 752 insertions(+), 151 deletions(-)
(limited to 'OpenSim/Tools/pCampBot/BotManager.cs')
diff --git a/OpenSim/Tools/pCampBot/BotManager.cs b/OpenSim/Tools/pCampBot/BotManager.cs
index d615b3f..0af9592 100644
--- a/OpenSim/Tools/pCampBot/BotManager.cs
+++ b/OpenSim/Tools/pCampBot/BotManager.cs
@@ -38,10 +38,19 @@ using log4net.Repository;
using Nini.Config;
using OpenSim.Framework;
using OpenSim.Framework.Console;
+using OpenSim.Framework.Monitoring;
using pCampBot.Interfaces;
namespace pCampBot
{
+ public enum BotManagerBotConnectingState
+ {
+ Initializing,
+ Ready,
+ Connecting,
+ Disconnecting
+ }
+
///
/// Thread/Bot manager for the application
///
@@ -52,6 +61,16 @@ namespace pCampBot
public const int DefaultLoginDelay = 5000;
///
+ /// Is pCampbot ready to connect or currently in the process of connecting or disconnecting bots?
+ ///
+ public BotManagerBotConnectingState BotConnectingState { get; private set; }
+
+ ///
+ /// Used to control locking as we can't lock an enum.
+ ///
+ private object BotConnectingStateChangeObject = new object();
+
+ ///
/// Delay between logins of multiple bots.
///
/// TODO: This value needs to be configurable by a command line argument.
@@ -63,19 +82,24 @@ namespace pCampBot
protected CommandConsole m_console;
///
- /// Created bots, whether active or inactive.
+ /// Controls whether bots start out sending agent updates on connection.
///
- protected List m_lBot;
+ public bool InitBotSendAgentUpdates { get; set; }
///
- /// Random number generator.
+ /// Controls whether bots request textures for the object information they receive
///
- public Random Rng { get; private set; }
+ public bool InitBotRequestObjectTextures { get; set; }
///
- /// Overall configuration.
+ /// Created bots, whether active or inactive.
///
- public IConfig Config { get; private set; }
+ protected List m_bots;
+
+ ///
+ /// Random number generator.
+ ///
+ public Random Rng { get; private set; }
///
/// Track the assets we have and have not received so we don't endlessly repeat requests.
@@ -88,10 +112,68 @@ namespace pCampBot
public Dictionary RegionsKnown { get; private set; }
///
+ /// First name for bots
+ ///
+ private string m_firstName;
+
+ ///
+ /// Last name stem for bots
+ ///
+ private string m_lastNameStem;
+
+ ///
+ /// Password for bots
+ ///
+ private string m_password;
+
+ ///
+ /// Login URI for bots.
+ ///
+ private string m_loginUri;
+
+ ///
+ /// Start location for bots.
+ ///
+ private string m_startUri;
+
+ ///
+ /// Postfix bot number at which bot sequence starts.
+ ///
+ private int m_fromBotNumber;
+
+ ///
+ /// Wear setting for bots.
+ ///
+ private string m_wearSetting;
+
+ ///
+ /// Behaviour switches for bots.
+ ///
+ private HashSet m_defaultBehaviourSwitches = new HashSet();
+
+ ///
+ /// Collects general information on this server (which reveals this to be a misnamed class).
+ ///
+ private ServerStatsCollector m_serverStatsCollector;
+
+ ///
/// Constructor Creates MainConsole.Instance to take commands and provide the place to write data
///
public BotManager()
{
+ // We set this to avoid issues with bots running out of HTTP connections if many are run from a single machine
+ // to multiple regions.
+ Settings.MAX_HTTP_CONNECTIONS = int.MaxValue;
+
+// System.Threading.ThreadPool.SetMaxThreads(600, 240);
+//
+// int workerThreads, iocpThreads;
+// System.Threading.ThreadPool.GetMaxThreads(out workerThreads, out iocpThreads);
+// Console.WriteLine("ThreadPool.GetMaxThreads {0} {1}", workerThreads, iocpThreads);
+
+ InitBotSendAgentUpdates = true;
+ InitBotRequestObjectTextures = true;
+
LoginDelay = DefaultLoginDelay;
Rng = new Random(Environment.TickCount);
@@ -117,30 +199,84 @@ namespace pCampBot
}
}
- m_console.Commands.AddCommand("bot", false, "shutdown",
- "shutdown",
- "Shutdown bots and exit", HandleShutdown);
-
- m_console.Commands.AddCommand("bot", false, "quit",
- "quit",
- "Shutdown bots and exit",
- HandleShutdown);
-
- m_console.Commands.AddCommand("bot", false, "show regions",
- "show regions",
- "Show regions known to bots",
- HandleShowRegions);
-
- m_console.Commands.AddCommand("bot", false, "show bots",
- "show bots",
- "Shows the status of all bots",
- HandleShowStatus);
-
-// m_console.Commands.AddCommand("bot", false, "add bots",
-// "add bots ",
-// "Add more bots", HandleAddBots);
-
- m_lBot = new List();
+ m_console.Commands.AddCommand(
+ "Bots", false, "shutdown", "shutdown", "Shutdown bots and exit", HandleShutdown);
+
+ m_console.Commands.AddCommand(
+ "Bots", false, "quit", "quit", "Shutdown bots and exit", HandleShutdown);
+
+ m_console.Commands.AddCommand(
+ "Bots", false, "connect", "connect []", "Connect bots",
+ "If an is given, then the first disconnected bots by postfix number are connected.\n"
+ + "If no is given, then all currently disconnected bots are connected.",
+ HandleConnect);
+
+ m_console.Commands.AddCommand(
+ "Bots", false, "disconnect", "disconnect []", "Disconnect bots",
+ "Disconnecting bots will interupt any bot connection process, including connection on startup.\n"
+ + "If an is given, then the last connected bots by postfix number are disconnected.\n"
+ + "If no is given, then all currently connected bots are disconnected.",
+ HandleDisconnect);
+
+ m_console.Commands.AddCommand(
+ "Bots", false, "add behaviour", "add behaviour []",
+ "Add a behaviour to a bot",
+ "If no bot number is specified then behaviour is added to all bots.\n"
+ + "Can be performed on connected or disconnected bots.",
+ HandleAddBehaviour);
+
+ m_console.Commands.AddCommand(
+ "Bots", false, "remove behaviour", "remove behaviour []",
+ "Remove a behaviour from a bot",
+ "If no bot number is specified then behaviour is added to all bots.\n"
+ + "Can be performed on connected or disconnected bots.",
+ HandleRemoveBehaviour);
+
+ m_console.Commands.AddCommand(
+ "Bots", false, "sit", "sit", "Sit all bots on the ground.",
+ HandleSit);
+
+ m_console.Commands.AddCommand(
+ "Bots", false, "stand", "stand", "Stand all bots.",
+ HandleStand);
+
+ m_console.Commands.AddCommand(
+ "Bots", false, "set bots", "set bots ", "Set a setting for all bots.", HandleSetBots);
+
+ m_console.Commands.AddCommand(
+ "Bots", false, "show regions", "show regions", "Show regions known to bots", HandleShowRegions);
+
+ m_console.Commands.AddCommand(
+ "Bots", false, "show bots", "show bots", "Shows the status of all bots.", HandleShowBotsStatus);
+
+ m_console.Commands.AddCommand(
+ "Bots", false, "show bot", "show bot ",
+ "Shows the detailed status and settings of a particular bot.", HandleShowBotStatus);
+
+ m_console.Commands.AddCommand(
+ "Debug",
+ false,
+ "debug lludp packet",
+ "debug lludp packet ",
+ "Turn on received packet logging.",
+ "If level > 0 then all received packets that are not duplicates are logged.\n"
+ + "If level <= 0 then no received packets are logged.",
+ HandleDebugLludpPacketCommand);
+
+ m_console.Commands.AddCommand(
+ "Bots", false, "show status", "show status", "Shows pCampbot status.", HandleShowStatus);
+
+ m_bots = new List();
+
+ Watchdog.Enabled = true;
+ StatsManager.RegisterConsoleCommands(m_console);
+
+ m_serverStatsCollector = new ServerStatsCollector();
+ m_serverStatsCollector.Initialise(null);
+ m_serverStatsCollector.Enabled = true;
+ m_serverStatsCollector.Start();
+
+ BotConnectingState = BotManagerBotConnectingState.Ready;
}
///
@@ -148,74 +284,195 @@ namespace pCampBot
///
/// How many bots to start up
/// The configuration for the bots to use
- public void dobotStartup(int botcount, IConfig cs)
+ public void CreateBots(int botcount, IConfig startupConfig)
{
- Config = cs;
+ m_firstName = startupConfig.GetString("firstname");
+ m_lastNameStem = startupConfig.GetString("lastname");
+ m_password = startupConfig.GetString("password");
+ m_loginUri = startupConfig.GetString("loginuri");
+ m_fromBotNumber = startupConfig.GetInt("from", 0);
+ m_wearSetting = startupConfig.GetString("wear", "no");
- string firstName = cs.GetString("firstname");
- string lastNameStem = cs.GetString("lastname");
- string password = cs.GetString("password");
- string loginUri = cs.GetString("loginuri");
+ m_startUri = ParseInputStartLocationToUri(startupConfig.GetString("start", "last"));
- HashSet behaviourSwitches = new HashSet();
Array.ForEach(
- cs.GetString("behaviours", "p").Split(new char[] { ',' }), b => behaviourSwitches.Add(b));
+ startupConfig.GetString("behaviours", "p").Split(new char[] { ',' }), b => m_defaultBehaviourSwitches.Add(b));
- MainConsole.Instance.OutputFormat(
- "[BOT MANAGER]: Starting {0} bots connecting to {1}, named {2} {3}_",
- botcount,
- loginUri,
- firstName,
- lastNameStem);
+ for (int i = 0; i < botcount; i++)
+ {
+ lock (m_bots)
+ {
+ string lastName = string.Format("{0}_{1}", m_lastNameStem, i + m_fromBotNumber);
+
+ CreateBot(
+ this,
+ CreateBehavioursFromAbbreviatedNames(m_defaultBehaviourSwitches),
+ m_firstName, lastName, m_password, m_loginUri, m_startUri, m_wearSetting);
+ }
+ }
+ }
- MainConsole.Instance.OutputFormat("[BOT MANAGER]: Delay between logins is {0}ms", LoginDelay);
+ private List CreateBehavioursFromAbbreviatedNames(HashSet abbreviatedNames)
+ {
+ // We must give each bot its own list of instantiated behaviours since they store state.
+ List behaviours = new List();
- for (int i = 0; i < botcount; i++)
+ // Hard-coded for now
+ foreach (string abName in abbreviatedNames)
{
- string lastName = string.Format("{0}_{1}", lastNameStem, i);
-
- // We must give each bot its own list of instantiated behaviours since they store state.
- List behaviours = new List();
-
- // Hard-coded for now
- if (behaviourSwitches.Contains("p"))
- behaviours.Add(new PhysicsBehaviour());
-
- if (behaviourSwitches.Contains("g"))
- behaviours.Add(new GrabbingBehaviour());
-
- if (behaviourSwitches.Contains("t"))
- behaviours.Add(new TeleportBehaviour());
-
- if (behaviourSwitches.Contains("c"))
- behaviours.Add(new CrossBehaviour());
-
- StartBot(this, behaviours, firstName, lastName, password, loginUri);
+ IBehaviour newBehaviour = null;
+
+ if (abName == "c")
+ newBehaviour = new CrossBehaviour();
+
+ if (abName == "g")
+ newBehaviour = new GrabbingBehaviour();
+
+ if (abName == "n")
+ newBehaviour = new NoneBehaviour();
+
+ if (abName == "p")
+ newBehaviour = new PhysicsBehaviour();
+
+ if (abName == "t")
+ newBehaviour = new TeleportBehaviour();
+
+ if (abName == "tw")
+ newBehaviour = new TwitchyBehaviour();
+
+ if (abName == "ph2")
+ newBehaviour = new PhysicsBehaviour2();
+
+ if (abName == "inv")
+ newBehaviour = new InventoryDownloadBehaviour();
+
+ if (newBehaviour != null)
+ {
+ behaviours.Add(newBehaviour);
+ }
+ else
+ {
+ MainConsole.Instance.OutputFormat("No behaviour with abbreviated name {0} found", abName);
+ }
}
+
+ return behaviours;
}
-// ///
-// /// Add additional bots (and threads) to our bot pool
-// ///
-// /// How Many of them to add
-// public void addbots(int botcount)
-// {
-// int len = m_td.Length;
-// Thread[] m_td2 = new Thread[len + botcount];
-// for (int i = 0; i < len; i++)
-// {
-// m_td2[i] = m_td[i];
-// }
-// m_td = m_td2;
-// int newlen = len + botcount;
-// for (int i = len; i < newlen; i++)
-// {
-// startupBot(Config);
-// }
-// }
+ public void ConnectBots(int botcount)
+ {
+ lock (BotConnectingStateChangeObject)
+ {
+ if (BotConnectingState != BotManagerBotConnectingState.Ready)
+ {
+ MainConsole.Instance.OutputFormat(
+ "Bot connecting status is {0}. Please wait for previous process to complete.", BotConnectingState);
+ return;
+ }
+
+ BotConnectingState = BotManagerBotConnectingState.Connecting;
+ }
+
+ Thread connectBotThread = new Thread(o => ConnectBotsInternal(botcount));
+
+ connectBotThread.Name = "Bots connection thread";
+ connectBotThread.Start();
+ }
+
+ private void ConnectBotsInternal(int botCount)
+ {
+ m_log.InfoFormat(
+ "[BOT MANAGER]: Starting {0} bots connecting to {1}, location {2}, named {3} {4}_",
+ botCount,
+ m_loginUri,
+ m_startUri,
+ m_firstName,
+ m_lastNameStem);
+
+ m_log.DebugFormat("[BOT MANAGER]: Delay between logins is {0}ms", LoginDelay);
+ m_log.DebugFormat("[BOT MANAGER]: BotsSendAgentUpdates is {0}", InitBotSendAgentUpdates);
+ m_log.DebugFormat("[BOT MANAGER]: InitBotRequestObjectTextures is {0}", InitBotRequestObjectTextures);
+
+ List botsToConnect = new List();
+
+ lock (m_bots)
+ {
+ foreach (Bot bot in m_bots)
+ {
+ if (bot.ConnectionState == ConnectionState.Disconnected)
+ botsToConnect.Add(bot);
+
+ if (botsToConnect.Count >= botCount)
+ break;
+ }
+ }
+
+ foreach (Bot bot in botsToConnect)
+ {
+ lock (BotConnectingStateChangeObject)
+ {
+ if (BotConnectingState != BotManagerBotConnectingState.Connecting)
+ {
+ MainConsole.Instance.Output(
+ "[BOT MANAGER]: Aborting bot connection due to user-initiated disconnection");
+ return;
+ }
+ }
+
+ bot.Connect();
+
+ // Stagger logins
+ Thread.Sleep(LoginDelay);
+ }
+
+ lock (BotConnectingStateChangeObject)
+ {
+ if (BotConnectingState == BotManagerBotConnectingState.Connecting)
+ BotConnectingState = BotManagerBotConnectingState.Ready;
+ }
+ }
+
+ ///
+ /// Parses the command line start location to a start string/uri that the login mechanism will recognize.
+ ///
+ ///
+ /// The input start location to URI.
+ ///
+ ///
+ /// Start location.
+ ///
+ private string ParseInputStartLocationToUri(string startLocation)
+ {
+ if (startLocation == "home" || startLocation == "last")
+ return startLocation;
+
+ string regionName;
+
+ // Just a region name or only one (!) extra component. Like a viewer, we will stick 128/128/0 on the end
+ Vector3 startPos = new Vector3(128, 128, 0);
+
+ string[] startLocationComponents = startLocation.Split('/');
+
+ regionName = startLocationComponents[0];
+
+ if (startLocationComponents.Length >= 2)
+ {
+ float.TryParse(startLocationComponents[1], out startPos.X);
+
+ if (startLocationComponents.Length >= 3)
+ {
+ float.TryParse(startLocationComponents[2], out startPos.Y);
+
+ if (startLocationComponents.Length >= 4)
+ float.TryParse(startLocationComponents[3], out startPos.Z);
+ }
+ }
+
+ return string.Format("uri:{0}&{1}&{2}&{3}", regionName, startPos.X, startPos.Y, startPos.Z);
+ }
///
- /// This starts up the bot and stores the thread for the bot in the thread array
+ /// This creates a bot but does not start it.
///
///
/// Behaviours for this bot to perform.
@@ -223,30 +480,25 @@ namespace pCampBot
/// Last name
/// Password
/// Login URI
- public void StartBot(
+ /// Location to start the bot. Can be "last", "home" or a specific sim name.
+ ///
+ public void CreateBot(
BotManager bm, List behaviours,
- string firstName, string lastName, string password, string loginUri)
+ string firstName, string lastName, string password, string loginUri, string startLocation, string wearSetting)
{
MainConsole.Instance.OutputFormat(
- "[BOT MANAGER]: Starting bot {0} {1}, behaviours are {2}",
+ "[BOT MANAGER]: Creating bot {0} {1}, behaviours are {2}",
firstName, lastName, string.Join(",", behaviours.ConvertAll(b => b.Name).ToArray()));
- Bot pb = new Bot(bm, behaviours, firstName, lastName, password, loginUri);
+ Bot pb = new Bot(bm, behaviours, firstName, lastName, password, startLocation, loginUri);
+ pb.wear = wearSetting;
+ pb.Client.Settings.SEND_AGENT_UPDATES = InitBotSendAgentUpdates;
+ pb.RequestObjectTextures = InitBotRequestObjectTextures;
pb.OnConnected += handlebotEvent;
pb.OnDisconnected += handlebotEvent;
- lock (m_lBot)
- m_lBot.Add(pb);
-
- Thread pbThread = new Thread(pb.startup);
- pbThread.Name = pb.Name;
- pbThread.IsBackground = true;
-
- pbThread.Start();
-
- // Stagger logins
- Thread.Sleep(LoginDelay);
+ m_bots.Add(pb);
}
///
@@ -259,52 +511,322 @@ namespace pCampBot
switch (eventt)
{
case EventType.CONNECTED:
+ {
m_log.Info("[" + callbot.FirstName + " " + callbot.LastName + "]: Connected");
break;
+ }
+
case EventType.DISCONNECTED:
+ {
m_log.Info("[" + callbot.FirstName + " " + callbot.LastName + "]: Disconnected");
+ break;
+ }
+ }
+ }
- lock (m_lBot)
- {
- if (m_lBot.TrueForAll(b => b.ConnectionState == ConnectionState.Disconnected))
- Environment.Exit(0);
+ ///
+ /// Standard CreateConsole routine
+ ///
+ ///
+ protected CommandConsole CreateConsole()
+ {
+ return new LocalConsole("pCampbot");
+ }
- break;
+ private void HandleConnect(string module, string[] cmd)
+ {
+ lock (m_bots)
+ {
+ int botsToConnect;
+ int disconnectedBots = m_bots.Count(b => b.ConnectionState == ConnectionState.Disconnected);
+
+ if (cmd.Length == 1)
+ {
+ botsToConnect = disconnectedBots;
+ }
+ else
+ {
+ if (!ConsoleUtil.TryParseConsoleNaturalInt(MainConsole.Instance, cmd[1], out botsToConnect))
+ return;
+
+ botsToConnect = Math.Min(botsToConnect, disconnectedBots);
+ }
+
+ MainConsole.Instance.OutputFormat("Connecting {0} bots", botsToConnect);
+
+ ConnectBots(botsToConnect);
+ }
+ }
+
+ private void HandleAddBehaviour(string module, string[] cmd)
+ {
+ if (cmd.Length < 3 || cmd.Length > 4)
+ {
+ MainConsole.Instance.OutputFormat("Usage: add behaviour []");
+ return;
+ }
+
+ string rawBehaviours = cmd[2];
+
+ List botsToEffect = new List();
+
+ if (cmd.Length == 3)
+ {
+ lock (m_bots)
+ botsToEffect.AddRange(m_bots);
+ }
+ else
+ {
+ int botNumber;
+ if (!ConsoleUtil.TryParseConsoleNaturalInt(MainConsole.Instance, cmd[3], out botNumber))
+ return;
+
+ Bot bot = GetBotFromNumber(botNumber);
+
+ if (bot == null)
+ {
+ MainConsole.Instance.OutputFormat("Error: No bot found with number {0}", botNumber);
+ return;
+ }
+
+ botsToEffect.Add(bot);
+ }
+
+
+ HashSet rawAbbreviatedSwitchesToAdd = new HashSet();
+ Array.ForEach(rawBehaviours.Split(new char[] { ',' }), b => rawAbbreviatedSwitchesToAdd.Add(b));
+
+ foreach (Bot bot in botsToEffect)
+ {
+ List behavioursAdded = new List();
+
+ foreach (IBehaviour behaviour in CreateBehavioursFromAbbreviatedNames(rawAbbreviatedSwitchesToAdd))
+ {
+ if (bot.AddBehaviour(behaviour))
+ behavioursAdded.Add(behaviour);
+ }
+
+ MainConsole.Instance.OutputFormat(
+ "Added behaviours {0} to bot {1}",
+ string.Join(", ", behavioursAdded.ConvertAll(b => b.Name).ToArray()), bot.Name);
+ }
+ }
+
+ private void HandleRemoveBehaviour(string module, string[] cmd)
+ {
+ if (cmd.Length < 3 || cmd.Length > 4)
+ {
+ MainConsole.Instance.OutputFormat("Usage: remove behaviour []");
+ return;
+ }
+
+ string rawBehaviours = cmd[2];
+
+ List botsToEffect = new List();
+
+ if (cmd.Length == 3)
+ {
+ lock (m_bots)
+ botsToEffect.AddRange(m_bots);
+ }
+ else
+ {
+ int botNumber;
+ if (!ConsoleUtil.TryParseConsoleNaturalInt(MainConsole.Instance, cmd[3], out botNumber))
+ return;
+
+ Bot bot = GetBotFromNumber(botNumber);
+
+ if (bot == null)
+ {
+ MainConsole.Instance.OutputFormat("Error: No bot found with number {0}", botNumber);
+ return;
+ }
+
+ botsToEffect.Add(bot);
+ }
+
+ HashSet abbreviatedBehavioursToRemove = new HashSet();
+ Array.ForEach(rawBehaviours.Split(new char[] { ',' }), b => abbreviatedBehavioursToRemove.Add(b));
+
+ foreach (Bot bot in botsToEffect)
+ {
+ List behavioursRemoved = new List();
+
+ foreach (string b in abbreviatedBehavioursToRemove)
+ {
+ IBehaviour behaviour;
+
+ if (bot.TryGetBehaviour(b, out behaviour))
+ {
+ bot.RemoveBehaviour(b);
+ behavioursRemoved.Add(behaviour);
}
+ }
+
+ MainConsole.Instance.OutputFormat(
+ "Removed behaviours {0} from bot {1}",
+ string.Join(", ", behavioursRemoved.ConvertAll(b => b.Name).ToArray()), bot.Name);
}
}
- ///
- /// Shut down all bots
- ///
- ///
- /// We launch each shutdown on its own thread so that a slow shutting down bot doesn't hold up all the others.
- ///
- public void doBotShutdown()
+ private void HandleDisconnect(string module, string[] cmd)
+ {
+ List connectedBots;
+ int botsToDisconnectCount;
+
+ lock (m_bots)
+ connectedBots = m_bots.FindAll(b => b.ConnectionState == ConnectionState.Connected);
+
+ if (cmd.Length == 1)
+ {
+ botsToDisconnectCount = connectedBots.Count;
+ }
+ else
+ {
+ if (!ConsoleUtil.TryParseConsoleNaturalInt(MainConsole.Instance, cmd[1], out botsToDisconnectCount))
+ return;
+
+ botsToDisconnectCount = Math.Min(botsToDisconnectCount, connectedBots.Count);
+ }
+
+ lock (BotConnectingStateChangeObject)
+ BotConnectingState = BotManagerBotConnectingState.Disconnecting;
+
+ Thread disconnectBotThread = new Thread(o => DisconnectBotsInternal(connectedBots, botsToDisconnectCount));
+
+ disconnectBotThread.Name = "Bots disconnection thread";
+ disconnectBotThread.Start();
+ }
+
+ private void DisconnectBotsInternal(List connectedBots, int disconnectCount)
{
- lock (m_lBot)
+ MainConsole.Instance.OutputFormat("Disconnecting {0} bots", disconnectCount);
+
+ int disconnectedBots = 0;
+
+ for (int i = connectedBots.Count - 1; i >= 0; i--)
{
- foreach (Bot bot in m_lBot)
+ if (disconnectedBots >= disconnectCount)
+ break;
+
+ Bot thisBot = connectedBots[i];
+
+ if (thisBot.ConnectionState == ConnectionState.Connected)
{
- Bot thisBot = bot;
- Util.FireAndForget(o => thisBot.shutdown());
+ ThreadPool.QueueUserWorkItem(o => thisBot.Disconnect());
+ disconnectedBots++;
}
}
+
+ lock (BotConnectingStateChangeObject)
+ BotConnectingState = BotManagerBotConnectingState.Ready;
}
- ///
- /// Standard CreateConsole routine
- ///
- ///
- protected CommandConsole CreateConsole()
+ private void HandleSit(string module, string[] cmd)
{
- return new LocalConsole("pCampbot");
+ lock (m_bots)
+ {
+ foreach (Bot bot in m_bots)
+ {
+ if (bot.ConnectionState == ConnectionState.Connected)
+ {
+ MainConsole.Instance.OutputFormat("Sitting bot {0} on ground.", bot.Name);
+ bot.SitOnGround();
+ }
+ }
+ }
+ }
+
+ private void HandleStand(string module, string[] cmd)
+ {
+ lock (m_bots)
+ {
+ foreach (Bot bot in m_bots)
+ {
+ if (bot.ConnectionState == ConnectionState.Connected)
+ {
+ MainConsole.Instance.OutputFormat("Standing bot {0} from ground.", bot.Name);
+ bot.Stand();
+ }
+ }
+ }
}
private void HandleShutdown(string module, string[] cmd)
{
- m_log.Info("[BOTMANAGER]: Shutting down bots");
- doBotShutdown();
+ lock (m_bots)
+ {
+ int connectedBots = m_bots.Count(b => b.ConnectionState == ConnectionState.Connected);
+
+ if (connectedBots > 0)
+ {
+ MainConsole.Instance.OutputFormat("Please disconnect {0} connected bots first", connectedBots);
+ return;
+ }
+ }
+
+ MainConsole.Instance.Output("Shutting down");
+
+ m_serverStatsCollector.Close();
+
+ Environment.Exit(0);
+ }
+
+ private void HandleSetBots(string module, string[] cmd)
+ {
+ string key = cmd[2];
+ string rawValue = cmd[3];
+
+ if (key == "SEND_AGENT_UPDATES")
+ {
+ bool newSendAgentUpdatesSetting;
+
+ if (!ConsoleUtil.TryParseConsoleBool(MainConsole.Instance, rawValue, out newSendAgentUpdatesSetting))
+ return;
+
+ MainConsole.Instance.OutputFormat(
+ "Setting SEND_AGENT_UPDATES to {0} for all bots", newSendAgentUpdatesSetting);
+
+ lock (m_bots)
+ m_bots.ForEach(b => b.Client.Settings.SEND_AGENT_UPDATES = newSendAgentUpdatesSetting);
+ }
+ else
+ {
+ MainConsole.Instance.Output("Error: Only setting currently available is SEND_AGENT_UPDATES");
+ }
+ }
+
+ private void HandleDebugLludpPacketCommand(string module, string[] args)
+ {
+ if (args.Length != 6)
+ {
+ MainConsole.Instance.OutputFormat("Usage: debug lludp packet ");
+ return;
+ }
+
+ int level;
+
+ if (!ConsoleUtil.TryParseConsoleInt(MainConsole.Instance, args[3], out level))
+ return;
+
+ string botFirstName = args[4];
+ string botLastName = args[5];
+
+ Bot bot;
+
+ lock (m_bots)
+ bot = m_bots.FirstOrDefault(b => b.FirstName == botFirstName && b.LastName == botLastName);
+
+ if (bot == null)
+ {
+ MainConsole.Instance.OutputFormat("No bot named {0} {1}", botFirstName, botLastName);
+ return;
+ }
+
+ bot.PacketDebugLevel = level;
+
+ MainConsole.Instance.OutputFormat("Set debug level of {0} to {1}", bot.Name, bot.PacketDebugLevel);
}
private void HandleShowRegions(string module, string[] cmd)
@@ -324,41 +846,120 @@ namespace pCampBot
private void HandleShowStatus(string module, string[] cmd)
{
- string outputFormat = "{0,-30} {1, -30} {2,-14}";
- MainConsole.Instance.OutputFormat(outputFormat, "Name", "Region", "Status");
+ ConsoleDisplayList cdl = new ConsoleDisplayList();
+ cdl.AddRow("Bot connecting state", BotConnectingState);
- lock (m_lBot)
+ MainConsole.Instance.Output(cdl.ToString());
+ }
+
+ private void HandleShowBotsStatus(string module, string[] cmd)
+ {
+ ConsoleDisplayTable cdt = new ConsoleDisplayTable();
+ cdt.AddColumn("Name", 24);
+ cdt.AddColumn("Region", 24);
+ cdt.AddColumn("Status", 13);
+ cdt.AddColumn("Conns", 5);
+ cdt.AddColumn("Behaviours", 20);
+
+ Dictionary totals = new Dictionary();
+ foreach (object o in Enum.GetValues(typeof(ConnectionState)))
+ totals[(ConnectionState)o] = 0;
+
+ lock (m_bots)
{
- foreach (Bot pb in m_lBot)
+ foreach (Bot bot in m_bots)
{
- Simulator currentSim = pb.Client.Network.CurrentSim;
-
- MainConsole.Instance.OutputFormat(
- outputFormat,
- pb.Name, currentSim != null ? currentSim.Name : "(none)", pb.ConnectionState);
+ Simulator currentSim = bot.Client.Network.CurrentSim;
+ totals[bot.ConnectionState]++;
+
+ cdt.AddRow(
+ bot.Name,
+ currentSim != null ? currentSim.Name : "(none)",
+ bot.ConnectionState,
+ bot.SimulatorsCount,
+ string.Join(",", bot.Behaviours.Keys.ToArray()));
}
}
+
+ MainConsole.Instance.Output(cdt.ToString());
+
+ ConsoleDisplayList cdl = new ConsoleDisplayList();
+
+ foreach (KeyValuePair kvp in totals)
+ cdl.AddRow(kvp.Key, kvp.Value);
+
+ MainConsole.Instance.Output(cdl.ToString());
}
- /*
- private void HandleQuit(string module, string[] cmd)
+ private void HandleShowBotStatus(string module, string[] cmd)
{
- m_console.Warn("DANGER", "This should only be used to quit the program if you've already used the shutdown command and the program hasn't quit");
- Environment.Exit(0);
+ if (cmd.Length != 3)
+ {
+ MainConsole.Instance.Output("Usage: show bot ");
+ return;
+ }
+
+ int botNumber;
+
+ if (!ConsoleUtil.TryParseConsoleInt(MainConsole.Instance, cmd[2], out botNumber))
+ return;
+
+ Bot bot = GetBotFromNumber(botNumber);
+
+ if (bot == null)
+ {
+ MainConsole.Instance.OutputFormat("Error: No bot found with number {0}", botNumber);
+ return;
+ }
+
+ ConsoleDisplayList cdl = new ConsoleDisplayList();
+ cdl.AddRow("Name", bot.Name);
+ cdl.AddRow("Status", bot.ConnectionState);
+
+ Simulator currentSim = bot.Client.Network.CurrentSim;
+ cdl.AddRow("Region", currentSim != null ? currentSim.Name : "(none)");
+
+ List connectedSimulators = bot.Simulators;
+ List simulatorNames = connectedSimulators.ConvertAll(cs => cs.Name);
+ cdl.AddRow("Connections", string.Join(", ", simulatorNames.ToArray()));
+
+ MainConsole.Instance.Output(cdl.ToString());
+
+ MainConsole.Instance.Output("Settings");
+
+ ConsoleDisplayList statusCdl = new ConsoleDisplayList();
+
+ statusCdl.AddRow(
+ "Behaviours",
+ string.Join(", ", bot.Behaviours.Values.ToList().ConvertAll(b => b.Name).ToArray()));
+
+ GridClient botClient = bot.Client;
+ statusCdl.AddRow("SEND_AGENT_UPDATES", botClient.Settings.SEND_AGENT_UPDATES);
+
+ MainConsole.Instance.Output(statusCdl.ToString());
+ }
+
+ ///
+ /// Get a specific bot from its number.
+ ///
+ /// null if no bot was found
+ ///
+ private Bot GetBotFromNumber(int botNumber)
+ {
+ string name = GenerateBotNameFromNumber(botNumber);
+
+ Bot bot;
+
+ lock (m_bots)
+ bot = m_bots.Find(b => b.Name == name);
+
+ return bot;
+ }
+
+ private string GenerateBotNameFromNumber(int botNumber)
+ {
+ return string.Format("{0} {1}_{2}", m_firstName, m_lastNameStem, botNumber);
}
- */
-//
-// private void HandleAddBots(string module, string[] cmd)
-// {
-// int newbots = 0;
-//
-// if (cmd.Length > 2)
-// {
-// Int32.TryParse(cmd[2], out newbots);
-// }
-// if (newbots > 0)
-// addbots(newbots);
-// }
internal void Grid_GridRegion(object o, GridRegionEventArgs args)
{
@@ -379,4 +980,4 @@ namespace pCampBot
}
}
}
-}
+}
\ No newline at end of file
--
cgit v1.1