예제 #1
0
            protected override void Draw(DrawingHandleBase handle, OverlaySpace currentSpace)
            {
                var map = _owner.eyeManager.CurrentMap;

                var            worldHandle   = (DrawingHandleWorld)handle;
                ShaderInstance?currentShader = null;
                var            player        = _playerManager.LocalPlayer?.ControlledEntity;

                foreach (var effect in _owner._Effects)
                {
                    if (effect.AttachedEntity?.Transform.MapID != player?.Transform.MapID &&
                        _mapManager.GetGrid(effect.Coordinates.GetGridId(_entityManager)).ParentMapId != map)
                    {
                        continue;
                    }

                    var newShader = effect.Shaded ? null : _unshadedShader;

                    if (newShader != currentShader)
                    {
                        worldHandle.UseShader(newShader);
                        currentShader = newShader;
                    }

                    var effectSprite = effect.EffectSprite;
                    var effectOrigin = effect.AttachedEntity?.Transform.MapPosition.Position + effect.AttachedOffset ??
                                       effect.Coordinates.ToMapPos(_entityManager);

                    var effectArea = Box2.CenteredAround(effectOrigin, effect.Size);

                    var rotatedBox = new Box2Rotated(effectArea, effect.Rotation, effectOrigin);

                    worldHandle.DrawTextureRect(effectSprite, rotatedBox, ToColor(effect.Color));
                }
            }
예제 #2
0
        public IList <IEntity> GetEntitiesUnderPosition(MapCoordinates coordinates)
        {
            // Find all the entities intersecting our click
            var entities = EntityManager.GetEntitiesIntersecting(coordinates.MapId,
                                                                 Box2.CenteredAround(coordinates.Position, (1, 1)));

            // Check the entities against whether or not we can click them
            var foundEntities = new List <(IEntity clicked, int drawDepth, uint renderOrder)>();

            foreach (var entity in entities)
            {
                if (entity.TryGetComponent <ClickableComponent>(out var component) &&
                    entity.Transform.IsMapTransform &&
                    component.CheckClick(coordinates.Position, out var drawDepthClicked, out var renderOrder))
                {
                    foundEntities.Add((entity, drawDepthClicked, renderOrder));
                }
            }

            if (foundEntities.Count == 0)
            {
                return(new List <IEntity>());
            }

            foundEntities.Sort(new ClickableEntityComparer());
            // 0 is the top element.
            foundEntities.Reverse();
            return(foundEntities.Select(a => a.clicked).ToList());
        }
        protected bool TryGetContextEntities(IEntity player, MapCoordinates targetPos, [NotNullWhen(true)] out List <IEntity>?contextEntities, bool buffer = false)
        {
            contextEntities = null;
            var length = buffer ? 1.0f: 0.5f;

            var entities = EntityManager.GetEntitiesIntersecting(targetPos.MapId,
                                                                 Box2.CenteredAround(targetPos.Position, (length, length))).ToList();

            if (entities.Count == 0)
            {
                return(false);
            }

            // Check if we have LOS to the clicked-location, otherwise no popup.
            var vectorDiff = player.Transform.MapPosition.Position - targetPos.Position;
            var distance   = vectorDiff.Length + 0.01f;

            bool Ignored(IEntity entity)
            {
                return(entities.Contains(entity) ||
                       entity == player ||
                       !entity.TryGetComponent(out OccluderComponent? occluder) ||
                       !occluder.Enabled);
            }

            var result = player.InRangeUnobstructed(targetPos, distance, CollisionGroup.Opaque, Ignored);

            if (!result)
            {
                return(false);
            }

            contextEntities = entities;
            return(true);
        }
        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);
                }
            }
        }
예제 #5
0
        protected override void Draw(DrawingHandleBase handle, OverlaySpace overlay)
        {
            var drawHandle = (DrawingHandleWorld)handle;

            var mapId = _eyeManager.CurrentMap;
            var eye   = _eyeManager.CurrentEye;

            var worldBounds = Box2.CenteredAround(eye.Position.Position,
                                                  _clyde.ScreenSize / (float)EyeManager.PixelsPerMeter * eye.Zoom);

            foreach (var mapGrid in _mapManager.FindGridsIntersecting(mapId, worldBounds))
            {
                if (!_gasTileOverlaySystem.HasData(mapGrid.Index))
                {
                    continue;
                }

                var gridBounds = new Box2(mapGrid.WorldToLocal(worldBounds.BottomLeft), mapGrid.WorldToLocal(worldBounds.TopRight));

                foreach (var tile in mapGrid.GetTilesIntersecting(gridBounds))
                {
                    foreach (var(texture, color) in _gasTileOverlaySystem.GetOverlays(mapGrid.Index, tile.GridIndices))
                    {
                        drawHandle.DrawTexture(texture, mapGrid.LocalToWorld(new Vector2(tile.X, tile.Y)), color);
                    }
                }
            }
        }
