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.
---
.../Tools/pCampBot/Behaviours/AbstractBehaviour.cs | 19 +-
.../Tools/pCampBot/Behaviours/CrossBehaviour.cs | 6 +-
.../Tools/pCampBot/Behaviours/GrabbingBehaviour.cs | 9 +-
.../Behaviours/InventoryDownloadBehaviour.cs | 121 +++
OpenSim/Tools/pCampBot/Behaviours/NoneBehaviour.cs | 60 ++
.../Tools/pCampBot/Behaviours/PhysicsBehaviour.cs | 9 +
.../Tools/pCampBot/Behaviours/PhysicsBehaviour2.cs | 86 ++
.../Tools/pCampBot/Behaviours/TeleportBehaviour.cs | 9 +-
.../Tools/pCampBot/Behaviours/TwitchyBehaviour.cs | 73 ++
OpenSim/Tools/pCampBot/Bot.cs | 348 ++++++--
OpenSim/Tools/pCampBot/BotManager.cs | 903 +++++++++++++++++----
OpenSim/Tools/pCampBot/Interfaces/IBehaviour.cs | 21 +
OpenSim/Tools/pCampBot/Properties/AssemblyInfo.cs | 4 +-
OpenSim/Tools/pCampBot/pCampBot.cs | 89 +-
14 files changed, 1501 insertions(+), 256 deletions(-)
create mode 100644 OpenSim/Tools/pCampBot/Behaviours/InventoryDownloadBehaviour.cs
create mode 100644 OpenSim/Tools/pCampBot/Behaviours/NoneBehaviour.cs
create mode 100644 OpenSim/Tools/pCampBot/Behaviours/PhysicsBehaviour2.cs
create mode 100644 OpenSim/Tools/pCampBot/Behaviours/TwitchyBehaviour.cs
(limited to 'OpenSim/Tools/pCampBot')
diff --git a/OpenSim/Tools/pCampBot/Behaviours/AbstractBehaviour.cs b/OpenSim/Tools/pCampBot/Behaviours/AbstractBehaviour.cs
index 9a9371d..c1ba36b 100644
--- a/OpenSim/Tools/pCampBot/Behaviours/AbstractBehaviour.cs
+++ b/OpenSim/Tools/pCampBot/Behaviours/AbstractBehaviour.cs
@@ -29,21 +29,36 @@ using OpenMetaverse;
using System;
using System.Collections.Generic;
using System.Linq;
+using System.Threading;
using pCampBot.Interfaces;
namespace pCampBot
{
- public class AbstractBehaviour : IBehaviour
+ public abstract class AbstractBehaviour : IBehaviour
{
+ ///
+ /// Abbreviated name of this behaviour.
+ ///
+ public string AbbreviatedName { get; protected set; }
+
public string Name { get; protected set; }
public Bot Bot { get; protected set; }
- public virtual void Action() {}
+ public abstract void Action();
+
+ public virtual void Interrupt() {}
+
+ protected AutoResetEvent m_interruptEvent = new AutoResetEvent(false);
public virtual void Initialize(Bot bot)
{
Bot = bot;
}
+
+ public virtual void Close()
+ {
+ Interrupt();
+ }
}
}
diff --git a/OpenSim/Tools/pCampBot/Behaviours/CrossBehaviour.cs b/OpenSim/Tools/pCampBot/Behaviours/CrossBehaviour.cs
index 1e01c64..4d806fc 100644
--- a/OpenSim/Tools/pCampBot/Behaviours/CrossBehaviour.cs
+++ b/OpenSim/Tools/pCampBot/Behaviours/CrossBehaviour.cs
@@ -47,7 +47,11 @@ namespace pCampBot
public const int m_regionCrossingTimeout = 1000 * 60;
- public CrossBehaviour() { Name = "Cross"; }
+ public CrossBehaviour()
+ {
+ AbbreviatedName = "c";
+ Name = "Cross";
+ }
public override void Action()
{
diff --git a/OpenSim/Tools/pCampBot/Behaviours/GrabbingBehaviour.cs b/OpenSim/Tools/pCampBot/Behaviours/GrabbingBehaviour.cs
index 66a336a..59f6244 100644
--- a/OpenSim/Tools/pCampBot/Behaviours/GrabbingBehaviour.cs
+++ b/OpenSim/Tools/pCampBot/Behaviours/GrabbingBehaviour.cs
@@ -29,6 +29,7 @@ using OpenMetaverse;
using System;
using System.Collections.Generic;
using System.Linq;
+using System.Threading;
using pCampBot.Interfaces;
namespace pCampBot
@@ -41,7 +42,11 @@ namespace pCampBot
///
public class GrabbingBehaviour : AbstractBehaviour
{
- public GrabbingBehaviour() { Name = "Grabbing"; }
+ public GrabbingBehaviour()
+ {
+ AbbreviatedName = "g";
+ Name = "Grabbing";
+ }
public override void Action()
{
@@ -56,6 +61,8 @@ namespace pCampBot
Bot.Client.Self.Grab(prim.LocalID);
Bot.Client.Self.GrabUpdate(prim.ID, Vector3.Zero);
Bot.Client.Self.DeGrab(prim.LocalID);
+
+ Thread.Sleep(1000);
}
}
}
\ No newline at end of file
diff --git a/OpenSim/Tools/pCampBot/Behaviours/InventoryDownloadBehaviour.cs b/OpenSim/Tools/pCampBot/Behaviours/InventoryDownloadBehaviour.cs
new file mode 100644
index 0000000..521415c
--- /dev/null
+++ b/OpenSim/Tools/pCampBot/Behaviours/InventoryDownloadBehaviour.cs
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) Contributors, http://opensimulator.org/
+ * See CONTRIBUTORS.TXT for a full list of copyright holders.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the OpenSimulator Project nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+using OpenMetaverse;
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Threading;
+using System.Linq;
+using pCampBot.Interfaces;
+
+namespace pCampBot
+{
+ ///
+ /// Do nothing
+ ///
+ public class InventoryDownloadBehaviour : AbstractBehaviour
+ {
+ private bool m_initialized;
+ private int m_Requests = 2;
+ private Stopwatch m_StopWatch = new Stopwatch();
+ private List m_processed = new List();
+
+ public InventoryDownloadBehaviour()
+ {
+ AbbreviatedName = "inv";
+ Name = "Inventory";
+ }
+
+ public override void Action()
+ {
+ if (!m_initialized)
+ {
+ m_initialized = true;
+ Bot.Client.Settings.HTTP_INVENTORY = true;
+ Bot.Client.Settings.FETCH_MISSING_INVENTORY = true;
+ Bot.Client.Inventory.FolderUpdated += Inventory_FolderUpdated;
+ Console.WriteLine("Lib owner is " + Bot.Client.Inventory.Store.LibraryRootNode.Data.OwnerID);
+ m_StopWatch.Start();
+ Bot.Client.Inventory.RequestFolderContents(Bot.Client.Inventory.Store.RootFolder.UUID, Bot.Client.Self.AgentID, true, true, InventorySortOrder.ByDate);
+ Bot.Client.Inventory.RequestFolderContents(Bot.Client.Inventory.Store.LibraryRootNode.Data.UUID, Bot.Client.Inventory.Store.LibraryRootNode.Data.OwnerID, true, true, InventorySortOrder.ByDate);
+ }
+
+ Thread.Sleep(1000);
+ Console.WriteLine("Total items: " + Bot.Client.Inventory.Store.Items.Count + "; Total requests: " + m_Requests + "; Time: " + m_StopWatch.Elapsed);
+
+ }
+
+ void Inventory_FolderUpdated(object sender, FolderUpdatedEventArgs e)
+ {
+ if (e.Success)
+ {
+ //Console.WriteLine("Folder " + e.FolderID + " updated");
+ bool fetch = false;
+ lock (m_processed)
+ {
+ if (!m_processed.Contains(e.FolderID))
+ {
+ m_processed.Add(e.FolderID);
+ fetch = true;
+ }
+ }
+
+ if (fetch)
+ {
+ List m_foldersToFetch = new List();
+ foreach (InventoryBase item in Bot.Client.Inventory.Store.GetContents(e.FolderID))
+ {
+ if (item is InventoryFolder)
+ {
+ InventoryFolder f = new InventoryFolder(item.UUID);
+ f.OwnerID = item.OwnerID;
+ m_foldersToFetch.Add(f);
+ }
+ }
+ if (m_foldersToFetch.Count > 0)
+ {
+ m_Requests += 1;
+ Bot.Client.Inventory.RequestFolderContentsCap(m_foldersToFetch, Bot.Client.Network.CurrentSim.Caps.CapabilityURI("FetchInventoryDescendents2"), true, true, InventorySortOrder.ByDate);
+ }
+ }
+
+ if (Bot.Client.Inventory.Store.Items.Count >= 15739)
+ {
+ m_StopWatch.Stop();
+ Console.WriteLine("Stop! Total items: " + Bot.Client.Inventory.Store.Items.Count + "; Total requests: " + m_Requests + "; Time: " + m_StopWatch.Elapsed);
+ }
+ }
+
+ }
+
+ public override void Interrupt()
+ {
+ m_interruptEvent.Set();
+ }
+ }
+}
\ No newline at end of file
diff --git a/OpenSim/Tools/pCampBot/Behaviours/NoneBehaviour.cs b/OpenSim/Tools/pCampBot/Behaviours/NoneBehaviour.cs
new file mode 100644
index 0000000..0d43781
--- /dev/null
+++ b/OpenSim/Tools/pCampBot/Behaviours/NoneBehaviour.cs
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) Contributors, http://opensimulator.org/
+ * See CONTRIBUTORS.TXT for a full list of copyright holders.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the OpenSimulator Project nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+using OpenMetaverse;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using pCampBot.Interfaces;
+
+namespace pCampBot
+{
+ ///
+ /// Do nothing
+ ///
+ public class NoneBehaviour : AbstractBehaviour
+ {
+ public NoneBehaviour()
+ {
+ AbbreviatedName = "n";
+ Name = "None";
+ }
+
+ public override void Action()
+ {
+ Bot.Client.Self.Jump(false);
+ Bot.Client.Self.Movement.Stop = true;
+ m_interruptEvent.WaitOne();
+ Bot.Client.Self.Movement.Stop = false;
+ }
+
+ public override void Interrupt()
+ {
+ m_interruptEvent.Set();
+ }
+ }
+}
\ No newline at end of file
diff --git a/OpenSim/Tools/pCampBot/Behaviours/PhysicsBehaviour.cs b/OpenSim/Tools/pCampBot/Behaviours/PhysicsBehaviour.cs
index daa7485..98ab931 100644
--- a/OpenSim/Tools/pCampBot/Behaviours/PhysicsBehaviour.cs
+++ b/OpenSim/Tools/pCampBot/Behaviours/PhysicsBehaviour.cs
@@ -46,6 +46,7 @@ namespace pCampBot
public PhysicsBehaviour()
{
+ AbbreviatedName = "p";
Name = "Physics";
talkarray = readexcuses();
}
@@ -77,6 +78,14 @@ namespace pCampBot
Bot.Client.Self.Chat(randomf, 0, ChatType.Normal);
}
+ public override void Close()
+ {
+ if (Bot.ConnectionState == ConnectionState.Connected)
+ Bot.Client.Self.Jump(false);
+
+ base.Close();
+ }
+
private string[] readexcuses()
{
string allexcuses = "";
diff --git a/OpenSim/Tools/pCampBot/Behaviours/PhysicsBehaviour2.cs b/OpenSim/Tools/pCampBot/Behaviours/PhysicsBehaviour2.cs
new file mode 100644
index 0000000..1ec2046
--- /dev/null
+++ b/OpenSim/Tools/pCampBot/Behaviours/PhysicsBehaviour2.cs
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) Contributors, http://opensimulator.org/
+ * See CONTRIBUTORS.TXT for a full list of copyright holders.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the OpenSimulator Project nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+using OpenMetaverse;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+using System.Threading;
+using log4net;
+using pCampBot.Interfaces;
+
+namespace pCampBot
+{
+ ///
+ /// This behavior is for the systematic study of some performance improvements made
+ /// for OSCC'13.
+ /// Walk around, sending AgentUpdate packets all the time.
+ ///
+ public class PhysicsBehaviour2 : AbstractBehaviour
+ {
+// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
+
+ public PhysicsBehaviour2()
+ {
+ AbbreviatedName = "ph2";
+ Name = "Physics2";
+ }
+
+ private const int TIME_WALKING = 5 * 10; // 5 seconds
+ private int counter = 0;
+
+ public override void Action()
+ {
+
+ if (counter >= TIME_WALKING)
+ {
+ counter = 0;
+
+ Vector3 target = new Vector3(Bot.Random.Next(1, 254), Bot.Random.Next(1, 254), Bot.Client.Self.SimPosition.Z);
+ MyTurnToward(target);
+
+ Bot.Client.Self.Movement.AtPos = true;
+
+ }
+ else
+ counter++;
+ // In any case, send an update
+ Bot.Client.Self.Movement.SendUpdate();
+ }
+
+ private void MyTurnToward(Vector3 target)
+ {
+ Quaternion between = Vector3.RotationBetween(Vector3.UnitX, Vector3.Normalize(target - Bot.Client.Self.SimPosition));
+ Quaternion rot = between ;
+
+ Bot.Client.Self.Movement.BodyRotation = rot;
+ Bot.Client.Self.Movement.HeadRotation = rot;
+ Bot.Client.Self.Movement.Camera.LookAt(Bot.Client.Self.SimPosition, target);
+ }
+ }
+}
\ No newline at end of file
diff --git a/OpenSim/Tools/pCampBot/Behaviours/TeleportBehaviour.cs b/OpenSim/Tools/pCampBot/Behaviours/TeleportBehaviour.cs
index fbb4e96..81f250d 100644
--- a/OpenSim/Tools/pCampBot/Behaviours/TeleportBehaviour.cs
+++ b/OpenSim/Tools/pCampBot/Behaviours/TeleportBehaviour.cs
@@ -29,6 +29,7 @@ using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
+using System.Threading;
using log4net;
using OpenMetaverse;
using pCampBot.Interfaces;
@@ -42,7 +43,11 @@ namespace pCampBot
{
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
- public TeleportBehaviour() { Name = "Teleport"; }
+ public TeleportBehaviour()
+ {
+ AbbreviatedName = "t";
+ Name = "Teleport";
+ }
public override void Action()
{
@@ -70,6 +75,8 @@ namespace pCampBot
Bot.Name, sourceRegion.Name, Bot.Client.Self.SimPosition, destRegion.Name, destPosition);
Bot.Client.Self.Teleport(destRegion.RegionHandle, destPosition);
+
+ Thread.Sleep(Bot.Random.Next(3000, 10000));
}
}
}
\ No newline at end of file
diff --git a/OpenSim/Tools/pCampBot/Behaviours/TwitchyBehaviour.cs b/OpenSim/Tools/pCampBot/Behaviours/TwitchyBehaviour.cs
new file mode 100644
index 0000000..7b4639d
--- /dev/null
+++ b/OpenSim/Tools/pCampBot/Behaviours/TwitchyBehaviour.cs
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) Contributors, http://opensimulator.org/
+ * See CONTRIBUTORS.TXT for a full list of copyright holders.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the OpenSimulator Project nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+using OpenMetaverse;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+using log4net;
+using pCampBot.Interfaces;
+
+namespace pCampBot
+{
+ ///
+ /// This behavior is for the systematic study of some performance improvements made
+ /// for OSCC'13.
+ /// Do nothing, but send AgentUpdate packets all the time that have only slightly
+ /// different state. The delta of difference will be filtered by OpenSim early on
+ /// in the packet processing pipeline. These filters did not exist before OSCC'13.
+ ///
+ public class TwitchyBehaviour : AbstractBehaviour
+ {
+// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
+
+ public TwitchyBehaviour()
+ {
+ AbbreviatedName = "tw";
+ Name = "Twitchy";
+ }
+
+ private const float TWITCH = 0.0001f;
+ private int direction = 1;
+
+ public override void Action()
+ {
+ Bot.Client.Self.Movement.BodyRotation = new Quaternion(Bot.Client.Self.Movement.BodyRotation.X + direction * TWITCH,
+ Bot.Client.Self.Movement.BodyRotation.Y,
+ Bot.Client.Self.Movement.BodyRotation.Z,
+ Bot.Client.Self.Movement.BodyRotation.W);
+
+ //m_log.DebugFormat("[TWITCH]: BodyRot {0}", Bot.Client.Self.Movement.BodyRotation);
+ direction = -direction;
+
+ Bot.Client.Self.Movement.SendUpdate();
+
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/OpenSim/Tools/pCampBot/Bot.cs b/OpenSim/Tools/pCampBot/Bot.cs
index daaa3c0..4f28733 100644
--- a/OpenSim/Tools/pCampBot/Bot.cs
+++ b/OpenSim/Tools/pCampBot/Bot.cs
@@ -35,11 +35,13 @@ using System.Timers;
using log4net;
using OpenMetaverse;
using OpenMetaverse.Assets;
+using OpenMetaverse.Packets;
using Nini.Config;
using OpenSim.Framework;
using OpenSim.Framework.Console;
using pCampBot.Interfaces;
using Timer = System.Timers.Timer;
+using PermissionMask = OpenSim.Framework.PermissionMask;
namespace pCampBot
{
@@ -55,25 +57,47 @@ namespace pCampBot
{
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
+ public int PacketDebugLevel
+ {
+ get { return m_packetDebugLevel; }
+ set
+ {
+ if (value == m_packetDebugLevel)
+ return;
+
+ m_packetDebugLevel = value;
+
+ if (Client != null)
+ {
+ if (m_packetDebugLevel <= 0)
+ Client.Network.UnregisterCallback(PacketType.Default, PacketReceivedDebugHandler);
+ else
+ Client.Network.RegisterCallback(PacketType.Default, PacketReceivedDebugHandler, false);
+ }
+ }
+ }
+ private int m_packetDebugLevel;
+
public delegate void AnEvent(Bot callbot, EventType someevent); // event delegate for bot events
///
- /// Bot manager.
+ /// Controls whether bots request textures for the object information they receive
///
- public BotManager Manager { get; private set; }
+ public bool RequestObjectTextures { get; set; }
///
- /// Bot config, passed from BotManager.
+ /// Bot manager.
///
- private IConfig startupConfig;
+ public BotManager Manager { get; private set; }
///
/// 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.
@@ -96,11 +120,35 @@ namespace pCampBot
///
public ConnectionState ConnectionState { get; private set; }
+ public List Simulators
+ {
+ get
+ {
+ lock (Client.Network.Simulators)
+ return new List(Client.Network.Simulators);
+ }
+ }
+
+ ///
+ /// The number of connections that this bot has to different simulators.
+ ///
+ /// Includes both root and child connections.
+ public int SimulatorsCount
+ {
+ get
+ {
+ lock (Client.Network.Simulators)
+ return Client.Network.Simulators.Count;
+ }
+ }
+
public string FirstName { get; private set; }
public string LastName { get; private set; }
public string Name { get; private set; }
public string Password { get; private set; }
public string LoginUri { get; private set; }
+ public string StartLocation { get; private set; }
+
public string saveDir;
public string wear;
@@ -136,94 +184,180 @@ namespace pCampBot
///
public Bot(
BotManager bm, List behaviours,
- string firstName, string lastName, string password, string loginUri)
+ string firstName, string lastName, string password, string startLocation, string loginUri)
{
ConnectionState = ConnectionState.Disconnected;
- behaviours.ForEach(b => b.Initialize(this));
-
- Client = new GridClient();
-
- Random = new Random(Environment.TickCount);// We do stuff randomly here
+ Random = new Random(bm.Rng.Next());
FirstName = firstName;
LastName = lastName;
Name = string.Format("{0} {1}", FirstName, LastName);
Password = password;
LoginUri = loginUri;
+ StartLocation = startLocation;
Manager = bm;
- startupConfig = bm.Config;
- readconfig();
- Behaviours = behaviours;
+ Behaviours = new Dictionary();
+ foreach (IBehaviour behaviour in behaviours)
+ AddBehaviour(behaviour);
+
+ // Only calling for use as a template.
+ CreateLibOmvClient();
+ }
+
+ public bool TryGetBehaviour(string abbreviatedName, out IBehaviour behaviour)
+ {
+ lock (Behaviours)
+ return Behaviours.TryGetValue(abbreviatedName, out behaviour);
+ }
+
+ public bool AddBehaviour(IBehaviour behaviour)
+ {
+ Dictionary updatedBehaviours = new Dictionary(Behaviours);
+
+ if (!updatedBehaviours.ContainsKey(behaviour.AbbreviatedName))
+ {
+ behaviour.Initialize(this);
+ updatedBehaviours.Add(behaviour.AbbreviatedName, behaviour);
+ Behaviours = updatedBehaviours;
+
+ return true;
+ }
+
+ return false;
+ }
+
+ public bool RemoveBehaviour(string abbreviatedName)
+ {
+ if (Behaviours.Count <= 0)
+ return false;
+
+ Dictionary updatedBehaviours = new Dictionary(Behaviours);
+ IBehaviour behaviour;
+
+ if (!updatedBehaviours.TryGetValue(abbreviatedName, out behaviour))
+ return false;
+
+ updatedBehaviours.Remove(abbreviatedName);
+ Behaviours = updatedBehaviours;
+
+ behaviour.Close();
+
+ return true;
+ }
+
+ private void CreateLibOmvClient()
+ {
+ GridClient newClient = new GridClient();
+
+ if (Client != null)
+ {
+ // Remove any registered debug handlers
+ Client.Network.UnregisterCallback(PacketType.Default, PacketReceivedDebugHandler);
+
+ newClient.Settings.LOGIN_SERVER = Client.Settings.LOGIN_SERVER;
+ newClient.Settings.ALWAYS_DECODE_OBJECTS = Client.Settings.ALWAYS_DECODE_OBJECTS;
+ newClient.Settings.AVATAR_TRACKING = Client.Settings.AVATAR_TRACKING;
+ newClient.Settings.OBJECT_TRACKING = Client.Settings.OBJECT_TRACKING;
+ newClient.Settings.SEND_AGENT_THROTTLE = Client.Settings.SEND_AGENT_THROTTLE;
+ newClient.Settings.SEND_AGENT_UPDATES = Client.Settings.SEND_AGENT_UPDATES;
+ newClient.Settings.SEND_PINGS = Client.Settings.SEND_PINGS;
+ newClient.Settings.STORE_LAND_PATCHES = Client.Settings.STORE_LAND_PATCHES;
+ newClient.Settings.USE_ASSET_CACHE = Client.Settings.USE_ASSET_CACHE;
+ newClient.Settings.MULTIPLE_SIMS = Client.Settings.MULTIPLE_SIMS;
+ newClient.Throttle.Asset = Client.Throttle.Asset;
+ newClient.Throttle.Land = Client.Throttle.Land;
+ newClient.Throttle.Task = Client.Throttle.Task;
+ newClient.Throttle.Texture = Client.Throttle.Texture;
+ newClient.Throttle.Wind = Client.Throttle.Wind;
+ newClient.Throttle.Total = Client.Throttle.Total;
+ }
+ else
+ {
+ newClient.Settings.LOGIN_SERVER = LoginUri;
+ newClient.Settings.ALWAYS_DECODE_OBJECTS = false;
+ newClient.Settings.AVATAR_TRACKING = false;
+ newClient.Settings.OBJECT_TRACKING = false;
+ newClient.Settings.SEND_AGENT_THROTTLE = true;
+ newClient.Settings.SEND_PINGS = true;
+ newClient.Settings.STORE_LAND_PATCHES = false;
+ newClient.Settings.USE_ASSET_CACHE = false;
+ newClient.Settings.MULTIPLE_SIMS = true;
+ newClient.Throttle.Asset = 100000;
+ newClient.Throttle.Land = 100000;
+ newClient.Throttle.Task = 100000;
+ newClient.Throttle.Texture = 100000;
+ newClient.Throttle.Wind = 100000;
+ newClient.Throttle.Total = 400000;
+ }
+
+ newClient.Network.LoginProgress += Network_LoginProgress;
+ newClient.Network.SimConnected += Network_SimConnected;
+ newClient.Network.SimDisconnected += Network_SimDisconnected;
+ newClient.Network.Disconnected += Network_OnDisconnected;
+ newClient.Objects.ObjectUpdate += Objects_NewPrim;
+
+ if (m_packetDebugLevel > 0)
+ newClient.Network.RegisterCallback(PacketType.Default, PacketReceivedDebugHandler);
+
+ Client = newClient;
}
//We do our actions here. This is where one would
//add additional steps and/or things the bot should do
private void Action()
{
- while (true)
- 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();
- }
- );
- }
+ while (ConnectionState == ConnectionState.Connected)
+ {
+ 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();
+ }
+ }
- ///
- /// Read the Nini config and initialize
- ///
- public void readconfig()
- {
- wear = startupConfig.GetString("wear", "no");
+ foreach (IBehaviour b in Behaviours.Values)
+ b.Close();
}
///
/// Tells LibSecondLife to logout and disconnect. Raises the disconnect events once it finishes.
///
- public void shutdown()
+ public void Disconnect()
{
ConnectionState = ConnectionState.Disconnecting;
-
- if (m_actionThread != null)
- m_actionThread.Abort();
+
+ foreach (IBehaviour behaviour in Behaviours.Values)
+ behaviour.Close();
Client.Network.Logout();
}
+ public void Connect()
+ {
+ Thread connectThread = new Thread(ConnectInternal);
+ connectThread.Name = Name;
+ connectThread.IsBackground = true;
+
+ connectThread.Start();
+ }
+
///
/// This is the bot startup loop.
///
- public void startup()
+ private void ConnectInternal()
{
- Client.Settings.LOGIN_SERVER = LoginUri;
- Client.Settings.ALWAYS_DECODE_OBJECTS = false;
- Client.Settings.AVATAR_TRACKING = false;
- Client.Settings.OBJECT_TRACKING = false;
- Client.Settings.SEND_AGENT_THROTTLE = true;
- Client.Settings.SEND_PINGS = true;
- Client.Settings.STORE_LAND_PATCHES = false;
- Client.Settings.USE_ASSET_CACHE = false;
- Client.Settings.MULTIPLE_SIMS = true;
- Client.Throttle.Asset = 100000;
- Client.Throttle.Land = 100000;
- Client.Throttle.Task = 100000;
- Client.Throttle.Texture = 100000;
- Client.Throttle.Wind = 100000;
- Client.Throttle.Total = 400000;
- Client.Network.LoginProgress += this.Network_LoginProgress;
- Client.Network.SimConnected += this.Network_SimConnected;
- Client.Network.Disconnected += this.Network_OnDisconnected;
- Client.Objects.ObjectUpdate += Objects_NewPrim;
-
ConnectionState = ConnectionState.Connecting;
- if (Client.Network.Login(FirstName, LastName, Password, "pCampBot", "Your name"))
+ // Current create a new client on each connect. libomv doesn't seem to process new sim
+ // information (e.g. EstablishAgentCommunication events) if connecting after a disceonnect with the same
+ // client
+ CreateLibOmvClient();
+
+ if (Client.Network.Login(FirstName, LastName, Password, "pCampBot", StartLocation, "pCampBot"))
{
ConnectionState = ConnectionState.Connected;
@@ -234,7 +368,6 @@ namespace pCampBot
// OnConnected(this, EventType.CONNECTED);
if (wear == "save")
{
- Client.Appearance.SetPreviousAppearance();
SaveDefaultAppearance();
}
else if (wear != "no")
@@ -267,6 +400,30 @@ namespace pCampBot
}
}
+ ///
+ /// Sit this bot on the ground.
+ ///
+ public void SitOnGround()
+ {
+ if (ConnectionState == ConnectionState.Connected)
+ Client.Self.SitOnGround();
+ }
+
+ ///
+ /// Stand this bot
+ ///
+ public void Stand()
+ {
+ if (ConnectionState == ConnectionState.Connected)
+ {
+ // Unlike sit on ground, here libomv checks whether we have SEND_AGENT_UPDATES enabled.
+ bool prevUpdatesSetting = Client.Settings.SEND_AGENT_UPDATES;
+ Client.Settings.SEND_AGENT_UPDATES = true;
+ Client.Self.Stand();
+ Client.Settings.SEND_AGENT_UPDATES = prevUpdatesSetting;
+ }
+ }
+
public void SaveDefaultAppearance()
{
saveDir = "MyAppearance/" + FirstName + "_" + LastName;
@@ -362,7 +519,7 @@ namespace pCampBot
asset.Encode();
transid = Client.Assets.RequestUpload(asset,true);
Client.Inventory.RequestCreateItem(clothfolder.UUID, "MyClothing" + i.ToString(), "MyClothing", AssetType.Clothing,
- transid, InventoryType.Wearable, asset.WearableType, PermissionMask.All, delegate(bool success, InventoryItem item)
+ transid, InventoryType.Wearable, asset.WearableType, (OpenMetaverse.PermissionMask)PermissionMask.All, delegate(bool success, InventoryItem item)
{
if (success)
{
@@ -386,7 +543,7 @@ namespace pCampBot
asset.Encode();
transid = Client.Assets.RequestUpload(asset,true);
Client.Inventory.RequestCreateItem(clothfolder.UUID, "MyBodyPart" + i.ToString(), "MyBodyPart", AssetType.Bodypart,
- transid, InventoryType.Wearable, asset.WearableType, PermissionMask.All, delegate(bool success, InventoryItem item)
+ transid, InventoryType.Wearable, asset.WearableType, (OpenMetaverse.PermissionMask)PermissionMask.All, delegate(bool success, InventoryItem item)
{
if (success)
{
@@ -450,7 +607,13 @@ namespace pCampBot
public void Network_SimConnected(object sender, SimConnectedEventArgs args)
{
m_log.DebugFormat(
- "[BOT]: Bot {0} connected to {1} at {2}", Name, args.Simulator.Name, args.Simulator.IPEndPoint);
+ "[BOT]: Bot {0} connected to region {1} at {2}", Name, args.Simulator.Name, args.Simulator.IPEndPoint);
+ }
+
+ public void Network_SimDisconnected(object sender, SimDisconnectedEventArgs args)
+ {
+ m_log.DebugFormat(
+ "[BOT]: Bot {0} disconnected from region {1} at {2}", Name, args.Simulator.Name, args.Simulator.IPEndPoint);
}
public void Network_OnDisconnected(object sender, DisconnectedEventArgs args)
@@ -458,7 +621,7 @@ namespace pCampBot
ConnectionState = ConnectionState.Disconnected;
m_log.DebugFormat(
- "[BOT]: Bot {0} disconnected reason {1}, message {2}", Name, args.Reason, args.Message);
+ "[BOT]: Bot {0} disconnected from grid, reason {1}, message {2}", Name, args.Reason, args.Message);
// m_log.ErrorFormat("Fired Network_OnDisconnected");
@@ -467,6 +630,8 @@ namespace pCampBot
// || args.Reason == NetworkManager.DisconnectType.NetworkTimeout)
// && OnDisconnected != null)
+
+
if (
(args.Reason == NetworkManager.DisconnectType.ClientInitiated
|| args.Reason == NetworkManager.DisconnectType.ServerInitiated
@@ -480,8 +645,8 @@ namespace pCampBot
public void Objects_NewPrim(object sender, PrimEventArgs args)
{
-// if (Name.EndsWith("4"))
-// throw new Exception("Aaargh");
+ if (!RequestObjectTextures)
+ return;
Primitive prim = args.Prim;
@@ -494,7 +659,7 @@ namespace pCampBot
{
if (prim.Textures.DefaultTexture.TextureID != UUID.Zero)
{
- GetTexture(prim.Textures.DefaultTexture.TextureID);
+ GetTextureOrMesh(prim.Textures.DefaultTexture.TextureID, true);
}
for (int i = 0; i < prim.Textures.FaceTextures.Length; i++)
@@ -506,32 +671,56 @@ namespace pCampBot
UUID textureID = prim.Textures.FaceTextures[i].TextureID;
if (textureID != UUID.Zero)
- GetTexture(textureID);
+ GetTextureOrMesh(textureID, true);
}
}
}
if (prim.Sculpt != null && prim.Sculpt.SculptTexture != UUID.Zero)
- GetTexture(prim.Sculpt.SculptTexture);
+ {
+ bool mesh = (prim.Sculpt.Type == SculptType.Mesh);
+ GetTextureOrMesh(prim.Sculpt.SculptTexture, !mesh);
+ }
}
}
- private void GetTexture(UUID textureID)
+ private void GetTextureOrMesh(UUID assetID, bool texture)
{
lock (Manager.AssetsReceived)
{
// Don't request assets more than once.
- if (Manager.AssetsReceived.ContainsKey(textureID))
+ if (Manager.AssetsReceived.ContainsKey(assetID))
return;
- Manager.AssetsReceived[textureID] = false;
- Client.Assets.RequestImage(textureID, ImageType.Normal, Asset_TextureCallback_Texture);
+ Manager.AssetsReceived[assetID] = false;
+ }
+
+ try
+ {
+ if (texture)
+ Client.Assets.RequestImage(assetID, ImageType.Normal, Asset_TextureCallback_Texture);
+ else
+ Client.Assets.RequestMesh(assetID, Asset_MeshCallback);
+ }
+ catch (Exception e)
+ {
+ m_log.Warn(string.Format("Error requesting {0} {1}", texture ? "texture" : "mesh", assetID), e);
}
}
public void Asset_TextureCallback_Texture(TextureRequestState state, AssetTexture assetTexture)
{
- //TODO: Implement texture saving and applying
+ if (state == TextureRequestState.Finished)
+ {
+ lock (Manager.AssetsReceived)
+ Manager.AssetsReceived[assetTexture.AssetID] = true;
+ }
+ }
+
+ private void Asset_MeshCallback(bool success, AssetMesh assetMesh)
+ {
+ lock (Manager.AssetsReceived)
+ Manager.AssetsReceived[assetMesh.AssetID] = success;
}
public void Asset_ReceivedCallback(AssetDownload transfer, Asset asset)
@@ -544,5 +733,16 @@ namespace pCampBot
// SaveAsset((AssetWearable) asset);
// }
}
+
+ private void PacketReceivedDebugHandler(object o, PacketReceivedEventArgs args)
+ {
+ Packet p = args.Packet;
+ Header h = p.Header;
+ Simulator s = args.Simulator;
+
+ m_log.DebugFormat(
+ "[BOT]: Bot {0} received from {1} packet {2} #{3}, rel {4}, res {5}",
+ Name, s.Name, p.Type, h.Sequence, h.Reliable, h.Resent);
+ }
}
}
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
diff --git a/OpenSim/Tools/pCampBot/Interfaces/IBehaviour.cs b/OpenSim/Tools/pCampBot/Interfaces/IBehaviour.cs
index 9c984be..660c630 100644
--- a/OpenSim/Tools/pCampBot/Interfaces/IBehaviour.cs
+++ b/OpenSim/Tools/pCampBot/Interfaces/IBehaviour.cs
@@ -32,6 +32,11 @@ namespace pCampBot.Interfaces
public interface IBehaviour
{
///
+ /// Abbreviated name of this behaviour.
+ ///
+ string AbbreviatedName { get; }
+
+ ///
/// Name of this behaviour.
///
string Name { get; }
@@ -46,6 +51,22 @@ namespace pCampBot.Interfaces
void Initialize(Bot bot);
///
+ /// Interrupt the behaviour.
+ ///
+ ///
+ /// This should cause the current Action call() to terminate if this is active.
+ ///
+ void Interrupt();
+
+ ///
+ /// Close down this behaviour.
+ ///
+ ///
+ /// This is triggered if a behaviour is removed via explicit command and when a bot is disconnected
+ ///
+ void Close();
+
+ ///
/// Action to take when this behaviour is invoked.
///
///
diff --git a/OpenSim/Tools/pCampBot/Properties/AssemblyInfo.cs b/OpenSim/Tools/pCampBot/Properties/AssemblyInfo.cs
index 20598f1..f551135 100644
--- a/OpenSim/Tools/pCampBot/Properties/AssemblyInfo.cs
+++ b/OpenSim/Tools/pCampBot/Properties/AssemblyInfo.cs
@@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
// Build Number
// Revision
//
-[assembly: AssemblyVersion("0.7.5.*")]
-[assembly: AssemblyFileVersion("1.0.0.0")]
+[assembly: AssemblyVersion("0.8.3.*")]
+
diff --git a/OpenSim/Tools/pCampBot/pCampBot.cs b/OpenSim/Tools/pCampBot/pCampBot.cs
index 9e82577..1fb0e03 100644
--- a/OpenSim/Tools/pCampBot/pCampBot.cs
+++ b/OpenSim/Tools/pCampBot/pCampBot.cs
@@ -26,6 +26,7 @@
*/
using System;
+using System.IO;
using System.Reflection;
using System.Threading;
using log4net;
@@ -50,30 +51,62 @@ namespace pCampBot
{
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
+ public const string ConfigFileName = "pCampBot.ini";
+
[STAThread]
public static void Main(string[] args)
{
XmlConfigurator.Configure();
- IConfig config = ParseConfig(args);
- if (config.Get("help") != null || config.Get("loginuri") == null)
+ IConfig commandLineConfig = ParseConfig(args);
+ if (commandLineConfig.Get("help") != null || commandLineConfig.Get("loginuri") == null)
{
Help();
}
- else if (config.Get("firstname") == null || config.Get("lastname") == null || config.Get("password") == null)
+ else if (
+ commandLineConfig.Get("firstname") == null
+ || commandLineConfig.Get("lastname") == null
+ || commandLineConfig.Get("password") == null)
{
Console.WriteLine("ERROR: You must supply a firstname, lastname and password for the bots.");
}
else
{
- int botcount = config.GetInt("botcount", 1);
-
BotManager bm = new BotManager();
- //startup specified number of bots. 1 is the default
- Thread startBotThread = new Thread(o => bm.dobotStartup(botcount, config));
- startBotThread.Name = "Initial start bots thread";
- startBotThread.Start();
+ string iniFilePath = Path.GetFullPath(Path.Combine(Util.configDir(), ConfigFileName));
+
+ if (File.Exists(iniFilePath))
+ {
+ m_log.InfoFormat("[PCAMPBOT]: Reading configuration settings from {0}", iniFilePath);
+
+ IConfigSource configSource = new IniConfigSource(iniFilePath);
+
+ IConfig botManagerConfig = configSource.Configs["BotManager"];
+
+ if (botManagerConfig != null)
+ {
+ bm.LoginDelay = botManagerConfig.GetInt("LoginDelay", bm.LoginDelay);
+ }
+
+ IConfig botConfig = configSource.Configs["Bot"];
+
+ if (botConfig != null)
+ {
+ bm.InitBotSendAgentUpdates
+ = botConfig.GetBoolean("SendAgentUpdates", bm.InitBotSendAgentUpdates);
+ bm.InitBotRequestObjectTextures
+ = botConfig.GetBoolean("RequestObjectTextures", bm.InitBotRequestObjectTextures);
+ }
+ }
+
+ int botcount = commandLineConfig.GetInt("botcount", 1);
+ bool startConnected = commandLineConfig.Get("connect") != null;
+
+ bm.CreateBots(botcount, commandLineConfig);
+
+ if (startConnected)
+ bm.ConnectBots(botcount);
while (true)
{
@@ -94,8 +127,11 @@ namespace pCampBot
//Set up our nifty config.. thanks to nini
ArgvConfigSource cs = new ArgvConfigSource(args);
+ cs.AddSwitch("Startup", "connect", "c");
cs.AddSwitch("Startup", "botcount", "n");
+ cs.AddSwitch("Startup", "from", "f");
cs.AddSwitch("Startup", "loginuri", "l");
+ cs.AddSwitch("Startup", "start", "s");
cs.AddSwitch("Startup", "firstname");
cs.AddSwitch("Startup", "lastname");
cs.AddSwitch("Startup", "password");
@@ -113,22 +149,27 @@ namespace pCampBot
// You can either say no, to not load anything, yes, to load one of the default wearables, a folder
// name, to load an specific folder, or save, to save an avatar with some already existing wearables
// worn to the folder MyAppearance/FirstName_LastName, and the load it.
+
Console.WriteLine(
- "usage: pCampBot <-loginuri loginuri> [OPTIONS]\n" +
- "Spawns a set of bots to test an OpenSim region\n\n" +
- " -l, -loginuri loginuri for sim to log into (required)\n" +
- " -n, -botcount number of bots to start (default: 1)\n" +
- " -firstname first name for the bots\n" +
- " -lastname lastname for the bots. Each lastname will have _ appended, e.g. Ima Bot_0\n" +
- " -password password for the bots\n" +
- " -b, behaviours behaviours for bots. Comma separated, e.g. p,g. Default is p\n" +
- " current options are:\n" +
- " p (physics)\n" +
- " g (grab)\n" +
- " t (teleport)\n" +
-// " c (cross)" +
- " -wear set appearance folder to load from (default: no)\n" +
- " -h, -help show this message");
+ "Usage: pCampBot -loginuri -firstname -lastname -password [OPTIONS]\n"
+ + "Spawns a set of bots to test an OpenSim region\n\n"
+ + " -l, -loginuri loginuri for grid/standalone (required)\n"
+ + " -s, -start start location for bots (default: last) (optional). Can be \"last\", \"home\" or a specific location with or without co-ords (e.g. \"region1\" or \"region2/50/30/90\"\n"
+ + " -firstname first name for the bots (required)\n"
+ + " -lastname lastname for the bots (required). Each lastname will have _ appended, e.g. Ima Bot_0\n"
+ + " -password password for the bots (required)\n"
+ + " -n, -botcount number of bots to start (default: 1) (optional)\n"
+ + " -f, -from starting number for login bot names, e.g. 25 will login Ima Bot_25, Ima Bot_26, etc. (default: 0) (optional)\n"
+ + " -c, -connect connect all bots at startup (optional)\n"
+ + " -b, behaviours behaviours for bots. Comma separated, e.g. p,g (default: p) (optional)\n"
+ + " current options are:\n"
+ + " p (physics - bots constantly move and jump around)\n"
+ + " g (grab - bots randomly click prims whether set clickable or not)\n"
+ + " n (none - bots do nothing)\n"
+ + " t (teleport - bots regularly teleport between regions on the grid)\n"
+// " c (cross)\n" +
+ + " -wear folder from which to load appearance data, \"no\" if there is no such folder (default: no) (optional)\n"
+ + " -h, -help show this message.\n");
}
}
}
--
cgit v1.1