]> git.smokeofanarchy.ru Git - space-station-14.git/commitdiff
Roof data rework (#35388)
authormetalgearsloth <31366439+metalgearsloth@users.noreply.github.com>
Sun, 23 Feb 2025 07:23:00 +0000 (18:23 +1100)
committerGitHub <noreply@github.com>
Sun, 23 Feb 2025 07:23:00 +0000 (18:23 +1100)
12 files changed:
Content.Client/Light/RoofOverlay.cs
Content.Client/Overlays/StencilOverlay.Weather.cs
Content.Client/Weather/WeatherSystem.cs
Content.Shared/Light/Components/IsRoofComponent.cs [new file with mode: 0644]
Content.Shared/Light/Components/RoofComponent.cs
Content.Shared/Light/EntitySystems/SharedRoofSystem.cs
Content.Shared/Maps/ContentTileDefinition.cs
Content.Shared/Parallax/Biomes/Layers/BiomeTileLayer.cs
Content.Shared/Parallax/Biomes/SharedBiomeSystem.cs
Content.Shared/Weather/SharedWeatherSystem.cs
Resources/Prototypes/Entities/Structures/Walls/walls.yml
Resources/Prototypes/Procedural/biome_templates.yml

index 5543103cdc64de2233b014584c4eb8cfc4f69a51..0648f8624fae3f090765bd77ff0d97504d30d487 100644 (file)
@@ -1,10 +1,12 @@
 using System.Numerics;
 using Content.Shared.Light.Components;
+using Content.Shared.Light.EntitySystems;
 using Content.Shared.Maps;
 using Robust.Client.Graphics;
 using Robust.Shared.Enums;
 using Robust.Shared.Map;
 using Robust.Shared.Map.Components;
+using Robust.Shared.Map.Enumerators;
 using Robust.Shared.Physics;
 
 namespace Content.Client.Light;
@@ -17,9 +19,9 @@ public sealed class RoofOverlay : Overlay
 
     private readonly EntityLookupSystem _lookup;
     private readonly SharedMapSystem _mapSystem;
+    private readonly SharedRoofSystem _roof = default!;
     private readonly SharedTransformSystem _xformSystem;
 
-    private readonly HashSet<Entity<OccluderComponent>> _occluders = new();
     private List<Entity<MapGridComponent>> _grids = new();
 
     public override OverlaySpace Space => OverlaySpace.BeforeLighting;
@@ -33,6 +35,7 @@ public sealed class RoofOverlay : Overlay
 
         _lookup = _entManager.System<EntityLookupSystem>();
         _mapSystem = _entManager.System<SharedMapSystem>();
+        _roof = _entManager.System<SharedRoofSystem>();
         _xformSystem = _entManager.System<SharedTransformSystem>();
 
         ZIndex = ContentZIndex;
@@ -86,29 +89,14 @@ public sealed class RoofOverlay : Overlay
                     worldHandle.SetTransform(matty);
 
                     var tileEnumerator = _mapSystem.GetTilesEnumerator(grid.Owner, grid, bounds);
+                    var roofEnt = (grid.Owner, grid.Comp, roof);
 
                     // Due to stencilling we essentially draw on unrooved tiles
                     while (tileEnumerator.MoveNext(out var tileRef))
                     {
-                        if ((tileRef.Tile.Flags & (byte) TileFlag.Roof) == 0x0)
+                        if (!_roof.IsRooved(roofEnt, tileRef.GridIndices))
                         {
-                            // Check if the tile is occluded in which case hide it anyway.
-                            // This is to avoid lit walls bleeding over to unlit tiles.
-                            _occluders.Clear();
-                            _lookup.GetLocalEntitiesIntersecting(grid.Owner, tileRef.GridIndices, _occluders);
-                            var found = false;
-
-                            foreach (var occluder in _occluders)
-                            {
-                                if (!occluder.Comp.Enabled)
-                                    continue;
-
-                                found = true;
-                                break;
-                            }
-
-                            if (!found)
-                                continue;
+                            continue;
                         }
 
                         var local = _lookup.GetLocalBounds(tileRef, grid.Comp.TileSize);
index ad69522dfdab0d2c038c567f3b0549cb1adcb9b6..b1a521433a89dda4ce1a85be84a70b7382f955f2 100644 (file)
@@ -1,4 +1,5 @@
 using System.Numerics;
+using Content.Shared.Light.Components;
 using Content.Shared.Weather;
 using Robust.Client.Graphics;
 using Robust.Shared.Map.Components;
@@ -34,11 +35,12 @@ public sealed partial class StencilOverlay
                 var matrix = _transform.GetWorldMatrix(grid, xformQuery);
                 var matty =  Matrix3x2.Multiply(matrix, invMatrix);
                 worldHandle.SetTransform(matty);
+                _entManager.TryGetComponent(grid.Owner, out RoofComponent? roofComp);
 
                 foreach (var tile in _map.GetTilesIntersecting(grid.Owner, grid, worldAABB))
                 {
                     // Ignored tiles for stencil
-                    if (_weather.CanWeatherAffect(grid.Owner, grid, tile))
+                    if (_weather.CanWeatherAffect(grid.Owner, grid, tile, roofComp))
                     {
                         continue;
                     }
index 975831392cb7b85796ad3f601b99104023d7be07..26def25a15f2de519a1476304fd97e8528b987b6 100644 (file)
@@ -1,4 +1,5 @@
 using System.Numerics;
+using Content.Shared.Light.Components;
 using Content.Shared.Weather;
 using Robust.Client.Audio;
 using Robust.Client.GameObjects;
@@ -57,6 +58,7 @@ public sealed class WeatherSystem : SharedWeatherSystem
         // Work out tiles nearby to determine volume.
         if (TryComp<MapGridComponent>(entXform.GridUid, out var grid))
         {
+            TryComp(entXform.GridUid, out RoofComponent? roofComp);
             var gridId = entXform.GridUid.Value;
             // FloodFill to the nearest tile and use that for audio.
             var seed = _mapSystem.GetTileRef(gridId, grid, entXform.Coordinates);
@@ -71,7 +73,7 @@ public sealed class WeatherSystem : SharedWeatherSystem
                 if (!visited.Add(node.GridIndices))
                     continue;
 
-                if (!CanWeatherAffect(entXform.GridUid.Value, grid, node))
+                if (!CanWeatherAffect(entXform.GridUid.Value, grid, node, roofComp))
                 {
                     // Add neighbors
                     // TODO: Ideally we pick some deterministically random direction and use that
diff --git a/Content.Shared/Light/Components/IsRoofComponent.cs b/Content.Shared/Light/Components/IsRoofComponent.cs
new file mode 100644 (file)
index 0000000..d64793f
--- /dev/null
@@ -0,0 +1,13 @@
+using Robust.Shared.GameStates;
+
+namespace Content.Shared.Light.Components;
+
+/// <summary>
+/// Counts the tile this entity on as being rooved.
+/// </summary>
+[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
+public sealed partial class IsRoofComponent : Component
+{
+    [DataField, AutoNetworkedField]
+    public bool Enabled = true;
+}
index 0e2adf527cda58a0d02fead28f5b2712e3111850..47de333af0af993f6efac03374287d2f803ac275 100644 (file)
@@ -3,11 +3,19 @@ using Robust.Shared.GameStates;
 namespace Content.Shared.Light.Components;
 
 /// <summary>
-/// Will draw shadows over tiles flagged as roof tiles on the attached map.
+/// Will draw shadows over tiles flagged as roof tiles on the attached grid.
 /// </summary>
 [RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
 public sealed partial class RoofComponent : Component
 {
+    public const int ChunkSize = 8;
+
     [DataField, AutoNetworkedField]
     public Color Color = Color.Black;
+
+    /// <summary>
+    /// Chunk origin and bitmask of value in chunk.
+    /// </summary>
+    [DataField, AutoNetworkedField]
+    public Dictionary<Vector2i, ulong> Data = new();
 }
index d06b5bcb0ce037e1d8ac19aedd998cbcbc42f56a..2d19b8ba87cec91dc7eefe64105f5cd32479787c 100644 (file)
@@ -10,33 +10,85 @@ namespace Content.Shared.Light.EntitySystems;
 /// </summary>
 public abstract class SharedRoofSystem : EntitySystem
 {
-    [Dependency] private readonly SharedMapSystem _maps = default!;
+    [Dependency] private readonly EntityLookupSystem _lookup = default!;
+
+    private HashSet<Entity<IsRoofComponent>> _roofSet = new();
+
+    /// <summary>
+    /// Returns whether the specified tile is roof-occupied.
+    /// </summary>
+    /// <returns>Returns false if no data or not rooved.</returns>
+    public bool IsRooved(Entity<MapGridComponent, RoofComponent> grid, Vector2i index)
+    {
+        var roof = grid.Comp2;
+        var chunkOrigin = SharedMapSystem.GetChunkIndices(index, RoofComponent.ChunkSize);
+
+        if (roof.Data.TryGetValue(chunkOrigin, out var bitMask))
+        {
+            var chunkRelative = SharedMapSystem.GetChunkRelative(index, RoofComponent.ChunkSize);
+            var bitFlag = (ulong) 1 << (chunkRelative.X + chunkRelative.Y * RoofComponent.ChunkSize);
+
+            var isRoof = (bitMask & bitFlag) == bitFlag;
+
+            // Early out, otherwise check for components on tile.
+            if (isRoof)
+                return true;
+        }
+
+        _roofSet.Clear();
+        _lookup.GetLocalEntitiesIntersecting(grid.Owner, index, _roofSet);
+
+        foreach (var isRoofEnt in _roofSet)
+        {
+            if (!isRoofEnt.Comp.Enabled)
+                continue;
+
+            return true;
+        }
+
+        return false;
+    }
 
     public void SetRoof(Entity<MapGridComponent?, RoofComponent?> grid, Vector2i index, bool value)
     {
         if (!Resolve(grid, ref grid.Comp1, ref grid.Comp2, false))
             return;
 
-        if (!_maps.TryGetTile(grid.Comp1, index, out var tile))
-            return;
+        var chunkOrigin = SharedMapSystem.GetChunkIndices(index, RoofComponent.ChunkSize);
+        var roof = grid.Comp2;
 
-        var mask = (tile.Flags & (byte)TileFlag.Roof);
-        var rooved = mask != 0x0;
+        if (!roof.Data.TryGetValue(chunkOrigin, out var chunkData))
+        {
+            // No value to remove so leave it.
+            if (!value)
+            {
+                return;
+            }
 
-        if (rooved == value)
-            return;
+            chunkData = 0;
+        }
 
-        Tile newTile;
+        var chunkRelative = SharedMapSystem.GetChunkRelative(index, RoofComponent.ChunkSize);
+        var bitFlag = (ulong) 1 << (chunkRelative.X + chunkRelative.Y * RoofComponent.ChunkSize);
 
         if (value)
         {
-            newTile = tile.WithFlag((byte)(tile.Flags | (ushort)TileFlag.Roof));
+            // Already set
+            if ((chunkData & bitFlag) == bitFlag)
+                return;
+
+            chunkData |= bitFlag;
         }
         else
         {
-            newTile = tile.WithFlag((byte)(tile.Flags & ~(ushort)TileFlag.Roof));
+            // Not already set
+            if ((chunkData & bitFlag) == 0x0)
+                return;
+
+            chunkData &= ~bitFlag;
         }
 
-        _maps.SetTile((grid.Owner, grid.Comp1), index, newTile);
+        roof.Data[chunkOrigin] = chunkData;
+        Dirty(grid.Owner, roof);
     }
 }
index 86ceac77be7eb63539555aff21d1104f00c9e499..a9ad016b8711900a039a65763ef16f55868fb13d 100644 (file)
@@ -120,11 +120,4 @@ namespace Content.Shared.Maps
             TileId = id;
         }
     }
-
-    [Flags]
-    public enum TileFlag : byte
-    {
-        None = 0,
-        Roof = 1 << 0,
-    }
 }
index 114b6b20b92acfd8067ba55321005af8d812d65a..9dee35da4e6deb57181cc62e80075b694d5a1362 100644 (file)
@@ -26,11 +26,4 @@ public sealed partial class BiomeTileLayer : IBiomeLayer
 
     [DataField(required: true)]
     public ProtoId<ContentTileDefinition> Tile = string.Empty;
-
-    // TODO: Need some good engine solution to this, see FlagSerializer for what needs changing.
-    /// <summary>
-    /// Flags to set on the tile when placed.
-    /// </summary>
-    [DataField]
-    public byte Flags = 0;
 }
index 32a7823273f29b5e9846b8ce14dbb68fc75592f6..b06574eb5bd050559dd2d54409a4bfeda9f4aa20 100644 (file)
@@ -129,7 +129,7 @@ public abstract class SharedBiomeSystem : EntitySystem
             if (layer is not BiomeTileLayer tileLayer)
                 continue;
 
-            if (TryGetTile(indices, noiseCopy, tileLayer.Invert, tileLayer.Threshold, ProtoManager.Index(tileLayer.Tile), tileLayer.Flags, tileLayer.Variants, out tile))
+            if (TryGetTile(indices, noiseCopy, tileLayer.Invert, tileLayer.Threshold, ProtoManager.Index(tileLayer.Tile), tileLayer.Variants, out tile))
             {
                 return true;
             }
@@ -142,7 +142,7 @@ public abstract class SharedBiomeSystem : EntitySystem
     /// <summary>
     /// Gets the underlying biome tile, ignoring any existing tile that may be there.
     /// </summary>
-    private bool TryGetTile(Vector2i indices, FastNoiseLite noise, bool invert, float threshold, ContentTileDefinition tileDef, byte tileFlags, List<byte>? variants, [NotNullWhen(true)] out Tile? tile)
+    private bool TryGetTile(Vector2i indices, FastNoiseLite noise, bool invert, float threshold, ContentTileDefinition tileDef, List<byte>? variants, [NotNullWhen(true)] out Tile? tile)
     {
         var found = noise.GetNoise(indices.X, indices.Y);
         found = invert ? found * -1 : found;
@@ -163,7 +163,7 @@ public abstract class SharedBiomeSystem : EntitySystem
             variant = _tile.PickVariant(tileDef, (int) variantValue);
         }
 
-        tile = new Tile(tileDef.TileId, flags: tileFlags, variant);
+        tile = new Tile(tileDef.TileId, variant);
         return true;
     }
 
index ca870afc9eb8fc402c0eee2ff4678aa5d5a3a889..382af645655e2fa156e1e5ad5d2f1ef86525b4c6 100644 (file)
@@ -1,3 +1,5 @@
+using Content.Shared.Light.Components;
+using Content.Shared.Light.EntitySystems;
 using Content.Shared.Maps;
 using Robust.Shared.Audio.Systems;
 using Robust.Shared.Map;
@@ -17,6 +19,7 @@ public abstract class SharedWeatherSystem : EntitySystem
     [Dependency] private readonly MetaDataSystem _metadata = default!;
     [Dependency] private readonly SharedAudioSystem _audio = default!;
     [Dependency] private readonly SharedMapSystem _mapSystem = default!;
+    [Dependency] private readonly SharedRoofSystem _roof = default!;
 
     private EntityQuery<BlockWeatherComponent> _blockQuery;
 
@@ -38,12 +41,12 @@ public abstract class SharedWeatherSystem : EntitySystem
         }
     }
 