예제 #6
0
            protected override void Draw(DrawingHandleBase handle, OverlaySpace currentSpace)
            {
                var map = _owner.eyeManager.CurrentMap;

                var            worldHandle   = (DrawingHandleWorld)handle;
                ShaderInstance?currentShader = null;

                foreach (var effect in _owner._Effects)
                {
                    if (_mapManager.GetGrid(effect.Coordinates.GridID).ParentMapId != map)
                    {
                        continue;
                    }

                    var newShader = effect.Shaded ? null : _unshadedShader;

                    if (newShader != currentShader)
                    {
                        worldHandle.UseShader(newShader);
                        currentShader = newShader;
                    }

                    var effectSprite = effect.EffectSprite;
                    var effectOrigin = effect.Coordinates.ToMapPos(_mapManager);
                    var effectArea   = Box2.CenteredAround(effectOrigin, effect.Size);

                    var rotatedBox = new Box2Rotated(effectArea, effect.Rotation, effectOrigin);

                    worldHandle.DrawTextureRect(effectSprite, rotatedBox, ToColor(effect.Color));
                }
            }
        /// <summary>
        ///     Get all of the entities in an area for displaying on the context menu.
        /// </summary>
        /// <param name="buffer">Whether we should slightly extend the entity search area.</param>
        public bool TryGetContextEntities(IEntity player, MapCoordinates targetPos,
                                          [NotNullWhen(true)] out List <IEntity>?contextEntities, bool buffer = false, bool ignoreVisibility = false)
        {
            contextEntities = null;

            // Check if we have LOS to the clicked-location.
            if (!ignoreVisibility && !player.InRangeUnOccluded(targetPos, range: ExamineSystemShared.ExamineRange))
            {
                return(false);
            }

            // Get entities
            var length   = buffer ? 1.0f : 0.5f;
            var entities = _lookup.GetEntitiesIntersecting(
                targetPos.MapId,
                Box2.CenteredAround(targetPos.Position, (length, length)))
                           .ToList();

            if (entities.Count == 0)
            {
                return(false);
            }

            if (ignoreVisibility)
            {
                contextEntities = entities;
                return(true);
            }

            // perform visibility checks
            var playerPos = player.Transform.MapPosition;

            foreach (var entity in entities.ToList())
            {
                if (entity.HasTag("HideContextMenu"))
                {
                    entities.Remove(entity);
                    continue;
                }

                if (!ExamineSystemShared.InRangeUnOccluded(
                        playerPos,
                        entity.Transform.MapPosition,
                        ExamineSystemShared.ExamineRange,
                        null))
                {
                    entities.Remove(entity);
                }
            }

            if (entities.Count == 0)
            {
                return(false);
            }

            contextEntities = entities;
            return(true);
        }
