internal static IEnumerable <Prim> LoadPrims(string rdbConnectionString, Guid regionId) { using (var conn = DBHelpers.GetConnection(rdbConnectionString)) { if (conn == null) { LOG.Warn($"Could not get connection to DB for region '{regionId}'."); return(null); } using (var cmd = conn.CreateCommand()) { cmd.CommandText = @"SELECT pr.UUID, pr.SceneGroupID, pr.LinkNumber, pr.Name, pr.ObjectFlags, ps.State, pr.PositionX, pr.PositionY, pr.PositionZ, pr.GroupPositionX, pr.GroupPositionY, pr.GroupPositionZ, ps.ScaleX, ps.ScaleY, ps.ScaleZ, pr.RotationX, pr.RotationY, pr.RotationZ, pr.RotationW, ps.Texture FROM prims pr INNER JOIN primshapes ps USING (UUID) WHERE pr.GroupPositionZ < 766 /* = max terrain height (510) + render height (256) */ AND LENGTH(ps.Texture) > 0 AND pr.ObjectFlags & (0 | 0x40000 | 0x20000) = 0 AND ps.ScaleX > 1.0 AND ps.ScaleY > 1.0 AND ps.ScaleZ > 1.0 AND ps.PCode NOT IN (255, 111, 95) AND RegionUUID = @region_id ORDER BY GroupPositionZ, PositionZ " ; cmd.Parameters.AddWithValue("region_id", regionId); cmd.CommandTimeout = 600; cmd.Prepare(); IDataReader reader = null; try { reader = DBHelpers.ExecuteReader(cmd); } catch (Exception e) { LOG.Warn($"Prims DB reader query threw an error when attempting to get prims for region '{regionId}'.", e); } if (reader == null) { LOG.Warn($"Prims DB reader query returned nothing for region '{regionId}'."); return(null); } var prims = new List <Prim>(); // List was chosen because it guarantees that insertion order will be preserved unless explictly sorted. var rootPrims = new Dictionary <Guid, Prim>(); var childPrims = new List <Prim>(); // List was chosen because it guarantees that insertion order will be preserved unless explictly sorted. try { while (reader.Read()) { // Nullables start here var groupPosX = RDBMap.GetDBValueOrNull <double>(reader, "GroupPositionX"); var groupPosY = RDBMap.GetDBValueOrNull <double>(reader, "GroupPositionY"); var groupPosZ = RDBMap.GetDBValueOrNull <double>(reader, "GroupPositionZ"); var posX = RDBMap.GetDBValueOrNull <double>(reader, "PositionX"); var posY = RDBMap.GetDBValueOrNull <double>(reader, "PositionY"); var posZ = RDBMap.GetDBValueOrNull <double>(reader, "PositionZ"); var rotW = RDBMap.GetDBValueOrNull <double>(reader, "RotationW"); var rotX = RDBMap.GetDBValueOrNull <double>(reader, "RotationX"); var rotY = RDBMap.GetDBValueOrNull <double>(reader, "RotationY"); var rotZ = RDBMap.GetDBValueOrNull <double>(reader, "RotationZ"); var prim = new Prim { GroupPosition = groupPosX != null && groupPosY != null && groupPosZ != null ? new Vector3( (float)groupPosX, (float)groupPosY, (float)groupPosZ ) : (Vector3?)null, Id = Guid.Parse(RDBMap.GetDBValue(reader, "UUID")), Name = RDBMap.GetDBValue(reader, "Name"), ObjectFlags = RDBMap.GetDBValue <int>(reader, "ObjectFlags"), Position = posX != null && posY != null && posZ != null ? new Vector3( (float)posX, (float)posY, (float)posZ ) : (Vector3?)null, RegionId = regionId, RootRotation = null, Rotation = rotW != null && rotX != null && rotY != null && rotZ != null ? new Quaternion( (float)rotX, (float)rotY, (float)rotZ, (float)rotW ) : (Quaternion?)null, Scale = new Vector3( (float)RDBMap.GetDBValue <double>(reader, "ScaleX"), (float)RDBMap.GetDBValue <double>(reader, "ScaleY"), (float)RDBMap.GetDBValue <double>(reader, "ScaleZ") ), State = RDBMap.GetDBValue <int>(reader, "State"), Texture = (byte[])reader["Texture"], }; prims.Add(prim); var sogIdStr = RDBMap.GetDBValue(reader, "SceneGroupID"); if (Guid.TryParse(sogIdStr, out var sogId)) { prim.SceneGroupId = sogId; var linkNumber = RDBMap.GetDBValue <int>(reader, "LinkNumber"); if (linkNumber == 1) { rootPrims.Add(sogId, prim); } else if (linkNumber > 1) { childPrims.Add(prim); } } } } finally { reader.Close(); } foreach (var prim in childPrims) { if (rootPrims.TryGetValue(prim.SceneGroupId, out var rootPrim)) { prim.RootRotation = rootPrim.Rotation; } } return(prims); } } }
public void UpdateMap() { // Stores RDB connection strings as keys to dictionaries of region UUIDs mapped to the region data. var region_list = new ConcurrentDictionary <Guid, Region>(); LOG.Debug("Loading region-to-host map from DB."); using (var conn = DBHelpers.GetConnection(CONNECTION_STRING)) { if (conn == null) { LOG.Warn($"Could not get connection to main DB, cannot update the map."); return; } using (var cmd = conn.CreateCommand()) { /* Gets the full list of what regions are on what host. * A null host_name indicates that that region's data is on this host, otherwise contains the host for the region's data. * A null regionName indicates that the region is shut down, otherwise that the region is up or crashed. */ cmd.CommandText = @"SELECT regionID, host_name, regionName, locX, locY, sizeX, sizeY, serverIP, serverPort FROM estate_map LEFT OUTER JOIN ( SELECT host_name, region_id FROM RdbHosts INNER JOIN RegionRdbMapping ON id = rdb_host_id ) AS rdbs ON regionID = region_id LEFT OUTER JOIN regions ON regionID = uuid ORDER BY host_name, region_id" ; cmd.CommandTimeout = 600; IDataReader reader = null; try { reader = DBHelpers.ExecuteReader(cmd); } catch (Exception e) { LOG.Warn($"Region list query DB reader threw an error when attempting to update the map.", e); } if (reader == null) { LOG.Warn($"Region list query DB reader returned nothing from main DB, cannot update the map."); return; } try { while (reader.Read()) { var rdbHostName = Convert.ToString(reader["host_name"]); var connString = GetRDBConnectionString(rdbHostName); var region_id = Guid.Parse(Convert.ToString(reader["regionID"])); // Check to see if the map already has this entry and if the new entry is shut down. if (region_list.TryGetValue(region_id, out var region) && Convert.IsDBNull(reader["regionName"])) { LOG.Debug($"Found offline region {region_id}."); // Region is offline, update the RDB connection in case that's changed. region._rdbConnectionString = connString; } else // The DB has the freshest information. Does not imply the region is online - it could have crashed. { var locationX = GetDBValueOrNull <int>(reader, "locX"); var locationY = GetDBValueOrNull <int>(reader, "locY"); region = new Region(connString) { Id = region_id, Location = locationX == null || locationY == null ? (Vector2?)null : new Vector2((float)locationX, (float)locationY), Name = reader.IsDBNull(reader.GetOrdinal("regionName")) ? null : Convert.ToString(reader["regionName"]), ServerIP = reader.IsDBNull(reader.GetOrdinal("serverIP")) ? null : Convert.ToString(reader["serverIP"]), ServerPort = GetDBValueOrNull <int>(reader, "serverPort"), Size = new Vector2(256f, 256f), // DB always has 0 as far as I'm aware. Looks like regions.sizeX and .sizeY are never even read by Halcyon code as of 9/3/2017. }; LOG.Debug($"Found online region {region_id} named '{region.Name}' at {locationX}, {locationY}."); } if (!region_list.TryAdd(region_id, region)) { LOG.Warn($"Attempted to add a duplicate region entry for RDB {rdbHostName}: Region is '{region.Name}' with UUID '{region_id}'. Check to see if you have duplicate entries in your 'regions' table, or if you have multiple entries in the 'RegionRdbMapping' for the same region UUID."); } } } finally { reader.Close(); } } } LOG.Debug("Preparing updated region map."); Parallel.ForEach(region_list.Values.ToList(), PARALLELISM_OPTIONS, region => { var oldPriority = Thread.CurrentThread.Priority; Thread.CurrentThread.Priority = ThreadPriority.BelowNormal; if (!MAP.TryAdd(region.Id, region)) { MAP.TryGetValue(region.Id, out var orig); LOG.Warn($"Region '{region.Id}' is a duplicate: name is '{region.Name}' and is duplicating a region with name '{orig?.Name}'."); } // Not all regions returned have a position, after all some could be in an offline state and never been seen before. if (region.HasKnownCoordinates()) { var coord = (Vector2)region.Location; if (!COORD_MAP.TryAdd(coord, region)) { COORD_MAP.TryGetValue(coord, out var orig); // Might be a bug here when this method is executed multiple times in a single execution of Anax, and a region was removed and another region was MOVED into the old region's location. // That would be resolved I think by executing DeleteOldMapEntries() before this method. LOG.Warn($"Region {region.Id} named '{region.Name}' at <{region.Location?.X},{region.Location?.Y}> at same location as {orig?.Id} named '{orig?.Name}' at <{orig?.Location?.X},{orig?.Location?.Y}>. Both of these regions are listed as online in the 'regions' table."); } } Thread.CurrentThread.Priority = oldPriority; }); LOG.Debug("Connecting adjacent regions."); foreach (var region in region_list.Values) { if (region.HasKnownCoordinates()) { var adjacentRegions = new List <Region>(); if (COORD_MAP.TryGetValue((Vector2)region.Location + new Vector2(0, 1), out var north)) { adjacentRegions.Add(north); } if (COORD_MAP.TryGetValue((Vector2)region.Location + new Vector2(-1, 1), out var northeast)) { adjacentRegions.Add(northeast); } if (COORD_MAP.TryGetValue((Vector2)region.Location + new Vector2(-1, 0), out var east)) { adjacentRegions.Add(east); } if (COORD_MAP.TryGetValue((Vector2)region.Location + new Vector2(-1, -1), out var southeast)) { adjacentRegions.Add(southeast); } if (COORD_MAP.TryGetValue((Vector2)region.Location + new Vector2(0, -1), out var south)) { adjacentRegions.Add(south); } if (COORD_MAP.TryGetValue((Vector2)region.Location + new Vector2(1, -1), out var southwest)) { adjacentRegions.Add(southwest); } if (COORD_MAP.TryGetValue((Vector2)region.Location + new Vector2(1, 0), out var west)) { adjacentRegions.Add(west); } if (COORD_MAP.TryGetValue((Vector2)region.Location + new Vector2(1, 1), out var northwest)) { adjacentRegions.Add(northwest); } region._adjacentRegions = adjacentRegions; } } }
public bool Update() { using (var conn = DBHelpers.GetConnection(_rdbConnectionString)) { if (conn == null) { LOG.Warn($"Could not get connection to DB for region '{_regionId}'."); return(false); } using (var cmd = conn.CreateCommand()) { cmd.CommandText = @"SELECT terrain_texture_1, terrain_texture_2, terrain_texture_3, terrain_texture_4, elevation_1_nw, elevation_2_nw, elevation_1_ne, elevation_2_ne, elevation_1_sw, elevation_2_sw, elevation_1_se, elevation_2_se, water_height, Heightfield FROM regionsettings NATURAL JOIN terrain WHERE RegionUUID = @region_id " ; cmd.Parameters.AddWithValue("region_id", _regionId.ToString()); cmd.Prepare(); IDataReader reader = null; try { reader = DBHelpers.ExecuteReader(cmd); } catch (Exception e) { LOG.Warn($"Prims query DB reader threw an error when attempting to get prims for region '{_regionId}'.", e); } if (reader == null) { LOG.Warn($"Terrain DB reader query returned nothing for region '{_regionId}'."); return(false); } try { reader.Read(); TerrainTexture1 = Guid.Parse(RDBMap.GetDBValue(reader, "terrain_texture_1")); TerrainTexture2 = Guid.Parse(RDBMap.GetDBValue(reader, "terrain_texture_2")); TerrainTexture3 = Guid.Parse(RDBMap.GetDBValue(reader, "terrain_texture_3")); TerrainTexture4 = Guid.Parse(RDBMap.GetDBValue(reader, "terrain_texture_4")); ElevationNWLow = RDBMap.GetDBValue <double>(reader, "elevation_1_nw"); ElevationNWHigh = RDBMap.GetDBValue <double>(reader, "elevation_2_nw"); ElevationNELow = RDBMap.GetDBValue <double>(reader, "elevation_1_ne"); ElevationNEHigh = RDBMap.GetDBValue <double>(reader, "elevation_2_ne"); ElevationSWLow = RDBMap.GetDBValue <double>(reader, "elevation_1_sw"); ElevationSWHigh = RDBMap.GetDBValue <double>(reader, "elevation_2_sw"); ElevationSELow = RDBMap.GetDBValue <double>(reader, "elevation_1_se"); ElevationSEHigh = RDBMap.GetDBValue <double>(reader, "elevation_2_se"); WaterHeight = RDBMap.GetDBValue <double>(reader, "water_height"); _heightmap.Initialize(); var minHeightFound = 510.0; // Max terrain height var br = new BinaryReader(new MemoryStream((byte[])reader["Heightfield"])); for (int x = 0; x < _heightmap.GetLength(0); x++) { for (int y = 0; y < _heightmap.GetLength(1); y++) { var height = br.ReadDouble(); _heightmap[x, y] = height; if (height < minHeightFound) { minHeightFound = height; } } } TerrainHeightMin = minHeightFound; } finally { reader.Close(); } } } return(true); }