public virtual void FixVacuum(MapIndices indices)
        {
            var tile = GetTile(indices);

            if (tile?.GridIndex != _gridId)
            {
                return;
            }
            var adjacent = GetAdjacentTiles(indices);

            tile.Air = new GasMixture(GetVolumeForCells(1), AtmosphereSystem)
            {
                Temperature = Atmospherics.T20C
            };
            Tiles[indices] = tile;

            var ratio = 1f / adjacent.Count;

            foreach (var(_, adj) in adjacent)
            {
                var mix = adj.Air.RemoveRatio(ratio);
                tile.Air.Merge(mix);
                adj.Air.Merge(mix);
            }
        }
示例#2
0
        private List <MapIndices> FindConnectedCells(MapIndices start)
        {
            var inner = new HashSet <MapIndices>();
            var edge  = new HashSet <MapIndices> {
                start
            };

            // Basic inner/edge finder
            // The inner list is all the positions we know are empty, and take no further actions.
            // The edge list is all the positions for whom we have not searched their neighbours.
            // Move stuff from edge to inner, while adding adjacent empty locations to edge
            // When edge is empty, we have filled the entire room.

            while (edge.Count > 0)
            {
                var temp = new List <MapIndices>(edge);
                edge.Clear();
                foreach (var pos in temp)
                {
                    inner.Add(pos);

                    if (IsSpace(pos))
                    {
                        return(null);
                    }

                    Check(inner, edge, pos, Direction.North);
                    Check(inner, edge, pos, Direction.South);
                    Check(inner, edge, pos, Direction.East);
                    Check(inner, edge, pos, Direction.West);
                }
            }

            return(new List <MapIndices>(inner));
        }
示例#3
0
        public void PryTile(MapIndices indices)
        {
            if (!Owner.TryGetComponent(out IMapGridComponent? mapGridComponent))
            {
                return;
            }
            if (IsSpace(indices) || IsAirBlocked(indices))
            {
                return;
            }

            var mapGrid = mapGridComponent.Grid;
            var tile    = mapGrid.GetTileRef(indices).Tile;

            var tileDef = (ContentTileDefinition)_tileDefinitionManager[tile.TypeId];

            var underplating = _tileDefinitionManager["underplating"];

            mapGrid.SetTile(indices, new Tile(underplating.TileId));

            //Actually spawn the relevant tile item at the right position and give it some offset to the corner.
            var tileItem = _serverEntityManager.SpawnEntity(tileDef.ItemDropPrototypeName, new GridCoordinates(indices.X, indices.Y, mapGrid));

            tileItem.Transform.WorldPosition += (0.2f, 0.2f);
        }
示例#4
0
            private GasOverlayMessage?ChunkToMessage(GasOverlayChunk chunk)
            {
                // Chunk data should already be up to date.
                // Only send relevant tiles to client.

                var tileData = new List <(MapIndices, GasOverlayData)>();

                for (var x = 0; x < ChunkSize; x++)
                {
                    for (var y = 0; y < ChunkSize; y++)
                    {
                        // TODO: Check could be more robust I think.
                        var data = chunk.TileData[x, y];
                        if ((data.Gas == null || data.Gas.Length == 0) && data.FireState == 0 && data.FireTemperature == 0.0f)
                        {
                            continue;
                        }

                        var indices = new MapIndices(chunk.MapIndices.X + x, chunk.MapIndices.Y + y);
                        tileData.Add((indices, data));
                    }
                }

                if (tileData.Count == 0)
                {
                    return(null);
                }

                return(new GasOverlayMessage(chunk.GridIndices, tileData));
            }
