clockwerk-opensim – Blame information for rev 1

Subversion Repositories:
Rev:
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 using OpenSim.Services.Interfaces;
49  
50 namespace OpenSim
51 {
52 /// <summary>
53 /// Interactive OpenSim region server
54 /// </summary>
55 public class OpenSim : OpenSimBase
56 {
57 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
58  
59 protected string m_startupCommandsFile;
60 protected string m_shutdownCommandsFile;
61 protected bool m_gui = false;
62 protected string m_consoleType = "local";
63 protected uint m_consolePort = 0;
64  
65 /// <summary>
66 /// Prompt to use for simulator command line.
67 /// </summary>
68 private string m_consolePrompt;
69  
70 /// <summary>
71 /// Regex for parsing out special characters in the prompt.
72 /// </summary>
73 private Regex m_consolePromptRegex = new Regex(@"([^\\])\\(\w)", RegexOptions.Compiled);
74  
75 private string m_timedScript = "disabled";
76 private int m_timeInterval = 1200;
77 private Timer m_scriptTimer;
78  
79 public OpenSim(IConfigSource configSource) : base(configSource)
80 {
81 }
82  
83 protected override void ReadExtraConfigSettings()
84 {
85 base.ReadExtraConfigSettings();
86  
87 IConfig startupConfig = Config.Configs["Startup"];
88 IConfig networkConfig = Config.Configs["Network"];
89  
90 int stpMinThreads = 2;
91 int stpMaxThreads = 15;
92  
93 if (startupConfig != null)
94 {
95 m_startupCommandsFile = startupConfig.GetString("startup_console_commands_file", "startup_commands.txt");
96 m_shutdownCommandsFile = startupConfig.GetString("shutdown_console_commands_file", "shutdown_commands.txt");
97  
98 if (startupConfig.GetString("console", String.Empty) == String.Empty)
99 m_gui = startupConfig.GetBoolean("gui", false);
100 else
101 m_consoleType= startupConfig.GetString("console", String.Empty);
102  
103 if (networkConfig != null)
104 m_consolePort = (uint)networkConfig.GetInt("console_port", 0);
105  
106 m_timedScript = startupConfig.GetString("timer_Script", "disabled");
107 if (m_timedScript != "disabled")
108 {
109 m_timeInterval = startupConfig.GetInt("timer_Interval", 1200);
110 }
111  
112 string asyncCallMethodStr = startupConfig.GetString("async_call_method", String.Empty);
113 FireAndForgetMethod asyncCallMethod;
114 if (!String.IsNullOrEmpty(asyncCallMethodStr) && Utils.EnumTryParse<FireAndForgetMethod>(asyncCallMethodStr, out asyncCallMethod))
115 Util.FireAndForgetMethod = asyncCallMethod;
116  
117 stpMinThreads = startupConfig.GetInt("MinPoolThreads", 15);
118 stpMaxThreads = startupConfig.GetInt("MaxPoolThreads", 300);
119 m_consolePrompt = startupConfig.GetString("ConsolePrompt", @"Region (\R) ");
120 }
121  
122 if (Util.FireAndForgetMethod == FireAndForgetMethod.SmartThreadPool)
123 Util.InitThreadPool(stpMinThreads, stpMaxThreads);
124  
125 m_log.Info("[OPENSIM MAIN]: Using async_call_method " + Util.FireAndForgetMethod);
126 }
127  
128 /// <summary>
129 /// Performs initialisation of the scene, such as loading configuration from disk.
130 /// </summary>
131 protected override void StartupSpecific()
132 {
133 m_log.Info("====================================================================");
134 m_log.Info("========================= STARTING OPENSIM =========================");
135 m_log.Info("====================================================================");
136  
137 //m_log.InfoFormat("[OPENSIM MAIN]: GC Is Server GC: {0}", GCSettings.IsServerGC.ToString());
138 // http://msdn.microsoft.com/en-us/library/bb384202.aspx
139 //GCSettings.LatencyMode = GCLatencyMode.Batch;
140 //m_log.InfoFormat("[OPENSIM MAIN]: GC Latency Mode: {0}", GCSettings.LatencyMode.ToString());
141  
142 if (m_gui) // Driven by external GUI
143 {
144 m_console = new CommandConsole("Region");
145 }
146 else
147 {
148 switch (m_consoleType)
149 {
150 case "basic":
151 m_console = new CommandConsole("Region");
152 break;
153 case "rest":
154 m_console = new RemoteConsole("Region");
155 ((RemoteConsole)m_console).ReadConfig(Config);
156 break;
157 default:
158 m_console = new LocalConsole("Region", Config.Configs["Startup"]);
159 break;
160 }
161 }
162  
163 MainConsole.Instance = m_console;
164  
165 LogEnvironmentInformation();
166 RegisterCommonAppenders(Config.Configs["Startup"]);
167 RegisterConsoleCommands();
168  
169 base.StartupSpecific();
170  
171 MainServer.Instance.AddStreamHandler(new OpenSim.SimStatusHandler());
172 MainServer.Instance.AddStreamHandler(new OpenSim.XSimStatusHandler(this));
173 if (userStatsURI != String.Empty)
174 MainServer.Instance.AddStreamHandler(new OpenSim.UXSimStatusHandler(this));
175  
176 if (managedStatsURI != String.Empty)
177 {
178 string urlBase = String.Format("/{0}/", managedStatsURI);
179 MainServer.Instance.AddHTTPHandler(urlBase, StatsManager.HandleStatsRequest);
180 m_log.InfoFormat("[OPENSIM] Enabling remote managed stats fetch. URL = {0}", urlBase);
181 }
182  
183 if (m_console is RemoteConsole)
184 {
185 if (m_consolePort == 0)
186 {
187 ((RemoteConsole)m_console).SetServer(m_httpServer);
188 }
189 else
190 {
191 ((RemoteConsole)m_console).SetServer(MainServer.GetHttpServer(m_consolePort));
192 }
193 }
194  
195 // Hook up to the watchdog timer
196 Watchdog.OnWatchdogTimeout += WatchdogTimeoutHandler;
197  
198 PrintFileToConsole("startuplogo.txt");
199  
200 // For now, start at the 'root' level by default
201 if (SceneManager.Scenes.Count == 1) // If there is only one region, select it
202 ChangeSelectedRegion("region",
203 new string[] {"change", "region", SceneManager.Scenes[0].RegionInfo.RegionName});
204 else
205 ChangeSelectedRegion("region", new string[] {"change", "region", "root"});
206  
207 //Run Startup Commands
208 if (String.IsNullOrEmpty(m_startupCommandsFile))
209 {
210 m_log.Info("[STARTUP]: No startup command script specified. Moving on...");
211 }
212 else
213 {
214 RunCommandScript(m_startupCommandsFile);
215 }
216  
217 // Start timer script (run a script every xx seconds)
218 if (m_timedScript != "disabled")
219 {
220 m_scriptTimer = new Timer();
221 m_scriptTimer.Enabled = true;
222 m_scriptTimer.Interval = m_timeInterval*1000;
223 m_scriptTimer.Elapsed += RunAutoTimerScript;
224 }
225 }
226  
227 /// <summary>
228 /// Register standard set of region console commands
229 /// </summary>
230 private void RegisterConsoleCommands()
231 {
232 MainServer.RegisterHttpConsoleCommands(m_console);
233  
234 m_console.Commands.AddCommand("Objects", false, "force update",
235 "force update",
236 "Force the update of all objects on clients",
237 HandleForceUpdate);
238  
239 m_console.Commands.AddCommand("General", false, "change region",
240 "change region <region name>",
241 "Change current console region",
242 ChangeSelectedRegion);
243  
244 m_console.Commands.AddCommand("Archiving", false, "save xml",
245 "save xml",
246 "Save a region's data in XML format",
247 SaveXml);
248  
249 m_console.Commands.AddCommand("Archiving", false, "save xml2",
250 "save xml2",
251 "Save a region's data in XML2 format",
252 SaveXml2);
253  
254 m_console.Commands.AddCommand("Archiving", false, "load xml",
255 "load xml [-newIDs [<x> <y> <z>]]",
256 "Load a region's data from XML format",
257 LoadXml);
258  
259 m_console.Commands.AddCommand("Archiving", false, "load xml2",
260 "load xml2",
261 "Load a region's data from XML2 format",
262 LoadXml2);
263  
264 m_console.Commands.AddCommand("Archiving", false, "save prims xml2",
265 "save prims xml2 [<prim name> <file name>]",
266 "Save named prim to XML2",
267 SavePrimsXml2);
268  
269 m_console.Commands.AddCommand("Archiving", false, "load oar",
270 "load oar [--merge] [--skip-assets]"
271 + " [--force-terrain] [--force-parcels]"
272 + " [--no-objects]"
273 + " [--rotation degrees] [--rotation-center \"<x,y,z>\"]"
274 + " [--displacement \"<x,y,z>\"]"
275 + " [--default-user \"User Name\"]"
276 + " [<OAR path>]",
277 "Load a region's data from an OAR archive.",
278 "--merge will merge the OAR with the existing scene (suppresses terrain and parcel info loading)." + Environment.NewLine
279 + "--skip-assets will load the OAR but ignore the assets it contains." + Environment.NewLine
280 + "--displacement will add this value to the position of every object loaded" + Environment.NewLine
281 + "--force-terrain forces the loading of terrain from the oar (undoes suppression done by --merge)" + Environment.NewLine
282 + "--force-parcels forces the loading of parcels from the oar (undoes suppression done by --merge)" + Environment.NewLine
283 + "--rotation specified rotation to be applied to the oar. Specified in degrees." + Environment.NewLine
284 + "--rotation-center Location (relative to original OAR) to apply rotation. Default is <128,128,0>" + Environment.NewLine
285 + "--no-objects suppresses the addition of any objects (good for loading only the terrain)" + Environment.NewLine
286 + "The path can be either a filesystem location or a URI."
287 + " If this is not given then the command looks for an OAR named region.oar in the current directory.",
288 LoadOar);
289  
290 m_console.Commands.AddCommand("Archiving", false, "save oar",
291 //"save oar [-v|--version=<N>] [-p|--profile=<url>] [<OAR path>]",
292 "save oar [-h|--home=<url>] [--noassets] [--publish] [--perm=<permissions>] [--all] [<OAR path>]",
293 "Save a region's data to an OAR archive.",
294 // "-v|--version=<N> generates scene objects as per older versions of the serialization (e.g. -v=0)" + Environment.NewLine
295 "-h|--home=<url> adds the url of the profile service to the saved user information.\n"
296 + "--noassets stops assets being saved to the OAR.\n"
297 + "--publish saves an OAR stripped of owner and last owner information.\n"
298 + " on reload, the estate owner will be the owner of all objects\n"
299 + " this is useful if you're making oars generally available that might be reloaded to the same grid from which you published\n"
300 + "--perm=<permissions> stops objects with insufficient permissions from being saved to the OAR.\n"
301 + " <permissions> can contain one or more of these characters: \"C\" = Copy, \"T\" = Transfer\n"
302 + "--all saves all the regions in the simulator, instead of just the current region.\n"
303 + "The OAR path must be a filesystem path."
304 + " If this is not given then the oar is saved to region.oar in the current directory.",
305 SaveOar);
306  
307 m_console.Commands.AddCommand("Objects", false, "edit scale",
308 "edit scale <name> <x> <y> <z>",
309 "Change the scale of a named prim",
310 HandleEditScale);
311  
312 m_console.Commands.AddCommand("Objects", false, "rotate scene",
313 "rotate scene <degrees> [centerX, centerY]",
314 "Rotates all scene objects around centerX, centerY (defailt 128, 128) (please back up your region before using)",
315 HandleRotateScene);
316  
317 m_console.Commands.AddCommand("Objects", false, "scale scene",
318 "scale scene <factor>",
319 "Scales the scene objects (please back up your region before using)",
320 HandleScaleScene);
321  
322 m_console.Commands.AddCommand("Objects", false, "translate scene",
323 "translate scene xOffset yOffset zOffset",
324 "translates the scene objects (please back up your region before using)",
325 HandleTranslateScene);
326  
327 m_console.Commands.AddCommand("Users", false, "kick user",
328 "kick user <first> <last> [--force] [message]",
329 "Kick a user off the simulator",
330 "The --force option will kick the user without any checks to see whether it's already in the process of closing\n"
331 + "Only use this option if you are sure the avatar is inactive and a normal kick user operation does not removed them",
332 KickUserCommand);
333  
334 m_console.Commands.AddCommand("Users", false, "show users",
335 "show users [full]",
336 "Show user data for users currently on the region",
337 "Without the 'full' option, only users actually on the region are shown."
338 + " With the 'full' option child agents of users in neighbouring regions are also shown.",
339 HandleShow);
340  
341 m_console.Commands.AddCommand("Comms", false, "show connections",
342 "show connections",
343 "Show connection data",
344 HandleShow);
345  
346 m_console.Commands.AddCommand("Comms", false, "show circuits",
347 "show circuits",
348 "Show agent circuit data",
349 HandleShow);
350  
351 m_console.Commands.AddCommand("Comms", false, "show pending-objects",
352 "show pending-objects",
353 "Show # of objects on the pending queues of all scene viewers",
354 HandleShow);
355  
356 m_console.Commands.AddCommand("General", false, "show modules",
357 "show modules",
358 "Show module data",
359 HandleShow);
360  
361 m_console.Commands.AddCommand("Regions", false, "show regions",
362 "show regions",
363 "Show region data",
364 HandleShow);
365  
366 m_console.Commands.AddCommand("Regions", false, "show ratings",
367 "show ratings",
368 "Show rating data",
369 HandleShow);
370  
371 m_console.Commands.AddCommand("Objects", false, "backup",
372 "backup",
373 "Persist currently unsaved object changes immediately instead of waiting for the normal persistence call.",
374 RunCommand);
375  
376 m_console.Commands.AddCommand("Regions", false, "create region",
377 "create region [\"region name\"] <region_file.ini>",
378 "Create a new region.",
379 "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."
380 + " If \"region name\" does not exist in <region_file.ini>, it will be added." + Environment.NewLine
381 + "Without \"region name\", the first region found in <region_file.ini> will be created." + Environment.NewLine
382 + "If <region_file.ini> does not exist, it will be created.",
383 HandleCreateRegion);
384  
385 m_console.Commands.AddCommand("Regions", false, "restart",
386 "restart",
387 "Restart all sims in this instance",
388 RunCommand);
389  
390 m_console.Commands.AddCommand("General", false, "command-script",
391 "command-script <script>",
392 "Run a command script from file",
393 RunCommand);
394  
395 m_console.Commands.AddCommand("Regions", false, "remove-region",
396 "remove-region <name>",
397 "Remove a region from this simulator",
398 RunCommand);
399  
400 m_console.Commands.AddCommand("Regions", false, "delete-region",
401 "delete-region <name>",
402 "Delete a region from disk",
403 RunCommand);
404  
405 m_console.Commands.AddCommand("Estates", false, "estate create",
406 "estate create <owner UUID> <estate name>",
407 "Creates a new estate with the specified name, owned by the specified user."
408 + " Estate name must be unique.",
409 CreateEstateCommand);
410  
411 m_console.Commands.AddCommand("Estates", false, "estate set owner",
412 "estate set owner <estate-id>[ <UUID> | <Firstname> <Lastname> ]",
413 "Sets the owner of the specified estate to the specified UUID or user. ",
414 SetEstateOwnerCommand);
415  
416 m_console.Commands.AddCommand("Estates", false, "estate set name",
417 "estate set name <estate-id> <new name>",
418 "Sets the name of the specified estate to the specified value. New name must be unique.",
419 SetEstateNameCommand);
420  
421 m_console.Commands.AddCommand("Estates", false, "estate link region",
422 "estate link region <estate ID> <region ID>",
423 "Attaches the specified region to the specified estate.",
424 EstateLinkRegionCommand);
425 }
426  
427 protected override void ShutdownSpecific()
428 {
429 if (m_shutdownCommandsFile != String.Empty)
430 {
431 RunCommandScript(m_shutdownCommandsFile);
432 }
433  
434 base.ShutdownSpecific();
435 }
436  
437 /// <summary>
438 /// Timer to run a specific text file as console commands. Configured in in the main ini file
439 /// </summary>
440 /// <param name="sender"></param>
441 /// <param name="e"></param>
442 private void RunAutoTimerScript(object sender, EventArgs e)
443 {
444 if (m_timedScript != "disabled")
445 {
446 RunCommandScript(m_timedScript);
447 }
448 }
449  
450 private void WatchdogTimeoutHandler(Watchdog.ThreadWatchdogInfo twi)
451 {
452 int now = Environment.TickCount & Int32.MaxValue;
453  
454 m_log.ErrorFormat(
455 "[WATCHDOG]: Timeout detected for thread \"{0}\". ThreadState={1}. Last tick was {2}ms ago. {3}",
456 twi.Thread.Name,
457 twi.Thread.ThreadState,
458 now - twi.LastTick,
459 twi.AlarmMethod != null ? string.Format("Data: {0}", twi.AlarmMethod()) : "");
460 }
461  
462 #region Console Commands
463  
464 /// <summary>
465 /// Kicks users off the region
466 /// </summary>
467 /// <param name="module"></param>
468 /// <param name="cmdparams">name of avatar to kick</param>
469 private void KickUserCommand(string module, string[] cmdparams)
470 {
471 bool force = false;
472  
473 OptionSet options = new OptionSet().Add("f|force", delegate (string v) { force = v != null; });
474  
475 List<string> mainParams = options.Parse(cmdparams);
476  
477 if (mainParams.Count < 4)
478 return;
479  
480 string alert = null;
481 if (mainParams.Count > 4)
482 alert = String.Format("\n{0}\n", String.Join(" ", cmdparams, 4, cmdparams.Length - 4));
483  
484 IList agents = SceneManager.GetCurrentSceneAvatars();
485  
486 foreach (ScenePresence presence in agents)
487 {
488 RegionInfo regionInfo = presence.Scene.RegionInfo;
489  
490 if (presence.Firstname.ToLower().Equals(mainParams[2].ToLower()) &&
491 presence.Lastname.ToLower().Equals(mainParams[3].ToLower()))
492 {
493 MainConsole.Instance.Output(
494 String.Format(
495 "Kicking user: {0,-16} {1,-16} {2,-37} in region: {3,-16}",
496 presence.Firstname, presence.Lastname, presence.UUID, regionInfo.RegionName));
497  
498 // kick client...
499 if (alert != null)
500 presence.ControllingClient.Kick(alert);
501 else
502 presence.ControllingClient.Kick("\nThe OpenSim manager kicked you out.\n");
503  
504 presence.Scene.CloseAgent(presence.UUID, force);
505 break;
506 }
507 }
508  
509 MainConsole.Instance.Output("");
510 }
511  
512 /// <summary>
513 /// Opens a file and uses it as input to the console command parser.
514 /// </summary>
515 /// <param name="fileName">name of file to use as input to the console</param>
516 private static void PrintFileToConsole(string fileName)
517 {
518 if (File.Exists(fileName))
519 {
520 StreamReader readFile = File.OpenText(fileName);
521 string currentLine;
522 while ((currentLine = readFile.ReadLine()) != null)
523 {
524 m_log.Info("[!]" + currentLine);
525 }
526 }
527 }
528  
529 /// <summary>
530 /// Force resending of all updates to all clients in active region(s)
531 /// </summary>
532 /// <param name="module"></param>
533 /// <param name="args"></param>
534 private void HandleForceUpdate(string module, string[] args)
535 {
536 MainConsole.Instance.Output("Updating all clients");
537 SceneManager.ForceCurrentSceneClientUpdate();
538 }
539  
540 /// <summary>
541 /// Edits the scale of a primative with the name specified
542 /// </summary>
543 /// <param name="module"></param>
544 /// <param name="args">0,1, name, x, y, z</param>
545 private void HandleEditScale(string module, string[] args)
546 {
547 if (args.Length == 6)
548 {
549 SceneManager.HandleEditCommandOnCurrentScene(args);
550 }
551 else
552 {
553 MainConsole.Instance.Output("Argument error: edit scale <prim name> <x> <y> <z>");
554 }
555 }
556  
557 private void HandleRotateScene(string module, string[] args)
558 {
559 string usage = "Usage: rotate scene <angle in degrees> [centerX centerY] (centerX and centerY are optional and default to Constants.RegionSize / 2";
560  
561 float centerX = Constants.RegionSize * 0.5f;
562 float centerY = Constants.RegionSize * 0.5f;
563  
564 if (args.Length < 3 || args.Length == 4)
565 {
566 MainConsole.Instance.Output(usage);
567 return;
568 }
569  
570 float angle = (float)(Convert.ToSingle(args[2]) / 180.0 * Math.PI);
571 OpenMetaverse.Quaternion rot = OpenMetaverse.Quaternion.CreateFromAxisAngle(0, 0, 1, angle);
572  
573 if (args.Length > 4)
574 {
575 centerX = Convert.ToSingle(args[3]);
576 centerY = Convert.ToSingle(args[4]);
577 }
578  
579 Vector3 center = new Vector3(centerX, centerY, 0.0f);
580  
581 SceneManager.ForEachSelectedScene(delegate(Scene scene)
582 {
583 scene.ForEachSOG(delegate(SceneObjectGroup sog)
584 {
585 if (!sog.IsAttachment)
586 {
587 sog.RootPart.UpdateRotation(rot * sog.GroupRotation);
588 Vector3 offset = sog.AbsolutePosition - center;
589 offset *= rot;
590 sog.UpdateGroupPosition(center + offset);
591 }
592 });
593 });
594 }
595  
596 private void HandleScaleScene(string module, string[] args)
597 {
598 string usage = "Usage: scale scene <factor>";
599  
600 if (args.Length < 3)
601 {
602 MainConsole.Instance.Output(usage);
603 return;
604 }
605  
606 float factor = (float)(Convert.ToSingle(args[2]));
607  
608 float minZ = float.MaxValue;
609  
610 SceneManager.ForEachSelectedScene(delegate(Scene scene)
611 {
612 scene.ForEachSOG(delegate(SceneObjectGroup sog)
613 {
614 if (!sog.IsAttachment)
615 {
616 if (sog.RootPart.AbsolutePosition.Z < minZ)
617 minZ = sog.RootPart.AbsolutePosition.Z;
618 }
619 });
620 });
621  
622 SceneManager.ForEachSelectedScene(delegate(Scene scene)
623 {
624 scene.ForEachSOG(delegate(SceneObjectGroup sog)
625 {
626 if (!sog.IsAttachment)
627 {
628 Vector3 tmpRootPos = sog.RootPart.AbsolutePosition;
629 tmpRootPos.Z -= minZ;
630 tmpRootPos *= factor;
631 tmpRootPos.Z += minZ;
632  
633 foreach (SceneObjectPart sop in sog.Parts)
634 {
635 if (sop.ParentID != 0)
636 sop.OffsetPosition *= factor;
637 sop.Scale *= factor;
638 }
639  
640 sog.UpdateGroupPosition(tmpRootPos);
641 }
642 });
643 });
644 }
645  
646 private void HandleTranslateScene(string module, string[] args)
647 {
648 string usage = "Usage: translate scene <xOffset, yOffset, zOffset>";
649  
650 if (args.Length < 5)
651 {
652 MainConsole.Instance.Output(usage);
653 return;
654 }
655  
656 float xOFfset = (float)Convert.ToSingle(args[2]);
657 float yOffset = (float)Convert.ToSingle(args[3]);
658 float zOffset = (float)Convert.ToSingle(args[4]);
659  
660 Vector3 offset = new Vector3(xOFfset, yOffset, zOffset);
661  
662 SceneManager.ForEachSelectedScene(delegate(Scene scene)
663 {
664 scene.ForEachSOG(delegate(SceneObjectGroup sog)
665 {
666 if (!sog.IsAttachment)
667 sog.UpdateGroupPosition(sog.AbsolutePosition + offset);
668 });
669 });
670 }
671  
672 /// <summary>
673 /// Creates a new region based on the parameters specified. This will ask the user questions on the console
674 /// </summary>
675 /// <param name="module"></param>
676 /// <param name="cmd">0,1,region name, region ini or XML file</param>
677 private void HandleCreateRegion(string module, string[] cmd)
678 {
679 string regionName = string.Empty;
680 string regionFile = string.Empty;
681  
682 if (cmd.Length == 3)
683 {
684 regionFile = cmd[2];
685 }
686 else if (cmd.Length > 3)
687 {
688 regionName = cmd[2];
689 regionFile = cmd[3];
690 }
691  
692 string extension = Path.GetExtension(regionFile).ToLower();
693 bool isXml = extension.Equals(".xml");
694 bool isIni = extension.Equals(".ini");
695  
696 if (!isXml && !isIni)
697 {
698 MainConsole.Instance.Output("Usage: create region [\"region name\"] <region_file.ini>");
699 return;
700 }
701  
702 if (!Path.IsPathRooted(regionFile))
703 {
704 string regionsDir = ConfigSource.Source.Configs["Startup"].GetString("regionload_regionsdir", "Regions").Trim();
705 regionFile = Path.Combine(regionsDir, regionFile);
706 }
707  
708 RegionInfo regInfo;
709 if (isXml)
710 {
711 regInfo = new RegionInfo(regionName, regionFile, false, ConfigSource.Source);
712 }
713 else
714 {
715 regInfo = new RegionInfo(regionName, regionFile, false, ConfigSource.Source, regionName);
716 }
717  
718 Scene existingScene;
719 if (SceneManager.TryGetScene(regInfo.RegionID, out existingScene))
720 {
721 MainConsole.Instance.OutputFormat(
722 "ERROR: Cannot create region {0} with ID {1}, this ID is already assigned to region {2}",
723 regInfo.RegionName, regInfo.RegionID, existingScene.RegionInfo.RegionName);
724  
725 return;
726 }
727  
728 bool changed = PopulateRegionEstateInfo(regInfo);
729 IScene scene;
730 CreateRegion(regInfo, true, out scene);
731  
732 if (changed)
733 m_estateDataService.StoreEstateSettings(regInfo.EstateSettings);
734 }
735  
736 /// <summary>
737 /// Runs commands issued by the server console from the operator
738 /// </summary>
739 /// <param name="command">The first argument of the parameter (the command)</param>
740 /// <param name="cmdparams">Additional arguments passed to the command</param>
741 public void RunCommand(string module, string[] cmdparams)
742 {
743 List<string> args = new List<string>(cmdparams);
744 if (args.Count < 1)
745 return;
746  
747 string command = args[0];
748 args.RemoveAt(0);
749  
750 cmdparams = args.ToArray();
751  
752 switch (command)
753 {
754 case "backup":
755 MainConsole.Instance.Output("Triggering save of pending object updates to persistent store");
756 SceneManager.BackupCurrentScene();
757 break;
758  
759 case "remove-region":
760 string regRemoveName = CombineParams(cmdparams, 0);
761  
762 Scene removeScene;
763 if (SceneManager.TryGetScene(regRemoveName, out removeScene))
764 RemoveRegion(removeScene, false);
765 else
766 MainConsole.Instance.Output("No region with that name");
767 break;
768  
769 case "delete-region":
770 string regDeleteName = CombineParams(cmdparams, 0);
771  
772 Scene killScene;
773 if (SceneManager.TryGetScene(regDeleteName, out killScene))
774 RemoveRegion(killScene, true);
775 else
776 MainConsole.Instance.Output("no region with that name");
777 break;
778  
779 case "restart":
780 SceneManager.RestartCurrentScene();
781 break;
782 }
783 }
784  
785 /// <summary>
786 /// Change the currently selected region. The selected region is that operated upon by single region commands.
787 /// </summary>
788 /// <param name="cmdParams"></param>
789 protected void ChangeSelectedRegion(string module, string[] cmdparams)
790 {
791 if (cmdparams.Length > 2)
792 {
793 string newRegionName = CombineParams(cmdparams, 2);
794  
795 if (!SceneManager.TrySetCurrentScene(newRegionName))
796 MainConsole.Instance.Output(String.Format("Couldn't select region {0}", newRegionName));
797 else
798 RefreshPrompt();
799 }
800 else
801 {
802 MainConsole.Instance.Output("Usage: change region <region name>");
803 }
804 }
805  
806 /// <summary>
807 /// Refreshs prompt with the current selection details.
808 /// </summary>
809 private void RefreshPrompt()
810 {
811 string regionName = (SceneManager.CurrentScene == null ? "root" : SceneManager.CurrentScene.RegionInfo.RegionName);
812 MainConsole.Instance.Output(String.Format("Currently selected region is {0}", regionName));
813  
814 // m_log.DebugFormat("Original prompt is {0}", m_consolePrompt);
815 string prompt = m_consolePrompt;
816  
817 // Replace "\R" with the region name
818 // Replace "\\" with "\"
819 prompt = m_consolePromptRegex.Replace(prompt, m =>
820 {
821 // m_log.DebugFormat("Matched {0}", m.Groups[2].Value);
822 if (m.Groups[2].Value == "R")
823 return m.Groups[1].Value + regionName;
824 else
825 return m.Groups[0].Value;
826 });
827  
828 m_console.DefaultPrompt = prompt;
829 m_console.ConsoleScene = SceneManager.CurrentScene;
830 }
831  
832 protected override void HandleRestartRegion(RegionInfo whichRegion)
833 {
834 base.HandleRestartRegion(whichRegion);
835  
836 // Where we are restarting multiple scenes at once, a previous call to RefreshPrompt may have set the
837 // m_console.ConsoleScene to null (indicating all scenes).
838 if (m_console.ConsoleScene != null && whichRegion.RegionName == ((Scene)m_console.ConsoleScene).Name)
839 SceneManager.TrySetCurrentScene(whichRegion.RegionName);
840  
841 RefreshPrompt();
842 }
843  
844 // see BaseOpenSimServer
845 /// <summary>
846 /// Many commands list objects for debugging. Some of the types are listed here
847 /// </summary>
848 /// <param name="mod"></param>
849 /// <param name="cmd"></param>
850 public override void HandleShow(string mod, string[] cmd)
851 {
852 base.HandleShow(mod, cmd);
853  
854 List<string> args = new List<string>(cmd);
855 args.RemoveAt(0);
856 string[] showParams = args.ToArray();
857  
858 switch (showParams[0])
859 {
860 case "users":
861 IList agents;
862 if (showParams.Length > 1 && showParams[1] == "full")
863 {
864 agents = SceneManager.GetCurrentScenePresences();
865 } else
866 {
867 agents = SceneManager.GetCurrentSceneAvatars();
868 }
869  
870 MainConsole.Instance.Output(String.Format("\nAgents connected: {0}\n", agents.Count));
871  
872 MainConsole.Instance.Output(
873 String.Format("{0,-16} {1,-16} {2,-37} {3,-11} {4,-16} {5,-30}", "Firstname", "Lastname",
874 "Agent ID", "Root/Child", "Region", "Position")
875 );
876  
877 foreach (ScenePresence presence in agents)
878 {
879 RegionInfo regionInfo = presence.Scene.RegionInfo;
880 string regionName;
881  
882 if (regionInfo == null)
883 {
884 regionName = "Unresolvable";
885 } else
886 {
887 regionName = regionInfo.RegionName;
888 }
889  
890 MainConsole.Instance.Output(
891 String.Format(
892 "{0,-16} {1,-16} {2,-37} {3,-11} {4,-16} {5,-30}",
893 presence.Firstname,
894 presence.Lastname,
895 presence.UUID,
896 presence.IsChildAgent ? "Child" : "Root",
897 regionName,
898 presence.AbsolutePosition.ToString())
899 );
900 }
901  
902 MainConsole.Instance.Output(String.Empty);
903 break;
904  
905 case "connections":
906 HandleShowConnections();
907 break;
908  
909 case "circuits":
910 HandleShowCircuits();
911 break;
912  
913 case "modules":
914 SceneManager.ForEachSelectedScene(
915 scene =>
916 {
917 MainConsole.Instance.OutputFormat("Loaded region modules in {0} are:", scene.Name);
918  
919 List<IRegionModuleBase> sharedModules = new List<IRegionModuleBase>();
920 List<IRegionModuleBase> nonSharedModules = new List<IRegionModuleBase>();
921  
922 foreach (IRegionModuleBase module in scene.RegionModules.Values)
923 {
924 if (module.GetType().GetInterface("ISharedRegionModule") == null)
925 nonSharedModules.Add(module);
926 else
927 sharedModules.Add(module);
928 }
929  
930 foreach (IRegionModuleBase module in sharedModules.OrderBy(m => m.Name))
931 MainConsole.Instance.OutputFormat("New Region Module (Shared): {0}", module.Name);
932  
933 foreach (IRegionModuleBase module in nonSharedModules.OrderBy(m => m.Name))
934 MainConsole.Instance.OutputFormat("New Region Module (Non-Shared): {0}", module.Name);
935 }
936 );
937  
938 MainConsole.Instance.Output("");
939 break;
940  
941 case "regions":
942 ConsoleDisplayTable cdt = new ConsoleDisplayTable();
943 cdt.AddColumn("Name", ConsoleDisplayUtil.RegionNameSize);
944 cdt.AddColumn("ID", ConsoleDisplayUtil.UuidSize);
945 cdt.AddColumn("Position", ConsoleDisplayUtil.CoordTupleSize);
946 cdt.AddColumn("Size", 11);
947 cdt.AddColumn("Port", ConsoleDisplayUtil.PortSize);
948 cdt.AddColumn("Ready?", 6);
949 cdt.AddColumn("Estate", ConsoleDisplayUtil.EstateNameSize);
950 SceneManager.ForEachScene(
951 scene =>
952 {
953 RegionInfo ri = scene.RegionInfo;
954 cdt.AddRow(
955 ri.RegionName,
956 ri.RegionID,
957 string.Format("{0},{1}", ri.RegionLocX, ri.RegionLocY),
958 string.Format("{0}x{1}", ri.RegionSizeX, ri.RegionSizeY),
959 ri.InternalEndPoint.Port,
960 scene.Ready ? "Yes" : "No",
961 ri.EstateSettings.EstateName);
962 }
963 );
964  
965 MainConsole.Instance.Output(cdt.ToString());
966 break;
967  
968 case "ratings":
969 SceneManager.ForEachScene(
970 delegate(Scene scene)
971 {
972 string rating = "";
973 if (scene.RegionInfo.RegionSettings.Maturity == 1)
974 {
975 rating = "MATURE";
976 }
977 else if (scene.RegionInfo.RegionSettings.Maturity == 2)
978 {
979 rating = "ADULT";
980 }
981 else
982 {
983 rating = "PG";
984 }
985 MainConsole.Instance.Output(String.Format(
986 "Region Name: {0}, Region Rating {1}",
987 scene.RegionInfo.RegionName,
988 rating));
989 });
990 break;
991 }
992 }
993  
994 private void HandleShowCircuits()
995 {
996 ConsoleDisplayTable cdt = new ConsoleDisplayTable();
997 cdt.AddColumn("Region", 20);
998 cdt.AddColumn("Avatar name", 24);
999 cdt.AddColumn("Type", 5);
1000 cdt.AddColumn("Code", 10);
1001 cdt.AddColumn("IP", 16);
1002 cdt.AddColumn("Viewer Name", 24);
1003  
1004 SceneManager.ForEachScene(
1005 s =>
1006 {
1007 foreach (AgentCircuitData aCircuit in s.AuthenticateHandler.GetAgentCircuits().Values)
1008 cdt.AddRow(
1009 s.Name,
1010 aCircuit.Name,
1011 aCircuit.child ? "child" : "root",
1012 aCircuit.circuitcode.ToString(),
1013 aCircuit.IPAddress != null ? aCircuit.IPAddress.ToString() : "not set",
1014 Util.GetViewerName(aCircuit));
1015 });
1016  
1017 MainConsole.Instance.Output(cdt.ToString());
1018 }
1019  
1020 private void HandleShowConnections()
1021 {
1022 ConsoleDisplayTable cdt = new ConsoleDisplayTable();
1023 cdt.AddColumn("Region", 20);
1024 cdt.AddColumn("Avatar name", 24);
1025 cdt.AddColumn("Circuit code", 12);
1026 cdt.AddColumn("Endpoint", 23);
1027 cdt.AddColumn("Active?", 7);
1028  
1029 SceneManager.ForEachScene(
1030 s => s.ForEachClient(
1031 c => cdt.AddRow(
1032 s.Name,
1033 c.Name,
1034 c.CircuitCode.ToString(),
1035 c.RemoteEndPoint.ToString(),
1036 c.IsActive.ToString())));
1037  
1038 MainConsole.Instance.Output(cdt.ToString());
1039 }
1040  
1041 /// <summary>
1042 /// Use XML2 format to serialize data to a file
1043 /// </summary>
1044 /// <param name="module"></param>
1045 /// <param name="cmdparams"></param>
1046 protected void SavePrimsXml2(string module, string[] cmdparams)
1047 {
1048 if (cmdparams.Length > 5)
1049 {
1050 SceneManager.SaveNamedPrimsToXml2(cmdparams[3], cmdparams[4]);
1051 }
1052 else
1053 {
1054 SceneManager.SaveNamedPrimsToXml2("Primitive", DEFAULT_PRIM_BACKUP_FILENAME);
1055 }
1056 }
1057  
1058 /// <summary>
1059 /// Use XML format to serialize data to a file
1060 /// </summary>
1061 /// <param name="module"></param>
1062 /// <param name="cmdparams"></param>
1063 protected void SaveXml(string module, string[] cmdparams)
1064 {
1065 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.");
1066  
1067 if (cmdparams.Length > 0)
1068 {
1069 SceneManager.SaveCurrentSceneToXml(cmdparams[2]);
1070 }
1071 else
1072 {
1073 SceneManager.SaveCurrentSceneToXml(DEFAULT_PRIM_BACKUP_FILENAME);
1074 }
1075 }
1076  
1077 /// <summary>
1078 /// Loads data and region objects from XML format.
1079 /// </summary>
1080 /// <param name="module"></param>
1081 /// <param name="cmdparams"></param>
1082 protected void LoadXml(string module, string[] cmdparams)
1083 {
1084 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.");
1085  
1086 Vector3 loadOffset = new Vector3(0, 0, 0);
1087 if (cmdparams.Length > 2)
1088 {
1089 bool generateNewIDS = false;
1090 if (cmdparams.Length > 3)
1091 {
1092 if (cmdparams[3] == "-newUID")
1093 {
1094 generateNewIDS = true;
1095 }
1096 if (cmdparams.Length > 4)
1097 {
1098 loadOffset.X = (float)Convert.ToDecimal(cmdparams[4], Culture.NumberFormatInfo);
1099 if (cmdparams.Length > 5)
1100 {
1101 loadOffset.Y = (float)Convert.ToDecimal(cmdparams[5], Culture.NumberFormatInfo);
1102 }
1103 if (cmdparams.Length > 6)
1104 {
1105 loadOffset.Z = (float)Convert.ToDecimal(cmdparams[6], Culture.NumberFormatInfo);
1106 }
1107 MainConsole.Instance.Output(String.Format("loadOffsets <X,Y,Z> = <{0},{1},{2}>",loadOffset.X,loadOffset.Y,loadOffset.Z));
1108 }
1109 }
1110 SceneManager.LoadCurrentSceneFromXml(cmdparams[2], generateNewIDS, loadOffset);
1111 }
1112 else
1113 {
1114 try
1115 {
1116 SceneManager.LoadCurrentSceneFromXml(DEFAULT_PRIM_BACKUP_FILENAME, false, loadOffset);
1117 }
1118 catch (FileNotFoundException)
1119 {
1120 MainConsole.Instance.Output("Default xml not found. Usage: load-xml <filename>");
1121 }
1122 }
1123 }
1124 /// <summary>
1125 /// Serialize region data to XML2Format
1126 /// </summary>
1127 /// <param name="module"></param>
1128 /// <param name="cmdparams"></param>
1129 protected void SaveXml2(string module, string[] cmdparams)
1130 {
1131 if (cmdparams.Length > 2)
1132 {
1133 SceneManager.SaveCurrentSceneToXml2(cmdparams[2]);
1134 }
1135 else
1136 {
1137 SceneManager.SaveCurrentSceneToXml2(DEFAULT_PRIM_BACKUP_FILENAME);
1138 }
1139 }
1140  
1141 /// <summary>
1142 /// Load region data from Xml2Format
1143 /// </summary>
1144 /// <param name="module"></param>
1145 /// <param name="cmdparams"></param>
1146 protected void LoadXml2(string module, string[] cmdparams)
1147 {
1148 if (cmdparams.Length > 2)
1149 {
1150 try
1151 {
1152 SceneManager.LoadCurrentSceneFromXml2(cmdparams[2]);
1153 }
1154 catch (FileNotFoundException)
1155 {
1156 MainConsole.Instance.Output("Specified xml not found. Usage: load xml2 <filename>");
1157 }
1158 }
1159 else
1160 {
1161 try
1162 {
1163 SceneManager.LoadCurrentSceneFromXml2(DEFAULT_PRIM_BACKUP_FILENAME);
1164 }
1165 catch (FileNotFoundException)
1166 {
1167 MainConsole.Instance.Output("Default xml not found. Usage: load xml2 <filename>");
1168 }
1169 }
1170 }
1171  
1172 /// <summary>
1173 /// Load a whole region from an opensimulator archive.
1174 /// </summary>
1175 /// <param name="cmdparams"></param>
1176 protected void LoadOar(string module, string[] cmdparams)
1177 {
1178 try
1179 {
1180 SceneManager.LoadArchiveToCurrentScene(cmdparams);
1181 }
1182 catch (Exception e)
1183 {
1184 MainConsole.Instance.Output(e.Message);
1185 }
1186 }
1187  
1188 /// <summary>
1189 /// Save a region to a file, including all the assets needed to restore it.
1190 /// </summary>
1191 /// <param name="cmdparams"></param>
1192 protected void SaveOar(string module, string[] cmdparams)
1193 {
1194 SceneManager.SaveCurrentSceneToArchive(cmdparams);
1195 }
1196  
1197 protected void CreateEstateCommand(string module, string[] args)
1198 {
1199 string response = null;
1200 UUID userID;
1201  
1202 if (args.Length == 2)
1203 {
1204 response = "No user specified.";
1205 }
1206 else if (!UUID.TryParse(args[2], out userID))
1207 {
1208 response = String.Format("{0} is not a valid UUID", args[2]);
1209 }
1210 else if (args.Length == 3)
1211 {
1212 response = "No estate name specified.";
1213 }
1214 else
1215 {
1216 Scene scene = SceneManager.CurrentOrFirstScene;
1217  
1218 // TODO: Is there a better choice here?
1219 UUID scopeID = UUID.Zero;
1220 UserAccount account = scene.UserAccountService.GetUserAccount(scopeID, userID);
1221 if (account == null)
1222 {
1223 response = String.Format("Could not find user {0}", userID);
1224 }
1225 else
1226 {
1227 // concatenate it all to "name"
1228 StringBuilder sb = new StringBuilder(args[3]);
1229 for (int i = 4; i < args.Length; i++)
1230 sb.Append (" " + args[i]);
1231 string estateName = sb.ToString().Trim();
1232  
1233 // send it off for processing.
1234 IEstateModule estateModule = scene.RequestModuleInterface<IEstateModule>();
1235 response = estateModule.CreateEstate(estateName, userID);
1236 if (response == String.Empty)
1237 {
1238 List<int> estates = scene.EstateDataService.GetEstates(estateName);
1239 response = String.Format("Estate {0} created as \"{1}\"", estates.ElementAt(0), estateName);
1240 }
1241 }
1242 }
1243  
1244 // give the user some feedback
1245 if (response != null)
1246 MainConsole.Instance.Output(response);
1247 }
1248  
1249 protected void SetEstateOwnerCommand(string module, string[] args)
1250 {
1251 string response = null;
1252  
1253 Scene scene = SceneManager.CurrentOrFirstScene;
1254 IEstateModule estateModule = scene.RequestModuleInterface<IEstateModule>();
1255  
1256 if (args.Length == 3)
1257 {
1258 response = "No estate specified.";
1259 }
1260 else
1261 {
1262 int estateId;
1263 if (!int.TryParse(args[3], out estateId))
1264 {
1265 response = String.Format("\"{0}\" is not a valid ID for an Estate", args[3]);
1266 }
1267 else
1268 {
1269 if (args.Length == 4)
1270 {
1271 response = "No user specified.";
1272 }
1273 else
1274 {
1275 UserAccount account = null;
1276  
1277 // TODO: Is there a better choice here?
1278 UUID scopeID = UUID.Zero;
1279  
1280 string s1 = args[4];
1281 if (args.Length == 5)
1282 {
1283 // attempt to get account by UUID
1284 UUID u;
1285 if (UUID.TryParse(s1, out u))
1286 {
1287 account = scene.UserAccountService.GetUserAccount(scopeID, u);
1288 if (account == null)
1289 response = String.Format("Could not find user {0}", s1);
1290 }
1291 else
1292 {
1293 response = String.Format("Invalid UUID {0}", s1);
1294 }
1295 }
1296 else
1297 {
1298 // attempt to get account by Firstname, Lastname
1299 string s2 = args[5];
1300 account = scene.UserAccountService.GetUserAccount(scopeID, s1, s2);
1301 if (account == null)
1302 response = String.Format("Could not find user {0} {1}", s1, s2);
1303 }
1304  
1305 // If it's valid, send it off for processing.
1306 if (account != null)
1307 response = estateModule.SetEstateOwner(estateId, account);
1308  
1309 if (response == String.Empty)
1310 {
1311 response = String.Format("Estate owner changed to {0} ({1} {2})", account.PrincipalID, account.FirstName, account.LastName);
1312 }
1313 }
1314 }
1315 }
1316  
1317 // give the user some feedback
1318 if (response != null)
1319 MainConsole.Instance.Output(response);
1320 }
1321  
1322 protected void SetEstateNameCommand(string module, string[] args)
1323 {
1324 string response = null;
1325  
1326 Scene scene = SceneManager.CurrentOrFirstScene;
1327 IEstateModule estateModule = scene.RequestModuleInterface<IEstateModule>();
1328  
1329 if (args.Length == 3)
1330 {
1331 response = "No estate specified.";
1332 }
1333 else
1334 {
1335 int estateId;
1336 if (!int.TryParse(args[3], out estateId))
1337 {
1338 response = String.Format("\"{0}\" is not a valid ID for an Estate", args[3]);
1339 }
1340 else
1341 {
1342 if (args.Length == 4)
1343 {
1344 response = "No name specified.";
1345 }
1346 else
1347 {
1348 // everything after the estate ID is "name"
1349 StringBuilder sb = new StringBuilder(args[4]);
1350 for (int i = 5; i < args.Length; i++)
1351 sb.Append (" " + args[i]);
1352  
1353 string estateName = sb.ToString();
1354  
1355 // send it off for processing.
1356 response = estateModule.SetEstateName(estateId, estateName);
1357  
1358 if (response == String.Empty)
1359 {
1360 response = String.Format("Estate {0} renamed to \"{1}\"", estateId, estateName);
1361 }
1362 }
1363 }
1364 }
1365  
1366 // give the user some feedback
1367 if (response != null)
1368 MainConsole.Instance.Output(response);
1369 }
1370  
1371 private void EstateLinkRegionCommand(string module, string[] args)
1372 {
1373 int estateId =-1;
1374 UUID regionId = UUID.Zero;
1375 Scene scene = null;
1376 string response = null;
1377  
1378 if (args.Length == 3)
1379 {
1380 response = "No estate specified.";
1381 }
1382 else if (!int.TryParse(args [3], out estateId))
1383 {
1384 response = String.Format("\"{0}\" is not a valid ID for an Estate", args [3]);
1385 }
1386 else if (args.Length == 4)
1387 {
1388 response = "No region specified.";
1389 }
1390 else if (!UUID.TryParse(args[4], out regionId))
1391 {
1392 response = String.Format("\"{0}\" is not a valid UUID for a Region", args [4]);
1393 }
1394 else if (!SceneManager.TryGetScene(regionId, out scene))
1395 {
1396 // region may exist, but on a different sim.
1397 response = String.Format("No access to Region \"{0}\"", args [4]);
1398 }
1399  
1400 if (response != null)
1401 {
1402 MainConsole.Instance.Output(response);
1403 return;
1404 }
1405  
1406 // send it off for processing.
1407 IEstateModule estateModule = scene.RequestModuleInterface<IEstateModule>();
1408 response = estateModule.SetRegionEstate(scene.RegionInfo, estateId);
1409 if (response == String.Empty)
1410 {
1411 estateModule.TriggerRegionInfoChange();
1412 estateModule.sendRegionHandshakeToAll();
1413 response = String.Format ("Region {0} is now attached to estate {1}", regionId, estateId);
1414 }
1415  
1416 // give the user some feedback
1417 if (response != null)
1418 MainConsole.Instance.Output (response);
1419 }
1420  
1421 #endregion
1422  
1423 private static string CombineParams(string[] commandParams, int pos)
1424 {
1425 string result = String.Empty;
1426 for (int i = pos; i < commandParams.Length; i++)
1427 {
1428 result += commandParams[i] + " ";
1429 }
1430 result = result.TrimEnd(' ');
1431 return result;
1432 }
1433 }
1434 }