-    public bool CanWeatherAffect(EntityUid uid, MapGridComponent grid, TileRef tileRef)
+    public bool CanWeatherAffect(EntityUid uid, MapGridComponent grid, TileRef tileRef, RoofComponent? roofComp = null)
     {
         if (tileRef.Tile.IsEmpty)
             return true;
 
-        if ((tileRef.Tile.Flags & (byte) TileFlag.Roof) == (byte) TileFlag.Roof)
+        if (Resolve(uid, ref roofComp, false) && _roof.IsRooved((uid, grid, roofComp), tileRef.GridIndices))
             return false;
 
         var tileDef = (ContentTileDefinition) _tileDefManager[tileRef.Tile.TypeId];
index 278517e0e6a79ed41444a37c7337f0f102f77ca9..dd6b3d36bc1af1f728fd32b79ebda6065d8f58e6 100644 (file)
@@ -21,6 +21,7 @@
   - type: Tag
     tags:
     - Wall
+  - type: IsRoof
   - type: Sprite
     drawdepth: Walls
   - type: Icon
index 45293f582f96ed329c1bac1f220b732e5baf0814..588d95f40da5d00dfe58dfd3002a9694a54901e5 100644 (file)
     - !type:BiomeTileLayer
       threshold: -1.0
       tile: FloorAsteroidSand
-      flags: 1
 
 # Asteroid
 - type: biomeTemplate