aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Tools/pCampBot
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Tools/pCampBot')
-rw-r--r--OpenSim/Tools/pCampBot/Bot.cs142
-rw-r--r--OpenSim/Tools/pCampBot/BotManager.cs503
-rw-r--r--OpenSim/Tools/pCampBot/pCampBot.cs38
3 files changed, 496 insertions, 187 deletions
diff --git a/OpenSim/Tools/pCampBot/Bot.cs b/OpenSim/Tools/pCampBot/Bot.cs
index 32bf32b..d418288 100644
--- a/OpenSim/Tools/pCampBot/Bot.cs
+++ b/OpenSim/Tools/pCampBot/Bot.cs
@@ -97,6 +97,28 @@ namespace pCampBot
97 /// </summary> 97 /// </summary>
98 public ConnectionState ConnectionState { get; private set; } 98 public ConnectionState ConnectionState { get; private set; }
99 99
100 public List<Simulator> Simulators
101 {
102 get
103 {
104 lock (Client.Network.Simulators)
105 return new List<Simulator>(Client.Network.Simulators);
106 }
107 }
108
109 /// <summary>
110 /// The number of connections that this bot has to different simulators.
111 /// </summary>
112 /// <value>Includes both root and child connections.</value>
113 public int SimulatorsCount
114 {
115 get
116 {
117 lock (Client.Network.Simulators)
118 return Client.Network.Simulators.Count;
119 }
120 }
121
100 public string FirstName { get; private set; } 122 public string FirstName { get; private set; }
101 public string LastName { get; private set; } 123 public string LastName { get; private set; }
102 public string Name { get; private set; } 124 public string Name { get; private set; }
@@ -144,8 +166,6 @@ namespace pCampBot
144 ConnectionState = ConnectionState.Disconnected; 166 ConnectionState = ConnectionState.Disconnected;
145 167
146 behaviours.ForEach(b => b.Initialize(this)); 168 behaviours.ForEach(b => b.Initialize(this));
147
148 Client = new GridClient();
149 169
150 Random = new Random(Environment.TickCount);// We do stuff randomly here 170 Random = new Random(Environment.TickCount);// We do stuff randomly here
151 FirstName = firstName; 171 FirstName = firstName;
@@ -157,6 +177,59 @@ namespace pCampBot
157 177
158 Manager = bm; 178 Manager = bm;
159 Behaviours = behaviours; 179 Behaviours = behaviours;
180
181 // Only calling for use as a template.
182 CreateLibOmvClient();
183 }
184
185 private void CreateLibOmvClient()
186 {
187 GridClient newClient = new GridClient();
188
189 if (Client != null)
190 {
191 newClient.Settings.LOGIN_SERVER = Client.Settings.LOGIN_SERVER;
192 newClient.Settings.ALWAYS_DECODE_OBJECTS = Client.Settings.ALWAYS_DECODE_OBJECTS;
193 newClient.Settings.AVATAR_TRACKING = Client.Settings.AVATAR_TRACKING;
194 newClient.Settings.OBJECT_TRACKING = Client.Settings.OBJECT_TRACKING;
195 newClient.Settings.SEND_AGENT_THROTTLE = Client.Settings.SEND_AGENT_THROTTLE;
196 newClient.Settings.SEND_AGENT_UPDATES = Client.Settings.SEND_AGENT_UPDATES;
197 newClient.Settings.SEND_PINGS = Client.Settings.SEND_PINGS;
198 newClient.Settings.STORE_LAND_PATCHES = Client.Settings.STORE_LAND_PATCHES;
199 newClient.Settings.USE_ASSET_CACHE = Client.Settings.USE_ASSET_CACHE;
200 newClient.Settings.MULTIPLE_SIMS = Client.Settings.MULTIPLE_SIMS;
201 newClient.Throttle.Asset = Client.Throttle.Asset;
202 newClient.Throttle.Land = Client.Throttle.Land;
203 newClient.Throttle.Task = Client.Throttle.Task;
204 newClient.Throttle.Texture = Client.Throttle.Texture;
205 newClient.Throttle.Wind = Client.Throttle.Wind;
206 newClient.Throttle.Total = Client.Throttle.Total;
207 }
208 else
209 {
210 newClient.Settings.LOGIN_SERVER = LoginUri;
211 newClient.Settings.ALWAYS_DECODE_OBJECTS = false;
212 newClient.Settings.AVATAR_TRACKING = false;
213 newClient.Settings.OBJECT_TRACKING = false;
214 newClient.Settings.SEND_AGENT_THROTTLE = true;
215 newClient.Settings.SEND_PINGS = true;
216 newClient.Settings.STORE_LAND_PATCHES = false;
217 newClient.Settings.USE_ASSET_CACHE = false;
218 newClient.Settings.MULTIPLE_SIMS = true;
219 newClient.Throttle.Asset = 100000;
220 newClient.Throttle.Land = 100000;
221 newClient.Throttle.Task = 100000;
222 newClient.Throttle.Texture = 100000;
223 newClient.Throttle.Wind = 100000;
224 newClient.Throttle.Total = 400000;
225 }
226
227 newClient.Network.LoginProgress += this.Network_LoginProgress;
228 newClient.Network.SimConnected += this.Network_SimConnected;
229 newClient.Network.Disconnected += this.Network_OnDisconnected;
230 newClient.Objects.ObjectUpdate += Objects_NewPrim;
231
232 Client = newClient;
160 } 233 }
161 234
162 //We do our actions here. This is where one would 235 //We do our actions here. This is where one would
@@ -179,7 +252,7 @@ namespace pCampBot
179 /// <summary> 252 /// <summary>
180 /// Tells LibSecondLife to logout and disconnect. Raises the disconnect events once it finishes. 253 /// Tells LibSecondLife to logout and disconnect. Raises the disconnect events once it finishes.
181 /// </summary> 254 /// </summary>
182 public void shutdown() 255 public void Disconnect()
183 { 256 {
184 ConnectionState = ConnectionState.Disconnecting; 257 ConnectionState = ConnectionState.Disconnecting;
185 258
@@ -189,34 +262,27 @@ namespace pCampBot
189 Client.Network.Logout(); 262 Client.Network.Logout();
190 } 263 }
191 264
265 public void Connect()
266 {
267 Thread connectThread = new Thread(ConnectInternal);
268 connectThread.Name = Name;
269 connectThread.IsBackground = true;
270
271 connectThread.Start();
272 }
273
192 /// <summary> 274 /// <summary>
193 /// This is the bot startup loop. 275 /// This is the bot startup loop.
194 /// </summary> 276 /// </summary>
195 public void startup() 277 private void ConnectInternal()
196 { 278 {
197 Client.Settings.LOGIN_SERVER = LoginUri;
198 Client.Settings.ALWAYS_DECODE_OBJECTS = false;
199 Client.Settings.AVATAR_TRACKING = false;
200 Client.Settings.OBJECT_TRACKING = false;
201 Client.Settings.SEND_AGENT_THROTTLE = true;
202 Client.Settings.SEND_AGENT_UPDATES = false;
203 Client.Settings.SEND_PINGS = true;
204 Client.Settings.STORE_LAND_PATCHES = false;
205 Client.Settings.USE_ASSET_CACHE = false;
206 Client.Settings.MULTIPLE_SIMS = true;
207 Client.Throttle.Asset = 100000;
208 Client.Throttle.Land = 100000;
209 Client.Throttle.Task = 100000;
210 Client.Throttle.Texture = 100000;
211 Client.Throttle.Wind = 100000;
212 Client.Throttle.Total = 400000;
213 Client.Network.LoginProgress += this.Network_LoginProgress;
214 Client.Network.SimConnected += this.Network_SimConnected;
215 Client.Network.Disconnected += this.Network_OnDisconnected;
216 Client.Objects.ObjectUpdate += Objects_NewPrim;
217
218 ConnectionState = ConnectionState.Connecting; 279 ConnectionState = ConnectionState.Connecting;
219 280
281 // Current create a new client on each connect. libomv doesn't seem to process new sim
282 // information (e.g. EstablishAgentCommunication events) if connecting after a disceonnect with the same
283 // client
284 CreateLibOmvClient();
285
220 if (Client.Network.Login(FirstName, LastName, Password, "pCampBot", StartLocation, "Your name")) 286 if (Client.Network.Login(FirstName, LastName, Password, "pCampBot", StartLocation, "Your name"))
221 { 287 {
222 ConnectionState = ConnectionState.Connected; 288 ConnectionState = ConnectionState.Connected;
@@ -261,6 +327,30 @@ namespace pCampBot
261 } 327 }
262 } 328 }
263 329
330 /// <summary>
331 /// Sit this bot on the ground.
332 /// </summary>
333 public void SitOnGround()
334 {
335 if (ConnectionState == ConnectionState.Connected)
336 Client.Self.SitOnGround();
337 }
338
339 /// <summary>
340 /// Stand this bot
341 /// </summary>
342 public void Stand()
343 {
344 if (ConnectionState == ConnectionState.Connected)
345 {
346 // Unlike sit on ground, here libomv checks whether we have SEND_AGENT_UPDATES enabled.
347 bool prevUpdatesSetting = Client.Settings.SEND_AGENT_UPDATES;
348 Client.Settings.SEND_AGENT_UPDATES = true;
349 Client.Self.Stand();
350 Client.Settings.SEND_AGENT_UPDATES = prevUpdatesSetting;
351 }
352 }
353
264 public void SaveDefaultAppearance() 354 public void SaveDefaultAppearance()
265 { 355 {
266 saveDir = "MyAppearance/" + FirstName + "_" + LastName; 356 saveDir = "MyAppearance/" + FirstName + "_" + LastName;
@@ -461,6 +551,8 @@ namespace pCampBot
461// || args.Reason == NetworkManager.DisconnectType.NetworkTimeout) 551// || args.Reason == NetworkManager.DisconnectType.NetworkTimeout)
462// && OnDisconnected != null) 552// && OnDisconnected != null)
463 553
554
555
464 if ( 556 if (
465 (args.Reason == NetworkManager.DisconnectType.ClientInitiated 557 (args.Reason == NetworkManager.DisconnectType.ClientInitiated
466 || args.Reason == NetworkManager.DisconnectType.ServerInitiated 558 || args.Reason == NetworkManager.DisconnectType.ServerInitiated
diff --git a/OpenSim/Tools/pCampBot/BotManager.cs b/OpenSim/Tools/pCampBot/BotManager.cs
index dee02c3..5c3835b 100644
--- a/OpenSim/Tools/pCampBot/BotManager.cs
+++ b/OpenSim/Tools/pCampBot/BotManager.cs
@@ -52,9 +52,14 @@ namespace pCampBot
52 public const int DefaultLoginDelay = 5000; 52 public const int DefaultLoginDelay = 5000;
53 53
54 /// <summary> 54 /// <summary>
55 /// True if pCampbot is in the process of shutting down. 55 /// Is pCampbot in the process of connecting bots?
56 /// </summary> 56 /// </summary>
57 public bool ShuttingDown { get; private set; } 57 public bool ConnectingBots { get; private set; }
58
59 /// <summary>
60 /// Is pCampbot in the process of disconnecting bots?
61 /// </summary>
62 public bool DisconnectingBots { get; private set; }
58 63
59 /// <summary> 64 /// <summary>
60 /// Delay between logins of multiple bots. 65 /// Delay between logins of multiple bots.
@@ -80,7 +85,7 @@ namespace pCampBot
80 /// <summary> 85 /// <summary>
81 /// Created bots, whether active or inactive. 86 /// Created bots, whether active or inactive.
82 /// </summary> 87 /// </summary>
83 protected List<Bot> m_lBot; 88 protected List<Bot> m_bots;
84 89
85 /// <summary> 90 /// <summary>
86 /// Random number generator. 91 /// Random number generator.
@@ -98,6 +103,46 @@ namespace pCampBot
98 public Dictionary<ulong, GridRegion> RegionsKnown { get; private set; } 103 public Dictionary<ulong, GridRegion> RegionsKnown { get; private set; }
99 104
100 /// <summary> 105 /// <summary>
106 /// First name for bots
107 /// </summary>
108 private string m_firstName;
109
110 /// <summary>
111 /// Last name stem for bots
112 /// </summary>
113 private string m_lastNameStem;
114
115 /// <summary>
116 /// Password for bots
117 /// </summary>
118 private string m_password;
119
120 /// <summary>
121 /// Login URI for bots.
122 /// </summary>
123 private string m_loginUri;
124
125 /// <summary>
126 /// Start location for bots.
127 /// </summary>
128 private string m_startUri;
129
130 /// <summary>
131 /// Postfix bot number at which bot sequence starts.
132 /// </summary>
133 private int m_fromBotNumber;
134
135 /// <summary>
136 /// Wear setting for bots.
137 /// </summary>
138 private string m_wearSetting;
139
140 /// <summary>
141 /// Behaviour switches for bots.
142 /// </summary>
143 private HashSet<string> m_behaviourSwitches = new HashSet<string>();
144
145 /// <summary>
101 /// Constructor Creates MainConsole.Instance to take commands and provide the place to write data 146 /// Constructor Creates MainConsole.Instance to take commands and provide the place to write data
102 /// </summary> 147 /// </summary>
103 public BotManager() 148 public BotManager()
@@ -130,30 +175,47 @@ namespace pCampBot
130 } 175 }
131 } 176 }
132 177
133 m_console.Commands.AddCommand("bot", false, "shutdown", 178 m_console.Commands.AddCommand(
134 "shutdown", 179 "bot", false, "shutdown", "shutdown", "Shutdown bots and exit", HandleShutdown);
135 "Shutdown bots and exit", HandleShutdown); 180
181 m_console.Commands.AddCommand(
182 "bot", false, "quit", "quit", "Shutdown bots and exit", HandleShutdown);
136 183
137 m_console.Commands.AddCommand("bot", false, "quit", 184 m_console.Commands.AddCommand(
138 "quit", 185 "bot", false, "connect", "connect [<n>]", "Connect bots",
139 "Shutdown bots and exit", 186 "If an <n> is given, then the first <n> disconnected bots by postfix number are connected.\n"
140 HandleShutdown); 187 + "If no <n> is given, then all currently disconnected bots are connected.",
188 HandleConnect);
141 189
142 m_console.Commands.AddCommand("bot", false, "show regions", 190 m_console.Commands.AddCommand(
143 "show regions", 191 "bot", false, "disconnect", "disconnect [<n>]", "Disconnect bots",
144 "Show regions known to bots", 192 "Disconnecting bots will interupt any bot connection process, including connection on startup.\n"
145 HandleShowRegions); 193 + "If an <n> is given, then the last <n> connected bots by postfix number are disconnected.\n"
194 + "If no <n> is given, then all currently connected bots are disconnected.",
195 HandleDisconnect);
146 196
147 m_console.Commands.AddCommand("bot", false, "show bots", 197 m_console.Commands.AddCommand(
148 "show bots", 198 "bot", false, "sit", "sit", "Sit all bots on the ground.",
149 "Shows the status of all bots", 199 HandleSit);
150 HandleShowStatus);
151 200
152// m_console.Commands.AddCommand("bot", false, "add bots", 201 m_console.Commands.AddCommand(
153// "add bots <number>", 202 "bot", false, "stand", "stand", "Stand all bots.",
154// "Add more bots", HandleAddBots); 203 HandleStand);
155 204
156 m_lBot = new List<Bot>(); 205 m_console.Commands.AddCommand(
206 "bot", false, "set bots", "set bots <key> <value>", "Set a setting for all bots.", HandleSetBots);
207
208 m_console.Commands.AddCommand(
209 "bot", false, "show regions", "show regions", "Show regions known to bots", HandleShowRegions);
210
211 m_console.Commands.AddCommand(
212 "bot", false, "show bots", "show bots", "Shows the status of all bots", HandleShowBotsStatus);
213
214 m_console.Commands.AddCommand(
215 "bot", false, "show bot", "show bot <n>",
216 "Shows the detailed status and settings of a particular bot.", HandleShowBotStatus);
217
218 m_bots = new List<Bot>();
157 } 219 }
158 220
159 /// <summary> 221 /// <summary>
@@ -161,62 +223,102 @@ namespace pCampBot
161 /// </summary> 223 /// </summary>
162 /// <param name="botcount">How many bots to start up</param> 224 /// <param name="botcount">How many bots to start up</param>
163 /// <param name="cs">The configuration for the bots to use</param> 225 /// <param name="cs">The configuration for the bots to use</param>
164 public void dobotStartup(int botcount, IConfig startupConfig) 226 public void CreateBots(int botcount, IConfig startupConfig)
165 { 227 {
166 string firstName = startupConfig.GetString("firstname"); 228 m_firstName = startupConfig.GetString("firstname");
167 string lastNameStem = startupConfig.GetString("lastname"); 229 m_lastNameStem = startupConfig.GetString("lastname");
168 string password = startupConfig.GetString("password"); 230 m_password = startupConfig.GetString("password");
169 string loginUri = startupConfig.GetString("loginuri"); 231 m_loginUri = startupConfig.GetString("loginuri");
170 string startLocation = startupConfig.GetString("start", "last"); 232 m_fromBotNumber = startupConfig.GetInt("from", 0);
171 int fromBotNumber = startupConfig.GetInt("from", 0); 233 m_wearSetting = startupConfig.GetString("wear", "no");
172 string wearSetting = startupConfig.GetString("wear", "no");
173 234
174 string startUri = ParseInputStartLocationToUri(startLocation); 235 m_startUri = ParseInputStartLocationToUri(startupConfig.GetString("start", "last"));
175 236
176 HashSet<string> behaviourSwitches = new HashSet<string>();
177 Array.ForEach<string>( 237 Array.ForEach<string>(
178 startupConfig.GetString("behaviours", "p").Split(new char[] { ',' }), b => behaviourSwitches.Add(b)); 238 startupConfig.GetString("behaviours", "p").Split(new char[] { ',' }), b => m_behaviourSwitches.Add(b));
239
240 for (int i = 0; i < botcount; i++)
241 {
242 lock (m_bots)
243 {
244 string lastName = string.Format("{0}_{1}", m_lastNameStem, i + m_fromBotNumber);
245
246 // We must give each bot its own list of instantiated behaviours since they store state.
247 List<IBehaviour> behaviours = new List<IBehaviour>();
248
249 // Hard-coded for now
250 if (m_behaviourSwitches.Contains("c"))
251 behaviours.Add(new CrossBehaviour());
252
253 if (m_behaviourSwitches.Contains("g"))
254 behaviours.Add(new GrabbingBehaviour());
255
256 if (m_behaviourSwitches.Contains("n"))
257 behaviours.Add(new NoneBehaviour());
258
259 if (m_behaviourSwitches.Contains("p"))
260 behaviours.Add(new PhysicsBehaviour());
261
262 if (m_behaviourSwitches.Contains("t"))
263 behaviours.Add(new TeleportBehaviour());
264
265 CreateBot(this, behaviours, m_firstName, lastName, m_password, m_loginUri, m_startUri, m_wearSetting);
266 }
267 }
268 }
179 269
270 public void ConnectBots(int botcount)
271 {
272 ConnectingBots = true;
273
274 Thread connectBotThread = new Thread(o => ConnectBotsInternal(botcount));
275
276 connectBotThread.Name = "Bots connection thread";
277 connectBotThread.Start();
278 }
279
280 private void ConnectBotsInternal(int botCount)
281 {
180 MainConsole.Instance.OutputFormat( 282 MainConsole.Instance.OutputFormat(
181 "[BOT MANAGER]: Starting {0} bots connecting to {1}, location {2}, named {3} {4}_<n>", 283 "[BOT MANAGER]: Starting {0} bots connecting to {1}, location {2}, named {3} {4}_<n>",
182 botcount, 284 botCount,
183 loginUri, 285 m_loginUri,
184 startUri, 286 m_startUri,
185 firstName, 287 m_firstName,
186 lastNameStem); 288 m_lastNameStem);
187 289
188 MainConsole.Instance.OutputFormat("[BOT MANAGER]: Delay between logins is {0}ms", LoginDelay); 290 MainConsole.Instance.OutputFormat("[BOT MANAGER]: Delay between logins is {0}ms", LoginDelay);
189 MainConsole.Instance.OutputFormat("[BOT MANAGER]: BotsSendAgentUpdates is {0}", InitBotSendAgentUpdates); 291 MainConsole.Instance.OutputFormat("[BOT MANAGER]: BotsSendAgentUpdates is {0}", InitBotSendAgentUpdates);
190 MainConsole.Instance.OutputFormat("[BOT MANAGER]: InitBotRequestObjectTextures is {0}", InitBotRequestObjectTextures); 292 MainConsole.Instance.OutputFormat("[BOT MANAGER]: InitBotRequestObjectTextures is {0}", InitBotRequestObjectTextures);
191 293
192 for (int i = 0; i < botcount; i++) 294 int connectedBots = 0;
193 {
194 if (ShuttingDown)
195 break;
196
197 string lastName = string.Format("{0}_{1}", lastNameStem, i + fromBotNumber);
198
199 // We must give each bot its own list of instantiated behaviours since they store state.
200 List<IBehaviour> behaviours = new List<IBehaviour>();
201
202 // Hard-coded for now
203 if (behaviourSwitches.Contains("c"))
204 behaviours.Add(new CrossBehaviour());
205 295
206 if (behaviourSwitches.Contains("g")) 296 for (int i = 0; i < m_bots.Count; i++)
207 behaviours.Add(new GrabbingBehaviour()); 297 {
298 lock (m_bots)
299 {
300 if (DisconnectingBots)
301 {
302 MainConsole.Instance.Output(
303 "[BOT MANAGER]: Aborting bot connection due to user-initiated disconnection");
304 break;
305 }
208 306
209 if (behaviourSwitches.Contains("n")) 307 if (m_bots[i].ConnectionState == ConnectionState.Disconnected)
210 behaviours.Add(new NoneBehaviour()); 308 {
309 m_bots[i].Connect();
310 connectedBots++;
211 311
212 if (behaviourSwitches.Contains("p")) 312 if (connectedBots >= botCount)
213 behaviours.Add(new PhysicsBehaviour()); 313 break;
214
215 if (behaviourSwitches.Contains("t"))
216 behaviours.Add(new TeleportBehaviour());
217 314
218 StartBot(this, behaviours, firstName, lastName, password, loginUri, startUri, wearSetting); 315 // Stagger logins
316 Thread.Sleep(LoginDelay);
317 }
318 }
219 } 319 }
320
321 ConnectingBots = false;
220 } 322 }
221 323
222 /// <summary> 324 /// <summary>
@@ -258,28 +360,8 @@ namespace pCampBot
258 return string.Format("uri:{0}&{1}&{2}&{3}", regionName, startPos.X, startPos.Y, startPos.Z); 360 return string.Format("uri:{0}&{1}&{2}&{3}", regionName, startPos.X, startPos.Y, startPos.Z);
259 } 361 }
260 362
261// /// <summary>
262// /// Add additional bots (and threads) to our bot pool
263// /// </summary>
264// /// <param name="botcount">How Many of them to add</param>
265// public void addbots(int botcount)
266// {
267// int len = m_td.Length;
268// Thread[] m_td2 = new Thread[len + botcount];
269// for (int i = 0; i < len; i++)
270// {
271// m_td2[i] = m_td[i];
272// }
273// m_td = m_td2;
274// int newlen = len + botcount;
275// for (int i = len; i < newlen; i++)
276// {
277// startupBot(Config);
278// }
279// }
280
281 /// <summary> 363 /// <summary>
282 /// This starts up the bot and stores the thread for the bot in the thread array 364 /// This creates a bot but does not start it.
283 /// </summary> 365 /// </summary>
284 /// <param name="bm"></param> 366 /// <param name="bm"></param>
285 /// <param name="behaviours">Behaviours for this bot to perform.</param> 367 /// <param name="behaviours">Behaviours for this bot to perform.</param>
@@ -289,12 +371,12 @@ namespace pCampBot
289 /// <param name="loginUri">Login URI</param> 371 /// <param name="loginUri">Login URI</param>
290 /// <param name="startLocation">Location to start the bot. Can be "last", "home" or a specific sim name.</param> 372 /// <param name="startLocation">Location to start the bot. Can be "last", "home" or a specific sim name.</param>
291 /// <param name="wearSetting"></param> 373 /// <param name="wearSetting"></param>
292 public void StartBot( 374 public void CreateBot(
293 BotManager bm, List<IBehaviour> behaviours, 375 BotManager bm, List<IBehaviour> behaviours,
294 string firstName, string lastName, string password, string loginUri, string startLocation, string wearSetting) 376 string firstName, string lastName, string password, string loginUri, string startLocation, string wearSetting)
295 { 377 {
296 MainConsole.Instance.OutputFormat( 378 MainConsole.Instance.OutputFormat(
297 "[BOT MANAGER]: Starting bot {0} {1}, behaviours are {2}", 379 "[BOT MANAGER]: Creating bot {0} {1}, behaviours are {2}",
298 firstName, lastName, string.Join(",", behaviours.ConvertAll<string>(b => b.Name).ToArray())); 380 firstName, lastName, string.Join(",", behaviours.ConvertAll<string>(b => b.Name).ToArray()));
299 381
300 Bot pb = new Bot(bm, behaviours, firstName, lastName, password, startLocation, loginUri); 382 Bot pb = new Bot(bm, behaviours, firstName, lastName, password, startLocation, loginUri);
@@ -305,17 +387,7 @@ namespace pCampBot
305 pb.OnConnected += handlebotEvent; 387 pb.OnConnected += handlebotEvent;
306 pb.OnDisconnected += handlebotEvent; 388 pb.OnDisconnected += handlebotEvent;
307 389
308 lock (m_lBot) 390 m_bots.Add(pb);
309 m_lBot.Add(pb);
310
311 Thread pbThread = new Thread(pb.startup);
312 pbThread.Name = pb.Name;
313 pbThread.IsBackground = true;
314
315 pbThread.Start();
316
317 // Stagger logins
318 Thread.Sleep(LoginDelay);
319 } 391 }
320 392
321 /// <summary> 393 /// <summary>
@@ -328,54 +400,158 @@ namespace pCampBot
328 switch (eventt) 400 switch (eventt)
329 { 401 {
330 case EventType.CONNECTED: 402 case EventType.CONNECTED:
403 {
331 m_log.Info("[" + callbot.FirstName + " " + callbot.LastName + "]: Connected"); 404 m_log.Info("[" + callbot.FirstName + " " + callbot.LastName + "]: Connected");
332 break; 405 break;
406 }
407
333 case EventType.DISCONNECTED: 408 case EventType.DISCONNECTED:
409 {
334 m_log.Info("[" + callbot.FirstName + " " + callbot.LastName + "]: Disconnected"); 410 m_log.Info("[" + callbot.FirstName + " " + callbot.LastName + "]: Disconnected");
335 411 break;
336 lock (m_lBot) 412 }
337 {
338 if (m_lBot.TrueForAll(b => b.ConnectionState == ConnectionState.Disconnected))
339 Environment.Exit(0);
340
341 break;
342 }
343 } 413 }
344 } 414 }
345 415
346 /// <summary> 416 /// <summary>
347 /// Shut down all bots 417 /// Standard CreateConsole routine
348 /// </summary> 418 /// </summary>
349 /// <remarks> 419 /// <returns></returns>
350 /// We launch each shutdown on its own thread so that a slow shutting down bot doesn't hold up all the others. 420 protected CommandConsole CreateConsole()
351 /// </remarks> 421 {
352 public void doBotShutdown() 422 return new LocalConsole("pCampbot");
423 }
424
425 private void HandleConnect(string module, string[] cmd)
426 {
427 if (ConnectingBots)
428 {
429 MainConsole.Instance.Output("Still connecting bots. Please wait for previous process to complete.");
430 return;
431 }
432
433 lock (m_bots)
434 {
435 int botsToConnect;
436 int disconnectedBots = m_bots.Count(b => b.ConnectionState == ConnectionState.Disconnected);
437
438 if (cmd.Length == 1)
439 {
440 botsToConnect = disconnectedBots;
441 }
442 else
443 {
444 if (!ConsoleUtil.TryParseConsoleNaturalInt(MainConsole.Instance, cmd[1], out botsToConnect))
445 return;
446
447 botsToConnect = Math.Min(botsToConnect, disconnectedBots);
448 }
449
450 MainConsole.Instance.OutputFormat("Connecting {0} bots", botsToConnect);
451
452 ConnectBots(botsToConnect);
453 }
454 }
455
456 private void HandleDisconnect(string module, string[] cmd)
353 { 457 {
354 lock (m_lBot) 458 lock (m_bots)
355 { 459 {
356 foreach (Bot bot in m_lBot) 460 int botsToDisconnect;
461 int connectedBots = m_bots.Count(b => b.ConnectionState == ConnectionState.Connected);
462
463 if (cmd.Length == 1)
464 {
465 botsToDisconnect = connectedBots;
466 }
467 else
468 {
469 if (!ConsoleUtil.TryParseConsoleNaturalInt(MainConsole.Instance, cmd[1], out botsToDisconnect))
470 return;
471
472 botsToDisconnect = Math.Min(botsToDisconnect, connectedBots);
473 }
474
475 DisconnectingBots = true;
476
477 MainConsole.Instance.OutputFormat("Disconnecting {0} bots", botsToDisconnect);
478
479 int disconnectedBots = 0;
480
481 for (int i = m_bots.Count - 1; i >= 0; i--)
357 { 482 {
358 Bot thisBot = bot; 483 if (disconnectedBots >= botsToDisconnect)
359 Util.FireAndForget(o => thisBot.shutdown()); 484 break;
485
486 Bot thisBot = m_bots[i];
487
488 if (thisBot.ConnectionState == ConnectionState.Connected)
489 {
490 Util.FireAndForget(o => thisBot.Disconnect());
491 disconnectedBots++;
492 }
360 } 493 }
494
495 DisconnectingBots = false;
361 } 496 }
362 } 497 }
363 498
364 /// <summary> 499 private void HandleSit(string module, string[] cmd)
365 /// Standard CreateConsole routine
366 /// </summary>
367 /// <returns></returns>
368 protected CommandConsole CreateConsole()
369 { 500 {
370 return new LocalConsole("pCampbot"); 501 lock (m_bots)
502 {
503 m_bots.ForEach(b => b.SitOnGround());
504 }
505 }
506
507 private void HandleStand(string module, string[] cmd)
508 {
509 lock (m_bots)
510 {
511 m_bots.ForEach(b => b.Stand());
512 }
371 } 513 }
372 514
373 private void HandleShutdown(string module, string[] cmd) 515 private void HandleShutdown(string module, string[] cmd)
374 { 516 {
517 lock (m_bots)
518 {
519 int connectedBots = m_bots.Count(b => b.ConnectionState == ConnectionState.Connected);
520
521 if (connectedBots > 0)
522 {
523 MainConsole.Instance.OutputFormat("Please disconnect {0} connected bots first", connectedBots);
524 return;
525 }
526 }
527
375 MainConsole.Instance.Output("Shutting down"); 528 MainConsole.Instance.Output("Shutting down");
376 529
377 ShuttingDown = true; 530 Environment.Exit(0);
378 doBotShutdown(); 531 }
532
533 private void HandleSetBots(string module, string[] cmd)
534 {
535 string key = cmd[2];
536 string rawValue = cmd[3];
537
538 if (key == "SEND_AGENT_UPDATES")
539 {
540 bool newSendAgentUpdatesSetting;
541
542 if (!ConsoleUtil.TryParseConsoleBool(MainConsole.Instance, rawValue, out newSendAgentUpdatesSetting))
543 return;
544
545 MainConsole.Instance.OutputFormat(
546 "Setting SEND_AGENT_UPDATES to {0} for all bots", newSendAgentUpdatesSetting);
547
548 lock (m_bots)
549 m_bots.ForEach(b => b.Client.Settings.SEND_AGENT_UPDATES = newSendAgentUpdatesSetting);
550 }
551 else
552 {
553 MainConsole.Instance.Output("Error: Only setting currently available is SEND_AGENT_UPDATES");
554 }
379 } 555 }
380 556
381 private void HandleShowRegions(string module, string[] cmd) 557 private void HandleShowRegions(string module, string[] cmd)
@@ -393,56 +569,87 @@ namespace pCampBot
393 } 569 }
394 } 570 }
395 571
396 private void HandleShowStatus(string module, string[] cmd) 572 private void HandleShowBotsStatus(string module, string[] cmd)
397 { 573 {
398 string outputFormat = "{0,-30} {1, -30} {2,-14}"; 574 ConsoleDisplayTable cdt = new ConsoleDisplayTable();
399 MainConsole.Instance.OutputFormat(outputFormat, "Name", "Region", "Status"); 575 cdt.AddColumn("Name", 30);
576 cdt.AddColumn("Region", 30);
577 cdt.AddColumn("Status", 14);
578 cdt.AddColumn("Connections", 11);
400 579
401 Dictionary<ConnectionState, int> totals = new Dictionary<ConnectionState, int>(); 580 Dictionary<ConnectionState, int> totals = new Dictionary<ConnectionState, int>();
402 foreach (object o in Enum.GetValues(typeof(ConnectionState))) 581 foreach (object o in Enum.GetValues(typeof(ConnectionState)))
403 totals[(ConnectionState)o] = 0; 582 totals[(ConnectionState)o] = 0;
404 583
405 lock (m_lBot) 584 lock (m_bots)
406 { 585 {
407 foreach (Bot pb in m_lBot) 586 foreach (Bot pb in m_bots)
408 { 587 {
409 Simulator currentSim = pb.Client.Network.CurrentSim; 588 Simulator currentSim = pb.Client.Network.CurrentSim;
410 totals[pb.ConnectionState]++; 589 totals[pb.ConnectionState]++;
411 590
412 MainConsole.Instance.OutputFormat( 591 cdt.AddRow(
413 outputFormat, 592 pb.Name, currentSim != null ? currentSim.Name : "(none)", pb.ConnectionState, pb.SimulatorsCount);
414 pb.Name, currentSim != null ? currentSim.Name : "(none)", pb.ConnectionState);
415 } 593 }
416 } 594 }
417 595
596 MainConsole.Instance.Output(cdt.ToString());
597
418 ConsoleDisplayList cdl = new ConsoleDisplayList(); 598 ConsoleDisplayList cdl = new ConsoleDisplayList();
419 599
420 foreach (KeyValuePair<ConnectionState, int> kvp in totals) 600 foreach (KeyValuePair<ConnectionState, int> kvp in totals)
421 cdl.AddRow(kvp.Key, kvp.Value); 601 cdl.AddRow(kvp.Key, kvp.Value);
422 602
423 603 MainConsole.Instance.Output(cdl.ToString());
424 MainConsole.Instance.OutputFormat("\n{0}", cdl.ToString());
425 } 604 }
426 605
427 /* 606 private void HandleShowBotStatus(string module, string[] cmd)
428 private void HandleQuit(string module, string[] cmd)
429 { 607 {
430 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"); 608 if (cmd.Length != 3)
431 Environment.Exit(0); 609 {
610 MainConsole.Instance.Output("Usage: show bot <n>");
611 return;
612 }
613
614 int botNumber;
615
616 if (!ConsoleUtil.TryParseConsoleInt(MainConsole.Instance, cmd[2], out botNumber))
617 return;
618
619 string name = string.Format("{0} {1}_{2}", m_firstName, m_lastNameStem, botNumber);
620
621 Bot bot;
622
623 lock (m_bots)
624 bot = m_bots.Find(b => b.Name == name);
625
626 if (bot == null)
627 {
628 MainConsole.Instance.Output("No bot found with name {0}", name);
629 return;
630 }
631
632 ConsoleDisplayList cdl = new ConsoleDisplayList();
633 cdl.AddRow("Name", bot.Name);
634 cdl.AddRow("Status", bot.ConnectionState);
635
636 Simulator currentSim = bot.Client.Network.CurrentSim;
637 cdl.AddRow("Region", currentSim != null ? currentSim.Name : "(none)");
638
639 List<Simulator> connectedSimulators = bot.Simulators;
640 List<string> simulatorNames = connectedSimulators.ConvertAll<string>(cs => cs.Name);
641 cdl.AddRow("Connections", string.Join(", ", simulatorNames.ToArray()));
642
643 MainConsole.Instance.Output(cdl.ToString());
644
645 MainConsole.Instance.Output("Settings");
646
647 ConsoleDisplayList statusCdl = new ConsoleDisplayList();
648 GridClient botClient = bot.Client;
649 statusCdl.AddRow("SEND_AGENT_UPDATES", botClient.Settings.SEND_AGENT_UPDATES);
650
651 MainConsole.Instance.Output(statusCdl.ToString());
432 } 652 }
433 */
434//
435// private void HandleAddBots(string module, string[] cmd)
436// {
437// int newbots = 0;
438//
439// if (cmd.Length > 2)
440// {
441// Int32.TryParse(cmd[2], out newbots);
442// }
443// if (newbots > 0)
444// addbots(newbots);
445// }
446 653
447 internal void Grid_GridRegion(object o, GridRegionEventArgs args) 654 internal void Grid_GridRegion(object o, GridRegionEventArgs args)
448 { 655 {
@@ -463,4 +670,4 @@ namespace pCampBot
463 } 670 }
464 } 671 }
465 } 672 }
466} 673} \ No newline at end of file
diff --git a/OpenSim/Tools/pCampBot/pCampBot.cs b/OpenSim/Tools/pCampBot/pCampBot.cs
index b02f917..781bb00 100644
--- a/OpenSim/Tools/pCampBot/pCampBot.cs
+++ b/OpenSim/Tools/pCampBot/pCampBot.cs
@@ -51,7 +51,7 @@ namespace pCampBot
51 { 51 {
52 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 52 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
53 53
54 public const string ConfigFileName = "pCampbot.ini"; 54 public const string ConfigFileName = "pCampBot.ini";
55 55
56 [STAThread] 56 [STAThread]
57 public static void Main(string[] args) 57 public static void Main(string[] args)
@@ -82,6 +82,13 @@ namespace pCampBot
82 82
83 IConfigSource configSource = new IniConfigSource(iniFilePath); 83 IConfigSource configSource = new IniConfigSource(iniFilePath);
84 84
85 IConfig botManagerConfig = configSource.Configs["BotManager"];
86
87 if (botManagerConfig != null)
88 {
89 bm.LoginDelay = botManagerConfig.GetInt("LoginDelay", bm.LoginDelay);
90 }
91
85 IConfig botConfig = configSource.Configs["Bot"]; 92 IConfig botConfig = configSource.Configs["Bot"];
86 93
87 if (botConfig != null) 94 if (botConfig != null)
@@ -94,11 +101,12 @@ namespace pCampBot
94 } 101 }
95 102
96 int botcount = commandLineConfig.GetInt("botcount", 1); 103 int botcount = commandLineConfig.GetInt("botcount", 1);
104 bool startConnected = commandLineConfig.Get("connect") != null;
105
106 bm.CreateBots(botcount, commandLineConfig);
97 107
98 //startup specified number of bots. 1 is the default 108 if (startConnected)
99 Thread startBotThread = new Thread(o => bm.dobotStartup(botcount, commandLineConfig)); 109 bm.ConnectBots(botcount);
100 startBotThread.Name = "Initial start bots thread";
101 startBotThread.Start();
102 110
103 while (true) 111 while (true)
104 { 112 {
@@ -119,6 +127,7 @@ namespace pCampBot
119 //Set up our nifty config.. thanks to nini 127 //Set up our nifty config.. thanks to nini
120 ArgvConfigSource cs = new ArgvConfigSource(args); 128 ArgvConfigSource cs = new ArgvConfigSource(args);
121 129
130 cs.AddSwitch("Startup", "connect", "c");
122 cs.AddSwitch("Startup", "botcount", "n"); 131 cs.AddSwitch("Startup", "botcount", "n");
123 cs.AddSwitch("Startup", "from", "f"); 132 cs.AddSwitch("Startup", "from", "f");
124 cs.AddSwitch("Startup", "loginuri", "l"); 133 cs.AddSwitch("Startup", "loginuri", "l");
@@ -145,20 +154,21 @@ namespace pCampBot
145 "usage: pCampBot <-loginuri loginuri> [OPTIONS]\n" 154 "usage: pCampBot <-loginuri loginuri> [OPTIONS]\n"
146 + "Spawns a set of bots to test an OpenSim region\n\n" 155 + "Spawns a set of bots to test an OpenSim region\n\n"
147 + " -l, -loginuri loginuri for grid/standalone (required)\n" 156 + " -l, -loginuri loginuri for grid/standalone (required)\n"
148 + " -s, -start optional start location for bots. Can be \"last\", \"home\" or a specific location with or without co-ords (e.g. \"region1\" or \"region2/50/30/90\"\n" 157 + " -s, -start start location for bots (optional). Can be \"last\", \"home\" or a specific location with or without co-ords (e.g. \"region1\" or \"region2/50/30/90\"\n"
149 + " -firstname first name for the bots\n" 158 + " -firstname first name for the bots (required)\n"
150 + " -lastname lastname for the bots. Each lastname will have _<bot-number> appended, e.g. Ima Bot_0\n" 159 + " -lastname lastname for the bots (required). Each lastname will have _<bot-number> appended, e.g. Ima Bot_0\n"
151 + " -password password for the bots\n" 160 + " -password password for the bots (required)\n"
152 + " -n, -botcount optional number of bots to start (default: 1)\n" 161 + " -n, -botcount number of bots to start (default: 1) (optional)\n"
153 + " -f, -from optional starting number for login bot names, e.g. 25 will login Ima Bot_25, Ima Bot_26, etc. (default: 0)" 162 + " -f, -from starting number for login bot names, e.g. 25 will login Ima Bot_25, Ima Bot_26, etc. (default: 0) (optional)\n"
154 + " -b, behaviours behaviours for bots. Comma separated, e.g. p,g. Default is p\n" 163 + " -c, -connect connect all bots at startup (optional)\n"
164 + " -b, behaviours behaviours for bots. Comma separated, e.g. p,g. Default is p (required)\n"
155 + " current options are:\n" 165 + " current options are:\n"
156 + " p (physics - bots constantly move and jump around)\n" 166 + " p (physics - bots constantly move and jump around)\n"
157 + " g (grab - bots randomly click prims whether set clickable or not)\n" 167 + " g (grab - bots randomly click prims whether set clickable or not)\n"
158 + " n (none - bots do nothing)\n" 168 + " n (none - bots do nothing)\n"
159 + " t (teleport - bots regularly teleport between regions on the grid)\n" 169 + " t (teleport - bots regularly teleport between regions on the grid)\n"
160// " c (cross)" + 170// " c (cross)\n" +
161 + " -wear optional folder from which to load appearance data, \"no\" if there is no such folder (default: no)\n" 171 + " -wear folder from which to load appearance data, \"no\" if there is no such folder (default: no) (optional)\n"
162 + " -h, -help show this message.\n"); 172 + " -h, -help show this message.\n");
163 } 173 }
164 } 174 }