예제 #8
0
    /// <summary>
    ///     Look for grids in an area and returns them. Also selects a special grid that will be used to determine the
    ///     orientation of an explosion in space.
    /// </summary>
    /// <remarks>
    ///     Note that even though an explosion may start ON a grid, the explosion in space may still be orientated to
    ///     match a separate grid. This is done so that if you have something like a tiny suicide-bomb shuttle exploding
    ///     near a large station, the explosion will still orient to match the station, not the tiny shuttle.
    /// </remarks>
    public (List <EntityUid>, EntityUid?, float) GetLocalGrids(MapCoordinates epicenter, float totalIntensity, float slope, float maxIntensity)
    {
        // Get the explosion radius (approx radius if it were in open-space). Note that if the explosion is confined in
        // some directions but not in others, the actual explosion may reach further than this distance from the
        // epicenter. Conversely, it might go nowhere near as far.
        var radius = 0.5f + IntensityToRadius(totalIntensity, slope, maxIntensity);

        // to avoid a silly lookup for silly input numbers, cap the radius to half of the theoretical maximum (lookup area gets doubled later on).
        radius = Math.Min(radius, MaxIterations / 4);

        EntityUid?referenceGrid = null;
        float     mass          = 0;

        // First attempt to find a grid that is relatively close to the explosion's center. Instead of looking in a
        // diameter x diameter sized box, use a smaller box with radius sized sides:
        var box = Box2.CenteredAround(epicenter.Position, (radius, radius));

        foreach (var grid in _mapManager.FindGridsIntersecting(epicenter.MapId, box))
        {
            if (TryComp(grid.GridEntityId, out PhysicsComponent? physics) && physics.Mass > mass)
            {
                mass          = physics.Mass;
                referenceGrid = grid.GridEntityId;
            }
        }

        // Next, we use a much larger lookup to determine all grids relevant to the explosion. This is used to determine
        // what grids should be included during the grid-edge transformation steps. This means that if a grid is not in
        // this set, the explosion can never propagate from space onto this grid.

        // As mentioned before, the `diameter` is only indicative, as an explosion that is obstructed (e.g., in a
        // tunnel) may travel further away from the epicenter. But this should be very rare for space-traversing
        // explosions. So instead of using the largest possible distance that an explosion could theoretically travel
        // and using that for the grid look-up, we will just arbitrarily fudge the lookup size to be twice the diameter.

        radius *= 4;
        box     = Box2.CenteredAround(epicenter.Position, (radius, radius));
        var mapGrids = _mapManager.FindGridsIntersecting(epicenter.MapId, box).ToList();
        var grids    = mapGrids.Select(x => x.GridEntityId).ToList();

        if (referenceGrid != null)
        {
            return(grids, referenceGrid, radius);
        }

        // We still don't have are reference grid. So lets also look in the enlarged region
        foreach (var grid in mapGrids)
        {
            if (TryComp(grid.GridEntityId, out PhysicsComponent? physics) && physics.Mass > mass)
            {
                mass          = physics.Mass;
                referenceGrid = grid.GridEntityId;
            }
        }

        return(grids, referenceGrid, radius);
    }
예제 #9
0
        private Box2 GetEntityBox(IEntity entity)
        {
            // Need to clip the aabb as anything with an edge intersecting another tile might be picked up, such as walls.
            if (entity.TryGetComponent(out IPhysicsComponent? physics))
            {
                return(new Box2(physics.WorldAABB.BottomLeft + 0.01f, physics.WorldAABB.TopRight - 0.01f));
            }

            // Don't want to accidentally get neighboring tiles unless we're near an edge
            return(Box2.CenteredAround(entity.Transform.Coordinates.ToMapPos(EntityManager), Vector2.One / 2));
        }
예제 #10
0
        private List <GasOverlayChunk> GetChunksInRange(IEntity entity)
        {
            var inRange = new List <GasOverlayChunk>();

            // This is the max in any direction that we can get a chunk (e.g. max 2 chunks away of data).
            var(maxXDiff, maxYDiff) = ((int)(_updateRange / ChunkSize) + 1, (int)(_updateRange / ChunkSize) + 1);

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

            foreach (var grid in _mapManager.FindGridsIntersecting(entity.Transform.MapID, worldBounds))
            {
                if (!_overlay.TryGetValue(grid.Index, out var chunks))
                {
                    continue;
                }

                var entityTile = grid.GetTileRef(entity.Transform.Coordinates).GridIndices;

                for (var x = -maxXDiff; x <= maxXDiff; x++)
                {
                    for (var y = -maxYDiff; y <= maxYDiff; y++)
                    {
                        var chunkIndices = GetGasChunkIndices(new MapIndices(entityTile.X + x * ChunkSize, entityTile.Y + y * ChunkSize));

                        if (!chunks.TryGetValue(chunkIndices, out var chunk))
                        {
                            continue;
                        }

                        // Now we'll check if it's in range and relevant for us
                        // (e.g. if we're on the very edge of a chunk we may need more chunks).

                        var(xDiff, yDiff) = (chunkIndices.X - entityTile.X, chunkIndices.Y - entityTile.Y);
                        if (xDiff > 0 && xDiff > _updateRange ||
                            yDiff > 0 && yDiff > _updateRange ||
                            xDiff < 0 && Math.Abs(xDiff + ChunkSize) > _updateRange ||
                            yDiff < 0 && Math.Abs(yDiff + ChunkSize) > _updateRange)
                        {
                            continue;
                        }

                        inRange.Add(chunk);
                    }
                }
            }

            return(inRange);
        }
예제 #11
0
        public override void FrameUpdate(float frameTime)
        {
            var eye = _eyeManager.CurrentEye;

            // So we could calculate the correct size of the entities based on the contents of their sprite...
            // Or we can just assume that no entity is larger than 10x10 and get a stupid easy check.
            // TODO: Make this check more accurate.
            var worldBounds = Box2.CenteredAround(eye.Position.Position,
                                                  _clyde.ScreenSize / EyeManager.PIXELSPERMETER * eye.Zoom).Enlarged(5);

            var mapEntity = _mapManager.GetMapEntityId(eye.Position.MapId);

            var parentMatrix = Matrix3.Identity;

            RunUpdatesRecurse(frameTime, worldBounds, EntityManager.GetEntity(mapEntity), ref parentMatrix);
        }