示例#5
0
        public void FixVacuum(MapIndices indices)
        {
            if (!Owner.TryGetComponent(out IMapGridComponent? mapGrid))
            {
                return;
            }
            var tile = GetTile(indices);

            if (tile?.GridIndex != mapGrid.Grid.Index)
            {
                return;
            }
            var adjacent = GetAdjacentTiles(indices);

            tile.Air = new GasMixture(GetVolumeForCells(1))
            {
                Temperature = Atmospherics.T20C
            };
            _tiles[indices] = tile;

            var ratio = 1f / adjacent.Count;

            foreach (var(direction, adj) in adjacent)
            {
                var mix = adj.Air.RemoveRatio(ratio);
                tile.Air.Merge(mix);
                adj.Air.Merge(mix);
            }
        }
        public override void Update(float frameTime)
        {
            AccumulatedFrameTime += frameTime;
            _updateCooldown       = 1 / _configManager.GetCVar <float>("net.atmosdbgoverlaytickrate");

            if (AccumulatedFrameTime < _updateCooldown)
            {
                return;
            }

            // This is the timer from GasTileOverlaySystem
            AccumulatedFrameTime -= _updateCooldown;

            var currentTick = _gameTiming.CurTick;

            // Now we'll go through each player, then through each chunk in range of that player checking if the player is still in range
            // If they are, check if they need the new data to send (i.e. if there's an overlay for the gas).
            // Afterwards we reset all the chunk data for the next time we tick.
            foreach (var session in PlayerObservers)
            {
                if (session.AttachedEntity == null)
                {
                    continue;
                }

                var entity = session.AttachedEntity;

                var worldBounds = Box2.CenteredAround(entity.Transform.WorldPosition,
                                                      new Vector2(LocalViewRange, LocalViewRange));

                foreach (var grid in _mapManager.FindGridsIntersecting(entity.Transform.MapID, worldBounds))
                {
                    if (!_entityManager.TryGetEntity(grid.GridEntityId, out var gridEnt))
                    {
                        continue;
                    }

                    if (!gridEnt.TryGetComponent <GridAtmosphereComponent>(out var gam))
                    {
                        continue;
                    }

                    var entityTile          = grid.GetTileRef(entity.Transform.Coordinates).GridIndices;
                    var baseTile            = new MapIndices(entityTile.X - (LocalViewRange / 2), entityTile.Y - (LocalViewRange / 2));
                    var debugOverlayContent = new AtmosDebugOverlayData[LocalViewRange * LocalViewRange];

                    var index = 0;
                    for (var y = 0; y < LocalViewRange; y++)
                    {
                        for (var x = 0; x < LocalViewRange; x++)
                        {
                            var mapIndices = new MapIndices(baseTile.X + x, baseTile.Y + y);
                            debugOverlayContent[index++] = ConvertTileToData(gam.GetTile(mapIndices));
                        }
                    }

                    RaiseNetworkEvent(new AtmosDebugOverlayMessage(grid.Index, baseTile, debugOverlayContent), session.ConnectedClient);
                }
            }
        }
示例#7
0
        private void UpdatePosition()
        {
            if (!_mapManager.TryGetGrid(Owner.Transform.GridID, out var grid))
            {
                Logger.WarningS(LogCategory, "Entity {0} snapgrid didn't find grid {1}. Race condition?", Owner.Uid, Owner.Transform.GridID);
                return;
            }

            if (IsSet)
            {
                grid.RemoveFromSnapGridCell(Position, Offset, this);
            }

            IsSet = true;

            var oldPos = Position;

            Position = grid.SnapGridCellFor(Owner.Transform.GridPosition, Offset);
            grid.AddToSnapGridCell(Position, Offset, this);

            if (oldPos != Position)
            {
                OnPositionChanged?.Invoke();
            }
        }
示例#8
0
        public TileAtmosphere?GetTile(MapIndices indices)
        {
            if (!Owner.TryGetComponent(out IMapGridComponent? mapGrid))
            {
                return(null);
            }

            if (_tiles.TryGetValue(indices, out var tile))
            {
                return(tile);
            }

            // We don't have that tile!
            if (IsSpace(indices))
            {
                var space = new TileAtmosphere(this, mapGrid.Grid.Index, indices, new GasMixture(int.MaxValue)
                {
                    Temperature = Atmospherics.TCMB
                });
                space.Air.MarkImmutable();
                return(space);
            }

            return(null);
        }
