示例#1
0
        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);
                }
            }
        }
示例#2
0
        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;
                }
            }
        }
示例#3
0
        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);
        }