From 7284cb76b64b0f814d82a0d9332119fc2b81077b Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Tue, 3 Sep 2013 18:51:55 +0100 Subject: [PATCH] Add ability to adjust pCampbot bot behaviours whilst running with "add behaviour " console commad --- OpenSim/Tools/pCampBot/Bot.cs | 51 ++++++--- OpenSim/Tools/pCampBot/BotManager.cs | 155 +++++++++++++++++++++------ 2 files changed, 161 insertions(+), 45 deletions(-) diff --git a/OpenSim/Tools/pCampBot/Bot.cs b/OpenSim/Tools/pCampBot/Bot.cs index d418288434..60375162cb 100644 --- a/OpenSim/Tools/pCampBot/Bot.cs +++ b/OpenSim/Tools/pCampBot/Bot.cs @@ -72,9 +72,10 @@ namespace pCampBot /// Behaviours implemented by this bot. /// /// - /// Lock this list before manipulating it. + /// Indexed by abbreviated name. There can only be one instance of a particular behaviour. + /// Lock this structure before manipulating it. /// - public List Behaviours { get; private set; } + public Dictionary Behaviours { get; private set; } /// /// Objects that the bot has discovered. @@ -165,8 +166,6 @@ namespace pCampBot { ConnectionState = ConnectionState.Disconnected; - behaviours.ForEach(b => b.Initialize(this)); - Random = new Random(Environment.TickCount);// We do stuff randomly here FirstName = firstName; LastName = lastName; @@ -176,12 +175,31 @@ namespace pCampBot StartLocation = startLocation; Manager = bm; - Behaviours = behaviours; + + Behaviours = new Dictionary(); + foreach (IBehaviour behaviour in behaviours) + AddBehaviour(behaviour); // Only calling for use as a template. CreateLibOmvClient(); } + public bool AddBehaviour(IBehaviour behaviour) + { + lock (Behaviours) + { + if (!Behaviours.ContainsKey(behaviour.AbbreviatedName)) + { + behaviour.Initialize(this); + Behaviours.Add(behaviour.AbbreviatedName, behaviour); + + return true; + } + } + + return false; + } + private void CreateLibOmvClient() { GridClient newClient = new GridClient(); @@ -237,16 +255,21 @@ namespace pCampBot private void Action() { while (ConnectionState != ConnectionState.Disconnecting) + { lock (Behaviours) - Behaviours.ForEach( - b => - { - Thread.Sleep(Random.Next(3000, 10000)); - - // m_log.DebugFormat("[pCAMPBOT]: For {0} performing action {1}", Name, b.GetType()); - b.Action(); - } - ); + { + foreach (IBehaviour behaviour in Behaviours.Values) + { + Thread.Sleep(Random.Next(3000, 10000)); + + // m_log.DebugFormat("[pCAMPBOT]: For {0} performing action {1}", Name, b.GetType()); + behaviour.Action(); + } + } + + // XXX: This is a really shitty way of yielding so that behaviours can be added/removed + Thread.Sleep(100); + } } /// diff --git a/OpenSim/Tools/pCampBot/BotManager.cs b/OpenSim/Tools/pCampBot/BotManager.cs index 3e446af417..51c5ff4c93 100644 --- a/OpenSim/Tools/pCampBot/BotManager.cs +++ b/OpenSim/Tools/pCampBot/BotManager.cs @@ -140,7 +140,7 @@ namespace pCampBot /// /// Behaviour switches for bots. /// - private HashSet m_behaviourSwitches = new HashSet(); + private HashSet m_defaultBehaviourSwitches = new HashSet(); /// /// Constructor Creates MainConsole.Instance to take commands and provide the place to write data @@ -194,6 +194,18 @@ namespace pCampBot + "If no is given, then all currently connected bots are disconnected.", HandleDisconnect); + m_console.Commands.AddCommand( + "bot", false, "add behaviour", "add behaviour ", + "Add a behaviour to a bot", + "Can be performed on connected or disconnected bots.", + HandleAddBehaviour); + +// m_console.Commands.AddCommand( +// "bot", false, "remove behaviour", "remove behaviour ", +// "Remove a behaviour from a bot", +// "Can be performed on connected or disconnected bots.", +// HandleRemoveBehaviour); + m_console.Commands.AddCommand( "bot", false, "sit", "sit", "Sit all bots on the ground.", HandleSit); @@ -235,7 +247,7 @@ namespace pCampBot m_startUri = ParseInputStartLocationToUri(startupConfig.GetString("start", "last")); Array.ForEach( - startupConfig.GetString("behaviours", "p").Split(new char[] { ',' }), b => m_behaviourSwitches.Add(b)); + startupConfig.GetString("behaviours", "p").Split(new char[] { ',' }), b => m_defaultBehaviourSwitches.Add(b)); for (int i = 0; i < botcount; i++) { @@ -243,30 +255,52 @@ namespace pCampBot { string lastName = string.Format("{0}_{1}", m_lastNameStem, i + m_fromBotNumber); - // We must give each bot its own list of instantiated behaviours since they store state. - List behaviours = new List(); - - // Hard-coded for now - if (m_behaviourSwitches.Contains("c")) - behaviours.Add(new CrossBehaviour()); - - if (m_behaviourSwitches.Contains("g")) - behaviours.Add(new GrabbingBehaviour()); - - if (m_behaviourSwitches.Contains("n")) - behaviours.Add(new NoneBehaviour()); - - if (m_behaviourSwitches.Contains("p")) - behaviours.Add(new PhysicsBehaviour()); - - if (m_behaviourSwitches.Contains("t")) - behaviours.Add(new TeleportBehaviour()); - - CreateBot(this, behaviours, m_firstName, lastName, m_password, m_loginUri, m_startUri, m_wearSetting); + CreateBot( + this, + CreateBehavioursFromAbbreviatedNames(m_defaultBehaviourSwitches), + m_firstName, lastName, m_password, m_loginUri, m_startUri, m_wearSetting); } } } + private List CreateBehavioursFromAbbreviatedNames(HashSet abbreviatedNames) + { + // We must give each bot its own list of instantiated behaviours since they store state. + List behaviours = new List(); + + // Hard-coded for now + foreach (string abName in abbreviatedNames) + { + 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 (newBehaviour != null) + { + behaviours.Add(newBehaviour); + } + else + { + MainConsole.Instance.OutputFormat("No behaviour with abbreviated name {0} found", abName); + } + } + + return behaviours; + } + public void ConnectBots(int botcount) { ConnectingBots = true; @@ -453,6 +487,44 @@ namespace pCampBot } } + private void HandleAddBehaviour(string module, string[] cmd) + { + if (cmd.Length != 4) + { + MainConsole.Instance.OutputFormat("Usage: add behaviour "); + return; + } + + string rawBehaviours = cmd[2]; + 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; + } + + HashSet rawAbbreviatedSwitchesToAdd = new HashSet(); + Array.ForEach(rawBehaviours.Split(new char[] { ',' }), b => rawAbbreviatedSwitchesToAdd.Add(b)); + + 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 HandleDisconnect(string module, string[] cmd) { lock (m_bots) @@ -594,7 +666,7 @@ namespace pCampBot currentSim != null ? currentSim.Name : "(none)", bot.ConnectionState, bot.SimulatorsCount, - string.Join(",", bot.Behaviours.ConvertAll(behaviour => behaviour.AbbreviatedName).ToArray())); + string.Join(",", bot.Behaviours.Keys.ToArray())); } } @@ -621,16 +693,11 @@ namespace pCampBot if (!ConsoleUtil.TryParseConsoleInt(MainConsole.Instance, cmd[2], out botNumber)) return; - string name = string.Format("{0} {1}_{2}", m_firstName, m_lastNameStem, botNumber); - - Bot bot; - - lock (m_bots) - bot = m_bots.Find(b => b.Name == name); + Bot bot = GetBotFromNumber(botNumber); if (bot == null) { - MainConsole.Instance.Output("No bot found with name {0}", name); + MainConsole.Instance.OutputFormat("Error: No bot found with number {0}", botNumber); return; } @@ -650,13 +717,39 @@ namespace pCampBot MainConsole.Instance.Output("Settings"); ConsoleDisplayList statusCdl = new ConsoleDisplayList(); - statusCdl.AddRow("Behaviours", string.Join(", ", bot.Behaviours.ConvertAll(b => b.Name).ToArray())); + + 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); + } + internal void Grid_GridRegion(object o, GridRegionEventArgs args) { lock (RegionsKnown)