示例#9
0
        public bool Execute(IDebugConsole console, params string[] args)
        {
            if (args.Length != 2 && args.Length != 3)
            {
                console.AddLine("Must pass exactly 2 or 3 arguments", Color.Red);
                return(false);
            }

            var            gridID     = new GridId(int.Parse(args[0], CultureInfo.InvariantCulture));
            var            indexSplit = args[1].Split(',');
            var            x          = int.Parse(indexSplit[0], CultureInfo.InvariantCulture);
            var            y          = int.Parse(indexSplit[1], CultureInfo.InvariantCulture);
            var            indices    = new MapIndices(x, y);
            SnapGridOffset offset     = SnapGridOffset.Center;

            if (args.Length == 3)
            {
                offset = (SnapGridOffset)Enum.Parse(typeof(SnapGridOffset), args[2]);
            }

            var mapMan = IoCManager.Resolve <IMapManager>();
            var grid   = mapMan.GetGrid(gridID);

            foreach (var entity in grid.GetSnapGridCell(indices, offset))
            {
                console.AddLine(entity.Owner.Uid.ToString());
            }

            return(false);
        }
 public TemperatureExposeEvent(MapIndices indices, GridId gridId, GasMixture air, float temperature, float volume)
 {
     Indices     = indices;
     Grid        = gridId;
     Air         = air;
     Temperature = temperature;
     Volume      = volume;
 }
        /// <summary>
        ///     Flags Dirty if the data is different.
        /// </summary>
        /// <param name="data"></param>
        /// <param name="indices"></param>
        public void Update(SharedGasTileOverlaySystem.GasOverlayData data, MapIndices indices)
        {
            DebugTools.Assert(InBounds(indices));
            var(offsetX, offsetY) = (indices.X - MapIndices.X,
                                     indices.Y - MapIndices.Y);

            TileData[offsetX, offsetY] = data;
        }
示例#12
0
 public TileAtmosphere(GridAtmosphereComponent atmosphereComponent, GridId gridIndex, MapIndices gridIndices, GasMixture mixture = null)
 {
     IoCManager.InjectDependencies(this);
     _gridAtmosphereComponent = atmosphereComponent;
     GridIndex   = gridIndex;
     GridIndices = gridIndices;
     Air         = mixture;
 }
示例#13
0
        public static bool PryTile(this MapIndices indices, GridId gridId,
                                   IMapManager?mapManager = null, ITileDefinitionManager?tileDefinitionManager = null, IEntityManager?entityManager = null)
        {
            mapManager ??= IoCManager.Resolve <IMapManager>();
            var grid    = mapManager.GetGrid(gridId);
            var tileRef = grid.GetTileRef(indices);

            return(tileRef.PryTile(mapManager, tileDefinitionManager, entityManager));
        }
        public virtual void PryTile(MapIndices indices)
        {
            if (IsSpace(indices) || IsAirBlocked(indices))
            {
                return;
            }

            indices.PryTile(_gridId, _mapManager, _tileDefinitionManager, _serverEntityManager);
        }
        public void SetTileOverlay(GridId gridIndex, MapIndices indices, GasData[] gasData, int fireState = 0, float fireTemperature = 0f)
        {
            if (!_overlay.TryGetValue(gridIndex, out var _))
            {
                _overlay[gridIndex] = new Dictionary <MapIndices, GasOverlayData>();
            }

            _overlay[gridIndex][indices] = new GasOverlayData(fireState, fireTemperature, gasData);
            _queue.Add(GetData(gridIndex, indices));
        }
        public void _setChunkDirty(IMapGrid grid, MapIndices chunk)
        {
            var data = _mapChunkData[grid.Index];

            if (data.TryGetValue(chunk, out var datum))
            {
                datum.Dirty = true;
            }
            // Don't need to set it if we don't have an entry since lack of an entry is treated as dirty.
        }
        public void Invalidate(GridId gridIndex, MapIndices indices)
        {
            if (!_invalid.TryGetValue(gridIndex, out var set) || set == null)
            {
                set = new HashSet <MapIndices>();
                _invalid.Add(gridIndex, set);
            }

            set.Add(indices);
        }