예제 #12
0
    public Box2Rotated GetWorldBounds(TileRef tileRef, Matrix3?worldMatrix = null, Angle?angle = null)
    {
        var grid = _mapManager.GetGrid(tileRef.GridIndex);

        if (worldMatrix == null || angle == null)
        {
            var gridXform = EntityManager.GetComponent <TransformComponent>(grid.GridEntityId);
            var(_, wAng, wMat) = gridXform.GetWorldPositionRotationMatrix();
            worldMatrix        = wMat;
            angle = wAng;
        }

        var center        = worldMatrix.Value.Transform((Vector2)tileRef.GridIndices + 0.5f) * grid.TileSize;
        var translatedBox = Box2.CenteredAround(center, (grid.TileSize, grid.TileSize));

        return(new Box2Rotated(translatedBox, -angle.Value, center));
    }
예제 #13
0
        public override void FrameUpdate(float frameTime)
        {
            var eye = _eyeManager.CurrentEye;

            // So we could calculate the correct size of the entities based on the contents of their sprite...
            // Or we can just assume that no entity is larger than 10x10 and get a stupid easy check.
            // TODO: Make this check more accurate.
            var worldBounds = Box2.CenteredAround(eye.Position.Position,
                                                  _clyde.ScreenSize / EyeManager.PIXELSPERMETER * eye.Zoom).Enlarged(5);

            foreach (var entity in EntityManager.GetEntities(EntityQuery))
            {
                var transform = entity.Transform;
                if (!worldBounds.Contains(transform.WorldPosition))
                {
                    continue;
                }

                // TODO: Don't call this on components without RSIs loaded.
                // Serious performance benefit here.
                entity.GetComponent <ISpriteComponent>().FrameUpdate(frameTime);
            }
        }
예제 #14
0
        private void _drawLights(Box2 worldBounds)
        {
            if (!_lightManager.Enabled)
            {
                return;
            }

            var map = _eyeManager.CurrentMap;

            GL.BindFramebuffer(FramebufferTarget.Framebuffer, LightRenderTarget.ObjectHandle.Handle);
            var converted = Color.FromSrgb(new Color(0.1f, 0.1f, 0.1f));

            GL.ClearColor(converted.R, converted.G, converted.B, 1);
            GL.Clear(ClearBufferMask.ColorBufferBit);

            var(lightW, lightH) = _lightMapSize();
            GL.Viewport(0, 0, lightW, lightH);

            _lightShader.Use();

            GL.BlendFunc(BlendingFactor.SrcAlpha, BlendingFactor.One);

            var     lastRange = float.NaN;
            var     lastPower = float.NaN;
            var     lastColor = new Color(float.NaN, float.NaN, float.NaN, float.NaN);
            Texture lastMask  = null;

            foreach (var component in _componentManager.GetAllComponents <PointLightComponent>())
            {
                if (!component.Enabled || component.Owner.Transform.MapID != map)
                {
                    continue;
                }

                var transform = component.Owner.Transform;
                var lightPos  = transform.WorldMatrix.Transform(component.Offset);

                var lightBounds = Box2.CenteredAround(lightPos, Vector2.One * component.Radius * 2);

                if (!lightBounds.Intersects(worldBounds))
                {
                    continue;
                }

                Texture mask     = null;
                var     rotation = Angle.Zero;
                if (component.Mask != null)
                {
                    mask     = component.Mask;
                    rotation = component.Rotation;

                    if (component.MaskAutoRotate)
                    {
                        rotation += transform.WorldRotation;
                    }
                }

                var maskTexture = mask ?? Texture.White;
                if (lastMask != maskTexture)
                {
                    var maskHandle = _loadedTextures[((ClydeTexture)maskTexture).TextureId].OpenGLObject;
                    GL.ActiveTexture(TextureUnit.Texture0);
                    GL.BindTexture(TextureTarget.Texture2D, maskHandle.Handle);
                    lastMask = maskTexture;
                    _lightShader.SetUniformTexture("lightMask", TextureUnit.Texture0);
                }

                if (!FloatMath.CloseTo(lastRange, component.Radius))
                {
                    lastRange = component.Radius;
                    _lightShader.SetUniform("lightRange", lastRange);
                }

                if (!FloatMath.CloseTo(lastPower, component.Energy))
                {
                    lastPower = component.Energy;
                    _lightShader.SetUniform("lightPower", lastPower);
                }

                if (lastColor != component.Color)
                {
                    lastColor = component.Color;
                    _lightShader.SetUniform("lightColor", lastColor);
                }

                _lightShader.SetUniform("lightCenter", lightPos);

                var offset = new Vector2(component.Radius, component.Radius);

                Matrix3 matrix;
                if (mask == null)
                {
                    matrix = Matrix3.Identity;
                }
                else
                {
                    // Only apply rotation if a mask is said, because else it doesn't matter.
                    matrix = Matrix3.CreateRotation(rotation);
                }

                (matrix.R0C2, matrix.R1C2) = lightPos;

                _drawQuad(-offset, offset, ref matrix, _lightShader);
            }

            GL.BlendFunc(BlendingFactor.SrcAlpha, BlendingFactor.OneMinusSrcAlpha);

            GL.BindFramebuffer(FramebufferTarget.Framebuffer, 0);
            GL.Viewport(0, 0, ScreenSize.X, ScreenSize.Y);

            _lightingReady = true;
        }
