OpenSim
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros
GridService.cs
Go to the documentation of this file.
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.Generic;
30 using System.Net;
31 using System.Reflection;
32 using Nini.Config;
33 using log4net;
34 using OpenSim.Framework;
35 using OpenSim.Framework.Console;
36 using OpenSim.Data;
37 using OpenSim.Server.Base;
38 using OpenSim.Services.Interfaces;
40 using OpenMetaverse;
41 
42 namespace OpenSim.Services.GridService
43 {
45  {
46  private static readonly ILog m_log =
47  LogManager.GetLogger(
48  MethodBase.GetCurrentMethod().DeclaringType);
49  private string LogHeader = "[GRID SERVICE]";
50 
51  private bool m_DeleteOnUnregister = true;
52  private static GridService m_RootInstance = null;
53  protected IConfigSource m_config;
55 
56  protected IAuthenticationService m_AuthenticationService = null;
57  protected bool m_AllowDuplicateNames = false;
58  protected bool m_AllowHypergridMapSearch = false;
59 
60 
61  protected bool m_SuppressVarregionOverlapCheckOnRegistration = false;
62 
63  private static Dictionary<string,object> m_ExtraFeatures = new Dictionary<string, object>();
64 
65  public GridService(IConfigSource config)
66  : base(config)
67  {
68  m_log.DebugFormat("[GRID SERVICE]: Starting...");
69 
70  m_config = config;
71  IConfig gridConfig = config.Configs["GridService"];
72 
73  bool suppressConsoleCommands = false;
74 
75  if (gridConfig != null)
76  {
77  m_DeleteOnUnregister = gridConfig.GetBoolean("DeleteOnUnregister", true);
78 
79  string authService = gridConfig.GetString("AuthenticationService", String.Empty);
80 
81  if (authService != String.Empty)
82  {
83  Object[] args = new Object[] { config };
84  m_AuthenticationService = ServerUtils.LoadPlugin<IAuthenticationService>(authService, args);
85  }
86  m_AllowDuplicateNames = gridConfig.GetBoolean("AllowDuplicateNames", m_AllowDuplicateNames);
87  m_AllowHypergridMapSearch = gridConfig.GetBoolean("AllowHypergridMapSearch", m_AllowHypergridMapSearch);
88 
89  m_SuppressVarregionOverlapCheckOnRegistration = gridConfig.GetBoolean("SuppressVarregionOverlapCheckOnRegistration", m_SuppressVarregionOverlapCheckOnRegistration);
90 
91  // This service is also used locally by a simulator running in grid mode. This switches prevents
92  // inappropriate console commands from being registered
93  suppressConsoleCommands = gridConfig.GetBoolean("SuppressConsoleCommands", suppressConsoleCommands);
94  }
95 
96  if (m_RootInstance == null)
97  {
98  m_RootInstance = this;
99 
100  if (!suppressConsoleCommands && MainConsole.Instance != null)
101  {
102  MainConsole.Instance.Commands.AddCommand("Regions", true,
103  "deregister region id",
104  "deregister region id <region-id>+",
105  "Deregister a region manually.",
106  String.Empty,
107  HandleDeregisterRegion);
108 
109  MainConsole.Instance.Commands.AddCommand("Regions", true,
110  "show regions",
111  "show regions",
112  "Show details on all regions",
113  String.Empty,
114  HandleShowRegions);
115 
116  MainConsole.Instance.Commands.AddCommand("Regions", true,
117  "show region name",
118  "show region name <Region name>",
119  "Show details on a region",
120  String.Empty,
121  HandleShowRegion);
122 
123  MainConsole.Instance.Commands.AddCommand("Regions", true,
124  "show region at",
125  "show region at <x-coord> <y-coord>",
126  "Show details on a region at the given co-ordinate.",
127  "For example, show region at 1000 1000",
128  HandleShowRegionAt);
129 
130  MainConsole.Instance.Commands.AddCommand("General", true,
131  "show grid size",
132  "show grid size",
133  "Show the current grid size (excluding hyperlink references)",
134  String.Empty,
135  HandleShowGridSize);
136 
137  MainConsole.Instance.Commands.AddCommand("Regions", true,
138  "set region flags",
139  "set region flags <Region name> <flags>",
140  "Set database flags for region",
141  String.Empty,
142  HandleSetFlags);
143  }
144 
145  if (!suppressConsoleCommands)
146  SetExtraServiceURLs(config);
147 
148  m_HypergridLinker = new HypergridLinker(m_config, this, m_Database);
149  }
150  }
151 
152  private void SetExtraServiceURLs(IConfigSource config)
153  {
154  IConfig loginConfig = config.Configs["LoginService"];
155  IConfig gridConfig = config.Configs["GridService"];
156 
157  if (loginConfig == null || gridConfig == null)
158  return;
159 
160  string configVal;
161 
162  configVal = loginConfig.GetString("SearchURL", string.Empty);
163  if (!string.IsNullOrEmpty(configVal))
164  m_ExtraFeatures["search-server-url"] = configVal;
165 
166  configVal = loginConfig.GetString("MapTileURL", string.Empty);
167  if (!string.IsNullOrEmpty(configVal))
168  {
169  // This URL must end with '/', the viewer doesn't check
170  configVal = configVal.Trim();
171  if (!configVal.EndsWith("/"))
172  configVal = configVal + "/";
173  m_ExtraFeatures["map-server-url"] = configVal;
174  }
175 
176  configVal = loginConfig.GetString("DestinationGuide", string.Empty);
177  if (!string.IsNullOrEmpty(configVal))
178  m_ExtraFeatures["destination-guide-url"] = configVal;
179 
180  configVal = Util.GetConfigVarFromSections<string>(
181  config, "GatekeeperURI", new string[] { "Startup", "Hypergrid" }, String.Empty);
182  if (!string.IsNullOrEmpty(configVal))
183  m_ExtraFeatures["GridURL"] = configVal;
184 
185  configVal = Util.GetConfigVarFromSections<string>(
186  config, "GridName", new string[] { "Const", "Hypergrid" }, String.Empty);
187  if (string.IsNullOrEmpty(configVal))
188  configVal = Util.GetConfigVarFromSections<string>(
189  config, "gridname", new string[] { "GridInfo" }, String.Empty);
190  if (!string.IsNullOrEmpty(configVal))
191  m_ExtraFeatures["GridName"] = configVal;
192 
193  m_ExtraFeatures["ExportSupported"] = gridConfig.GetString("ExportSupported", "true");
194  }
195 
196  #region IGridService
197 
198  public string RegisterRegion(UUID scopeID, GridRegion regionInfos)
199  {
200  IConfig gridConfig = m_config.Configs["GridService"];
201 
202  if (regionInfos.RegionID == UUID.Zero)
203  return "Invalid RegionID - cannot be zero UUID";
204 
205  String reason = "Region overlaps another region";
206  // we should not need to check for overlaps
207 
208  RegionData region = m_Database.Get(regionInfos.RegionLocX, regionInfos.RegionLocY, scopeID);
209  if ((region != null) && (region.RegionID != regionInfos.RegionID))
210  {
211  // If not same ID and same coordinates, this new region has conflicts and can't be registered.
212  m_log.WarnFormat("{0} Register region conflict in scope {1}. {2}", LogHeader, scopeID, reason);
213  return reason;
214  }
215 
216  if (region != null)
217  {
218  // There is a preexisting record
219  //
220  // Get it's flags
221  //
222  OpenSim.Framework.RegionFlags rflags = (OpenSim.Framework.RegionFlags)Convert.ToInt32(region.Data["flags"]);
223 
224  // Is this a reservation?
225  //
226  if ((rflags & OpenSim.Framework.RegionFlags.Reservation) != 0)
227  {
228  // Regions reserved for the null key cannot be taken.
229  if ((string)region.Data["PrincipalID"] == UUID.Zero.ToString())
230  return "Region location is reserved";
231 
232  // Treat it as an auth request
233  //
234  // NOTE: Fudging the flags value here, so these flags
235  // should not be used elsewhere. Don't optimize
236  // this with the later retrieval of the same flags!
237  rflags |= OpenSim.Framework.RegionFlags.Authenticate;
238  }
239 
240  if ((rflags & OpenSim.Framework.RegionFlags.Authenticate) != 0)
241  {
242  // Can we authenticate at all?
243  //
244  if (m_AuthenticationService == null)
245  return "No authentication possible";
246 
247  if (!m_AuthenticationService.Verify(new UUID(region.Data["PrincipalID"].ToString()), regionInfos.Token, 30))
248  return "Bad authentication";
249  }
250  }
251 
252  // If we get here, the destination is clear. Now for the real check.
253 
254  if (!m_AllowDuplicateNames)
255  {
256  List<RegionData> dupe = m_Database.Get(Util.EscapeForLike(regionInfos.RegionName), scopeID);
257  if (dupe != null && dupe.Count > 0)
258  {
259  foreach (RegionData d in dupe)
260  {
261  if (d.RegionID != regionInfos.RegionID)
262  {
263  m_log.WarnFormat("[GRID SERVICE]: Region tried to register using a duplicate name. New region: {0} ({1}), existing region: {2} ({3}).",
264  regionInfos.RegionName, regionInfos.RegionID, d.RegionName, d.RegionID);
265  return "Duplicate region name";
266  }
267  }
268  }
269  }
270 
271  // If there is an old record for us, delete it if it is elsewhere.
272  region = m_Database.Get(regionInfos.RegionID, scopeID);
273  if ((region != null) && (region.RegionID == regionInfos.RegionID) &&
274  ((region.posX != regionInfos.RegionLocX) || (region.posY != regionInfos.RegionLocY)))
275  {
276  if ((Convert.ToInt32(region.Data["flags"]) & (int)OpenSim.Framework.RegionFlags.NoMove) != 0)
277  return "Can't move this region";
278 
279  if ((Convert.ToInt32(region.Data["flags"]) & (int)OpenSim.Framework.RegionFlags.LockedOut) != 0)
280  return "Region locked out";
281 
282  // Region reregistering in other coordinates. Delete the old entry
283  m_log.DebugFormat("[GRID SERVICE]: Region {0} ({1}) was previously registered at {2}-{3}. Deleting old entry.",
284  regionInfos.RegionName, regionInfos.RegionID, regionInfos.RegionLocX, regionInfos.RegionLocY);
285 
286  try
287  {
288  m_Database.Delete(regionInfos.RegionID);
289  }
290  catch (Exception e)
291  {
292  m_log.DebugFormat("[GRID SERVICE]: Database exception: {0}", e);
293  }
294  }
295 
296  // Everything is ok, let's register
297  RegionData rdata = RegionInfo2RegionData(regionInfos);
298  rdata.ScopeID = scopeID;
299 
300  if (region != null)
301  {
302  int oldFlags = Convert.ToInt32(region.Data["flags"]);
303 
304  oldFlags &= ~(int)OpenSim.Framework.RegionFlags.Reservation;
305 
306  rdata.Data["flags"] = oldFlags.ToString(); // Preserve flags
307  }
308  else
309  {
310  rdata.Data["flags"] = "0";
311  if ((gridConfig != null) && rdata.RegionName != string.Empty)
312  {
313  int newFlags = 0;
314  string regionName = rdata.RegionName.Trim().Replace(' ', '_');
315  newFlags = ParseFlags(newFlags, gridConfig.GetString("DefaultRegionFlags", String.Empty));
316  newFlags = ParseFlags(newFlags, gridConfig.GetString("Region_" + regionName, String.Empty));
317  newFlags = ParseFlags(newFlags, gridConfig.GetString("Region_" + rdata.RegionID.ToString(), String.Empty));
318  rdata.Data["flags"] = newFlags.ToString();
319  }
320  }
321 
322  int flags = Convert.ToInt32(rdata.Data["flags"]);
323  flags |= (int)OpenSim.Framework.RegionFlags.RegionOnline;
324  rdata.Data["flags"] = flags.ToString();
325 
326  try
327  {
328  rdata.Data["last_seen"] = Util.UnixTimeSinceEpoch();
329  m_Database.Store(rdata);
330  }
331  catch (Exception e)
332  {
333  m_log.DebugFormat("[GRID SERVICE]: Database exception: {0}", e);
334  }
335 
336  m_log.DebugFormat
337  ("[GRID SERVICE]: Region {0} ({1}, {2}x{3}) registered at {4},{5} with flags {6}",
338  regionInfos.RegionName, regionInfos.RegionID, regionInfos.RegionSizeX, regionInfos.RegionSizeY,
339  regionInfos.RegionCoordX, regionInfos.RegionCoordY,
341 
342  return String.Empty;
343  }
344 
355  private RegionData FindAnyConflictingRegion(GridRegion regionInfos, UUID scopeID, out string reason)
356  {
357  reason = "Reregistration";
358  // First see if there is an existing region right where this region is trying to go
359  // (We keep this result so it can be returned if suppressing errors)
360  RegionData noErrorRegion = m_Database.Get(regionInfos.RegionLocX, regionInfos.RegionLocY, scopeID);
361  RegionData region = noErrorRegion;
362  if (region != null
363  && region.RegionID == regionInfos.RegionID
364  && region.sizeX == regionInfos.RegionSizeX
365  && region.sizeY == regionInfos.RegionSizeY)
366  {
367  // If this seems to be exactly the same region, return this as it could be
368  // a re-registration (permissions checked by calling routine).
369  m_log.DebugFormat("{0} FindAnyConflictingRegion: re-register of {1}",
370  LogHeader, RegionString(regionInfos));
371  return region;
372  }
373 
374  // No region exactly there or we're resizing an existing region.
375  // Fetch regions that could be varregions overlapping requested location.
376  int xmin = regionInfos.RegionLocX - (int)Constants.MaximumRegionSize + 10;
377  int xmax = regionInfos.RegionLocX;
378  int ymin = regionInfos.RegionLocY - (int)Constants.MaximumRegionSize + 10;
379  int ymax = regionInfos.RegionLocY;
380  List<RegionData> rdatas = m_Database.Get(xmin, ymin, xmax, ymax, scopeID);
381  foreach (RegionData rdata in rdatas)
382  {
383  // m_log.DebugFormat("{0} FindAnyConflictingRegion: find existing. Checking {1}", LogHeader, RegionString(rdata) );
384  if ( (rdata.posX + rdata.sizeX > regionInfos.RegionLocX)
385  && (rdata.posY + rdata.sizeY > regionInfos.RegionLocY) )
386  {
387  region = rdata;
388  m_log.WarnFormat("{0} FindAnyConflictingRegion: conflict of {1} by existing varregion {2}",
389  LogHeader, RegionString(regionInfos), RegionString(region));
390  reason = String.Format("Region location is overlapped by existing varregion {0}",
391  RegionString(region));
392 
393  if (m_SuppressVarregionOverlapCheckOnRegistration)
394  region = noErrorRegion;
395  return region;
396  }
397  }
398 
399  // There isn't a region that overlaps this potential region.
400  // See if this potential region overlaps an existing region.
401  // First, a shortcut of not looking for overlap if new region is legacy region sized
402  // and connot overlap anything.
403  if (regionInfos.RegionSizeX != Constants.RegionSize
404  || regionInfos.RegionSizeY != Constants.RegionSize)
405  {
406  // trim range looked for so we don't pick up neighbor regions just off the edges
407  xmin = regionInfos.RegionLocX;
408  xmax = regionInfos.RegionLocX + regionInfos.RegionSizeX - 10;
409  ymin = regionInfos.RegionLocY;
410  ymax = regionInfos.RegionLocY + regionInfos.RegionSizeY - 10;
411  rdatas = m_Database.Get(xmin, ymin, xmax, ymax, scopeID);
412 
413  // If the region is being resized, the found region could be ourself.
414  foreach (RegionData rdata in rdatas)
415  {
416  // m_log.DebugFormat("{0} FindAnyConflictingRegion: see if overlap. Checking {1}", LogHeader, RegionString(rdata) );
417  if (region == null || region.RegionID != regionInfos.RegionID)
418  {
419  region = rdata;
420  m_log.WarnFormat("{0} FindAnyConflictingRegion: conflict of varregion {1} overlaps existing region {2}",
421  LogHeader, RegionString(regionInfos), RegionString(region));
422  reason = String.Format("Region {0} would overlap existing region {1}",
423  RegionString(regionInfos), RegionString(region));
424 
425  if (m_SuppressVarregionOverlapCheckOnRegistration)
426  region = noErrorRegion;
427  return region;
428  }
429  }
430  }
431 
432  // If we get here, region is either null (nothing found here) or
433  // is the non-conflicting region found at the location being requested.
434  return region;
435  }
436 
437  // String describing name and region location of passed region
438  private String RegionString(RegionData reg)
439  {
440  return String.Format("{0}/{1} at <{2},{3}>",
441  reg.RegionName, reg.RegionID, reg.coordX, reg.coordY);
442  }
443 
444  // String describing name and region location of passed region
445  private String RegionString(GridRegion reg)
446  {
447  return String.Format("{0}/{1} at <{2},{3}>",
448  reg.RegionName, reg.RegionID, reg.RegionCoordX, reg.RegionCoordY);
449  }
450 
451  public bool DeregisterRegion(UUID regionID)
452  {
453  RegionData region = m_Database.Get(regionID, UUID.Zero);
454  if (region == null)
455  return false;
456 
457  m_log.DebugFormat(
458  "[GRID SERVICE]: Deregistering region {0} ({1}) at {2}-{3}",
459  region.RegionName, region.RegionID, region.coordX, region.coordY);
460 
461  int flags = Convert.ToInt32(region.Data["flags"]);
462 
463  if ((!m_DeleteOnUnregister) || ((flags & (int)OpenSim.Framework.RegionFlags.Persistent) != 0))
464  {
465  flags &= ~(int)OpenSim.Framework.RegionFlags.RegionOnline;
466  region.Data["flags"] = flags.ToString();
467  region.Data["last_seen"] = Util.UnixTimeSinceEpoch();
468  try
469  {
470  m_Database.Store(region);
471  }
472  catch (Exception e)
473  {
474  m_log.DebugFormat("[GRID SERVICE]: Database exception: {0}", e);
475  }
476 
477  return true;
478  }
479 
480  return m_Database.Delete(regionID);
481  }
482 
483  public List<GridRegion> GetNeighbours(UUID scopeID, UUID regionID)
484  {
485  List<GridRegion> rinfos = new List<GridRegion>();
486  RegionData region = m_Database.Get(regionID, scopeID);
487 
488  if (region != null)
489  {
490  List<RegionData> rdatas = m_Database.Get(
491  region.posX - 1, region.posY - 1,
492  region.posX + region.sizeX + 1, region.posY + region.sizeY + 1, scopeID);
493 
494  foreach (RegionData rdata in rdatas)
495  {
496  if (rdata.RegionID != regionID)
497  {
498  int flags = Convert.ToInt32(rdata.Data["flags"]);
499  if ((flags & (int)Framework.RegionFlags.Hyperlink) == 0) // no hyperlinks as neighbours
500  rinfos.Add(RegionData2RegionInfo(rdata));
501  }
502  }
503 
504  // string rNames = "";
505  // foreach (GridRegion gr in rinfos)
506  // rNames += gr.RegionName + ",";
507  // m_log.DebugFormat("{0} region {1} has {2} neighbours ({3})",
508  // LogHeader, region.RegionName, rinfos.Count, rNames);
509  }
510  else
511  {
512  m_log.WarnFormat(
513  "[GRID SERVICE]: GetNeighbours() called for scope {0}, region {1} but no such region found",
514  scopeID, regionID);
515  }
516 
517  return rinfos;
518  }
519 
520  public GridRegion GetRegionByUUID(UUID scopeID, UUID regionID)
521  {
522  RegionData rdata = m_Database.Get(regionID, scopeID);
523  if (rdata != null)
524  return RegionData2RegionInfo(rdata);
525 
526  return null;
527  }
528 
529  // Get a region given its base coordinates.
530  // NOTE: this is NOT 'get a region by some point in the region'. The coordinate MUST
531  // be the base coordinate of the region.
532  // The snapping is technically unnecessary but is harmless because regions are always
533  // multiples of the legacy region size (256).
534 
535  public GridRegion GetRegionByPosition(UUID scopeID, int x, int y)
536  {
537  uint regionX = Util.WorldToRegionLoc((uint)x);
538  uint regionY = Util.WorldToRegionLoc((uint)y);
539  int snapX = (int)Util.RegionToWorldLoc(regionX);
540  int snapY = (int)Util.RegionToWorldLoc(regionY);
541 
542  RegionData rdata = m_Database.Get(snapX, snapY, scopeID);
543  if (rdata != null)
544  {
545  m_log.DebugFormat("{0} GetRegionByPosition. Found region {1} in database. Pos=<{2},{3}>",
546  LogHeader, rdata.RegionName, regionX, regionY);
547  return RegionData2RegionInfo(rdata);
548  }
549  else
550  {
551  m_log.DebugFormat("{0} GetRegionByPosition. Did not find region in database. Pos=<{1},{2}>",
552  LogHeader, regionX, regionY);
553  return null;
554  }
555  }
556 
557  public GridRegion GetRegionByName(UUID scopeID, string name)
558  {
559  List<RegionData> rdatas = m_Database.Get(Util.EscapeForLike(name), scopeID);
560  if ((rdatas != null) && (rdatas.Count > 0))
561  return RegionData2RegionInfo(rdatas[0]); // get the first
562 
563  if (m_AllowHypergridMapSearch)
564  {
565  GridRegion r = GetHypergridRegionByName(scopeID, name);
566  if (r != null)
567  return r;
568  }
569 
570  return null;
571  }
572 
573  public List<GridRegion> GetRegionsByName(UUID scopeID, string name, int maxNumber)
574  {
575 // m_log.DebugFormat("[GRID SERVICE]: GetRegionsByName {0}", name);
576 
577  List<RegionData> rdatas = m_Database.Get(Util.EscapeForLike(name) + "%", scopeID);
578 
579  int count = 0;
580  List<GridRegion> rinfos = new List<GridRegion>();
581 
582  if (rdatas != null)
583  {
584 // m_log.DebugFormat("[GRID SERVICE]: Found {0} regions", rdatas.Count);
585  foreach (RegionData rdata in rdatas)
586  {
587  if (count++ < maxNumber)
588  rinfos.Add(RegionData2RegionInfo(rdata));
589  }
590  }
591 
592  if (m_AllowHypergridMapSearch && (rdatas == null || (rdatas != null && rdatas.Count == 0)))
593  {
594  GridRegion r = GetHypergridRegionByName(scopeID, name);
595  if (r != null)
596  rinfos.Add(r);
597  }
598 
599  return rinfos;
600  }
601 
608  protected GridRegion GetHypergridRegionByName(UUID scopeID, string name)
609  {
610  if (name.Contains("."))
611  return m_HypergridLinker.LinkRegion(scopeID, name);
612  else
613  return null;
614  }
615 
616  public List<GridRegion> GetRegionRange(UUID scopeID, int xmin, int xmax, int ymin, int ymax)
617  {
618  int xminSnap = (int)(xmin / Constants.RegionSize) * (int)Constants.RegionSize;
619  int xmaxSnap = (int)(xmax / Constants.RegionSize) * (int)Constants.RegionSize;
620  int yminSnap = (int)(ymin / Constants.RegionSize) * (int)Constants.RegionSize;
621  int ymaxSnap = (int)(ymax / Constants.RegionSize) * (int)Constants.RegionSize;
622 
623  List<RegionData> rdatas = m_Database.Get(xminSnap, yminSnap, xmaxSnap, ymaxSnap, scopeID);
624  List<GridRegion> rinfos = new List<GridRegion>();
625  foreach (RegionData rdata in rdatas)
626  rinfos.Add(RegionData2RegionInfo(rdata));
627 
628  return rinfos;
629  }
630 
631  #endregion
632 
633  #region Data structure conversions
634 
636  {
637  RegionData rdata = new RegionData();
638  rdata.posX = (int)rinfo.RegionLocX;
639  rdata.posY = (int)rinfo.RegionLocY;
640  rdata.sizeX = rinfo.RegionSizeX;
641  rdata.sizeY = rinfo.RegionSizeY;
642  rdata.RegionID = rinfo.RegionID;
643  rdata.RegionName = rinfo.RegionName;
644  rdata.Data = rinfo.ToKeyValuePairs();
645  rdata.Data["regionHandle"] = Utils.UIntsToLong((uint)rdata.posX, (uint)rdata.posY);
646  rdata.Data["owner_uuid"] = rinfo.EstateOwner.ToString();
647  return rdata;
648  }
649 
651  {
652  GridRegion rinfo = new GridRegion(rdata.Data);
653  rinfo.RegionLocX = rdata.posX;
654  rinfo.RegionLocY = rdata.posY;
655  rinfo.RegionSizeX = rdata.sizeX;
656  rinfo.RegionSizeY = rdata.sizeY;
657  rinfo.RegionID = rdata.RegionID;
658  rinfo.RegionName = rdata.RegionName;
659  rinfo.ScopeID = rdata.ScopeID;
660 
661  return rinfo;
662  }
663 
664  #endregion
665 
666  public List<GridRegion> GetDefaultRegions(UUID scopeID)
667  {
668  List<GridRegion> ret = new List<GridRegion>();
669 
670  List<RegionData> regions = m_Database.GetDefaultRegions(scopeID);
671 
672  foreach (RegionData r in regions)
673  {
674  if ((Convert.ToInt32(r.Data["flags"]) & (int)OpenSim.Framework.RegionFlags.RegionOnline) != 0)
675  ret.Add(RegionData2RegionInfo(r));
676  }
677 
678  m_log.DebugFormat("[GRID SERVICE]: GetDefaultRegions returning {0} regions", ret.Count);
679  return ret;
680  }
681 
682  public List<GridRegion> GetDefaultHypergridRegions(UUID scopeID)
683  {
684  List<GridRegion> ret = new List<GridRegion>();
685 
686  List<RegionData> regions = m_Database.GetDefaultHypergridRegions(scopeID);
687 
688  foreach (RegionData r in regions)
689  {
690  if ((Convert.ToInt32(r.Data["flags"]) & (int)OpenSim.Framework.RegionFlags.RegionOnline) != 0)
691  ret.Add(RegionData2RegionInfo(r));
692  }
693 
694  int hgDefaultRegionsFoundOnline = regions.Count;
695 
696  // For now, hypergrid default regions will always be given precedence but we will also return simple default
697  // regions in case no specific hypergrid regions are specified.
698  ret.AddRange(GetDefaultRegions(scopeID));
699 
700  int normalDefaultRegionsFoundOnline = ret.Count - hgDefaultRegionsFoundOnline;
701 
702  m_log.DebugFormat(
703  "[GRID SERVICE]: GetDefaultHypergridRegions returning {0} hypergrid default and {1} normal default regions",
704  hgDefaultRegionsFoundOnline, normalDefaultRegionsFoundOnline);
705 
706  return ret;
707  }
708 
709  public List<GridRegion> GetFallbackRegions(UUID scopeID, int x, int y)
710  {
711  List<GridRegion> ret = new List<GridRegion>();
712 
713  List<RegionData> regions = m_Database.GetFallbackRegions(scopeID, x, y);
714 
715  foreach (RegionData r in regions)
716  {
717  if ((Convert.ToInt32(r.Data["flags"]) & (int)OpenSim.Framework.RegionFlags.RegionOnline) != 0)
718  ret.Add(RegionData2RegionInfo(r));
719  }
720 
721  m_log.DebugFormat("[GRID SERVICE]: Fallback returned {0} regions", ret.Count);
722  return ret;
723  }
724 
725  public List<GridRegion> GetHyperlinks(UUID scopeID)
726  {
727  List<GridRegion> ret = new List<GridRegion>();
728 
729  List<RegionData> regions = m_Database.GetHyperlinks(scopeID);
730 
731  foreach (RegionData r in regions)
732  {
733  if ((Convert.ToInt32(r.Data["flags"]) & (int)OpenSim.Framework.RegionFlags.RegionOnline) != 0)
734  ret.Add(RegionData2RegionInfo(r));
735  }
736 
737  m_log.DebugFormat("[GRID SERVICE]: Hyperlinks returned {0} regions", ret.Count);
738  return ret;
739  }
740 
741  public int GetRegionFlags(UUID scopeID, UUID regionID)
742  {
743  RegionData region = m_Database.Get(regionID, scopeID);
744 
745  if (region != null)
746  {
747  int flags = Convert.ToInt32(region.Data["flags"]);
748  //m_log.DebugFormat("[GRID SERVICE]: Request for flags of {0}: {1}", regionID, flags);
749  return flags;
750  }
751  else
752  return -1;
753  }
754 
755  private void HandleDeregisterRegion(string module, string[] cmd)
756  {
757  if (cmd.Length < 4)
758  {
759  MainConsole.Instance.Output("Usage: degregister region id <region-id>+");
760  return;
761  }
762 
763  for (int i = 3; i < cmd.Length; i++)
764  {
765  string rawRegionUuid = cmd[i];
766  UUID regionUuid;
767 
768  if (!UUID.TryParse(rawRegionUuid, out regionUuid))
769  {
770  MainConsole.Instance.OutputFormat("{0} is not a valid region uuid", rawRegionUuid);
771  return;
772  }
773 
774  GridRegion region = GetRegionByUUID(UUID.Zero, regionUuid);
775 
776  if (region == null)
777  {
778  MainConsole.Instance.OutputFormat("No region with UUID {0}", regionUuid);
779  return;
780  }
781 
782  if (DeregisterRegion(regionUuid))
783  {
784  MainConsole.Instance.OutputFormat("Deregistered {0} {1}", region.RegionName, regionUuid);
785  }
786  else
787  {
788  // I don't think this can ever occur if we know that the region exists.
789  MainConsole.Instance.OutputFormat("Error deregistering {0} {1}", region.RegionName, regionUuid);
790  }
791  }
792  }
793 
794  private void HandleShowRegions(string module, string[] cmd)
795  {
796  if (cmd.Length != 2)
797  {
798  MainConsole.Instance.Output("Syntax: show regions");
799  return;
800  }
801 
802  List<RegionData> regions = m_Database.Get(int.MinValue, int.MinValue, int.MaxValue, int.MaxValue, UUID.Zero);
803 
804  OutputRegionsToConsoleSummary(regions);
805  }
806 
807  private void HandleShowGridSize(string module, string[] cmd)
808  {
809  List<RegionData> regions = m_Database.Get(int.MinValue, int.MinValue, int.MaxValue, int.MaxValue, UUID.Zero);
810 
811  double size = 0;
812 
813  foreach (RegionData region in regions)
814  {
815  int flags = Convert.ToInt32(region.Data["flags"]);
816 
817  if ((flags & (int)Framework.RegionFlags.Hyperlink) == 0)
818  size += region.sizeX * region.sizeY;
819  }
820 
821  MainConsole.Instance.Output("This is a very rough approximation.");
822  MainConsole.Instance.Output("Although it will not count regions that are actually links to others over the Hypergrid, ");
823  MainConsole.Instance.Output("it will count regions that are inactive but were not deregistered from the grid service");
824  MainConsole.Instance.Output("(e.g. simulator crashed rather than shutting down cleanly).\n");
825 
826  MainConsole.Instance.OutputFormat("Grid size: {0} km squared.", size / 1000000);
827  }
828 
829  private void HandleShowRegion(string module, string[] cmd)
830  {
831  if (cmd.Length != 4)
832  {
833  MainConsole.Instance.Output("Syntax: show region name <region name>");
834  return;
835  }
836 
837  string regionName = cmd[3];
838 
839  List<RegionData> regions = m_Database.Get(Util.EscapeForLike(regionName), UUID.Zero);
840  if (regions == null || regions.Count < 1)
841  {
842  MainConsole.Instance.Output("No region with name {0} found", regionName);
843  return;
844  }
845 
846  OutputRegionsToConsole(regions);
847  }
848 
849  private void HandleShowRegionAt(string module, string[] cmd)
850  {
851  if (cmd.Length != 5)
852  {
853  MainConsole.Instance.Output("Syntax: show region at <x-coord> <y-coord>");
854  return;
855  }
856 
857  uint x, y;
858  if (!uint.TryParse(cmd[3], out x))
859  {
860  MainConsole.Instance.Output("x-coord must be an integer");
861  return;
862  }
863 
864  if (!uint.TryParse(cmd[4], out y))
865  {
866  MainConsole.Instance.Output("y-coord must be an integer");
867  return;
868  }
869 
870 
871  RegionData region = m_Database.Get((int)Util.RegionToWorldLoc(x), (int)Util.RegionToWorldLoc(y), UUID.Zero);
872 
873  if (region == null)
874  {
875  MainConsole.Instance.OutputFormat("No region found at {0},{1}", x, y);
876  return;
877  }
878 
879  OutputRegionToConsole(region);
880  }
881 
882  private void OutputRegionToConsole(RegionData r)
883  {
884  OpenSim.Framework.RegionFlags flags = (OpenSim.Framework.RegionFlags)Convert.ToInt32(r.Data["flags"]);
885 
886  ConsoleDisplayList dispList = new ConsoleDisplayList();
887  dispList.AddRow("Region Name", r.RegionName);
888  dispList.AddRow("Region ID", r.RegionID);
889  dispList.AddRow("Location", string.Format("{0},{1}", r.coordX, r.coordY));
890  dispList.AddRow("Size", string.Format("{0}x{1}", r.sizeX, r.sizeY));
891  dispList.AddRow("URI", r.Data["serverURI"]);
892  dispList.AddRow("Owner ID", r.Data["owner_uuid"]);
893  dispList.AddRow("Flags", flags);
894 
895  MainConsole.Instance.Output(dispList.ToString());
896  }
897 
898  private void OutputRegionsToConsole(List<RegionData> regions)
899  {
900  foreach (RegionData r in regions)
901  OutputRegionToConsole(r);
902  }
903 
904  private void OutputRegionsToConsoleSummary(List<RegionData> regions)
905  {
906  ConsoleDisplayTable dispTable = new ConsoleDisplayTable();
907  dispTable.AddColumn("Name", 44);
908  dispTable.AddColumn("ID", 36);
909  dispTable.AddColumn("Position", 11);
910  dispTable.AddColumn("Size", 11);
911  dispTable.AddColumn("Flags", 60);
912 
913  foreach (RegionData r in regions)
914  {
915  OpenSim.Framework.RegionFlags flags = (OpenSim.Framework.RegionFlags)Convert.ToInt32(r.Data["flags"]);
916  dispTable.AddRow(
917  r.RegionName,
918  r.RegionID.ToString(),
919  string.Format("{0},{1}", r.coordX, r.coordY),
920  string.Format("{0}x{1}", r.sizeX, r.sizeY),
921  flags.ToString());
922  }
923 
924  MainConsole.Instance.Output(dispTable.ToString());
925  }
926 
927  private int ParseFlags(int prev, string flags)
928  {
930 
931  string[] parts = flags.Split(new char[] {',', ' '}, StringSplitOptions.RemoveEmptyEntries);
932 
933  foreach (string p in parts)
934  {
935  int val;
936 
937  try
938  {
939  if (p.StartsWith("+"))
940  {
941  val = (int)Enum.Parse(typeof(OpenSim.Framework.RegionFlags), p.Substring(1));
943  }
944  else if (p.StartsWith("-"))
945  {
946  val = (int)Enum.Parse(typeof(OpenSim.Framework.RegionFlags), p.Substring(1));
948  }
949  else
950  {
951  val = (int)Enum.Parse(typeof(OpenSim.Framework.RegionFlags), p);
953  }
954  }
955  catch (Exception)
956  {
957  MainConsole.Instance.Output("Error in flag specification: " + p);
958  }
959  }
960 
961  return (int)f;
962  }
963 
964  private void HandleSetFlags(string module, string[] cmd)
965  {
966  if (cmd.Length < 5)
967  {
968  MainConsole.Instance.Output("Syntax: set region flags <region name> <flags>");
969  return;
970  }
971 
972  List<RegionData> regions = m_Database.Get(Util.EscapeForLike(cmd[3]), UUID.Zero);
973  if (regions == null || regions.Count < 1)
974  {
975  MainConsole.Instance.Output("Region not found");
976  return;
977  }
978 
979  foreach (RegionData r in regions)
980  {
981  int flags = Convert.ToInt32(r.Data["flags"]);
982  flags = ParseFlags(flags, cmd[4]);
983  r.Data["flags"] = flags.ToString();
985 
986  MainConsole.Instance.Output(String.Format("Set region {0} to {1}", r.RegionName, f));
987  m_Database.Store(r);
988  }
989  }
990 
999  public Dictionary<string,object> GetExtraFeatures()
1000  {
1001  return m_ExtraFeatures;
1002  }
1003  }
1004 }
Used to generated a formatted table for the console.
int posX
The position in meters of this region.
Definition: IRegionData.cs:44
List< GridRegion > GetNeighbours(UUID scopeID, UUID regionID)
Get information about the regions neighbouring the given co-ordinates (in meters).
Definition: GridService.cs:483
const uint MaximumRegionSize
Definition: Constants.cs:39
Used to generated a formatted table for the console.
int coordX
Return the x-coordinate of this region in region units.
Definition: IRegionData.cs:57
string RegisterRegion(UUID scopeID, GridRegion regionInfos)
Register a region with the grid service.
Definition: GridService.cs:198
List< GridRegion > GetDefaultRegions(UUID scopeID)
Definition: GridService.cs:666
GridRegion GetRegionByName(UUID scopeID, string name)
Get information about a region which exactly matches the name given.
Definition: GridService.cs:557
RegionData RegionInfo2RegionData(GridRegion rinfo)
Definition: GridService.cs:635
Dictionary< string, object > GetExtraFeatures()
Gets the grid extra service URls we wish for the region to send in OpenSimExtras to dynamically refre...
Definition: GridService.cs:999
List< GridRegion > GetRegionRange(UUID scopeID, int xmin, int xmax, int ymin, int ymax)
Definition: GridService.cs:616
List< GridRegion > GetRegionsByName(UUID scopeID, string name, int maxNumber)
Get information about regions starting with the provided name.
Definition: GridService.cs:573
int GetRegionFlags(UUID scopeID, UUID regionID)
Get internal OpenSimulator region flags.
Definition: GridService.cs:741
int posY
The position in meters of this region.
Definition: IRegionData.cs:49
Dictionary< string, object > Data
Definition: IRegionData.cs:64
int RegionLocX
The location of this region in meters. DANGER DANGER! Note that this name means something different i...
bool DeregisterRegion(UUID regionID)
Deregister a region with the grid service.
Definition: GridService.cs:451
List< GridRegion > GetDefaultHypergridRegions(UUID scopeID)
Definition: GridService.cs:682
RegionFlags
Region flags used internally by OpenSimulator to store installation specific information about region...
Definition: RegionFlags.cs:40
static ICommandConsole Instance
Definition: MainConsole.cs:35
int RegionLocY
The location of this region in meters. DANGER DANGER! Note that this name means something different i...
List< GridRegion > GetFallbackRegions(UUID scopeID, int x, int y)
Definition: GridService.cs:709
GridRegion GetHypergridRegionByName(UUID scopeID, string name)
Get a hypergrid region.
Definition: GridService.cs:608
Interactive OpenSim region server
Definition: OpenSim.cs:55
int coordY
Return the y-coordinate of this region in region units.
Definition: IRegionData.cs:62
static HypergridLinker m_HypergridLinker
Definition: GridService.cs:54
GridRegion GetRegionByUUID(UUID scopeID, UUID regionID)
Definition: GridService.cs:520
GridRegion RegionData2RegionInfo(RegionData rdata)
Definition: GridService.cs:650
OpenSim.Services.Interfaces.GridRegion GridRegion
Definition: GridService.cs:39
GridRegion GetRegionByPosition(UUID scopeID, int x, int y)
Get the region at the given position (in meters)
Definition: GridService.cs:535
List< GridRegion > GetHyperlinks(UUID scopeID)
Definition: GridService.cs:725