clockwerk-opensim-stable – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | vero | 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 | |||
28 | using System; |
||
29 | using System.Collections; |
||
30 | using System.Collections.Generic; |
||
31 | using System.Diagnostics; |
||
32 | using System.IO; |
||
33 | using System.Linq; |
||
34 | using System.Reflection; |
||
35 | using System.Text; |
||
36 | using System.Text.RegularExpressions; |
||
37 | using System.Timers; |
||
38 | using log4net; |
||
39 | using NDesk.Options; |
||
40 | using Nini.Config; |
||
41 | using OpenMetaverse; |
||
42 | using OpenSim.Framework; |
||
43 | using OpenSim.Framework.Console; |
||
44 | using OpenSim.Framework.Servers; |
||
45 | using OpenSim.Framework.Monitoring; |
||
46 | using OpenSim.Region.Framework.Interfaces; |
||
47 | using OpenSim.Region.Framework.Scenes; |
||
48 | |||
49 | namespace OpenSim |
||
50 | { |
||
51 | /// <summary> |
||
52 | /// Interactive OpenSim region server |
||
53 | /// </summary> |
||
54 | public class OpenSim : OpenSimBase |
||
55 | { |
||
56 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
||
57 | |||
58 | protected string m_startupCommandsFile; |
||
59 | protected string m_shutdownCommandsFile; |
||
60 | protected bool m_gui = false; |
||
61 | protected string m_consoleType = "local"; |
||
62 | protected uint m_consolePort = 0; |
||
63 | |||
64 | /// <summary> |
||
65 | /// Prompt to use for simulator command line. |
||
66 | /// </summary> |
||
67 | private string m_consolePrompt; |
||
68 | |||
69 | /// <summary> |
||
70 | /// Regex for parsing out special characters in the prompt. |
||
71 | /// </summary> |
||
72 | private Regex m_consolePromptRegex = new Regex(@"([^\\])\\(\w)", RegexOptions.Compiled); |
||
73 | |||
74 | private string m_timedScript = "disabled"; |
||
75 | private int m_timeInterval = 1200; |
||
76 | private Timer m_scriptTimer; |
||
77 | |||
78 | public OpenSim(IConfigSource configSource) : base(configSource) |
||
79 | { |
||
80 | } |
||
81 | |||
82 | protected override void ReadExtraConfigSettings() |
||
83 | { |
||
84 | base.ReadExtraConfigSettings(); |
||
85 | |||
86 | IConfig startupConfig = Config.Configs["Startup"]; |
||
87 | IConfig networkConfig = Config.Configs["Network"]; |
||
88 | |||
89 | int stpMinThreads = 2; |
||
90 | int stpMaxThreads = 15; |
||
91 | |||
92 | if (startupConfig != null) |
||
93 | { |
||
94 | m_startupCommandsFile = startupConfig.GetString("startup_console_commands_file", "startup_commands.txt"); |
||
95 | m_shutdownCommandsFile = startupConfig.GetString("shutdown_console_commands_file", "shutdown_commands.txt"); |
||
96 | |||
97 | if (startupConfig.GetString("console", String.Empty) == String.Empty) |
||
98 | m_gui = startupConfig.GetBoolean("gui", false); |
||
99 | else |
||
100 | m_consoleType= startupConfig.GetString("console", String.Empty); |
||
101 | |||
102 | if (networkConfig != null) |
||
103 | m_consolePort = (uint)networkConfig.GetInt("console_port", 0); |
||
104 | |||
105 | m_timedScript = startupConfig.GetString("timer_Script", "disabled"); |
||
106 | if (m_timedScript != "disabled") |
||
107 | { |
||
108 | m_timeInterval = startupConfig.GetInt("timer_Interval", 1200); |
||
109 | } |
||
110 | |||
111 | string asyncCallMethodStr = startupConfig.GetString("async_call_method", String.Empty); |
||
112 | FireAndForgetMethod asyncCallMethod; |
||
113 | if (!String.IsNullOrEmpty(asyncCallMethodStr) && Utils.EnumTryParse<FireAndForgetMethod>(asyncCallMethodStr, out asyncCallMethod)) |
||
114 | Util.FireAndForgetMethod = asyncCallMethod; |
||
115 | |||
116 | stpMinThreads = startupConfig.GetInt("MinPoolThreads", 15); |
||
117 | stpMaxThreads = startupConfig.GetInt("MaxPoolThreads", 15); |
||
118 | m_consolePrompt = startupConfig.GetString("ConsolePrompt", @"Region (\R) "); |
||
119 | } |
||
120 | |||
121 | if (Util.FireAndForgetMethod == FireAndForgetMethod.SmartThreadPool) |
||
122 | Util.InitThreadPool(stpMinThreads, stpMaxThreads); |
||
123 | |||
124 | m_log.Info("[OPENSIM MAIN]: Using async_call_method " + Util.FireAndForgetMethod); |
||
125 | } |
||
126 | |||
127 | /// <summary> |
||
128 | /// Performs initialisation of the scene, such as loading configuration from disk. |
||
129 | /// </summary> |
||
130 | protected override void StartupSpecific() |
||
131 | { |
||
132 | m_log.Info("===================================================================="); |
||
133 | m_log.Info("========================= STARTING OPENSIM ========================="); |
||
134 | m_log.Info("===================================================================="); |
||
135 | |||
136 | //m_log.InfoFormat("[OPENSIM MAIN]: GC Is Server GC: {0}", GCSettings.IsServerGC.ToString()); |
||
137 | // http://msdn.microsoft.com/en-us/library/bb384202.aspx |
||
138 | //GCSettings.LatencyMode = GCLatencyMode.Batch; |
||
139 | //m_log.InfoFormat("[OPENSIM MAIN]: GC Latency Mode: {0}", GCSettings.LatencyMode.ToString()); |
||
140 | |||
141 | if (m_gui) // Driven by external GUI |
||
142 | { |
||
143 | m_console = new CommandConsole("Region"); |
||
144 | } |
||
145 | else |
||
146 | { |
||
147 | switch (m_consoleType) |
||
148 | { |
||
149 | case "basic": |
||
150 | m_console = new CommandConsole("Region"); |
||
151 | break; |
||
152 | case "rest": |
||
153 | m_console = new RemoteConsole("Region"); |
||
154 | ((RemoteConsole)m_console).ReadConfig(Config); |
||
155 | break; |
||
156 | default: |
||
157 | m_console = new LocalConsole("Region"); |
||
158 | break; |
||
159 | } |
||
160 | } |
||
161 | |||
162 | MainConsole.Instance = m_console; |
||
163 | |||
164 | LogEnvironmentInformation(); |
||
165 | RegisterCommonAppenders(Config.Configs["Startup"]); |
||
166 | RegisterConsoleCommands(); |
||
167 | |||
168 | base.StartupSpecific(); |
||
169 | |||
170 | MainServer.Instance.AddStreamHandler(new OpenSim.SimStatusHandler()); |
||
171 | MainServer.Instance.AddStreamHandler(new OpenSim.XSimStatusHandler(this)); |
||
172 | if (userStatsURI != String.Empty) |
||
173 | MainServer.Instance.AddStreamHandler(new OpenSim.UXSimStatusHandler(this)); |
||
174 | |||
175 | if (managedStatsURI != String.Empty) |
||
176 | { |
||
177 | string urlBase = String.Format("/{0}/", managedStatsURI); |
||
178 | MainServer.Instance.AddHTTPHandler(urlBase, StatsManager.HandleStatsRequest); |
||
179 | m_log.InfoFormat("[OPENSIM] Enabling remote managed stats fetch. URL = {0}", urlBase); |
||
180 | } |
||
181 | |||
182 | if (m_console is RemoteConsole) |
||
183 | { |
||
184 | if (m_consolePort == 0) |
||
185 | { |
||
186 | ((RemoteConsole)m_console).SetServer(m_httpServer); |
||
187 | } |
||
188 | else |
||
189 | { |
||
190 | ((RemoteConsole)m_console).SetServer(MainServer.GetHttpServer(m_consolePort)); |
||
191 | } |
||
192 | } |
||
193 | |||
194 | // Hook up to the watchdog timer |
||
195 | Watchdog.OnWatchdogTimeout += WatchdogTimeoutHandler; |
||
196 | |||
197 | PrintFileToConsole("startuplogo.txt"); |
||
198 | |||
199 | // For now, start at the 'root' level by default |
||
200 | if (SceneManager.Scenes.Count == 1) // If there is only one region, select it |
||
201 | ChangeSelectedRegion("region", |
||
202 | new string[] {"change", "region", SceneManager.Scenes[0].RegionInfo.RegionName}); |
||
203 | else |
||
204 | ChangeSelectedRegion("region", new string[] {"change", "region", "root"}); |
||
205 | |||
206 | //Run Startup Commands |
||
207 | if (String.IsNullOrEmpty(m_startupCommandsFile)) |
||
208 | { |
||
209 | m_log.Info("[STARTUP]: No startup command script specified. Moving on..."); |
||
210 | } |
||
211 | else |
||
212 | { |
||
213 | RunCommandScript(m_startupCommandsFile); |
||
214 | } |
||
215 | |||
216 | // Start timer script (run a script every xx seconds) |
||
217 | if (m_timedScript != "disabled") |
||
218 | { |
||
219 | m_scriptTimer = new Timer(); |
||
220 | m_scriptTimer.Enabled = true; |
||
221 | m_scriptTimer.Interval = m_timeInterval*1000; |
||
222 | m_scriptTimer.Elapsed += RunAutoTimerScript; |
||
223 | } |
||
224 | } |
||
225 | |||
226 | /// <summary> |
||
227 | /// Register standard set of region console commands |
||
228 | /// </summary> |
||
229 | private void RegisterConsoleCommands() |
||
230 | { |
||
231 | MainServer.RegisterHttpConsoleCommands(m_console); |
||
232 | |||
233 | m_console.Commands.AddCommand("Objects", false, "force update", |
||
234 | "force update", |
||
235 | "Force the update of all objects on clients", |
||
236 | HandleForceUpdate); |
||
237 | |||
238 | m_console.Commands.AddCommand("General", false, "change region", |
||
239 | "change region <region name>", |
||
240 | "Change current console region", |
||
241 | ChangeSelectedRegion); |
||
242 | |||
243 | m_console.Commands.AddCommand("Archiving", false, "save xml", |
||
244 | "save xml", |
||
245 | "Save a region's data in XML format", |
||
246 | SaveXml); |
||
247 | |||
248 | m_console.Commands.AddCommand("Archiving", false, "save xml2", |
||
249 | "save xml2", |
||
250 | "Save a region's data in XML2 format", |
||
251 | SaveXml2); |
||
252 | |||
253 | m_console.Commands.AddCommand("Archiving", false, "load xml", |
||
254 | "load xml [-newIDs [<x> <y> <z>]]", |
||
255 | "Load a region's data from XML format", |
||
256 | LoadXml); |
||
257 | |||
258 | m_console.Commands.AddCommand("Archiving", false, "load xml2", |
||
259 | "load xml2", |
||
260 | "Load a region's data from XML2 format", |
||
261 | LoadXml2); |
||
262 | |||
263 | m_console.Commands.AddCommand("Archiving", false, "save prims xml2", |
||
264 | "save prims xml2 [<prim name> <file name>]", |
||
265 | "Save named prim to XML2", |
||
266 | SavePrimsXml2); |
||
267 | |||
268 | m_console.Commands.AddCommand("Archiving", false, "load oar", |
||
269 | "load oar [--merge] [--skip-assets] [<OAR path>]", |
||
270 | "Load a region's data from an OAR archive.", |
||
271 | "--merge will merge the OAR with the existing scene." + Environment.NewLine |
||
272 | + "--skip-assets will load the OAR but ignore the assets it contains." + Environment.NewLine |
||
273 | + "The path can be either a filesystem location or a URI." |
||
274 | + " If this is not given then the command looks for an OAR named region.oar in the current directory.", |
||
275 | LoadOar); |
||
276 | |||
277 | m_console.Commands.AddCommand("Archiving", false, "save oar", |
||
278 | //"save oar [-v|--version=<N>] [-p|--profile=<url>] [<OAR path>]", |
||
279 | "save oar [-h|--home=<url>] [--noassets] [--publish] [--perm=<permissions>] [--all] [<OAR path>]", |
||
280 | "Save a region's data to an OAR archive.", |
||
281 | // "-v|--version=<N> generates scene objects as per older versions of the serialization (e.g. -v=0)" + Environment.NewLine |
||
282 | "-h|--home=<url> adds the url of the profile service to the saved user information.\n" |
||
283 | + "--noassets stops assets being saved to the OAR.\n" |
||
284 | + "--publish saves an OAR stripped of owner and last owner information.\n" |
||
285 | + " on reload, the estate owner will be the owner of all objects\n" |
||
286 | + " this is useful if you're making oars generally available that might be reloaded to the same grid from which you published\n" |
||
287 | + "--perm=<permissions> stops objects with insufficient permissions from being saved to the OAR.\n" |
||
288 | + " <permissions> can contain one or more of these characters: \"C\" = Copy, \"T\" = Transfer\n" |
||
289 | + "--all saves all the regions in the simulator, instead of just the current region.\n" |
||
290 | + "The OAR path must be a filesystem path." |
||
291 | + " If this is not given then the oar is saved to region.oar in the current directory.", |
||
292 | SaveOar); |
||
293 | |||
294 | m_console.Commands.AddCommand("Objects", false, "edit scale", |
||
295 | "edit scale <name> <x> <y> <z>", |
||
296 | "Change the scale of a named prim", |
||
297 | HandleEditScale); |
||
298 | |||
299 | m_console.Commands.AddCommand("Users", false, "kick user", |
||
300 | "kick user <first> <last> [--force] [message]", |
||
301 | "Kick a user off the simulator", |
||
302 | "The --force option will kick the user without any checks to see whether it's already in the process of closing\n" |
||
303 | + "Only use this option if you are sure the avatar is inactive and a normal kick user operation does not removed them", |
||
304 | KickUserCommand); |
||
305 | |||
306 | m_console.Commands.AddCommand("Users", false, "show users", |
||
307 | "show users [full]", |
||
308 | "Show user data for users currently on the region", |
||
309 | "Without the 'full' option, only users actually on the region are shown." |
||
310 | + " With the 'full' option child agents of users in neighbouring regions are also shown.", |
||
311 | HandleShow); |
||
312 | |||
313 | m_console.Commands.AddCommand("Comms", false, "show connections", |
||
314 | "show connections", |
||
315 | "Show connection data", |
||
316 | HandleShow); |
||
317 | |||
318 | m_console.Commands.AddCommand("Comms", false, "show circuits", |
||
319 | "show circuits", |
||
320 | "Show agent circuit data", |
||
321 | HandleShow); |
||
322 | |||
323 | m_console.Commands.AddCommand("Comms", false, "show pending-objects", |
||
324 | "show pending-objects", |
||
325 | "Show # of objects on the pending queues of all scene viewers", |
||
326 | HandleShow); |
||
327 | |||
328 | m_console.Commands.AddCommand("General", false, "show modules", |
||
329 | "show modules", |
||
330 | "Show module data", |
||
331 | HandleShow); |
||
332 | |||
333 | m_console.Commands.AddCommand("Regions", false, "show regions", |
||
334 | "show regions", |
||
335 | "Show region data", |
||
336 | HandleShow); |
||
337 | |||
338 | m_console.Commands.AddCommand("Regions", false, "show ratings", |
||
339 | "show ratings", |
||
340 | "Show rating data", |
||
341 | HandleShow); |
||
342 | |||
343 | m_console.Commands.AddCommand("Objects", false, "backup", |
||
344 | "backup", |
||
345 | "Persist currently unsaved object changes immediately instead of waiting for the normal persistence call.", |
||
346 | RunCommand); |
||
347 | |||
348 | m_console.Commands.AddCommand("Regions", false, "create region", |
||
349 | "create region [\"region name\"] <region_file.ini>", |
||
350 | "Create a new region.", |
||
351 | "The settings for \"region name\" are read from <region_file.ini>. Paths specified with <region_file.ini> are relative to your Regions directory, unless an absolute path is given." |
||
352 | + " If \"region name\" does not exist in <region_file.ini>, it will be added." + Environment.NewLine |
||
353 | + "Without \"region name\", the first region found in <region_file.ini> will be created." + Environment.NewLine |
||
354 | + "If <region_file.ini> does not exist, it will be created.", |
||
355 | HandleCreateRegion); |
||
356 | |||
357 | m_console.Commands.AddCommand("Regions", false, "restart", |
||
358 | "restart", |
||
359 | "Restart all sims in this instance", |
||
360 | RunCommand); |
||
361 | |||
362 | m_console.Commands.AddCommand("General", false, "command-script", |
||
363 | "command-script <script>", |
||
364 | "Run a command script from file", |
||
365 | RunCommand); |
||
366 | |||
367 | m_console.Commands.AddCommand("Regions", false, "remove-region", |
||
368 | "remove-region <name>", |
||
369 | "Remove a region from this simulator", |
||
370 | RunCommand); |
||
371 | |||
372 | m_console.Commands.AddCommand("Regions", false, "delete-region", |
||
373 | "delete-region <name>", |
||
374 | "Delete a region from disk", |
||
375 | RunCommand); |
||
376 | } |
||
377 | |||
378 | protected override void ShutdownSpecific() |
||
379 | { |
||
380 | if (m_shutdownCommandsFile != String.Empty) |
||
381 | { |
||
382 | RunCommandScript(m_shutdownCommandsFile); |
||
383 | } |
||
384 | |||
385 | base.ShutdownSpecific(); |
||
386 | } |
||
387 | |||
388 | /// <summary> |
||
389 | /// Timer to run a specific text file as console commands. Configured in in the main ini file |
||
390 | /// </summary> |
||
391 | /// <param name="sender"></param> |
||
392 | /// <param name="e"></param> |
||
393 | private void RunAutoTimerScript(object sender, EventArgs e) |
||
394 | { |
||
395 | if (m_timedScript != "disabled") |
||
396 | { |
||
397 | RunCommandScript(m_timedScript); |
||
398 | } |
||
399 | } |
||
400 | |||
401 | private void WatchdogTimeoutHandler(Watchdog.ThreadWatchdogInfo twi) |
||
402 | { |
||
403 | int now = Environment.TickCount & Int32.MaxValue; |
||
404 | |||
405 | m_log.ErrorFormat( |
||
406 | "[WATCHDOG]: Timeout detected for thread \"{0}\". ThreadState={1}. Last tick was {2}ms ago. {3}", |
||
407 | twi.Thread.Name, |
||
408 | twi.Thread.ThreadState, |
||
409 | now - twi.LastTick, |
||
410 | twi.AlarmMethod != null ? string.Format("Data: {0}", twi.AlarmMethod()) : ""); |
||
411 | } |
||
412 | |||
413 | #region Console Commands |
||
414 | |||
415 | /// <summary> |
||
416 | /// Kicks users off the region |
||
417 | /// </summary> |
||
418 | /// <param name="module"></param> |
||
419 | /// <param name="cmdparams">name of avatar to kick</param> |
||
420 | private void KickUserCommand(string module, string[] cmdparams) |
||
421 | { |
||
422 | bool force = false; |
||
423 | |||
424 | OptionSet options = new OptionSet().Add("f|force", delegate (string v) { force = v != null; }); |
||
425 | |||
426 | List<string> mainParams = options.Parse(cmdparams); |
||
427 | |||
428 | if (mainParams.Count < 4) |
||
429 | return; |
||
430 | |||
431 | string alert = null; |
||
432 | if (mainParams.Count > 4) |
||
433 | alert = String.Format("\n{0}\n", String.Join(" ", cmdparams, 4, cmdparams.Length - 4)); |
||
434 | |||
435 | IList agents = SceneManager.GetCurrentSceneAvatars(); |
||
436 | |||
437 | foreach (ScenePresence presence in agents) |
||
438 | { |
||
439 | RegionInfo regionInfo = presence.Scene.RegionInfo; |
||
440 | |||
441 | if (presence.Firstname.ToLower().Equals(mainParams[2].ToLower()) && |
||
442 | presence.Lastname.ToLower().Equals(mainParams[3].ToLower())) |
||
443 | { |
||
444 | MainConsole.Instance.Output( |
||
445 | String.Format( |
||
446 | "Kicking user: {0,-16} {1,-16} {2,-37} in region: {3,-16}", |
||
447 | presence.Firstname, presence.Lastname, presence.UUID, regionInfo.RegionName)); |
||
448 | |||
449 | // kick client... |
||
450 | if (alert != null) |
||
451 | presence.ControllingClient.Kick(alert); |
||
452 | else |
||
453 | presence.ControllingClient.Kick("\nThe OpenSim manager kicked you out.\n"); |
||
454 | |||
455 | presence.Scene.CloseAgent(presence.UUID, force); |
||
456 | break; |
||
457 | } |
||
458 | } |
||
459 | |||
460 | MainConsole.Instance.Output(""); |
||
461 | } |
||
462 | |||
463 | /// <summary> |
||
464 | /// Opens a file and uses it as input to the console command parser. |
||
465 | /// </summary> |
||
466 | /// <param name="fileName">name of file to use as input to the console</param> |
||
467 | private static void PrintFileToConsole(string fileName) |
||
468 | { |
||
469 | if (File.Exists(fileName)) |
||
470 | { |
||
471 | StreamReader readFile = File.OpenText(fileName); |
||
472 | string currentLine; |
||
473 | while ((currentLine = readFile.ReadLine()) != null) |
||
474 | { |
||
475 | m_log.Info("[!]" + currentLine); |
||
476 | } |
||
477 | } |
||
478 | } |
||
479 | |||
480 | /// <summary> |
||
481 | /// Force resending of all updates to all clients in active region(s) |
||
482 | /// </summary> |
||
483 | /// <param name="module"></param> |
||
484 | /// <param name="args"></param> |
||
485 | private void HandleForceUpdate(string module, string[] args) |
||
486 | { |
||
487 | MainConsole.Instance.Output("Updating all clients"); |
||
488 | SceneManager.ForceCurrentSceneClientUpdate(); |
||
489 | } |
||
490 | |||
491 | /// <summary> |
||
492 | /// Edits the scale of a primative with the name specified |
||
493 | /// </summary> |
||
494 | /// <param name="module"></param> |
||
495 | /// <param name="args">0,1, name, x, y, z</param> |
||
496 | private void HandleEditScale(string module, string[] args) |
||
497 | { |
||
498 | if (args.Length == 6) |
||
499 | { |
||
500 | SceneManager.HandleEditCommandOnCurrentScene(args); |
||
501 | } |
||
502 | else |
||
503 | { |
||
504 | MainConsole.Instance.Output("Argument error: edit scale <prim name> <x> <y> <z>"); |
||
505 | } |
||
506 | } |
||
507 | |||
508 | /// <summary> |
||
509 | /// Creates a new region based on the parameters specified. This will ask the user questions on the console |
||
510 | /// </summary> |
||
511 | /// <param name="module"></param> |
||
512 | /// <param name="cmd">0,1,region name, region ini or XML file</param> |
||
513 | private void HandleCreateRegion(string module, string[] cmd) |
||
514 | { |
||
515 | string regionName = string.Empty; |
||
516 | string regionFile = string.Empty; |
||
517 | |||
518 | if (cmd.Length == 3) |
||
519 | { |
||
520 | regionFile = cmd[2]; |
||
521 | } |
||
522 | else if (cmd.Length > 3) |
||
523 | { |
||
524 | regionName = cmd[2]; |
||
525 | regionFile = cmd[3]; |
||
526 | } |
||
527 | |||
528 | string extension = Path.GetExtension(regionFile).ToLower(); |
||
529 | bool isXml = extension.Equals(".xml"); |
||
530 | bool isIni = extension.Equals(".ini"); |
||
531 | |||
532 | if (!isXml && !isIni) |
||
533 | { |
||
534 | MainConsole.Instance.Output("Usage: create region [\"region name\"] <region_file.ini>"); |
||
535 | return; |
||
536 | } |
||
537 | |||
538 | if (!Path.IsPathRooted(regionFile)) |
||
539 | { |
||
540 | string regionsDir = ConfigSource.Source.Configs["Startup"].GetString("regionload_regionsdir", "Regions").Trim(); |
||
541 | regionFile = Path.Combine(regionsDir, regionFile); |
||
542 | } |
||
543 | |||
544 | RegionInfo regInfo; |
||
545 | if (isXml) |
||
546 | { |
||
547 | regInfo = new RegionInfo(regionName, regionFile, false, ConfigSource.Source); |
||
548 | } |
||
549 | else |
||
550 | { |
||
551 | regInfo = new RegionInfo(regionName, regionFile, false, ConfigSource.Source, regionName); |
||
552 | } |
||
553 | |||
554 | Scene existingScene; |
||
555 | if (SceneManager.TryGetScene(regInfo.RegionID, out existingScene)) |
||
556 | { |
||
557 | MainConsole.Instance.OutputFormat( |
||
558 | "ERROR: Cannot create region {0} with ID {1}, this ID is already assigned to region {2}", |
||
559 | regInfo.RegionName, regInfo.RegionID, existingScene.RegionInfo.RegionName); |
||
560 | |||
561 | return; |
||
562 | } |
||
563 | |||
564 | bool changed = PopulateRegionEstateInfo(regInfo); |
||
565 | IScene scene; |
||
566 | CreateRegion(regInfo, true, out scene); |
||
567 | |||
568 | if (changed) |
||
569 | regInfo.EstateSettings.Save(); |
||
570 | } |
||
571 | |||
572 | /// <summary> |
||
573 | /// Runs commands issued by the server console from the operator |
||
574 | /// </summary> |
||
575 | /// <param name="command">The first argument of the parameter (the command)</param> |
||
576 | /// <param name="cmdparams">Additional arguments passed to the command</param> |
||
577 | public void RunCommand(string module, string[] cmdparams) |
||
578 | { |
||
579 | List<string> args = new List<string>(cmdparams); |
||
580 | if (args.Count < 1) |
||
581 | return; |
||
582 | |||
583 | string command = args[0]; |
||
584 | args.RemoveAt(0); |
||
585 | |||
586 | cmdparams = args.ToArray(); |
||
587 | |||
588 | switch (command) |
||
589 | { |
||
590 | case "backup": |
||
591 | MainConsole.Instance.Output("Triggering save of pending object updates to persistent store"); |
||
592 | SceneManager.BackupCurrentScene(); |
||
593 | break; |
||
594 | |||
595 | case "remove-region": |
||
596 | string regRemoveName = CombineParams(cmdparams, 0); |
||
597 | |||
598 | Scene removeScene; |
||
599 | if (SceneManager.TryGetScene(regRemoveName, out removeScene)) |
||
600 | RemoveRegion(removeScene, false); |
||
601 | else |
||
602 | MainConsole.Instance.Output("No region with that name"); |
||
603 | break; |
||
604 | |||
605 | case "delete-region": |
||
606 | string regDeleteName = CombineParams(cmdparams, 0); |
||
607 | |||
608 | Scene killScene; |
||
609 | if (SceneManager.TryGetScene(regDeleteName, out killScene)) |
||
610 | RemoveRegion(killScene, true); |
||
611 | else |
||
612 | MainConsole.Instance.Output("no region with that name"); |
||
613 | break; |
||
614 | |||
615 | case "restart": |
||
616 | SceneManager.RestartCurrentScene(); |
||
617 | break; |
||
618 | } |
||
619 | } |
||
620 | |||
621 | /// <summary> |
||
622 | /// Change the currently selected region. The selected region is that operated upon by single region commands. |
||
623 | /// </summary> |
||
624 | /// <param name="cmdParams"></param> |
||
625 | protected void ChangeSelectedRegion(string module, string[] cmdparams) |
||
626 | { |
||
627 | if (cmdparams.Length > 2) |
||
628 | { |
||
629 | string newRegionName = CombineParams(cmdparams, 2); |
||
630 | |||
631 | if (!SceneManager.TrySetCurrentScene(newRegionName)) |
||
632 | MainConsole.Instance.Output(String.Format("Couldn't select region {0}", newRegionName)); |
||
633 | else |
||
634 | RefreshPrompt(); |
||
635 | } |
||
636 | else |
||
637 | { |
||
638 | MainConsole.Instance.Output("Usage: change region <region name>"); |
||
639 | } |
||
640 | } |
||
641 | |||
642 | /// <summary> |
||
643 | /// Refreshs prompt with the current selection details. |
||
644 | /// </summary> |
||
645 | private void RefreshPrompt() |
||
646 | { |
||
647 | string regionName = (SceneManager.CurrentScene == null ? "root" : SceneManager.CurrentScene.RegionInfo.RegionName); |
||
648 | MainConsole.Instance.Output(String.Format("Currently selected region is {0}", regionName)); |
||
649 | |||
650 | // m_log.DebugFormat("Original prompt is {0}", m_consolePrompt); |
||
651 | string prompt = m_consolePrompt; |
||
652 | |||
653 | // Replace "\R" with the region name |
||
654 | // Replace "\\" with "\" |
||
655 | prompt = m_consolePromptRegex.Replace(prompt, m => |
||
656 | { |
||
657 | // m_log.DebugFormat("Matched {0}", m.Groups[2].Value); |
||
658 | if (m.Groups[2].Value == "R") |
||
659 | return m.Groups[1].Value + regionName; |
||
660 | else |
||
661 | return m.Groups[0].Value; |
||
662 | }); |
||
663 | |||
664 | m_console.DefaultPrompt = prompt; |
||
665 | m_console.ConsoleScene = SceneManager.CurrentScene; |
||
666 | } |
||
667 | |||
668 | protected override void HandleRestartRegion(RegionInfo whichRegion) |
||
669 | { |
||
670 | base.HandleRestartRegion(whichRegion); |
||
671 | |||
672 | // Where we are restarting multiple scenes at once, a previous call to RefreshPrompt may have set the |
||
673 | // m_console.ConsoleScene to null (indicating all scenes). |
||
674 | if (m_console.ConsoleScene != null && whichRegion.RegionName == ((Scene)m_console.ConsoleScene).Name) |
||
675 | SceneManager.TrySetCurrentScene(whichRegion.RegionName); |
||
676 | |||
677 | RefreshPrompt(); |
||
678 | } |
||
679 | |||
680 | // see BaseOpenSimServer |
||
681 | /// <summary> |
||
682 | /// Many commands list objects for debugging. Some of the types are listed here |
||
683 | /// </summary> |
||
684 | /// <param name="mod"></param> |
||
685 | /// <param name="cmd"></param> |
||
686 | public override void HandleShow(string mod, string[] cmd) |
||
687 | { |
||
688 | base.HandleShow(mod, cmd); |
||
689 | |||
690 | List<string> args = new List<string>(cmd); |
||
691 | args.RemoveAt(0); |
||
692 | string[] showParams = args.ToArray(); |
||
693 | |||
694 | switch (showParams[0]) |
||
695 | { |
||
696 | case "users": |
||
697 | IList agents; |
||
698 | if (showParams.Length > 1 && showParams[1] == "full") |
||
699 | { |
||
700 | agents = SceneManager.GetCurrentScenePresences(); |
||
701 | } else |
||
702 | { |
||
703 | agents = SceneManager.GetCurrentSceneAvatars(); |
||
704 | } |
||
705 | |||
706 | MainConsole.Instance.Output(String.Format("\nAgents connected: {0}\n", agents.Count)); |
||
707 | |||
708 | MainConsole.Instance.Output( |
||
709 | String.Format("{0,-16} {1,-16} {2,-37} {3,-11} {4,-16} {5,-30}", "Firstname", "Lastname", |
||
710 | "Agent ID", "Root/Child", "Region", "Position") |
||
711 | ); |
||
712 | |||
713 | foreach (ScenePresence presence in agents) |
||
714 | { |
||
715 | RegionInfo regionInfo = presence.Scene.RegionInfo; |
||
716 | string regionName; |
||
717 | |||
718 | if (regionInfo == null) |
||
719 | { |
||
720 | regionName = "Unresolvable"; |
||
721 | } else |
||
722 | { |
||
723 | regionName = regionInfo.RegionName; |
||
724 | } |
||
725 | |||
726 | MainConsole.Instance.Output( |
||
727 | String.Format( |
||
728 | "{0,-16} {1,-16} {2,-37} {3,-11} {4,-16} {5,-30}", |
||
729 | presence.Firstname, |
||
730 | presence.Lastname, |
||
731 | presence.UUID, |
||
732 | presence.IsChildAgent ? "Child" : "Root", |
||
733 | regionName, |
||
734 | presence.AbsolutePosition.ToString()) |
||
735 | ); |
||
736 | } |
||
737 | |||
738 | MainConsole.Instance.Output(String.Empty); |
||
739 | break; |
||
740 | |||
741 | case "connections": |
||
742 | HandleShowConnections(); |
||
743 | break; |
||
744 | |||
745 | case "circuits": |
||
746 | HandleShowCircuits(); |
||
747 | break; |
||
748 | |||
749 | case "modules": |
||
750 | SceneManager.ForEachSelectedScene( |
||
751 | scene => |
||
752 | { |
||
753 | MainConsole.Instance.OutputFormat("Loaded region modules in {0} are:", scene.Name); |
||
754 | |||
755 | List<IRegionModuleBase> sharedModules = new List<IRegionModuleBase>(); |
||
756 | List<IRegionModuleBase> nonSharedModules = new List<IRegionModuleBase>(); |
||
757 | |||
758 | foreach (IRegionModuleBase module in scene.RegionModules.Values) |
||
759 | { |
||
760 | if (module.GetType().GetInterface("ISharedRegionModule") != null) |
||
761 | nonSharedModules.Add(module); |
||
762 | else |
||
763 | sharedModules.Add(module); |
||
764 | } |
||
765 | |||
766 | foreach (IRegionModuleBase module in sharedModules.OrderBy(m => m.Name)) |
||
767 | MainConsole.Instance.OutputFormat("New Region Module (Shared): {0}", module.Name); |
||
768 | |||
769 | foreach (IRegionModuleBase module in sharedModules.OrderBy(m => m.Name)) |
||
770 | MainConsole.Instance.OutputFormat("New Region Module (Non-Shared): {0}", module.Name); |
||
771 | } |
||
772 | ); |
||
773 | |||
774 | MainConsole.Instance.Output(""); |
||
775 | break; |
||
776 | |||
777 | case "regions": |
||
778 | SceneManager.ForEachScene( |
||
779 | delegate(Scene scene) |
||
780 | { |
||
781 | MainConsole.Instance.Output(String.Format( |
||
782 | "Region Name: {0}, Region XLoc: {1}, Region YLoc: {2}, Region Port: {3}, Estate Name: {4}", |
||
783 | scene.RegionInfo.RegionName, |
||
784 | scene.RegionInfo.RegionLocX, |
||
785 | scene.RegionInfo.RegionLocY, |
||
786 | scene.RegionInfo.InternalEndPoint.Port, |
||
787 | scene.RegionInfo.EstateSettings.EstateName)); |
||
788 | }); |
||
789 | break; |
||
790 | |||
791 | case "ratings": |
||
792 | SceneManager.ForEachScene( |
||
793 | delegate(Scene scene) |
||
794 | { |
||
795 | string rating = ""; |
||
796 | if (scene.RegionInfo.RegionSettings.Maturity == 1) |
||
797 | { |
||
798 | rating = "MATURE"; |
||
799 | } |
||
800 | else if (scene.RegionInfo.RegionSettings.Maturity == 2) |
||
801 | { |
||
802 | rating = "ADULT"; |
||
803 | } |
||
804 | else |
||
805 | { |
||
806 | rating = "PG"; |
||
807 | } |
||
808 | MainConsole.Instance.Output(String.Format( |
||
809 | "Region Name: {0}, Region Rating {1}", |
||
810 | scene.RegionInfo.RegionName, |
||
811 | rating)); |
||
812 | }); |
||
813 | break; |
||
814 | } |
||
815 | } |
||
816 | |||
817 | private void HandleShowCircuits() |
||
818 | { |
||
819 | ConsoleDisplayTable cdt = new ConsoleDisplayTable(); |
||
820 | cdt.AddColumn("Region", 20); |
||
821 | cdt.AddColumn("Avatar name", 24); |
||
822 | cdt.AddColumn("Type", 5); |
||
823 | cdt.AddColumn("Code", 10); |
||
824 | cdt.AddColumn("IP", 16); |
||
825 | cdt.AddColumn("Viewer Name", 24); |
||
826 | |||
827 | SceneManager.ForEachScene( |
||
828 | s => |
||
829 | { |
||
830 | foreach (AgentCircuitData aCircuit in s.AuthenticateHandler.GetAgentCircuits().Values) |
||
831 | cdt.AddRow( |
||
832 | s.Name, |
||
833 | aCircuit.Name, |
||
834 | aCircuit.child ? "child" : "root", |
||
835 | aCircuit.circuitcode.ToString(), |
||
836 | aCircuit.IPAddress != null ? aCircuit.IPAddress.ToString() : "not set", |
||
837 | aCircuit.Viewer); |
||
838 | }); |
||
839 | |||
840 | MainConsole.Instance.Output(cdt.ToString()); |
||
841 | } |
||
842 | |||
843 | private void HandleShowConnections() |
||
844 | { |
||
845 | ConsoleDisplayTable cdt = new ConsoleDisplayTable(); |
||
846 | cdt.AddColumn("Region", 20); |
||
847 | cdt.AddColumn("Avatar name", 24); |
||
848 | cdt.AddColumn("Circuit code", 12); |
||
849 | cdt.AddColumn("Endpoint", 23); |
||
850 | cdt.AddColumn("Active?", 7); |
||
851 | |||
852 | SceneManager.ForEachScene( |
||
853 | s => s.ForEachClient( |
||
854 | c => cdt.AddRow( |
||
855 | s.Name, |
||
856 | c.Name, |
||
857 | c.CircuitCode.ToString(), |
||
858 | c.RemoteEndPoint.ToString(), |
||
859 | c.IsActive.ToString()))); |
||
860 | |||
861 | MainConsole.Instance.Output(cdt.ToString()); |
||
862 | } |
||
863 | |||
864 | /// <summary> |
||
865 | /// Use XML2 format to serialize data to a file |
||
866 | /// </summary> |
||
867 | /// <param name="module"></param> |
||
868 | /// <param name="cmdparams"></param> |
||
869 | protected void SavePrimsXml2(string module, string[] cmdparams) |
||
870 | { |
||
871 | if (cmdparams.Length > 5) |
||
872 | { |
||
873 | SceneManager.SaveNamedPrimsToXml2(cmdparams[3], cmdparams[4]); |
||
874 | } |
||
875 | else |
||
876 | { |
||
877 | SceneManager.SaveNamedPrimsToXml2("Primitive", DEFAULT_PRIM_BACKUP_FILENAME); |
||
878 | } |
||
879 | } |
||
880 | |||
881 | /// <summary> |
||
882 | /// Use XML format to serialize data to a file |
||
883 | /// </summary> |
||
884 | /// <param name="module"></param> |
||
885 | /// <param name="cmdparams"></param> |
||
886 | protected void SaveXml(string module, string[] cmdparams) |
||
887 | { |
||
888 | MainConsole.Instance.Output("PLEASE NOTE, save-xml is DEPRECATED and may be REMOVED soon. If you are using this and there is some reason you can't use save-xml2, please file a mantis detailing the reason."); |
||
889 | |||
890 | if (cmdparams.Length > 0) |
||
891 | { |
||
892 | SceneManager.SaveCurrentSceneToXml(cmdparams[2]); |
||
893 | } |
||
894 | else |
||
895 | { |
||
896 | SceneManager.SaveCurrentSceneToXml(DEFAULT_PRIM_BACKUP_FILENAME); |
||
897 | } |
||
898 | } |
||
899 | |||
900 | /// <summary> |
||
901 | /// Loads data and region objects from XML format. |
||
902 | /// </summary> |
||
903 | /// <param name="module"></param> |
||
904 | /// <param name="cmdparams"></param> |
||
905 | protected void LoadXml(string module, string[] cmdparams) |
||
906 | { |
||
907 | MainConsole.Instance.Output("PLEASE NOTE, load-xml is DEPRECATED and may be REMOVED soon. If you are using this and there is some reason you can't use load-xml2, please file a mantis detailing the reason."); |
||
908 | |||
909 | Vector3 loadOffset = new Vector3(0, 0, 0); |
||
910 | if (cmdparams.Length > 2) |
||
911 | { |
||
912 | bool generateNewIDS = false; |
||
913 | if (cmdparams.Length > 3) |
||
914 | { |
||
915 | if (cmdparams[3] == "-newUID") |
||
916 | { |
||
917 | generateNewIDS = true; |
||
918 | } |
||
919 | if (cmdparams.Length > 4) |
||
920 | { |
||
921 | loadOffset.X = (float)Convert.ToDecimal(cmdparams[4], Culture.NumberFormatInfo); |
||
922 | if (cmdparams.Length > 5) |
||
923 | { |
||
924 | loadOffset.Y = (float)Convert.ToDecimal(cmdparams[5], Culture.NumberFormatInfo); |
||
925 | } |
||
926 | if (cmdparams.Length > 6) |
||
927 | { |
||
928 | loadOffset.Z = (float)Convert.ToDecimal(cmdparams[6], Culture.NumberFormatInfo); |
||
929 | } |
||
930 | MainConsole.Instance.Output(String.Format("loadOffsets <X,Y,Z> = <{0},{1},{2}>",loadOffset.X,loadOffset.Y,loadOffset.Z)); |
||
931 | } |
||
932 | } |
||
933 | SceneManager.LoadCurrentSceneFromXml(cmdparams[2], generateNewIDS, loadOffset); |
||
934 | } |
||
935 | else |
||
936 | { |
||
937 | try |
||
938 | { |
||
939 | SceneManager.LoadCurrentSceneFromXml(DEFAULT_PRIM_BACKUP_FILENAME, false, loadOffset); |
||
940 | } |
||
941 | catch (FileNotFoundException) |
||
942 | { |
||
943 | MainConsole.Instance.Output("Default xml not found. Usage: load-xml <filename>"); |
||
944 | } |
||
945 | } |
||
946 | } |
||
947 | /// <summary> |
||
948 | /// Serialize region data to XML2Format |
||
949 | /// </summary> |
||
950 | /// <param name="module"></param> |
||
951 | /// <param name="cmdparams"></param> |
||
952 | protected void SaveXml2(string module, string[] cmdparams) |
||
953 | { |
||
954 | if (cmdparams.Length > 2) |
||
955 | { |
||
956 | SceneManager.SaveCurrentSceneToXml2(cmdparams[2]); |
||
957 | } |
||
958 | else |
||
959 | { |
||
960 | SceneManager.SaveCurrentSceneToXml2(DEFAULT_PRIM_BACKUP_FILENAME); |
||
961 | } |
||
962 | } |
||
963 | |||
964 | /// <summary> |
||
965 | /// Load region data from Xml2Format |
||
966 | /// </summary> |
||
967 | /// <param name="module"></param> |
||
968 | /// <param name="cmdparams"></param> |
||
969 | protected void LoadXml2(string module, string[] cmdparams) |
||
970 | { |
||
971 | if (cmdparams.Length > 2) |
||
972 | { |
||
973 | try |
||
974 | { |
||
975 | SceneManager.LoadCurrentSceneFromXml2(cmdparams[2]); |
||
976 | } |
||
977 | catch (FileNotFoundException) |
||
978 | { |
||
979 | MainConsole.Instance.Output("Specified xml not found. Usage: load xml2 <filename>"); |
||
980 | } |
||
981 | } |
||
982 | else |
||
983 | { |
||
984 | try |
||
985 | { |
||
986 | SceneManager.LoadCurrentSceneFromXml2(DEFAULT_PRIM_BACKUP_FILENAME); |
||
987 | } |
||
988 | catch (FileNotFoundException) |
||
989 | { |
||
990 | MainConsole.Instance.Output("Default xml not found. Usage: load xml2 <filename>"); |
||
991 | } |
||
992 | } |
||
993 | } |
||
994 | |||
995 | /// <summary> |
||
996 | /// Load a whole region from an opensimulator archive. |
||
997 | /// </summary> |
||
998 | /// <param name="cmdparams"></param> |
||
999 | protected void LoadOar(string module, string[] cmdparams) |
||
1000 | { |
||
1001 | try |
||
1002 | { |
||
1003 | SceneManager.LoadArchiveToCurrentScene(cmdparams); |
||
1004 | } |
||
1005 | catch (Exception e) |
||
1006 | { |
||
1007 | MainConsole.Instance.Output(e.Message); |
||
1008 | } |
||
1009 | } |
||
1010 | |||
1011 | /// <summary> |
||
1012 | /// Save a region to a file, including all the assets needed to restore it. |
||
1013 | /// </summary> |
||
1014 | /// <param name="cmdparams"></param> |
||
1015 | protected void SaveOar(string module, string[] cmdparams) |
||
1016 | { |
||
1017 | SceneManager.SaveCurrentSceneToArchive(cmdparams); |
||
1018 | } |
||
1019 | |||
1020 | private static string CombineParams(string[] commandParams, int pos) |
||
1021 | { |
||
1022 | string result = String.Empty; |
||
1023 | for (int i = pos; i < commandParams.Length; i++) |
||
1024 | { |
||
1025 | result += commandParams[i] + " "; |
||
1026 | } |
||
1027 | result = result.TrimEnd(' '); |
||
1028 | return result; |
||
1029 | } |
||
1030 | |||
1031 | #endregion |
||
1032 | } |
||
1033 | } |