Roof data rework (#35388)
This commit is contained in:
@@ -1,10 +1,12 @@
|
|||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
using Content.Shared.Light.Components;
|
using Content.Shared.Light.Components;
|
||||||
|
using Content.Shared.Light.EntitySystems;
|
||||||
using Content.Shared.Maps;
|
using Content.Shared.Maps;
|
||||||
using Robust.Client.Graphics;
|
using Robust.Client.Graphics;
|
||||||
using Robust.Shared.Enums;
|
using Robust.Shared.Enums;
|
||||||
using Robust.Shared.Map;
|
using Robust.Shared.Map;
|
||||||
using Robust.Shared.Map.Components;
|
using Robust.Shared.Map.Components;
|
||||||
|
using Robust.Shared.Map.Enumerators;
|
||||||
using Robust.Shared.Physics;
|
using Robust.Shared.Physics;
|
||||||
|
|
||||||
namespace Content.Client.Light;
|
namespace Content.Client.Light;
|
||||||
@@ -17,9 +19,9 @@ public sealed class RoofOverlay : Overlay
|
|||||||
|
|
||||||
private readonly EntityLookupSystem _lookup;
|
private readonly EntityLookupSystem _lookup;
|
||||||
private readonly SharedMapSystem _mapSystem;
|
private readonly SharedMapSystem _mapSystem;
|
||||||
|
private readonly SharedRoofSystem _roof = default!;
|
||||||
private readonly SharedTransformSystem _xformSystem;
|
private readonly SharedTransformSystem _xformSystem;
|
||||||
|
|
||||||
private readonly HashSet<Entity<OccluderComponent>> _occluders = new();
|
|
||||||
private List<Entity<MapGridComponent>> _grids = new();
|
private List<Entity<MapGridComponent>> _grids = new();
|
||||||
|
|
||||||
public override OverlaySpace Space => OverlaySpace.BeforeLighting;
|
public override OverlaySpace Space => OverlaySpace.BeforeLighting;
|
||||||
@@ -33,6 +35,7 @@ public sealed class RoofOverlay : Overlay
|
|||||||
|
|
||||||
_lookup = _entManager.System<EntityLookupSystem>();
|
_lookup = _entManager.System<EntityLookupSystem>();
|
||||||
_mapSystem = _entManager.System<SharedMapSystem>();
|
_mapSystem = _entManager.System<SharedMapSystem>();
|
||||||
|
_roof = _entManager.System<SharedRoofSystem>();
|
||||||
_xformSystem = _entManager.System<SharedTransformSystem>();
|
_xformSystem = _entManager.System<SharedTransformSystem>();
|
||||||
|
|
||||||
ZIndex = ContentZIndex;
|
ZIndex = ContentZIndex;
|
||||||
@@ -86,28 +89,13 @@ public sealed class RoofOverlay : Overlay
|
|||||||
worldHandle.SetTransform(matty);
|
worldHandle.SetTransform(matty);
|
||||||
|
|
||||||
var tileEnumerator = _mapSystem.GetTilesEnumerator(grid.Owner, grid, bounds);
|
var tileEnumerator = _mapSystem.GetTilesEnumerator(grid.Owner, grid, bounds);
|
||||||
|
var roofEnt = (grid.Owner, grid.Comp, roof);
|
||||||
|
|
||||||
// Due to stencilling we essentially draw on unrooved tiles
|
// Due to stencilling we essentially draw on unrooved tiles
|
||||||
while (tileEnumerator.MoveNext(out var tileRef))
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
|
using Content.Shared.Light.Components;
|
||||||
using Content.Shared.Weather;
|
using Content.Shared.Weather;
|
||||||
using Robust.Client.Graphics;
|
using Robust.Client.Graphics;
|
||||||
using Robust.Shared.Map.Components;
|
using Robust.Shared.Map.Components;
|
||||||
@@ -34,11 +35,12 @@ public sealed partial class StencilOverlay
|
|||||||
var matrix = _transform.GetWorldMatrix(grid, xformQuery);
|
var matrix = _transform.GetWorldMatrix(grid, xformQuery);
|
||||||
var matty = Matrix3x2.Multiply(matrix, invMatrix);
|
var matty = Matrix3x2.Multiply(matrix, invMatrix);
|
||||||
worldHandle.SetTransform(matty);
|
worldHandle.SetTransform(matty);
|
||||||
|
_entManager.TryGetComponent(grid.Owner, out RoofComponent? roofComp);
|
||||||
|
|
||||||
foreach (var tile in _map.GetTilesIntersecting(grid.Owner, grid, worldAABB))
|
foreach (var tile in _map.GetTilesIntersecting(grid.Owner, grid, worldAABB))
|
||||||
{
|
{
|
||||||
// Ignored tiles for stencil
|
// Ignored tiles for stencil
|
||||||
if (_weather.CanWeatherAffect(grid.Owner, grid, tile))
|
if (_weather.CanWeatherAffect(grid.Owner, grid, tile, roofComp))
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
|
using Content.Shared.Light.Components;
|
||||||
using Content.Shared.Weather;
|
using Content.Shared.Weather;
|
||||||
using Robust.Client.Audio;
|
using Robust.Client.Audio;
|
||||||
using Robust.Client.GameObjects;
|
using Robust.Client.GameObjects;
|
||||||
@@ -57,6 +58,7 @@ public sealed class WeatherSystem : SharedWeatherSystem
|
|||||||
// Work out tiles nearby to determine volume.
|
// Work out tiles nearby to determine volume.
|
||||||
if (TryComp<MapGridComponent>(entXform.GridUid, out var grid))
|
if (TryComp<MapGridComponent>(entXform.GridUid, out var grid))
|
||||||
{
|
{
|
||||||
|
TryComp(entXform.GridUid, out RoofComponent? roofComp);
|
||||||
var gridId = entXform.GridUid.Value;
|
var gridId = entXform.GridUid.Value;
|
||||||
// FloodFill to the nearest tile and use that for audio.
|
// FloodFill to the nearest tile and use that for audio.
|
||||||
var seed = _mapSystem.GetTileRef(gridId, grid, entXform.Coordinates);
|
var seed = _mapSystem.GetTileRef(gridId, grid, entXform.Coordinates);
|
||||||
@@ -71,7 +73,7 @@ public sealed class WeatherSystem : SharedWeatherSystem
|
|||||||
if (!visited.Add(node.GridIndices))
|
if (!visited.Add(node.GridIndices))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (!CanWeatherAffect(entXform.GridUid.Value, grid, node))
|
if (!CanWeatherAffect(entXform.GridUid.Value, grid, node, roofComp))
|
||||||
{
|
{
|
||||||
// Add neighbors
|
// Add neighbors
|
||||||
// TODO: Ideally we pick some deterministically random direction and use that
|
// TODO: Ideally we pick some deterministically random direction and use that
|
||||||
|
|||||||
13
Content.Shared/Light/Components/IsRoofComponent.cs
Normal file
13
Content.Shared/Light/Components/IsRoofComponent.cs
Normal file
@@ -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;
|
||||||
|
}
|
||||||
@@ -3,11 +3,19 @@ using Robust.Shared.GameStates;
|
|||||||
namespace Content.Shared.Light.Components;
|
namespace Content.Shared.Light.Components;
|
||||||
|
|
||||||
/// <summary>
|
/// <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>
|
/// </summary>
|
||||||
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
|
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
|
||||||
public sealed partial class RoofComponent : Component
|
public sealed partial class RoofComponent : Component
|
||||||
{
|
{
|
||||||
|
public const int ChunkSize = 8;
|
||||||
|
|
||||||
[DataField, AutoNetworkedField]
|
[DataField, AutoNetworkedField]
|
||||||
public Color Color = Color.Black;
|
public Color Color = Color.Black;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Chunk origin and bitmask of value in chunk.
|
||||||
|
/// </summary>
|
||||||
|
[DataField, AutoNetworkedField]
|
||||||
|
public Dictionary<Vector2i, ulong> Data = new();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,33 +10,85 @@ namespace Content.Shared.Light.EntitySystems;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public abstract class SharedRoofSystem : EntitySystem
|
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)
|
public void SetRoof(Entity<MapGridComponent?, RoofComponent?> grid, Vector2i index, bool value)
|
||||||
{
|
{
|
||||||
if (!Resolve(grid, ref grid.Comp1, ref grid.Comp2, false))
|
if (!Resolve(grid, ref grid.Comp1, ref grid.Comp2, false))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!_maps.TryGetTile(grid.Comp1, index, out var tile))
|
var chunkOrigin = SharedMapSystem.GetChunkIndices(index, RoofComponent.ChunkSize);
|
||||||
|
var roof = grid.Comp2;
|
||||||
|
|
||||||
|
if (!roof.Data.TryGetValue(chunkOrigin, out var chunkData))
|
||||||
|
{
|
||||||
|
// No value to remove so leave it.
|
||||||
|
if (!value)
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
var mask = (tile.Flags & (byte)TileFlag.Roof);
|
chunkData = 0;
|
||||||
var rooved = mask != 0x0;
|
}
|
||||||
|
|
||||||
if (rooved == value)
|
var chunkRelative = SharedMapSystem.GetChunkRelative(index, RoofComponent.ChunkSize);
|
||||||
return;
|
var bitFlag = (ulong) 1 << (chunkRelative.X + chunkRelative.Y * RoofComponent.ChunkSize);
|
||||||
|
|
||||||
Tile newTile;
|
|
||||||
|
|
||||||
if (value)
|
if (value)
|
||||||
{
|
{
|
||||||
newTile = tile.WithFlag((byte)(tile.Flags | (ushort)TileFlag.Roof));
|
// Already set
|
||||||
|
if ((chunkData & bitFlag) == bitFlag)
|
||||||
|
return;
|
||||||
|
|
||||||
|
chunkData |= bitFlag;
|
||||||
}
|
}
|
||||||
else
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -120,11 +120,4 @@ namespace Content.Shared.Maps
|
|||||||
TileId = id;
|
TileId = id;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[Flags]
|
|
||||||
public enum TileFlag : byte
|
|
||||||
{
|
|
||||||
None = 0,
|
|
||||||
Roof = 1 << 0,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,11 +26,4 @@ public sealed partial class BiomeTileLayer : IBiomeLayer
|
|||||||
|
|
||||||
[DataField(required: true)]
|
[DataField(required: true)]
|
||||||
public ProtoId<ContentTileDefinition> Tile = string.Empty;
|
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;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -129,7 +129,7 @@ public abstract class SharedBiomeSystem : EntitySystem
|
|||||||
if (layer is not BiomeTileLayer tileLayer)
|
if (layer is not BiomeTileLayer tileLayer)
|
||||||
continue;
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -142,7 +142,7 @@ public abstract class SharedBiomeSystem : EntitySystem
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the underlying biome tile, ignoring any existing tile that may be there.
|
/// Gets the underlying biome tile, ignoring any existing tile that may be there.
|
||||||
/// </summary>
|
/// </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);
|
var found = noise.GetNoise(indices.X, indices.Y);
|
||||||
found = invert ? found * -1 : found;
|
found = invert ? found * -1 : found;
|
||||||
@@ -163,7 +163,7 @@ public abstract class SharedBiomeSystem : EntitySystem
|
|||||||
variant = _tile.PickVariant(tileDef, (int) variantValue);
|
variant = _tile.PickVariant(tileDef, (int) variantValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
tile = new Tile(tileDef.TileId, flags: tileFlags, variant);
|
tile = new Tile(tileDef.TileId, variant);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
using Content.Shared.Light.Components;
|
||||||
|
using Content.Shared.Light.EntitySystems;
|
||||||
using Content.Shared.Maps;
|
using Content.Shared.Maps;
|
||||||
using Robust.Shared.Audio.Systems;
|
using Robust.Shared.Audio.Systems;
|
||||||
using Robust.Shared.Map;
|
using Robust.Shared.Map;
|
||||||
@@ -17,6 +19,7 @@ public abstract class SharedWeatherSystem : EntitySystem
|
|||||||
[Dependency] private readonly MetaDataSystem _metadata = default!;
|
[Dependency] private readonly MetaDataSystem _metadata = default!;
|
||||||
[Dependency] private readonly SharedAudioSystem _audio = default!;
|
[Dependency] private readonly SharedAudioSystem _audio = default!;
|
||||||
[Dependency] private readonly SharedMapSystem _mapSystem = default!;
|
[Dependency] private readonly SharedMapSystem _mapSystem = default!;
|
||||||
|
[Dependency] private readonly SharedRoofSystem _roof = default!;
|
||||||
|
|
||||||
private EntityQuery<BlockWeatherComponent> _blockQuery;
|
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)
|
if (tileRef.Tile.IsEmpty)
|
||||||
return true;
|
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;
|
return false;
|
||||||
|
|
||||||
var tileDef = (ContentTileDefinition) _tileDefManager[tileRef.Tile.TypeId];
|
var tileDef = (ContentTileDefinition) _tileDefManager[tileRef.Tile.TypeId];
|
||||||
|
|||||||
@@ -21,6 +21,7 @@
|
|||||||
- type: Tag
|
- type: Tag
|
||||||
tags:
|
tags:
|
||||||
- Wall
|
- Wall
|
||||||
|
- type: IsRoof
|
||||||
- type: Sprite
|
- type: Sprite
|
||||||
drawdepth: Walls
|
drawdepth: Walls
|
||||||
- type: Icon
|
- type: Icon
|
||||||
|
|||||||
@@ -544,7 +544,6 @@
|
|||||||
- !type:BiomeTileLayer
|
- !type:BiomeTileLayer
|
||||||
threshold: -1.0
|
threshold: -1.0
|
||||||
tile: FloorAsteroidSand
|
tile: FloorAsteroidSand
|
||||||
flags: 1
|
|
||||||
|
|
||||||
# Asteroid
|
# Asteroid
|
||||||
- type: biomeTemplate
|
- type: biomeTemplate
|
||||||
|
|||||||
Reference in New Issue
Block a user