diff options
Diffstat (limited to 'OpenSim/Tools/pCampBot')
-rw-r--r-- | OpenSim/Tools/pCampBot/Bot.cs | 142 | ||||
-rw-r--r-- | OpenSim/Tools/pCampBot/BotManager.cs | 503 | ||||
-rw-r--r-- | OpenSim/Tools/pCampBot/pCampBot.cs | 38 |
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 | } |