DecalPlacementSystem.cs 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. using System.Numerics;
  2. using Content.Client.Actions;
  3. using Content.Client.Decals.Overlays;
  4. using Content.Shared.Actions;
  5. using Content.Shared.Decals;
  6. using Robust.Client.GameObjects;
  7. using Robust.Client.Graphics;
  8. using Robust.Client.Input;
  9. using Robust.Shared.Input;
  10. using Robust.Shared.Input.Binding;
  11. using Robust.Shared.Prototypes;
  12. namespace Content.Client.Decals;
  13. // This is shit and basically a half-rewrite of PlacementManager
  14. // TODO refactor placementmanager so this isnt shit anymore
  15. public sealed class DecalPlacementSystem : EntitySystem
  16. {
  17. [Dependency] private readonly IInputManager _inputManager = default!;
  18. [Dependency] private readonly IOverlayManager _overlay = default!;
  19. [Dependency] private readonly IPrototypeManager _protoMan = default!;
  20. [Dependency] private readonly InputSystem _inputSystem = default!;
  21. [Dependency] private readonly MetaDataSystem _metaData = default!;
  22. [Dependency] private readonly SharedTransformSystem _transform = default!;
  23. [Dependency] private readonly SpriteSystem _sprite = default!;
  24. private string? _decalId;
  25. private Color _decalColor = Color.White;
  26. private Angle _decalAngle = Angle.Zero;
  27. private bool _snap;
  28. private int _zIndex;
  29. private bool _cleanable;
  30. private bool _active;
  31. private bool _placing;
  32. private bool _erasing;
  33. public (DecalPrototype? Decal, bool Snap, Angle Angle, Color Color) GetActiveDecal()
  34. {
  35. return _active && _decalId != null ?
  36. (_protoMan.Index<DecalPrototype>(_decalId), _snap, _decalAngle, _decalColor) :
  37. (null, false, Angle.Zero, Color.Wheat);
  38. }
  39. public override void Initialize()
  40. {
  41. base.Initialize();
  42. _overlay.AddOverlay(new DecalPlacementOverlay(this, _transform, _sprite));
  43. CommandBinds.Builder.Bind(EngineKeyFunctions.EditorPlaceObject, new PointerStateInputCmdHandler(
  44. (session, coords, uid) =>
  45. {
  46. if (!_active || _placing || _decalId == null)
  47. return false;
  48. _placing = true;
  49. if (_snap)
  50. {
  51. var newPos = new Vector2(
  52. (float) (MathF.Round(coords.X - 0.5f, MidpointRounding.AwayFromZero) + 0.5),
  53. (float) (MathF.Round(coords.Y - 0.5f, MidpointRounding.AwayFromZero) + 0.5)
  54. );
  55. coords = coords.WithPosition(newPos);
  56. }
  57. coords = coords.Offset(new Vector2(-0.5f, -0.5f));
  58. if (!coords.IsValid(EntityManager))
  59. return false;
  60. var decal = new Decal(coords.Position, _decalId, _decalColor, _decalAngle, _zIndex, _cleanable);
  61. RaiseNetworkEvent(new RequestDecalPlacementEvent(decal, GetNetCoordinates(coords)));
  62. return true;
  63. },
  64. (session, coords, uid) =>
  65. {
  66. if (!_active)
  67. return false;
  68. _placing = false;
  69. return true;
  70. }, true))
  71. .Bind(EngineKeyFunctions.EditorCancelPlace, new PointerStateInputCmdHandler(
  72. (session, coords, uid) =>
  73. {
  74. if (!_active || _erasing)
  75. return false;
  76. _erasing = true;
  77. RaiseNetworkEvent(new RequestDecalRemovalEvent(GetNetCoordinates(coords)));
  78. return true;
  79. }, (session, coords, uid) =>
  80. {
  81. if (!_active)
  82. return false;
  83. _erasing = false;
  84. return true;
  85. }, true)).Register<DecalPlacementSystem>();
  86. SubscribeLocalEvent<FillActionSlotEvent>(OnFillSlot);
  87. SubscribeLocalEvent<PlaceDecalActionEvent>(OnPlaceDecalAction);
  88. }
  89. private void OnPlaceDecalAction(PlaceDecalActionEvent args)
  90. {
  91. if (args.Handled)
  92. return;
  93. if (args.Target.GetGridUid(EntityManager) == null)
  94. return;
  95. args.Handled = true;
  96. if (args.Snap)
  97. {
  98. var newPos = new Vector2(
  99. (float) (MathF.Round(args.Target.X - 0.5f, MidpointRounding.AwayFromZero) + 0.5),
  100. (float) (MathF.Round(args.Target.Y - 0.5f, MidpointRounding.AwayFromZero) + 0.5)
  101. );
  102. args.Target = args.Target.WithPosition(newPos);
  103. }
  104. args.Target = args.Target.Offset(new Vector2(-0.5f, -0.5f));
  105. var decal = new Decal(args.Target.Position, args.DecalId, args.Color, Angle.FromDegrees(args.Rotation), args.ZIndex, args.Cleanable);
  106. RaiseNetworkEvent(new RequestDecalPlacementEvent(decal, GetNetCoordinates(args.Target)));
  107. }
  108. private void OnFillSlot(FillActionSlotEvent ev)
  109. {
  110. if (!_active || _placing)
  111. return;
  112. if (ev.Action != null)
  113. return;
  114. if (_decalId == null || !_protoMan.TryIndex<DecalPrototype>(_decalId, out var decalProto))
  115. return;
  116. var actionEvent = new PlaceDecalActionEvent()
  117. {
  118. DecalId = _decalId,
  119. Color = _decalColor,
  120. Rotation = _decalAngle.Degrees,
  121. Snap = _snap,
  122. ZIndex = _zIndex,
  123. Cleanable = _cleanable,
  124. };
  125. var actionId = Spawn(null);
  126. AddComp(actionId, new WorldTargetActionComponent
  127. {
  128. // non-unique actions may be considered duplicates when saving/loading.
  129. Icon = decalProto.Sprite,
  130. Repeat = true,
  131. ClientExclusive = true,
  132. CheckCanAccess = false,
  133. CheckCanInteract = false,
  134. Range = -1,
  135. Event = actionEvent,
  136. IconColor = _decalColor,
  137. });
  138. _metaData.SetEntityName(actionId, $"{_decalId} ({_decalColor.ToHex()}, {(int) _decalAngle.Degrees})");
  139. ev.Action = actionId;
  140. }
  141. public override void Shutdown()
  142. {
  143. base.Shutdown();
  144. _overlay.RemoveOverlay<DecalPlacementOverlay>();
  145. CommandBinds.Unregister<DecalPlacementSystem>();
  146. }
  147. public void UpdateDecalInfo(string id, Color color, float rotation, bool snap, int zIndex, bool cleanable)
  148. {
  149. _decalId = id;
  150. _decalColor = color;
  151. _decalAngle = Angle.FromDegrees(rotation);
  152. _snap = snap;
  153. _zIndex = zIndex;
  154. _cleanable = cleanable;
  155. }
  156. public void SetActive(bool active)
  157. {
  158. _active = active;
  159. if (_active)
  160. _inputManager.Contexts.SetActiveContext("editor");
  161. else
  162. _inputSystem.SetEntityContextActive();
  163. }
  164. }