예제 #15
0
        public void Render()
        {
            _debugStats.Reset();

            // Basic pre-render busywork.
            // Clear screen to black.
            ClearFramebuffer(Color.Black);

            // Update shared UBOs.
            _updateUniformConstants();

            _setSpace(CurrentSpace.ScreenSpace);

            // Short path to render only the splash.
            if (_drawingSplash)
            {
                _drawSplash(_renderHandle);
                _flushRenderHandle(_renderHandle);
                _window.SwapBuffers();
                return;
            }

            void RenderOverlays(OverlaySpace space)
            {
                using (DebugGroup($"Overlays: {space}"))
                {
                    foreach (var overlay in _overlayManager.AllOverlays
                             .Where(o => o.Space == space)
                             .OrderBy(o => o.ZIndex))
                    {
                        overlay.ClydeRender(_renderHandle);
                    }

                    _flushRenderHandle(_renderHandle);
                }
            }

            if (!_lite)
            {
                RenderOverlays(OverlaySpace.ScreenSpaceBelowWorld);

                _setSpace(CurrentSpace.WorldSpace);

                // Calculate world-space AABB for camera, to cull off-screen things.
                var eye         = _eyeManager.CurrentEye;
                var worldBounds = Box2.CenteredAround(eye.Position.Position,
                                                      _screenSize / EyeManager.PIXELSPERMETER * eye.Zoom);

                using (DebugGroup("Lights"))
                {
                    _drawLights(worldBounds);
                }

                using (DebugGroup("Grids"))
                {
                    _drawGrids(worldBounds);
                }

                using (DebugGroup("Entities"))
                {
                    _sortingSpritesList.Clear();
                    var map = _eyeManager.CurrentMap;

                    // So we could calculate the correct size of the entities based on the contents of their sprite...
                    // Or we can just assume that no entity is larger than 10x10 and get a stupid easy check.
                    // TODO: Make this check more accurate.
                    var widerBounds = worldBounds.Enlarged(5);

                    foreach (var sprite in _componentManager.GetAllComponents <SpriteComponent>())
                    {
                        var entity = sprite.Owner;
                        if (!entity.Transform.IsMapTransform || entity.Transform.MapID != map ||
                            !widerBounds.Contains(entity.Transform.WorldPosition) || !sprite.Visible)
                        {
                            continue;
                        }

                        _sortingSpritesList.Add(sprite);
                    }

                    _sortingSpritesList.Sort((a, b) =>
                    {
                        var cmp = ((int)a.DrawDepth).CompareTo((int)b.DrawDepth);
                        if (cmp != 0)
                        {
                            return(cmp);
                        }

                        cmp = a.RenderOrder.CompareTo(b.RenderOrder);

                        if (cmp != 0)
                        {
                            return(cmp);
                        }

                        return(a.Owner.Uid.CompareTo(b.Owner.Uid));
                    });

                    foreach (var sprite in _sortingSpritesList)
                    {
                        Vector2i roundedPos = default;
                        if (sprite.PostShader != null)
                        {
                            _renderHandle.UseRenderTarget(EntityPostRenderTarget);
                            _renderHandle.Clear(new Color());
                            // Calculate viewport so that the entity thinks it's drawing to the same position,
                            // which is necessary for light application,
                            // but it's ACTUALLY drawing into the center of the render target.
                            var spritePos = sprite.Owner.Transform.WorldPosition;
                            var screenPos = _eyeManager.WorldToScreen(spritePos);
                            var(roundedX, roundedY) = roundedPos = (Vector2i)screenPos;
                            var flippedPos = new Vector2i(roundedX, ScreenSize.Y - roundedY);
                            flippedPos -= EntityPostRenderTarget.Size / 2;
                            _renderHandle.Viewport(Box2i.FromDimensions(-flippedPos, ScreenSize));
                        }

                        sprite.OpenGLRender(_renderHandle.DrawingHandleWorld);

                        if (sprite.PostShader != null)
                        {
                            _renderHandle.UseRenderTarget(null);
                            _renderHandle.Viewport(Box2i.FromDimensions(Vector2i.Zero, ScreenSize));

                            _renderHandle.UseShader(sprite.PostShader);
                            _renderHandle.SetSpace(CurrentSpace.ScreenSpace);
                            _renderHandle.SetModelTransform(Matrix3.Identity);

                            var rounded = roundedPos - EntityPostRenderTarget.Size / 2;

                            var box = UIBox2i.FromDimensions(rounded, EntityPostRenderTarget.Size);

                            _renderHandle.DrawTexture(EntityPostRenderTarget.Texture, box.BottomLeft,
                                                      box.TopRight, Color.White, null, 0);

                            _renderHandle.SetSpace(CurrentSpace.WorldSpace);
                            _renderHandle.UseShader(null);
                        }
                    }

                    _flushRenderHandle(_renderHandle);
                }

                RenderOverlays(OverlaySpace.WorldSpace);

                _lightingReady = false;

                _setSpace(CurrentSpace.ScreenSpace);

                RenderOverlays(OverlaySpace.ScreenSpace);
            }

            using (DebugGroup("UI"))
            {
                _userInterfaceManager.Render(_renderHandle);
                _flushRenderHandle(_renderHandle);
            }

            // And finally, swap those buffers!
            _window.SwapBuffers();
        }
        public IList <EntityUid> GetEntitiesUnderPosition(MapCoordinates coordinates)
        {
            // Find all the entities intersecting our click
            var entities = IoCManager.Resolve <IEntityLookup>().GetEntitiesIntersecting(coordinates.MapId,
                                                                                        Box2.CenteredAround(coordinates.Position, (1, 1)));

            var containerSystem = _entitySystemManager.GetEntitySystem <SharedContainerSystem>();

            // Check the entities against whether or not we can click them
            var foundEntities = new List <(EntityUid clicked, int drawDepth, uint renderOrder)>();

            foreach (var entity in entities)
            {
                if (_entityManager.TryGetComponent <ClickableComponent?>(entity, out var component) &&
                    !containerSystem.IsEntityInContainer(entity) &&
                    component.CheckClick(coordinates.Position, out var drawDepthClicked, out var renderOrder))
                {
                    foundEntities.Add((entity, drawDepthClicked, renderOrder));
                }
            }

            if (foundEntities.Count == 0)
            {
                return(Array.Empty <EntityUid>());
            }

            foundEntities.Sort(_comparer);
            // 0 is the top element.
            foundEntities.Reverse();
            return(foundEntities.Select(a => a.clicked).ToList());
        }
 public GridEdgeData(Vector2i tile, EntityUid?grid, Vector2 center, Angle angle, float size)
 {
     Tile = tile;
     Grid = grid;
     Box  = new(Box2.CenteredAround(center, (size, size)), angle, center);
 }
