aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
-rw-r--r--OpenSim/Framework/Console/ConsoleTable.cs139
-rw-r--r--OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs1
-rw-r--r--OpenSim/Region/Framework/Scenes/EventManager.cs25
-rw-r--r--OpenSim/Region/Framework/Scenes/Scene.cs15
-rw-r--r--OpenSim/Region/OptionalModules/Avatar/Attachments/AttachmentsCommandModule.cs195
-rw-r--r--OpenSim/Tests/Common/Helpers/SceneHelpers.cs2
-rw-r--r--OpenSim/Tools/pCampBot/Bot.cs27
-rw-r--r--OpenSim/Tools/pCampBot/BotManager.cs67
-rw-r--r--OpenSim/Tools/pCampBot/pCampBot.cs5
9 files changed, 444 insertions, 32 deletions
diff --git a/OpenSim/Framework/Console/ConsoleTable.cs b/OpenSim/Framework/Console/ConsoleTable.cs
new file mode 100644
index 0000000..be3025b
--- /dev/null
+++ b/OpenSim/Framework/Console/ConsoleTable.cs
@@ -0,0 +1,139 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Linq;
31using System.Text;
32
33namespace OpenSim.Framework.Console
34{
35 /// <summary>
36 /// Used to generated a formatted table for the console.
37 /// </summary>
38 /// <remarks>
39 /// Currently subject to change. If you use this, be prepared to change your code when this class changes.
40 /// </remarks>
41 public class ConsoleTable
42 {
43 /// <summary>
44 /// Default number of spaces between table columns.
45 /// </summary>
46 public const int DefaultTableSpacing = 2;
47
48 /// <summary>
49 /// Table columns.
50 /// </summary>
51 public List<ConsoleTableColumn> Columns { get; private set; }
52
53 /// <summary>
54 /// Table rows
55 /// </summary>
56 public List<ConsoleTableRow> Rows { get; private set; }
57
58 /// <summary>
59 /// Number of spaces to indent the table.
60 /// </summary>
61 public int Indent { get; set; }
62
63 /// <summary>
64 /// Spacing between table columns
65 /// </summary>
66 public int TableSpacing { get; set; }
67
68 public ConsoleTable()
69 {
70 TableSpacing = DefaultTableSpacing;
71 Columns = new List<ConsoleTableColumn>();
72 Rows = new List<ConsoleTableRow>();
73 }
74
75 public override string ToString()
76 {
77 StringBuilder sb = new StringBuilder();
78 AddToStringBuilder(sb);
79 return sb.ToString();
80 }
81
82 public void AddToStringBuilder(StringBuilder sb)
83 {
84 string formatString = GetFormatString();
85// System.Console.WriteLine("FORMAT STRING [{0}]", formatString);
86
87 // columns
88 sb.AppendFormat(formatString, Columns.ConvertAll(c => c.Header).ToArray());
89
90 // rows
91 foreach (ConsoleTableRow row in Rows)
92 sb.AppendFormat(formatString, row.Cells.ToArray());
93 }
94
95 /// <summary>
96 /// Gets the format string for the table.
97 /// </summary>
98 private string GetFormatString()
99 {
100 StringBuilder formatSb = new StringBuilder();
101
102 formatSb.Append(' ', Indent);
103
104 for (int i = 0; i < Columns.Count; i++)
105 {
106 formatSb.Append(' ', TableSpacing);
107
108 // Can only do left formatting for now
109 formatSb.AppendFormat("{{{0},-{1}}}", i, Columns[i].Width);
110 }
111
112 formatSb.Append('\n');
113
114 return formatSb.ToString();
115 }
116 }
117
118 public struct ConsoleTableColumn
119 {
120 public string Header { get; set; }
121 public int Width { get; set; }
122
123 public ConsoleTableColumn(string header, int width) : this()
124 {
125 Header = header;
126 Width = width;
127 }
128 }
129
130 public struct ConsoleTableRow
131 {
132 public List<string> Cells { get; private set; }
133
134 public ConsoleTableRow(List<string> cells) : this()
135 {
136 Cells = cells;
137 }
138 }
139} \ No newline at end of file
diff --git a/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs b/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs
index e2bd769..5b03ac7 100644
--- a/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs
+++ b/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs
@@ -724,6 +724,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain
724 } 724 }
725 if (shouldTaint) 725 if (shouldTaint)
726 { 726 {
727 m_scene.EventManager.TriggerTerrainTainted();
727 m_tainted = true; 728 m_tainted = true;
728 } 729 }
729 } 730 }
diff --git a/OpenSim/Region/Framework/Scenes/EventManager.cs b/OpenSim/Region/Framework/Scenes/EventManager.cs
index e88a623..7688cf8 100644
--- a/OpenSim/Region/Framework/Scenes/EventManager.cs
+++ b/OpenSim/Region/Framework/Scenes/EventManager.cs
@@ -53,6 +53,10 @@ namespace OpenSim.Region.Framework.Scenes
53 53
54 public event ClientMovement OnClientMovement; 54 public event ClientMovement OnClientMovement;
55 55
56 public delegate void OnTerrainTaintedDelegate();
57
58 public event OnTerrainTaintedDelegate OnTerrainTainted;
59
56 public delegate void OnTerrainTickDelegate(); 60 public delegate void OnTerrainTickDelegate();
57 61
58 public delegate void OnTerrainUpdateDelegate(); 62 public delegate void OnTerrainUpdateDelegate();
@@ -938,6 +942,27 @@ namespace OpenSim.Region.Framework.Scenes
938 } 942 }
939 } 943 }
940 944
945 public void TriggerTerrainTainted()
946 {
947 OnTerrainTaintedDelegate handlerTerrainTainted = OnTerrainTainted;
948 if (handlerTerrainTainted != null)
949 {
950 foreach (OnTerrainTickDelegate d in handlerTerrainTainted.GetInvocationList())
951 {
952 try
953 {
954 d();
955 }
956 catch (Exception e)
957 {
958 m_log.ErrorFormat(
959 "[EVENT MANAGER]: Delegate for TriggerTerrainTainted failed - continuing. {0} {1}",
960 e.Message, e.StackTrace);
961 }
962 }
963 }
964 }
965
941 public void TriggerParcelPrimCountAdd(SceneObjectGroup obj) 966 public void TriggerParcelPrimCountAdd(SceneObjectGroup obj)
942 { 967 {
943 OnParcelPrimCountAddDelegate handlerParcelPrimCountAdd = OnParcelPrimCountAdd; 968 OnParcelPrimCountAddDelegate handlerParcelPrimCountAdd = OnParcelPrimCountAdd;
diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs
index ff2c46f..89cde05 100644
--- a/OpenSim/Region/Framework/Scenes/Scene.cs
+++ b/OpenSim/Region/Framework/Scenes/Scene.cs
@@ -1403,6 +1403,14 @@ namespace OpenSim.Region.Framework.Scenes
1403 1403
1404 try 1404 try
1405 { 1405 {
1406 // Apply taints in terrain module to terrain in physics scene
1407 if (Frame % m_update_terrain == 0)
1408 {
1409 terMS = Util.EnvironmentTickCount();
1410 UpdateTerrain();
1411 terrainMS = Util.EnvironmentTickCountSubtract(terMS);
1412 }
1413
1406 tmpPhysicsMS2 = Util.EnvironmentTickCount(); 1414 tmpPhysicsMS2 = Util.EnvironmentTickCount();
1407 if ((Frame % m_update_physics == 0) && m_physics_enabled) 1415 if ((Frame % m_update_physics == 0) && m_physics_enabled)
1408 m_sceneGraph.UpdatePreparePhysics(); 1416 m_sceneGraph.UpdatePreparePhysics();
@@ -1467,13 +1475,6 @@ namespace OpenSim.Region.Framework.Scenes
1467 backupMS = Util.EnvironmentTickCountSubtract(backMS); 1475 backupMS = Util.EnvironmentTickCountSubtract(backMS);
1468 } 1476 }
1469 1477
1470 if (Frame % m_update_terrain == 0)
1471 {
1472 terMS = Util.EnvironmentTickCount();
1473 UpdateTerrain();
1474 terrainMS = Util.EnvironmentTickCountSubtract(terMS);
1475 }
1476
1477 //if (Frame % m_update_land == 0) 1478 //if (Frame % m_update_land == 0)
1478 //{ 1479 //{
1479 // int ldMS = Util.EnvironmentTickCount(); 1480 // int ldMS = Util.EnvironmentTickCount();
diff --git a/OpenSim/Region/OptionalModules/Avatar/Attachments/AttachmentsCommandModule.cs b/OpenSim/Region/OptionalModules/Avatar/Attachments/AttachmentsCommandModule.cs
new file mode 100644
index 0000000..a95514c
--- /dev/null
+++ b/OpenSim/Region/OptionalModules/Avatar/Attachments/AttachmentsCommandModule.cs
@@ -0,0 +1,195 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Linq;
31using System.Reflection;
32using System.Text;
33using log4net;
34using Mono.Addins;
35using Nini.Config;
36using OpenMetaverse;
37using OpenSim.Framework;
38using OpenSim.Framework.Console;
39using OpenSim.Framework.Statistics;
40using OpenSim.Region.ClientStack.LindenUDP;
41using OpenSim.Region.Framework.Interfaces;
42using OpenSim.Region.Framework.Scenes;
43
44namespace OpenSim.Region.OptionalModules.Avatar.Attachments
45{
46 /// <summary>
47 /// A module that just holds commands for inspecting avatar appearance.
48 /// </summary>
49 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "AttachmentsCommandModule")]
50 public class AttachmentsCommandModule : ISharedRegionModule
51 {
52// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
53
54 private List<Scene> m_scenes = new List<Scene>();
55// private IAvatarFactoryModule m_avatarFactory;
56
57 public string Name { get { return "Attachments Command Module"; } }
58
59 public Type ReplaceableInterface { get { return null; } }
60
61 public void Initialise(IConfigSource source)
62 {
63// m_log.DebugFormat("[ATTACHMENTS COMMAND MODULE]: INITIALIZED MODULE");
64 }
65
66 public void PostInitialise()
67 {
68// m_log.DebugFormat("[ATTACHMENTS COMMAND MODULE]: POST INITIALIZED MODULE");
69 }
70
71 public void Close()
72 {
73// m_log.DebugFormat("[ATTACHMENTS COMMAND MODULE]: CLOSED MODULE");
74 }
75
76 public void AddRegion(Scene scene)
77 {
78// m_log.DebugFormat("[ATTACHMENTS COMMAND MODULE]: REGION {0} ADDED", scene.RegionInfo.RegionName);
79 }
80
81 public void RemoveRegion(Scene scene)
82 {
83// m_log.DebugFormat("[ATTACHMENTS COMMAND MODULE]: REGION {0} REMOVED", scene.RegionInfo.RegionName);
84
85 lock (m_scenes)
86 m_scenes.Remove(scene);
87 }
88
89 public void RegionLoaded(Scene scene)
90 {
91// m_log.DebugFormat("[ATTACHMENTS COMMAND MODULE]: REGION {0} LOADED", scene.RegionInfo.RegionName);
92
93 lock (m_scenes)
94 m_scenes.Add(scene);
95
96 scene.AddCommand(
97 "Users", this, "attachments show",
98 "attachments show [<first-name> <last-name>]",
99 "Show attachment information for avatars in this simulator.",
100 HandleShowAttachmentsCommand);
101 }
102
103 protected void HandleShowAttachmentsCommand(string module, string[] cmd)
104 {
105 if (cmd.Length != 2 && cmd.Length < 4)
106 {
107 MainConsole.Instance.OutputFormat("Usage: attachments show [<first-name> <last-name>]");
108 return;
109 }
110
111 bool targetNameSupplied = false;
112 string optionalTargetFirstName = null;
113 string optionalTargetLastName = null;
114
115 if (cmd.Length >= 4)
116 {
117 targetNameSupplied = true;
118 optionalTargetFirstName = cmd[2];
119 optionalTargetLastName = cmd[3];
120 }
121
122 StringBuilder sb = new StringBuilder();
123
124 lock (m_scenes)
125 {
126 foreach (Scene scene in m_scenes)
127 {
128 if (targetNameSupplied)
129 {
130 ScenePresence sp = scene.GetScenePresence(optionalTargetFirstName, optionalTargetLastName);
131 if (sp != null && !sp.IsChildAgent)
132 GetAttachmentsReport(sp, sb);
133 }
134 else
135 {
136 scene.ForEachRootScenePresence(sp => GetAttachmentsReport(sp, sb));
137 }
138 }
139 }
140
141 MainConsole.Instance.Output(sb.ToString());
142 }
143
144 private void GetAttachmentsReport(ScenePresence sp, StringBuilder sb)
145 {
146 sb.AppendFormat("Attachments for {0}\n", sp.Name);
147
148 ConsoleTable ct = new ConsoleTable() { Indent = 2 };
149 ct.Columns.Add(new ConsoleTableColumn("Attachment Name", 36));
150 ct.Columns.Add(new ConsoleTableColumn("Local ID", 10));
151 ct.Columns.Add(new ConsoleTableColumn("Item ID", 36));
152 ct.Columns.Add(new ConsoleTableColumn("Attach Point", 14));
153 ct.Columns.Add(new ConsoleTableColumn("Position", 15));
154
155// sb.AppendFormat(
156// " {0,-36} {1,-10} {2,-36} {3,-14} {4,-15}\n",
157// "Attachment Name", "Local ID", "Item ID", "Attach Point", "Position");
158
159 List<SceneObjectGroup> attachmentObjects = sp.GetAttachments();
160 foreach (SceneObjectGroup attachmentObject in attachmentObjects)
161 {
162// InventoryItemBase attachmentItem
163// = m_scenes[0].InventoryService.GetItem(new InventoryItemBase(attachmentObject.FromItemID));
164
165// if (attachmentItem == null)
166// {
167// sb.AppendFormat(
168// "WARNING: Couldn't find attachment for item {0} at point {1}\n",
169// attachmentData.ItemID, (AttachmentPoint)attachmentData.AttachPoint);
170// continue;
171// }
172// else
173// {
174// sb.AppendFormat(
175// " {0,-36} {1,-10} {2,-36} {3,-14} {4,-15}\n",
176// attachmentObject.Name, attachmentObject.LocalId, attachmentObject.FromItemID,
177// (AttachmentPoint)attachmentObject.AttachmentPoint, attachmentObject.RootPart.AttachedPos);
178 ct.Rows.Add(
179 new ConsoleTableRow(
180 new List<string>()
181 {
182 attachmentObject.Name,
183 attachmentObject.LocalId.ToString(),
184 attachmentObject.FromItemID.ToString(),
185 ((AttachmentPoint)attachmentObject.AttachmentPoint).ToString(),
186 attachmentObject.RootPart.AttachedPos.ToString()
187 }));
188// }
189 }
190
191 ct.AddToStringBuilder(sb);
192 sb.Append("\n");
193 }
194 }
195} \ No newline at end of file
diff --git a/OpenSim/Tests/Common/Helpers/SceneHelpers.cs b/OpenSim/Tests/Common/Helpers/SceneHelpers.cs
index dc24418..78f9434 100644
--- a/OpenSim/Tests/Common/Helpers/SceneHelpers.cs
+++ b/OpenSim/Tests/Common/Helpers/SceneHelpers.cs
@@ -66,7 +66,7 @@ namespace OpenSim.Tests.Common
66 private AgentCircuitManager m_acm = new AgentCircuitManager(); 66 private AgentCircuitManager m_acm = new AgentCircuitManager();
67 private ISimulationDataService m_simDataService 67 private ISimulationDataService m_simDataService
68 = OpenSim.Server.Base.ServerUtils.LoadPlugin<ISimulationDataService>("OpenSim.Tests.Common.dll", null); 68 = OpenSim.Server.Base.ServerUtils.LoadPlugin<ISimulationDataService>("OpenSim.Tests.Common.dll", null);
69 private IEstateDataService m_estateDataService; 69 private IEstateDataService m_estateDataService = null;
70 70
71 private LocalAssetServicesConnector m_assetService; 71 private LocalAssetServicesConnector m_assetService;
72 private LocalAuthenticationServicesConnector m_authenticationService; 72 private LocalAuthenticationServicesConnector m_authenticationService;
diff --git a/OpenSim/Tools/pCampBot/Bot.cs b/OpenSim/Tools/pCampBot/Bot.cs
index da090dd..b6cd287 100644
--- a/OpenSim/Tools/pCampBot/Bot.cs
+++ b/OpenSim/Tools/pCampBot/Bot.cs
@@ -43,6 +43,14 @@ using Timer = System.Timers.Timer;
43 43
44namespace pCampBot 44namespace pCampBot
45{ 45{
46 public enum ConnectionState
47 {
48 Disconnected,
49 Connecting,
50 Connected,
51 Disconnecting
52 }
53
46 public class Bot 54 public class Bot
47 { 55 {
48 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 56 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
@@ -86,7 +94,7 @@ namespace pCampBot
86 /// <summary> 94 /// <summary>
87 /// Is this bot connected to the grid? 95 /// Is this bot connected to the grid?
88 /// </summary> 96 /// </summary>
89 public bool IsConnected { get; private set; } 97 public ConnectionState ConnectionState { get; private set; }
90 98
91 public string FirstName { get; private set; } 99 public string FirstName { get; private set; }
92 public string LastName { get; private set; } 100 public string LastName { get; private set; }
@@ -130,6 +138,8 @@ namespace pCampBot
130 BotManager bm, List<IBehaviour> behaviours, 138 BotManager bm, List<IBehaviour> behaviours,
131 string firstName, string lastName, string password, string loginUri) 139 string firstName, string lastName, string password, string loginUri)
132 { 140 {
141 ConnectionState = ConnectionState.Disconnected;
142
133 behaviours.ForEach(b => b.Initialize(this)); 143 behaviours.ForEach(b => b.Initialize(this));
134 144
135 Client = new GridClient(); 145 Client = new GridClient();
@@ -157,10 +167,10 @@ namespace pCampBot
157 Behaviours.ForEach( 167 Behaviours.ForEach(
158 b => 168 b =>
159 { 169 {
170 Thread.Sleep(Random.Next(3000, 10000));
171
160 // m_log.DebugFormat("[pCAMPBOT]: For {0} performing action {1}", Name, b.GetType()); 172 // m_log.DebugFormat("[pCAMPBOT]: For {0} performing action {1}", Name, b.GetType());
161 b.Action(); 173 b.Action();
162
163 Thread.Sleep(Random.Next(1000, 10000));
164 } 174 }
165 ); 175 );
166 } 176 }
@@ -178,6 +188,8 @@ namespace pCampBot
178 /// </summary> 188 /// </summary>
179 public void shutdown() 189 public void shutdown()
180 { 190 {
191 ConnectionState = ConnectionState.Disconnecting;
192
181 if (m_actionThread != null) 193 if (m_actionThread != null)
182 m_actionThread.Abort(); 194 m_actionThread.Abort();
183 195
@@ -209,9 +221,11 @@ namespace pCampBot
209 Client.Network.Disconnected += this.Network_OnDisconnected; 221 Client.Network.Disconnected += this.Network_OnDisconnected;
210 Client.Objects.ObjectUpdate += Objects_NewPrim; 222 Client.Objects.ObjectUpdate += Objects_NewPrim;
211 223
224 ConnectionState = ConnectionState.Connecting;
225
212 if (Client.Network.Login(FirstName, LastName, Password, "pCampBot", "Your name")) 226 if (Client.Network.Login(FirstName, LastName, Password, "pCampBot", "Your name"))
213 { 227 {
214 IsConnected = true; 228 ConnectionState = ConnectionState.Connected;
215 229
216 Thread.Sleep(Random.Next(1000, 10000)); 230 Thread.Sleep(Random.Next(1000, 10000));
217 m_actionThread = new Thread(Action); 231 m_actionThread = new Thread(Action);
@@ -241,6 +255,8 @@ namespace pCampBot
241 } 255 }
242 else 256 else
243 { 257 {
258 ConnectionState = ConnectionState.Disconnected;
259
244 m_log.ErrorFormat( 260 m_log.ErrorFormat(
245 "{0} {1} cannot login: {2}", FirstName, LastName, Client.Network.LoginMessage); 261 "{0} {1} cannot login: {2}", FirstName, LastName, Client.Network.LoginMessage);
246 262
@@ -439,6 +455,8 @@ namespace pCampBot
439 455
440 public void Network_OnDisconnected(object sender, DisconnectedEventArgs args) 456 public void Network_OnDisconnected(object sender, DisconnectedEventArgs args)
441 { 457 {
458 ConnectionState = ConnectionState.Disconnected;
459
442 m_log.DebugFormat( 460 m_log.DebugFormat(
443 "[BOT]: Bot {0} disconnected reason {1}, message {2}", Name, args.Reason, args.Message); 461 "[BOT]: Bot {0} disconnected reason {1}, message {2}", Name, args.Reason, args.Message);
444 462
@@ -456,7 +474,6 @@ namespace pCampBot
456 && OnDisconnected != null) 474 && OnDisconnected != null)
457// if (OnDisconnected != null) 475// if (OnDisconnected != null)
458 { 476 {
459 IsConnected = false;
460 OnDisconnected(this, EventType.DISCONNECTED); 477 OnDisconnected(this, EventType.DISCONNECTED);
461 } 478 }
462 } 479 }
diff --git a/OpenSim/Tools/pCampBot/BotManager.cs b/OpenSim/Tools/pCampBot/BotManager.cs
index 0f501b7..d615b3f 100644
--- a/OpenSim/Tools/pCampBot/BotManager.cs
+++ b/OpenSim/Tools/pCampBot/BotManager.cs
@@ -49,6 +49,14 @@ namespace pCampBot
49 { 49 {
50 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 50 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
51 51
52 public const int DefaultLoginDelay = 5000;
53
54 /// <summary>
55 /// Delay between logins of multiple bots.
56 /// </summary>
57 /// <remarks>TODO: This value needs to be configurable by a command line argument.</remarks>
58 public int LoginDelay { get; set; }
59
52 /// <summary> 60 /// <summary>
53 /// Command console 61 /// Command console
54 /// </summary> 62 /// </summary>
@@ -84,6 +92,8 @@ namespace pCampBot
84 /// </summary> 92 /// </summary>
85 public BotManager() 93 public BotManager()
86 { 94 {
95 LoginDelay = DefaultLoginDelay;
96
87 Rng = new Random(Environment.TickCount); 97 Rng = new Random(Environment.TickCount);
88 AssetsReceived = new Dictionary<UUID, bool>(); 98 AssetsReceived = new Dictionary<UUID, bool>();
89 RegionsKnown = new Dictionary<ulong, GridRegion>(); 99 RegionsKnown = new Dictionary<ulong, GridRegion>();
@@ -151,28 +161,34 @@ namespace pCampBot
151 Array.ForEach<string>( 161 Array.ForEach<string>(
152 cs.GetString("behaviours", "p").Split(new char[] { ',' }), b => behaviourSwitches.Add(b)); 162 cs.GetString("behaviours", "p").Split(new char[] { ',' }), b => behaviourSwitches.Add(b));
153 163
164 MainConsole.Instance.OutputFormat(
165 "[BOT MANAGER]: Starting {0} bots connecting to {1}, named {2} {3}_<n>",
166 botcount,
167 loginUri,
168 firstName,
169 lastNameStem);
170
171 MainConsole.Instance.OutputFormat("[BOT MANAGER]: Delay between logins is {0}ms", LoginDelay);
172
154 for (int i = 0; i < botcount; i++) 173 for (int i = 0; i < botcount; i++)
155 { 174 {
156 string lastName = string.Format("{0}_{1}", lastNameStem, i); 175 string lastName = string.Format("{0}_{1}", lastNameStem, i);
157 176
177 // We must give each bot its own list of instantiated behaviours since they store state.
158 List<IBehaviour> behaviours = new List<IBehaviour>(); 178 List<IBehaviour> behaviours = new List<IBehaviour>();
159 179
160 // Hard-coded for now 180 // Hard-coded for now
161 if (behaviourSwitches.Contains("p")) 181 if (behaviourSwitches.Contains("p"))
162 behaviours.Add(new PhysicsBehaviour()); 182 behaviours.Add(new PhysicsBehaviour());
163 183
164 if (behaviourSwitches.Contains("g")) 184 if (behaviourSwitches.Contains("g"))
165 behaviours.Add(new GrabbingBehaviour()); 185 behaviours.Add(new GrabbingBehaviour());
166 186
167 if (behaviourSwitches.Contains("t")) 187 if (behaviourSwitches.Contains("t"))
168 behaviours.Add(new TeleportBehaviour()); 188 behaviours.Add(new TeleportBehaviour());
169 189
170 if (behaviourSwitches.Contains("c")) 190 if (behaviourSwitches.Contains("c"))
171 behaviours.Add(new CrossBehaviour()); 191 behaviours.Add(new CrossBehaviour());
172
173 MainConsole.Instance.OutputFormat(
174 "[BOT MANAGER]: Bot {0} {1} configured for behaviours {2}",
175 firstName, lastName, string.Join(",", behaviours.ConvertAll<string>(b => b.Name).ToArray()));
176 192
177 StartBot(this, behaviours, firstName, lastName, password, loginUri); 193 StartBot(this, behaviours, firstName, lastName, password, loginUri);
178 } 194 }
@@ -211,6 +227,10 @@ namespace pCampBot
211 BotManager bm, List<IBehaviour> behaviours, 227 BotManager bm, List<IBehaviour> behaviours,
212 string firstName, string lastName, string password, string loginUri) 228 string firstName, string lastName, string password, string loginUri)
213 { 229 {
230 MainConsole.Instance.OutputFormat(
231 "[BOT MANAGER]: Starting bot {0} {1}, behaviours are {2}",
232 firstName, lastName, string.Join(",", behaviours.ConvertAll<string>(b => b.Name).ToArray()));
233
214 Bot pb = new Bot(bm, behaviours, firstName, lastName, password, loginUri); 234 Bot pb = new Bot(bm, behaviours, firstName, lastName, password, loginUri);
215 235
216 pb.OnConnected += handlebotEvent; 236 pb.OnConnected += handlebotEvent;
@@ -222,7 +242,11 @@ namespace pCampBot
222 Thread pbThread = new Thread(pb.startup); 242 Thread pbThread = new Thread(pb.startup);
223 pbThread.Name = pb.Name; 243 pbThread.Name = pb.Name;
224 pbThread.IsBackground = true; 244 pbThread.IsBackground = true;
245
225 pbThread.Start(); 246 pbThread.Start();
247
248 // Stagger logins
249 Thread.Sleep(LoginDelay);
226 } 250 }
227 251
228 /// <summary> 252 /// <summary>
@@ -242,7 +266,7 @@ namespace pCampBot
242 266
243 lock (m_lBot) 267 lock (m_lBot)
244 { 268 {
245 if (m_lBot.TrueForAll(b => !b.IsConnected)) 269 if (m_lBot.TrueForAll(b => b.ConnectionState == ConnectionState.Disconnected))
246 Environment.Exit(0); 270 Environment.Exit(0);
247 271
248 break; 272 break;
@@ -251,13 +275,21 @@ namespace pCampBot
251 } 275 }
252 276
253 /// <summary> 277 /// <summary>
254 /// Shutting down all bots 278 /// Shut down all bots
255 /// </summary> 279 /// </summary>
280 /// <remarks>
281 /// We launch each shutdown on its own thread so that a slow shutting down bot doesn't hold up all the others.
282 /// </remarks>
256 public void doBotShutdown() 283 public void doBotShutdown()
257 { 284 {
258 lock (m_lBot) 285 lock (m_lBot)
259 foreach (Bot pb in m_lBot) 286 {
260 pb.shutdown(); 287 foreach (Bot bot in m_lBot)
288 {
289 Bot thisBot = bot;
290 Util.FireAndForget(o => thisBot.shutdown());
291 }
292 }
261 } 293 }
262 294
263 /// <summary> 295 /// <summary>
@@ -271,11 +303,8 @@ namespace pCampBot
271 303
272 private void HandleShutdown(string module, string[] cmd) 304 private void HandleShutdown(string module, string[] cmd)
273 { 305 {
274 Util.FireAndForget(o => 306 m_log.Info("[BOTMANAGER]: Shutting down bots");
275 { 307 doBotShutdown();
276 m_log.Warn("[BOTMANAGER]: Shutting down bots");
277 doBotShutdown();
278 });
279 } 308 }
280 309
281 private void HandleShowRegions(string module, string[] cmd) 310 private void HandleShowRegions(string module, string[] cmd)
@@ -302,9 +331,11 @@ namespace pCampBot
302 { 331 {
303 foreach (Bot pb in m_lBot) 332 foreach (Bot pb in m_lBot)
304 { 333 {
334 Simulator currentSim = pb.Client.Network.CurrentSim;
335
305 MainConsole.Instance.OutputFormat( 336 MainConsole.Instance.OutputFormat(
306 outputFormat, 337 outputFormat,
307 pb.Name, pb.Client.Network.CurrentSim.Name, pb.IsConnected ? "Connected" : "Disconnected"); 338 pb.Name, currentSim != null ? currentSim.Name : "(none)", pb.ConnectionState);
308 } 339 }
309 } 340 }
310 } 341 }
diff --git a/OpenSim/Tools/pCampBot/pCampBot.cs b/OpenSim/Tools/pCampBot/pCampBot.cs
index ec5ad04..52e7501 100644
--- a/OpenSim/Tools/pCampBot/pCampBot.cs
+++ b/OpenSim/Tools/pCampBot/pCampBot.cs
@@ -27,6 +27,7 @@
27 27
28using System; 28using System;
29using System.Reflection; 29using System.Reflection;
30using System.Threading;
30using log4net; 31using log4net;
31using Nini.Config; 32using Nini.Config;
32using OpenSim.Framework; 33using OpenSim.Framework;
@@ -67,7 +68,9 @@ namespace pCampBot
67 BotManager bm = new BotManager(); 68 BotManager bm = new BotManager();
68 69
69 //startup specified number of bots. 1 is the default 70 //startup specified number of bots. 1 is the default
70 bm.dobotStartup(botcount, config); 71 Thread startBotThread = new Thread(o => bm.dobotStartup(botcount, config));
72 startBotThread.Name = "Initial start bots thread";
73 startBotThread.Start();
71 74
72 while (true) 75 while (true)
73 { 76 {