mirror of
https://github.com/space-syndicate/space-station-14.git
synced 2026-10-09 10:21:18 +03:00
149 lines
5 KiB
C#
149 lines
5 KiB
C#
using System.Linq;
|
|
using System.Numerics;
|
|
using Content.Client.Decals.Overlays;
|
|
using Content.Shared.Decals;
|
|
using Content.Shared.Maps;
|
|
using Robust.Client.GameObjects;
|
|
using Robust.Client.Graphics;
|
|
using Robust.Shared.GameStates;
|
|
using Robust.Shared.Map;
|
|
using Robust.Shared.Map.Components;
|
|
|
|
namespace Content.Client.Decals
|
|
{
|
|
public sealed partial class DecalSystem : SharedDecalSystem
|
|
{
|
|
[Dependency] private IOverlayManager _overlayManager = default!;
|
|
[Dependency] private SpriteSystem _sprites = default!;
|
|
[Dependency] private SharedMapSystem _mapSystem = default!;
|
|
[Dependency] private SharedTransformSystem _transform = default!;
|
|
[Dependency] private TurfSystem _turf = default!;
|
|
[Dependency] private EntityQuery<MapGridComponent> _gridQuery;
|
|
|
|
private DecalOverlay? _overlay;
|
|
|
|
public override void Initialize()
|
|
{
|
|
base.Initialize();
|
|
|
|
_overlay = new DecalOverlay(_sprites, EntityManager, ProtoMan);
|
|
_overlayManager.AddOverlay(_overlay);
|
|
}
|
|
|
|
[SubscribeLocalEvent]
|
|
private void OnDecalAfterState(EntityUid uid, DecalChunkComponent component, ref AfterAutoHandleStateEvent args)
|
|
{
|
|
component.NextPredictedDecal = ushort.MaxValue;
|
|
}
|
|
|
|
protected override void OnDecalPlacementRequest(RequestDecalPlacementEvent ev, EntitySessionEventArgs eventArgs)
|
|
{
|
|
var coordinates = GetCoordinates(ev.Coordinates);
|
|
if (!coordinates.IsValid(EntityManager))
|
|
return;
|
|
|
|
TryAddDecal(ev.Decal, coordinates, out _);
|
|
}
|
|
|
|
public override bool TryAddDecal(Decal decal, EntityCoordinates coordinates, out DecalIndex decalId)
|
|
{
|
|
decalId = default;
|
|
|
|
if (!ProtoMan.HasIndex<DecalPrototype>(decal.Id))
|
|
return false;
|
|
|
|
var gridUid = _transform.GetGrid(coordinates);
|
|
if (gridUid == null || !_gridQuery.TryComp(gridUid.Value, out var grid))
|
|
return false;
|
|
|
|
if (_turf.IsSpace(_mapSystem.GetTileRef(gridUid.Value, grid, coordinates)))
|
|
return false;
|
|
|
|
var chunk = ChunkEntities.GetOrCreateChunk(gridUid.Value, ChunkEntitySystem.GetChunkIndices(decal.Coordinates));
|
|
var decals = EnsureComp<DecalChunkComponent>(chunk.Owner);
|
|
|
|
if (!TryAllocatePredictedDecalId(decals, out var predictedDecalId))
|
|
return false;
|
|
|
|
decals.Decals[predictedDecalId] = decal;
|
|
DirtyField(chunk.Owner, decals, nameof(DecalChunkComponent.Decals));
|
|
decalId = new DecalIndex(ChunkEntitySystem.GetChunkIndices(decal.Coordinates), predictedDecalId);
|
|
return true;
|
|
}
|
|
|
|
protected override void OnDecalRemovalRequest(RequestDecalRemovalEvent ev, EntitySessionEventArgs eventArgs)
|
|
{
|
|
var coordinates = GetCoordinates(ev.Coordinates);
|
|
if (!coordinates.IsValid(EntityManager))
|
|
return;
|
|
|
|
var gridUid = _transform.GetGrid(coordinates);
|
|
if (gridUid == null)
|
|
return;
|
|
|
|
foreach (var (decalId, _) in GetDecalsInRange(gridUid.Value, ev.Coordinates.Position))
|
|
{
|
|
RemoveDecal(gridUid.Value, decalId);
|
|
}
|
|
}
|
|
|
|
private bool TryAllocatePredictedDecalId(DecalChunkComponent decals, out ushort decalId)
|
|
{
|
|
// Iterate top-down to find next free index.
|
|
for (var i = 0; i < DecalChunkComponent.PredictedDecalCount; i++)
|
|
{
|
|
var next = decals.NextPredictedDecal;
|
|
decals.NextPredictedDecal = next == DecalChunkComponent.MinPredictedDecalId
|
|
? ushort.MaxValue
|
|
: (ushort) (next - 1);
|
|
|
|
if (decals.Decals.ContainsKey(next))
|
|
continue;
|
|
|
|
decalId = next;
|
|
return true;
|
|
}
|
|
|
|
decalId = default;
|
|
return false;
|
|
}
|
|
|
|
public override bool RemoveDecal(EntityUid gridId, DecalIndex decal)
|
|
{
|
|
if (!ChunkEntities.TryGetChunk(gridId, decal.Chunk, out var chunkEnt) ||
|
|
!DecalChunkQuery.TryComp(chunkEnt.Value.Owner, out var decals) ||
|
|
!decals.Decals.Remove(decal.Id))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
DirtyField(chunkEnt.Value.Owner, decals, nameof(DecalChunkComponent.Decals));
|
|
return true;
|
|
}
|
|
|
|
public void ToggleOverlay()
|
|
{
|
|
if (_overlay == null)
|
|
return;
|
|
|
|
if (_overlayManager.HasOverlay<DecalOverlay>())
|
|
{
|
|
_overlayManager.RemoveOverlay(_overlay);
|
|
}
|
|
else
|
|
{
|
|
_overlayManager.AddOverlay(_overlay);
|
|
}
|
|
}
|
|
|
|
public override void Shutdown()
|
|
{
|
|
base.Shutdown();
|
|
|
|
if (_overlay == null)
|
|
return;
|
|
|
|
_overlayManager.RemoveOverlay(_overlay);
|
|
}
|
|
}
|
|
}
|