예제 #18
0
        protected override void Draw(DrawingHandleBase handle, OverlaySpace overlay)
        {
            var drawHandle = (DrawingHandleWorld)handle;

            var mapId = _eyeManager.CurrentMap;
            var eye   = _eyeManager.CurrentEye;

            var worldBounds = Box2.CenteredAround(eye.Position.Position,
                                                  _clyde.ScreenSize / (float)EyeManager.PixelsPerMeter * eye.Zoom);

            // IF YOU ARE ABOUT TO INTRODUCE CHUNKING OR SOME OTHER OPTIMIZATION INTO THIS CODE:
            //  -- THINK! --
            // 1. "Is this going to make a critical atmos debugging tool harder to debug itself?"
            // 2. "Is this going to do anything that could cause the atmos debugging tool to use resources, server-side or client-side, when nobody's using it?"
            // 3. "Is this going to make it harder for atmos programmers to add data that may not be chunk-friendly into the atmos debugger?"
            // Nanotrasen needs YOU! to avoid premature optimization in critical debugging tools - 20kdc

            foreach (var mapGrid in _mapManager.FindGridsIntersecting(mapId, worldBounds))
            {
                if (!_atmosDebugOverlaySystem.HasData(mapGrid.Index))
                {
                    continue;
                }

                var gridBounds = new Box2(mapGrid.WorldToLocal(worldBounds.BottomLeft), mapGrid.WorldToLocal(worldBounds.TopRight));

                for (var pass = 0; pass < 2; pass++)
                {
                    foreach (var tile in mapGrid.GetTilesIntersecting(gridBounds))
                    {
                        var dataMaybeNull = _atmosDebugOverlaySystem.GetData(mapGrid.Index, tile.GridIndices);
                        if (dataMaybeNull != null)
                        {
                            var data = (SharedAtmosDebugOverlaySystem.AtmosDebugOverlayData)dataMaybeNull !;
                            if (pass == 0)
                            {
                                // -- Mole Count --
                                float total = 0;
                                switch (_atmosDebugOverlaySystem.CfgMode)
                                {
                                case AtmosDebugOverlayMode.TotalMoles:
                                    foreach (float f in data.Moles)
                                    {
                                        total += f;
                                    }
                                    break;

                                case AtmosDebugOverlayMode.GasMoles:
                                    total = data.Moles[_atmosDebugOverlaySystem.CfgSpecificGas];
                                    break;

                                case AtmosDebugOverlayMode.Temperature:
                                    total = data.Temperature;
                                    break;
                                }
                                var   interp = ((total - _atmosDebugOverlaySystem.CfgBase) / _atmosDebugOverlaySystem.CfgScale);
                                Color res;
                                if (_atmosDebugOverlaySystem.CfgCBM)
                                {
                                    // Greyscale interpolation
                                    res = Color.InterpolateBetween(Color.Black, Color.White, interp);
                                }
                                else
                                {
                                    // Red-Green-Blue interpolation
                                    if (interp < 0.5f)
                                    {
                                        res = Color.InterpolateBetween(Color.Red, Color.Green, interp * 2);
                                    }
                                    else
                                    {
                                        res = Color.InterpolateBetween(Color.Green, Color.Blue, (interp - 0.5f) * 2);
                                    }
                                }
                                res = res.WithAlpha(0.75f);
                                drawHandle.DrawRect(Box2.FromDimensions(mapGrid.LocalToWorld(new Vector2(tile.X, tile.Y)), new Vector2(1, 1)), res);
                            }
                            else if (pass == 1)
                            {
                                // -- Blocked Directions --
                                void CheckAndShowBlockDir(AtmosDirection dir)
                                {
                                    if (data.BlockDirection.HasFlag(dir))
                                    {
                                        // Account for South being 0.
                                        var atmosAngle       = dir.ToAngle() - Angle.FromDegrees(90);
                                        var atmosAngleOfs    = atmosAngle.ToVec() * 0.45f;
                                        var atmosAngleOfsR90 = new Vector2(atmosAngleOfs.Y, -atmosAngleOfs.X);
                                        var tileCentre       = new Vector2(tile.X + 0.5f, tile.Y + 0.5f);
                                        var basisA           = mapGrid.LocalToWorld(tileCentre + atmosAngleOfs - atmosAngleOfsR90);
                                        var basisB           = mapGrid.LocalToWorld(tileCentre + atmosAngleOfs + atmosAngleOfsR90);
                                        drawHandle.DrawLine(basisA, basisB, Color.Azure);
                                    }
                                }

                                CheckAndShowBlockDir(AtmosDirection.North);
                                CheckAndShowBlockDir(AtmosDirection.South);
                                CheckAndShowBlockDir(AtmosDirection.East);
                                CheckAndShowBlockDir(AtmosDirection.West);
                                // -- Pressure Direction --
                                if (data.PressureDirection != AtmosDirection.Invalid)
                                {
                                    // Account for South being 0.
                                    var atmosAngle    = data.PressureDirection.ToAngle() - Angle.FromDegrees(90);
                                    var atmosAngleOfs = atmosAngle.ToVec() * 0.4f;
                                    var tileCentre    = new Vector2(tile.X + 0.5f, tile.Y + 0.5f);
                                    var basisA        = mapGrid.LocalToWorld(tileCentre);
                                    var basisB        = mapGrid.LocalToWorld(tileCentre + atmosAngleOfs);
                                    drawHandle.DrawLine(basisA, basisB, Color.Blue);
                                }
                                // -- Excited Groups --
                                if (data.InExcitedGroup)
                                {
                                    var tilePos = new Vector2(tile.X, tile.Y);
                                    var basisA  = mapGrid.LocalToWorld(tilePos);
                                    var basisB  = mapGrid.LocalToWorld(tilePos + new Vector2(1.0f, 1.0f));
                                    var basisC  = mapGrid.LocalToWorld(tilePos + new Vector2(0.0f, 1.0f));
                                    var basisD  = mapGrid.LocalToWorld(tilePos + new Vector2(1.0f, 0.0f));
                                    drawHandle.DrawLine(basisA, basisB, Color.Cyan);
                                    drawHandle.DrawLine(basisC, basisD, Color.Cyan);
                                }
                            }
                        }
                    }
                }
            }
        }