示例#18
0
        public void Invalidate(GridId gridIndex, MapIndices indices)
        {
            if (!_invalidTiles.TryGetValue(gridIndex, out var existing))
            {
                existing = new HashSet <MapIndices>();
                _invalidTiles[gridIndex] = existing;
            }

            existing.Add(indices);
        }
        public static IEnumerable <IEntity> GetEntitiesInTileFast(this MapIndices indices, GridId gridId, GridTileLookupSystem?gridTileLookup = null)
        {
            var turf = indices.GetTileRef(gridId);

            if (turf == null)
            {
                return(Enumerable.Empty <IEntity>());
            }

            return(GetEntitiesInTileFast(turf.Value, gridTileLookup));
        }
示例#20
0
        private PathfindingChunk CreateChunk(GridId gridId, MapIndices indices)
        {
            var newChunk = new PathfindingChunk(gridId, indices);

            newChunk.Initialize();
            if (!_graph.ContainsKey(gridId))
            {
                _graph.Add(gridId, new Dictionary <MapIndices, PathfindingChunk>());
            }
            _graph[gridId].Add(indices, newChunk);
            return(newChunk);
        }
 public bool InBounds(MapIndices mapIndices)
 {
     if (mapIndices.X < _indices.X || mapIndices.Y < _indices.Y)
     {
         return(false);
     }
     if (mapIndices.X >= _indices.X + ChunkSize || mapIndices.Y >= _indices.Y + ChunkSize)
     {
         return(false);
     }
     return(true);
 }
        private AirtightComponent GetObstructingComponent(MapIndices indices)
        {
            foreach (var v in _grid.GetSnapGridCell(indices, SnapGridOffset.Center))
            {
                if (v.Owner.TryGetComponent <AirtightComponent>(out var ac))
                {
                    return(ac);
                }
            }

            return(null);
        }
        public Dictionary <Direction, TileAtmosphere> GetAdjacentTiles(MapIndices indices)
        {
            var sides = new Dictionary <Direction, TileAtmosphere>();

            foreach (var dir in Cardinal())
            {
                var side = indices.Offset(dir);
                sides[dir] = GetTile(side);
            }

            return(sides);
        }
        internal GridTileLookupChunk(GridId gridId, MapIndices indices)
        {
            GridId  = gridId;
            Indices = indices;

            for (var x = 0; x < ChunkSize; x++)
            {
                for (var y = 0; y < ChunkSize; y++)
                {
                    _nodes[x, y] = new GridTileLookupNode(this, new MapIndices(Indices.X + x, Indices.Y + y));
                }
            }
        }
示例#25
0
        private void MergeAtmospheres(MapIndices pos)
        {
            var adjacent = new HashSet <Atmosphere>(GetAdjacentAtmospheres(pos).Values);

            // If this block doesn't separate two atmospheres, there's nothing to do
            if (adjacent.Count <= 1)
            {
                return;
            }

            var allCells = new List <MapIndices> {
                pos
            };

            foreach (var atmos in adjacent)
            {
                allCells.AddRange(FindRoomContents(atmos));
            }

            // Fuse all adjacent atmospheres
            Atmosphere replacement;

            if (adjacent.Contains(null))
            {
                replacement = null;
            }
            else
            {
                replacement = new Atmosphere(GetVolumeForCells(allCells.Count));
                foreach (var atmos in adjacent)
                {
                    if (atmos == null)
                    {
                        continue;
                    }

                    // Copy all the gasses across
                    foreach (var gas in atmos.Gasses)
                    {
                        replacement.Add(gas.Gas, gas.Volume, atmos.Temperature);
                    }
                }
            }

            foreach (var cellPos in allCells)
            {
                _atmospheres[cellPos] = replacement;
            }
        }
