CatStation/Content.Client/Decals/DecalPlacementSystem.cs
TemporalOroboros 84b2f07157
The IMapManager is dead (#44002)
* Axes the easy IMapManager references

* Axes the references to unported (obsolete) IMapManager methods

* Converts salvageruler command to a LocalizedEntityCommand so it can use SharedMapSystem

* Removes IMapManager from GameTicker
This required axing the map nuke during restart, but that should be fine?
Maps are entities so EntityManager.FlushEntities should delete them all and that's the preceding line

* submodule update(?)

---------

Co-authored-by: ArtisticRoomba <145879011+ArtisticRoomba@users.noreply.github.com>
2026-07-01 20:44:54 -07:00

197 lines
6.4 KiB
C#

using System.Numerics;
using Content.Client.Actions;
using Content.Client.Decals.Overlays;
using Content.Shared.Actions;
using Content.Shared.Actions.Components;
using Content.Shared.Decals;
using Robust.Client.GameObjects;
using Robust.Client.Graphics;
using Robust.Client.Input;
using Robust.Shared.Input;
using Robust.Shared.Input.Binding;
using Robust.Shared.Prototypes;
namespace Content.Client.Decals;
// This is shit and basically a half-rewrite of PlacementManager
// TODO refactor placementmanager so this isnt shit anymore
public sealed partial class DecalPlacementSystem : EntitySystem
{
[Dependency] private IInputManager _inputManager = default!;
[Dependency] private IOverlayManager _overlay = default!;
[Dependency] private InputSystem _inputSystem = default!;
[Dependency] private MetaDataSystem _metaData = default!;
[Dependency] private SharedActionsSystem _actions = default!;
[Dependency] private SharedMapSystem _maps = default!;
[Dependency] private SharedTransformSystem _transform = default!;
[Dependency] private SpriteSystem _sprite = default!;
public static readonly EntProtoId DecalAction = "BaseMappingDecalAction";
private string? _decalId;
private Color _decalColor = Color.White;
private Angle _decalAngle = Angle.Zero;
private bool _snap;
private int _zIndex;
private bool _cleanable;
private bool _active;
private bool _placing;
private bool _erasing;
public (DecalPrototype? Decal, bool Snap, Angle Angle, Color Color) GetActiveDecal()
{
return _active && _decalId != null ?
(ProtoMan.Index<DecalPrototype>(_decalId), _snap, _decalAngle, _decalColor) :
(null, false, Angle.Zero, Color.Wheat);
}
public override void Initialize()
{
base.Initialize();
_overlay.AddOverlay(new DecalPlacementOverlay(this, _maps, _transform, _sprite));
CommandBinds.Builder.Bind(EngineKeyFunctions.EditorPlaceObject, new PointerStateInputCmdHandler(
(session, coords, uid) =>
{
if (!_active || _placing || _decalId == null)
return false;
_placing = true;
if (_snap)
{
var newPos = new Vector2(
(float) (MathF.Round(coords.X - 0.5f, MidpointRounding.AwayFromZero) + 0.5),
(float) (MathF.Round(coords.Y - 0.5f, MidpointRounding.AwayFromZero) + 0.5)
);
coords = coords.WithPosition(newPos);
}
coords = coords.Offset(new Vector2(-0.5f, -0.5f));
if (!coords.IsValid(EntityManager))
return false;
var decal = new Decal(coords.Position, _decalId, _decalColor, _decalAngle, _zIndex, _cleanable);
RaiseNetworkEvent(new RequestDecalPlacementEvent(decal, GetNetCoordinates(coords)));
return true;
},
(session, coords, uid) =>
{
if (!_active)
return false;
_placing = false;
return true;
}, true))
.Bind(EngineKeyFunctions.EditorCancelPlace, new PointerStateInputCmdHandler(
(session, coords, uid) =>
{
if (!_active || _erasing)
return false;
_erasing = true;
RaiseNetworkEvent(new RequestDecalRemovalEvent(GetNetCoordinates(coords)));
return true;
}, (session, coords, uid) =>
{
if (!_active)
return false;
_erasing = false;
return true;
}, true)).Register<DecalPlacementSystem>();
SubscribeLocalEvent<FillActionSlotEvent>(OnFillSlot);
SubscribeLocalEvent<PlaceDecalActionEvent>(OnPlaceDecalAction);
}
private void OnPlaceDecalAction(PlaceDecalActionEvent args)
{
if (args.Handled)
return;
if (_transform.GetGrid(args.Target) == null)
return;
args.Handled = true;
if (args.Snap)
{
var newPos = new Vector2(
(float) (MathF.Round(args.Target.X - 0.5f, MidpointRounding.AwayFromZero) + 0.5),
(float) (MathF.Round(args.Target.Y - 0.5f, MidpointRounding.AwayFromZero) + 0.5)
);
args.Target = args.Target.WithPosition(newPos);
}
args.Target = args.Target.Offset(new Vector2(-0.5f, -0.5f));
var decal = new Decal(args.Target.Position, args.DecalId, args.Color, Angle.FromDegrees(args.Rotation), args.ZIndex, args.Cleanable);
RaiseNetworkEvent(new RequestDecalPlacementEvent(decal, GetNetCoordinates(args.Target)));
}
private void OnFillSlot(FillActionSlotEvent ev)
{
if (!_active || _placing)
return;
if (ev.Action != null)
return;
if (_decalId == null || !ProtoMan.TryIndex<DecalPrototype>(_decalId, out var decalProto))
return;
var actionEvent = new PlaceDecalActionEvent()
{
DecalId = _decalId,
Color = _decalColor,
Rotation = _decalAngle.Degrees,
Snap = _snap,
ZIndex = _zIndex,
Cleanable = _cleanable,
};
var actionId = Spawn(DecalAction);
var action = Comp<ActionComponent>(actionId);
var ent = (actionId, action);
_actions.SetEvent(actionId, actionEvent);
_actions.SetIcon(ent, decalProto.Sprite);
_actions.SetIconColor(ent, _decalColor);
_metaData.SetEntityName(actionId, $"{_decalId} ({_decalColor.ToHex()}, {(int) _decalAngle.Degrees})");
ev.Action = actionId;
}
public override void Shutdown()
{
base.Shutdown();
_overlay.RemoveOverlay<DecalPlacementOverlay>();
CommandBinds.Unregister<DecalPlacementSystem>();
}
public void UpdateDecalInfo(string id, Color color, float rotation, bool snap, int zIndex, bool cleanable)
{
_decalId = id;
_decalColor = color;
_decalAngle = Angle.FromDegrees(rotation);
_snap = snap;
_zIndex = zIndex;
_cleanable = cleanable;
}
public void SetActive(bool active)
{
_active = active;
if (_active)
_inputManager.Contexts.SetActiveContext("editor");
else
_inputSystem.SetEntityContextActive();
}
}