예제 #19
0
        protected override void Draw(DrawingHandleBase handle, OverlaySpace overlay)
        {
            var drawHandle = (DrawingHandleWorld)handle;

            var mapId = _eyeManager.CurrentMap;
            var eye   = _eyeManager.CurrentEye;

            var worldBounds = Box2.CenteredAround(eye.Position.Position,
                                                  _clyde.ScreenSize / (float)EyeManager.PixelsPerMeter * eye.Zoom);

            // IF YOU ARE ABOUT TO INTRODUCE CHUNKING OR SOME OTHER OPTIMIZATION INTO THIS CODE:
            //  -- THINK! --
            // 1. "Is this going to make a critical atmos debugging tool harder to debug itself?"
            // 2. "Is this going to do anything that could cause the atmos debugging tool to use resources, server-side or client-side, when nobody's using it?"
            // 3. "Is this going to make it harder for atmos programmers to add data that may not be chunk-friendly into the atmos debugger?"
            // Nanotrasen needs YOU! to avoid premature optimization in critical debugging tools - 20kdc

            foreach (var mapGrid in _mapManager.FindGridsIntersecting(mapId, worldBounds))
            {
                if (!_atmosDebugOverlaySystem.HasData(mapGrid.Index))
                {
                    continue;
                }

                var gridBounds = new Box2(mapGrid.WorldToLocal(worldBounds.BottomLeft), mapGrid.WorldToLocal(worldBounds.TopRight));

                for (var pass = 0; pass < 3; pass++)
                {
                    foreach (var tile in mapGrid.GetTilesIntersecting(gridBounds))
                    {
                        var dataMaybeNull = _atmosDebugOverlaySystem.GetData(mapGrid.Index, tile.GridIndices);
                        if (dataMaybeNull != null)
                        {
                            var data = (SharedAtmosDebugOverlaySystem.AtmosDebugOverlayData)dataMaybeNull !;
                            if (pass == 0)
                            {
                                float total = 0;
                                foreach (float f in data.Moles)
                                {
                                    total += f;
                                }
                                var interp = total / (Atmospherics.MolesCellStandard * 2);
                                var res    = Color.InterpolateBetween(Color.Red, Color.Green, interp).WithAlpha(0.75f);
                                drawHandle.DrawRect(Box2.FromDimensions(mapGrid.LocalToWorld(new Vector2(tile.X, tile.Y)), new Vector2(1, 1)), res);
                            }
                            else if (pass == 1)
                            {
                                if (data.PressureDirection != AtmosDirection.Invalid)
                                {
                                    var atmosAngle    = data.PressureDirection.ToAngle();
                                    var atmosAngleOfs = atmosAngle.ToVec() * 0.4f;
                                    var tileCentre    = new Vector2(tile.X + 0.5f, tile.Y + 0.5f);
                                    var basisA        = mapGrid.LocalToWorld(tileCentre);
                                    var basisB        = mapGrid.LocalToWorld(tileCentre + atmosAngleOfs);
                                    drawHandle.DrawLine(basisA, basisB, Color.Blue);
                                }
                            }
                            else if (pass == 2)
                            {
                                if (data.InExcitedGroup)
                                {
                                    var tilePos = new Vector2(tile.X, tile.Y);
                                    var basisA  = mapGrid.LocalToWorld(tilePos);
                                    var basisB  = mapGrid.LocalToWorld(tilePos + new Vector2(1.0f, 1.0f));
                                    var basisC  = mapGrid.LocalToWorld(tilePos + new Vector2(0.0f, 1.0f));
                                    var basisD  = mapGrid.LocalToWorld(tilePos + new Vector2(1.0f, 0.0f));
                                    drawHandle.DrawLine(basisA, basisB, Color.Cyan);
                                    drawHandle.DrawLine(basisC, basisD, Color.Cyan);
                                }
                            }
                        }
                    }
                }
            }
        }