示例#26
0
        private void Check(ICollection <MapIndices> inner, ISet <MapIndices> edges, MapIndices pos, Direction dir)
        {
            pos += (MapIndices)dir.CardinalToIntVec();
            if (IsObstructed(pos))
            {
                return;
            }

            if (inner.Contains(pos))
            {
                return;
            }

            edges.Add(pos);
        }
示例#27
0
        public virtual void PryTile(MapIndices indices)
        {
            if (!Owner.TryGetComponent(out IMapGridComponent? mapGridComponent))
            {
                return;
            }
            if (IsSpace(indices) || IsAirBlocked(indices))
            {
                return;
            }

            var mapGrid = mapGridComponent.Grid;

            indices.PryTile(mapGrid.Index, _mapManager, _tileDefinitionManager, _serverEntityManager);
        }
        public AtmosDebugOverlayData?GetData(GridId gridIndex, MapIndices indices)
        {
            if (!_tileData.TryGetValue(gridIndex, out var srcMsg))
            {
                return(null);
            }

            var relative = indices - srcMsg.BaseIdx;

            if (relative.X < 0 || relative.Y < 0 || relative.X >= LocalViewRange || relative.Y >= LocalViewRange)
            {
                return(null);
            }

            return(srcMsg.OverlayData[relative.X + (relative.Y * LocalViewRange)]);
        }
示例#29
0
        public Dictionary <Direction, TileAtmosphere> GetAdjacentTiles(MapIndices indices)
        {
            var sides = new Dictionary <Direction, TileAtmosphere>();

            foreach (var dir in Cardinal)
            {
                var side = indices.Offset(dir);
                var tile = GetTile(side);
                if (tile?.Air != null)
                {
                    sides[dir] = tile;
                }
            }

            return(sides);
        }
示例#30
0
        /// <summary>
        /// Return our neighboring nodes (even across chunks)
        /// </summary>
        /// <returns></returns>
        public IEnumerable <PathfindingNode> GetNeighbors()
        {
            List <PathfindingChunk> neighborChunks = null;

            if (ParentChunk.OnEdge(this))
            {
                neighborChunks = ParentChunk.RelevantChunks(this).ToList();
            }

            for (var x = -1; x <= 1; x++)
            {
                for (var y = -1; y <= 1; y++)
                {
                    if (x == 0 && y == 0)
                    {
                        continue;
                    }
                    var indices = new MapIndices(TileRef.X + x, TileRef.Y + y);
                    if (ParentChunk.InBounds(indices))
                    {
                        var(relativeX, relativeY) = (indices.X - ParentChunk.Indices.X,
                                                     indices.Y - ParentChunk.Indices.Y);
                        yield return(ParentChunk.Nodes[relativeX, relativeY]);
                    }
                    else
                    {
                        DebugTools.AssertNotNull(neighborChunks);
                        // Get the relevant chunk and then get the node on it
                        foreach (var neighbor in neighborChunks)
                        {
                            // A lot of edge transitions are going to have a single neighboring chunk
                            // (given > 1 only affects corners)
                            // So we can just check the count to see if it's inbound
                            if (neighborChunks.Count > 0 && !neighbor.InBounds(indices))
                            {
                                continue;
                            }
                            var(relativeX, relativeY) = (indices.X - neighbor.Indices.X,
                                                         indices.Y - neighbor.Indices.Y);
                            yield return(neighbor.Nodes[relativeX, relativeY]);

                            break;
                        }
                    }
                }
            }
        }