/Aurora/Services/DataService/Connectors/Database/Grid/LocalGridConnector.cs
C# | 594 lines | 478 code | 90 blank | 26 comment | 77 complexity | 37851c40ef8962a3ef5173a7270762d0 MD5 | raw file
1/* 2 * Copyright (c) Contributors, http://aurora-sim.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 Aurora-Sim 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 28using Aurora.Framework; 29using Aurora.Framework.ConsoleFramework; 30using Aurora.Framework.DatabaseInterfaces; 31using Aurora.Framework.Modules; 32using Aurora.Framework.SceneInfo; 33using Aurora.Framework.Services; 34using Aurora.Framework.Utilities; 35using Nini.Config; 36using OpenMetaverse; 37using OpenMetaverse.StructuredData; 38using System; 39using System.Collections.Generic; 40using GridRegion = Aurora.Framework.Services.GridRegion; 41using RegionFlags = Aurora.Framework.Services.RegionFlags; 42 43namespace Aurora.Services.DataService 44{ 45 public class LocalGridConnector : IRegionData 46 { 47 private IGenericData GD; 48 private string m_realm = "gridregions"; 49 50 #region IRegionData Members 51 52 public void Initialize(IGenericData GenericData, IConfigSource source, IRegistryCore simBase, 53 string defaultConnectionString) 54 { 55 if (source.Configs["AuroraConnectors"].GetString("GridConnector", "LocalConnector") == "LocalConnector") 56 { 57 GD = GenericData; 58 59 string connectionString = (source.Configs[Name] != null) 60 ? connectionString = 61 source.Configs[Name].GetString("ConnectionString", 62 defaultConnectionString) 63 : defaultConnectionString; 64 65 if (GD != null) 66 GD.ConnectToDatabase(connectionString, "GridRegions", 67 source.Configs["AuroraConnectors"].GetBoolean("ValidateTables", true)); 68 69 Framework.Utilities.DataManager.RegisterPlugin(this); 70 71 if (MainConsole.Instance != null) 72 { 73 MainConsole.Instance.Commands.AddCommand("fix missing region owner", "fix missing region owner", 74 "Attempts to fix missing region owners in the database.", 75 delegate(string[] cmd) { FixMissingRegionOwners(); }); 76 } 77 } 78 } 79 80 public string Name 81 { 82 get { return "IRegionData"; } 83 } 84 85 private void FixMissingRegionOwners() 86 { 87 QueryFilter filter = new QueryFilter(); 88 filter.andFilters["OwnerUUID"] = UUID.Zero; 89 90 List<GridRegion> borked = ParseQuery(null, GD.Query(new string[1] {"*"}, m_realm, filter, null, null, null)); 91 92 if (borked.Count < 1) 93 { 94 MainConsole.Instance.Debug("[LocalGridConnector] No regions found with missing owners."); 95 } 96 IEstateConnector estatePlugin = Framework.Utilities.DataManager.RequestPlugin<IEstateConnector>(); 97 98 if (estatePlugin == null) 99 { 100 MainConsole.Instance.Error("[LocalGridConnector] " + borked.Count + 101 " regions found with missing owners, but could not get IEstateConnector plugin."); 102 return; 103 } 104 else 105 { 106 MainConsole.Instance.Error("[LocalGridConnector] " + borked.Count + 107 " regions found with missing owners, attempting fix."); 108 } 109 110 Dictionary<int, List<GridRegion>> borkedByEstate = new Dictionary<int, List<GridRegion>>(); 111 foreach (GridRegion region in borked) 112 { 113 int estateID = estatePlugin.GetEstateID(region.RegionID); 114 if (!borkedByEstate.ContainsKey(estateID)) 115 { 116 borkedByEstate[estateID] = new List<GridRegion>(); 117 } 118 borkedByEstate[estateID].Add(region); 119 } 120 121 Dictionary<int, UUID> estateOwnerIDs = new Dictionary<int, UUID>(); 122 uint estateFail = 0; 123 foreach (int estateID in borkedByEstate.Keys) 124 { 125 EstateSettings es = estatePlugin.GetEstateSettings(estateID); 126 if (es == null) 127 { 128 MainConsole.Instance.Error("[LocalGridConnector] Cannot fix missing owner for regions in Estate " + 129 estateID + ", could not get estate settings."); 130 } 131 else if (es.EstateOwner == UUID.Zero) 132 { 133 MainConsole.Instance.Error("[LocalGridConnector] Cannot fix missing owner for regions in Estate " + 134 estateID + ", Estate Owner is also missing."); 135 } 136 if (es == null || es.EstateOwner == UUID.Zero) 137 { 138 ++estateFail; 139 continue; 140 } 141 estateOwnerIDs[estateID] = es.EstateOwner; 142 } 143 144 if (estateFail > 0) 145 { 146 if (estateFail == borkedByEstate.Count) 147 { 148 MainConsole.Instance.Error("[LocalGridConnector] " + borked.Count + 149 " regions found with missing owners, could not locate any estate settings from IEstateConnector plugin."); 150 return; 151 } 152 else 153 { 154 MainConsole.Instance.Error("[LocalGridConnector] " + borked.Count + 155 " regions found with missing owners, could not locate estate settings for " + 156 estateFail + " estates."); 157 } 158 } 159 160 uint storeSuccess = 0; 161 uint storeFail = 0; 162 int borkedCount = borked.Count; 163 foreach (KeyValuePair<int, UUID> kvp in estateOwnerIDs) 164 { 165 List<GridRegion> regions = borkedByEstate[kvp.Key]; 166 foreach (GridRegion region in regions) 167 { 168 region.EstateOwner = kvp.Value; 169 if (!Store(region)) 170 { 171 MainConsole.Instance.Error("[LocalGridConnector] Failed to fix missing region for " + 172 region.RegionName + " (" + region.RegionID + ")"); 173 ++storeFail; 174 } 175 else 176 { 177 ++storeSuccess; 178 borked.Remove(region); 179 } 180 } 181 } 182 183 if (storeFail > 0) 184 { 185 MainConsole.Instance.Error("[LocalGridConnector] " + borkedCount + 186 " regions found with missing owners, fix failed on " + storeFail + 187 " regions, fix attempted on " + storeSuccess + " regions."); 188 } 189 else if (storeSuccess != borked.Count) 190 { 191 MainConsole.Instance.Error("[LocalGridConnector] " + borkedCount + 192 " regions found with missing owners, fix attempted on " + storeSuccess + 193 " regions."); 194 } 195 else 196 { 197 MainConsole.Instance.Info( 198 "[LocalGridConnector] All regions found with missing owners should have their owners restored."); 199 } 200 if (borked.Count > 0) 201 { 202 List<string> blurbs = new List<string>(borked.Count); 203 foreach (GridRegion region in borked) 204 { 205 blurbs.Add(region.RegionName + " (" + region.RegionID + ")"); 206 } 207 MainConsole.Instance.Info("[LocalGridConnector] Failed to fix missing region owners for regions " + 208 string.Join(", ", blurbs.ToArray())); 209 } 210 } 211 212 public uint GetCount(string regionName, List<UUID> scopeIDs) 213 { 214 QueryFilter filter = new QueryFilter(); 215 filter.andLikeFilters["RegionName"] = regionName; 216 217 return uint.Parse(GD.Query(new[] {"COUNT(*)"}, m_realm, filter, null, null, null)[0]); 218 } 219 220 public List<GridRegion> Get(string regionName, List<UUID> scopeIDs, uint? start, uint? count) 221 { 222 QueryFilter filter = new QueryFilter(); 223 filter.andLikeFilters["RegionName"] = regionName; 224 225 List<string> query = GD.Query(new string[1] {"*"}, m_realm, filter, null, start, count); 226 227 return (query.Count == 0) ? null : ParseQuery(scopeIDs, query); 228 } 229 230 public List<GridRegion> Get(RegionFlags flags) 231 { 232 QueryFilter filter = new QueryFilter(); 233 filter.andBitfieldAndFilters["Flags"] = (uint) flags; 234 return ParseQuery(null, GD.Query(new string[1] {"*"}, m_realm, filter, null, null, null)); 235 } 236 237 public GridRegion GetZero(int posX, int posY, List<UUID> scopeIDs) 238 { 239 QueryFilter filter = new QueryFilter(); 240 filter.andFilters["LocX"] = posX; 241 filter.andFilters["LocY"] = posY; 242 243 List<string> query = GD.Query(new string[1] {"*"}, m_realm, filter, null, null, null); 244 245 return (query.Count == 0) ? null : ParseQuery(scopeIDs, query)[0]; 246 } 247 248 public List<GridRegion> Get(int posX, int posY, List<UUID> scopeIDs) 249 { 250 QueryFilter filter = new QueryFilter(); 251 filter.andFilters["LocX"] = posX; 252 filter.andFilters["LocY"] = posY; 253 254 Dictionary<string, bool> sort = new Dictionary<string, bool>(1); 255 sort["LocZ"] = true; 256 257 return ParseQuery(scopeIDs, GD.Query(new string[1] {"*"}, m_realm, filter, sort, null, null)); 258 } 259 260 public GridRegion Get(UUID regionID, List<UUID> scopeIDs) 261 { 262 List<string> query; 263 Dictionary<string, object> where = new Dictionary<string, object>(); 264 265 where["RegionUUID"] = regionID; 266 267 query = GD.Query(new string[1] {"*"}, m_realm, new QueryFilter 268 { 269 andFilters = where 270 }, null, null, null); 271 272 return (query.Count == 0) ? null : ParseQuery(scopeIDs, query)[0]; 273 } 274 275 public List<GridRegion> Get(int startX, int startY, int endX, int endY, List<UUID> scopeIDs) 276 { 277 int foo; 278 if (startX > endX) 279 { 280 foo = endX; 281 endX = startX; 282 startX = foo; 283 } 284 if (startY > endY) 285 { 286 foo = endY; 287 endY = startY; 288 startY = foo; 289 } 290 QueryFilter filter = new QueryFilter(); 291 filter.andGreaterThanEqFilters["LocX"] = startX; 292 filter.andLessThanEqFilters["LocX"] = endX; 293 filter.andGreaterThanEqFilters["LocY"] = startY; 294 filter.andLessThanEqFilters["LocY"] = endY; 295 296 return ParseQuery(scopeIDs, GD.Query(new string[1] {"*"}, m_realm, filter, null, null, null)); 297 } 298 299 public List<GridRegion> Get(RegionFlags flags, Dictionary<string, bool> sort) 300 { 301 return Get(flags, 0, null, null, sort); 302 } 303 304 public List<GridRegion> Get(uint start, uint count, uint estateID, RegionFlags flags, 305 Dictionary<string, bool> sort) 306 { 307 List<GridRegion> resp = new List<GridRegion>(); 308 IEstateConnector estates = Framework.Utilities.DataManager.RequestPlugin<IEstateConnector>(); 309 310 if (count == 0 || estates == null) 311 { 312 return resp; 313 } 314 315 EstateSettings es = estates.GetEstateSettings((int) estateID); 316 317 QueryFilter filter = new QueryFilter(); 318 filter.andBitfieldAndFilters["Flags"] = (uint) flags; 319 320 while (resp.Count < count) 321 { 322 uint limit = count - (uint) resp.Count; 323 List<GridRegion> query = ParseQuery(null, 324 GD.Query(new string[] {"*"}, m_realm, filter, sort, start, count)); 325 326 if (query.Count == 0) 327 { 328 break; 329 } 330 331 query.ForEach(delegate(GridRegion region) 332 { 333 if (region.EstateOwner == es.EstateOwner && 334 estates.GetEstateID(region.RegionID) == es.EstateID) 335 { 336 resp.Add(region); 337 } 338 }); 339 340 start += limit; 341 } 342 343 return resp; 344 } 345 346 public List<GridRegion> Get(RegionFlags includeFlags, RegionFlags excludeFlags, uint? start, uint? count, 347 Dictionary<string, bool> sort) 348 { 349 QueryFilter filter = new QueryFilter(); 350 if (includeFlags > 0) 351 { 352 filter.andBitfieldAndFilters["Flags"] = (uint) includeFlags; 353 } 354 if (excludeFlags > 0) 355 { 356 filter.andBitfieldNandFilters["Flags"] = (uint) excludeFlags; 357 } 358 359 return ParseQuery(null, GD.Query(new string[1] {"*"}, m_realm, filter, sort, start, count)); 360 } 361 362 public uint Count(RegionFlags includeFlags, RegionFlags excludeFlags) 363 { 364 QueryFilter filter = new QueryFilter(); 365 if (includeFlags > 0) 366 { 367 filter.andBitfieldAndFilters["Flags"] = (uint) includeFlags; 368 } 369 if (excludeFlags > 0) 370 { 371 filter.andBitfieldNandFilters["Flags"] = (uint) excludeFlags; 372 } 373 374 return uint.Parse(GD.Query(new string[1] {"COUNT(*)"}, m_realm, filter, null, null, null)[0]); 375 } 376 377 public List<GridRegion> GetNeighbours(UUID regionID, List<UUID> scopeIDs, uint squareRangeFromCenterInMeters) 378 { 379 List<GridRegion> regions = new List<GridRegion>(0); 380 GridRegion region = Get(regionID, scopeIDs); 381 382 if (region != null) 383 { 384 int centerX = region.RegionLocX + (region.RegionSizeX/2); // calculate center of region 385 int centerY = region.RegionLocY + (region.RegionSizeY/2); // calculate center of region 386 387 regions = Get(scopeIDs, region.RegionID, centerX, centerY, squareRangeFromCenterInMeters); 388 } 389 390 return regions; 391 } 392 393 public List<GridRegion> Get(List<UUID> scopeIDs, UUID excludeRegion, float centerX, float centerY, 394 uint squareRangeFromCenterInMeters) 395 { 396 QueryFilter filter = new QueryFilter(); 397 398 if (excludeRegion != UUID.Zero) 399 { 400 filter.andNotFilters["RegionUUID"] = excludeRegion; 401 } 402 filter.andGreaterThanEqFilters["(LocX + SizeX)"] = centerX - squareRangeFromCenterInMeters; 403 filter.andGreaterThanEqFilters["(LocY + SizeY)"] = centerY - squareRangeFromCenterInMeters; 404 filter.andLessThanEqFilters["(LocX - SizeX)"] = centerX + squareRangeFromCenterInMeters; 405 filter.andLessThanEqFilters["(LocY - SizeY)"] = centerY + squareRangeFromCenterInMeters; 406 407 Dictionary<string, bool> sort = new Dictionary<string, bool>(3); 408 sort["LocZ"] = true; 409 sort["LocX"] = true; 410 sort["LocY"] = true; 411 412 return ParseQuery(scopeIDs, GD.Query(new string[] {"*"}, m_realm, filter, sort, null, null)); 413 } 414 415 public uint Count(uint estateID, RegionFlags flags) 416 { 417 IEstateConnector estates = Framework.Utilities.DataManager.RequestPlugin<IEstateConnector>(); 418 419 if (estates == null) 420 { 421 return 0; 422 } 423 424 EstateSettings es = estates.GetEstateSettings((int) estateID); 425 426 QueryFilter filter = new QueryFilter(); 427 filter.andBitfieldAndFilters["Flags"] = (uint) flags; 428 429 List<GridRegion> query = ParseQuery(null, GD.Query(new string[] {"*"}, m_realm, filter, null, null, null)); 430 431 uint count = 0; 432 query.ForEach(delegate(GridRegion region) 433 { 434 if (region.EstateOwner == es.EstateOwner && 435 estates.GetEstateID(region.RegionID) == es.EstateID) 436 { 437 ++count; 438 } 439 }); 440 441 return count; 442 } 443 444 public bool Store(GridRegion region) 445 { 446 if (region.EstateOwner == UUID.Zero) 447 { 448 IEstateConnector EstateConnector = Framework.Utilities.DataManager.RequestPlugin<IEstateConnector>(); 449 EstateSettings ES = null; 450 if (EstateConnector != null) 451 { 452 ES = EstateConnector.GetEstateSettings(region.RegionID); 453 if (ES != null) 454 region.EstateOwner = ES.EstateOwner; 455 } 456 if (region.EstateOwner == UUID.Zero && ES != null && ES.EstateID != 0) 457 { 458 MainConsole.Instance.Error( 459 "[LocalGridConnector] Attempt to store region with owner of UUID.Zero detected:" + 460 (new System.Diagnostics.StackTrace()).GetFrame(1).ToString()); 461 } 462 } 463 464 Dictionary<string, object> row = new Dictionary<string, object>(14); 465 row["ScopeID"] = region.ScopeID; 466 row["RegionUUID"] = region.RegionID; 467 row["RegionName"] = region.RegionName; 468 row["LocX"] = region.RegionLocX; 469 row["LocY"] = region.RegionLocY; 470 row["LocZ"] = region.RegionLocZ; 471 row["OwnerUUID"] = region.EstateOwner; 472 row["Access"] = region.Access; 473 row["SizeX"] = region.RegionSizeX; 474 row["SizeY"] = region.RegionSizeY; 475 row["SizeZ"] = region.RegionSizeZ; 476 row["Flags"] = region.Flags; 477 row["SessionID"] = region.SessionID; 478 row["Info"] = OSDParser.SerializeJsonString(region.ToOSD()); 479 480 return GD.Replace(m_realm, row); 481 } 482 483 public bool Delete(UUID regionID) 484 { 485 QueryFilter filter = new QueryFilter(); 486 filter.andFilters["RegionUUID"] = regionID; 487 return GD.Delete(m_realm, filter); 488 } 489 490 public bool DeleteAll(string[] criteriaKey, object[] criteriaValue) 491 { 492 QueryFilter filter = new QueryFilter(); 493 int i = 0; 494 foreach (object value in criteriaValue) 495 { 496 filter.andFilters[criteriaKey[i++]] = value; 497 } 498 return GD.Delete(m_realm, filter); 499 } 500 501 public List<GridRegion> GetDefaultRegions(List<UUID> scopeIDs) 502 { 503 return Get((int) RegionFlags.DefaultRegion, scopeIDs); 504 } 505 506 public List<GridRegion> GetFallbackRegions(List<UUID> scopeIDs, int x, int y) 507 { 508 List<GridRegion> regions = Get((int) RegionFlags.FallbackRegion, scopeIDs); 509 RegionDataDistanceCompare distanceComparer = new RegionDataDistanceCompare(x, y); 510 regions.Sort(distanceComparer); 511 return regions; 512 } 513 514 public List<GridRegion> GetSafeRegions(List<UUID> scopeIDs, int x, int y) 515 { 516 List<GridRegion> Regions = Get((int) RegionFlags.Safe, scopeIDs); 517 Regions.AddRange(Get((int) RegionFlags.RegionOnline, scopeIDs)); 518 519 RegionDataDistanceCompare distanceComparer = new RegionDataDistanceCompare(x, y); 520 Regions.Sort(distanceComparer); 521 return Regions; 522 } 523 524 #endregion 525 526 public void Dispose() 527 { 528 } 529 530 private List<GridRegion> Get(int regionFlags, List<UUID> scopeIDs) 531 { 532 QueryFilter filter = new QueryFilter(); 533 filter.andBitfieldAndFilters["Flags"] = (uint) regionFlags; 534 535 return ParseQuery(scopeIDs, GD.Query(new string[1] {"*"}, m_realm, filter, null, null, null)); 536 } 537 538 protected List<GridRegion> ParseQuery(List<UUID> scopeIDs, List<string> query) 539 { 540 List<GridRegion> regionData = new List<GridRegion>(); 541 542 if ((query.Count%14) == 0) 543 { 544 for (int i = 0; i < query.Count; i += 14) 545 { 546 GridRegion data = new GridRegion(); 547 OSDMap map = (OSDMap) OSDParser.DeserializeJson(query[i + 13]); 548 map["owner_uuid"] = (!map.ContainsKey("owner_uuid") || map["owner_uuid"].AsUUID() == UUID.Zero) 549 ? OSD.FromUUID(UUID.Parse(query[i + 6])) 550 : map["owner_uuid"]; 551 map["EstateOwner"] = (!map.ContainsKey("EstateOwner") || map["EstateOwner"].AsUUID() == UUID.Zero) 552 ? OSD.FromUUID(UUID.Parse(query[i + 6])) 553 : map["EstateOwner"]; 554 data.FromOSD(map); 555 556 if (!regionData.Contains(data)) 557 regionData.Add(data); 558 } 559 } 560 561 return AllScopeIDImpl.CheckScopeIDs(scopeIDs, regionData); 562 } 563 564 #region Nested type: RegionDataDistanceCompare 565 566 public class RegionDataDistanceCompare : IComparer<GridRegion> 567 { 568 private readonly Vector2 m_origin; 569 570 public RegionDataDistanceCompare(int x, int y) 571 { 572 m_origin = new Vector2(x, y); 573 } 574 575 #region IComparer<GridRegion> Members 576 577 public int Compare(GridRegion regionA, GridRegion regionB) 578 { 579 Vector2 vectorA = new Vector2(regionA.RegionLocX, regionA.RegionLocY); 580 Vector2 vectorB = new Vector2(regionB.RegionLocX, regionB.RegionLocY); 581 return Math.Sign(VectorDistance(m_origin, vectorA) - VectorDistance(m_origin, vectorB)); 582 } 583 584 #endregion 585 586 private float VectorDistance(Vector2 x, Vector2 y) 587 { 588 return (x - y).Length(); 589 } 590 } 591 592 #endregion 593 } 594}