diff --git a/Content.Client/DragDrop/DragDropHelper.cs b/Content.Client/DragDrop/DragDropHelper.cs
index 959ff5e789..c5d0ccffc0 100644
--- a/Content.Client/DragDrop/DragDropHelper.cs
+++ b/Content.Client/DragDrop/DragDropHelper.cs
@@ -1,165 +1,163 @@
using Robust.Client.Input;
using Robust.Shared.Map;
-namespace Content.Client.DragDrop
+namespace Content.Client.DragDrop;
+
+///
+/// Helper for implementing drag and drop interactions.
+///
+/// The basic flow for a drag drop interaction as per this helper is:
+/// 1. User presses mouse down on something (using class should communicate this to helper by calling MouseDown()).
+/// 2. User continues to hold the mouse down and moves the mouse outside of the defined
+/// deadzone. OnBeginDrag is invoked to see if a drag should be initiated. If so, initiates a drag.
+/// If user didn't move the mouse beyond the deadzone the drag is not initiated (OnEndDrag invoked).
+/// 3. Every Update/FrameUpdate, OnContinueDrag is invoked.
+/// 4. User lifts mouse up. This is not handled by DragDropHelper. The using class of the helper should
+/// do whatever they want and then end the drag by calling EndDrag() (which invokes OnEndDrag).
+///
+/// If for any reason the drag is ended, OnEndDrag is invoked.
+///
+/// thing being dragged and dropped
+public sealed class DragDropHelper
{
+ private readonly IInputManager _inputManager;
+
+ private readonly OnBeginDrag _onBeginDrag;
+ private readonly OnEndDrag _onEndDrag;
+ private readonly OnContinueDrag _onContinueDrag;
+ public float Deadzone = 2f;
+
///
- /// Helper for implementing drag and drop interactions.
- ///
- /// The basic flow for a drag drop interaction as per this helper is:
- /// 1. User presses mouse down on something (using class should communicate this to helper by calling MouseDown()).
- /// 2. User continues to hold the mouse down and moves the mouse outside of the defined
- /// deadzone. OnBeginDrag is invoked to see if a drag should be initiated. If so, initiates a drag.
- /// If user didn't move the mouse beyond the deadzone the drag is not initiated (OnEndDrag invoked).
- /// 3. Every Update/FrameUpdate, OnContinueDrag is invoked.
- /// 4. User lifts mouse up. This is not handled by DragDropHelper. The using class of the helper should
- /// do whatever they want and then end the drag by calling EndDrag() (which invokes OnEndDrag).
- ///
- /// If for any reason the drag is ended, OnEndDrag is invoked.
+ /// Convenience method, current mouse screen position as provided by inputmanager.
///
- /// thing being dragged and dropped
- public sealed class DragDropHelper
+ public ScreenCoordinates MouseScreenPosition => _inputManager.MouseScreenPosition;
+
+ ///
+ /// True if initiated a drag and currently dragging something.
+ /// I.e. this will be false if we've just had a mousedown over something but the mouse
+ /// has not moved outside of the drag deadzone.
+ ///
+ public bool IsDragging => _state == DragState.Dragging;
+
+ ///
+ /// Current thing being dragged or which mouse button is being held down on.
+ ///
+ public T? Dragged { get; private set; }
+
+ // screen pos where the mouse down began for the drag
+ private ScreenCoordinates _mouseDownScreenPos;
+ private DragState _state = DragState.NotDragging;
+
+ private enum DragState : byte
{
- private readonly IInputManager _inputManager;
+ NotDragging,
+ // not dragging yet, waiting to see
+ // if they hold for long enough
+ MouseDown,
+ // currently dragging something
+ Dragging,
+ }
- private readonly OnBeginDrag _onBeginDrag;
- private readonly OnEndDrag _onEndDrag;
- private readonly OnContinueDrag _onContinueDrag;
- public float Deadzone = 2f;
+ ///
+ ///
+ ///
+ public DragDropHelper(OnBeginDrag onBeginDrag, OnContinueDrag onContinueDrag, OnEndDrag onEndDrag)
+ {
+ _inputManager = IoCManager.Resolve();
+ _onBeginDrag = onBeginDrag;
+ _onEndDrag = onEndDrag;
+ _onContinueDrag = onContinueDrag;
+ }
- ///
- /// Convenience method, current mouse screen position as provided by inputmanager.
- ///
- public ScreenCoordinates MouseScreenPosition => _inputManager.MouseScreenPosition;
-
- ///
- /// True if initiated a drag and currently dragging something.
- /// I.e. this will be false if we've just had a mousedown over something but the mouse
- /// has not moved outside of the drag deadzone.
- ///
- public bool IsDragging => _state == DragState.Dragging;
-
- ///
- /// Current thing being dragged or which mouse button is being held down on.
- ///
- public T? Dragged { get; private set; }
-
- // screen pos where the mouse down began for the drag
- private ScreenCoordinates _mouseDownScreenPos;
- private DragState _state = DragState.NotDragging;
-
- private enum DragState : byte
+ ///
+ /// Tell the helper that the mouse button was pressed down on
+ /// a target, thus a drag has the possibility to begin for this target.
+ /// Assumes current mouse screen position is the location the mouse was clicked.
+ ///
+ /// EndDrag should be called when the drag is done.
+ ///
+ public void MouseDown(T target)
+ {
+ if (_state != DragState.NotDragging)
{
- NotDragging,
- // not dragging yet, waiting to see
- // if they hold for long enough
- MouseDown,
- // currently dragging something
- Dragging,
+ EndDrag();
}
- ///
- ///
- ///
- public DragDropHelper(OnBeginDrag onBeginDrag, OnContinueDrag onContinueDrag, OnEndDrag onEndDrag)
+ Dragged = target;
+ _state = DragState.MouseDown;
+ _mouseDownScreenPos = _inputManager.MouseScreenPosition;
+ }
+
+ ///
+ /// Stop the current drag / drop operation no matter what state it is in.
+ ///
+ public void EndDrag()
+ {
+ Dragged = default;
+ _state = DragState.NotDragging;
+ _onEndDrag.Invoke();
+ }
+
+ private void StartDragging()
+ {
+ if (_onBeginDrag.Invoke())
{
- _inputManager = IoCManager.Resolve();
- _onBeginDrag = onBeginDrag;
- _onEndDrag = onEndDrag;
- _onContinueDrag = onContinueDrag;
+ _state = DragState.Dragging;
}
-
- ///
- /// Tell the helper that the mouse button was pressed down on
- /// a target, thus a drag has the possibility to begin for this target.
- /// Assumes current mouse screen position is the location the mouse was clicked.
- ///
- /// EndDrag should be called when the drag is done.
- ///
- public void MouseDown(T target)
+ else
{
- if (_state != DragState.NotDragging)
- {
- EndDrag();
- }
-
- Dragged = target;
- _state = DragState.MouseDown;
- _mouseDownScreenPos = _inputManager.MouseScreenPosition;
- }
-
- ///
- /// Stop the current drag / drop operation no matter what state it is in.
- ///
- public void EndDrag()
- {
- Dragged = default;
- _state = DragState.NotDragging;
- _onEndDrag.Invoke();
- }
-
- private void StartDragging()
- {
- if (_onBeginDrag.Invoke())
- {
- _state = DragState.Dragging;
- }
- else
- {
- EndDrag();
- }
- }
-
- ///
- /// Should be invoked by using class every FrameUpdate or Update.
- ///
- public void Update(float frameTime)
- {
- switch (_state)
- {
- // check if dragging should begin
- case DragState.MouseDown:
- {
- var screenPos = _inputManager.MouseScreenPosition;
- if ((_mouseDownScreenPos.Position - screenPos.Position).Length > Deadzone)
- {
- StartDragging();
- }
-
- break;
- }
- case DragState.Dragging:
- {
- if (!_onContinueDrag.Invoke(frameTime))
- {
- EndDrag();
- }
-
- break;
- }
- }
+ EndDrag();
}
}
///
- /// Invoked when a drag is confirmed and going to be initiated. Implementation should
- /// typically set the drag shadow texture based on the target.
+ /// Should be invoked by using class every FrameUpdate or Update.
///
- /// true if drag should begin, false to end.
- public delegate bool OnBeginDrag();
+ public void Update(float frameTime)
+ {
+ switch (_state)
+ {
+ // check if dragging should begin
+ case DragState.MouseDown:
+ {
+ var screenPos = _inputManager.MouseScreenPosition;
+ if ((_mouseDownScreenPos.Position - screenPos.Position).Length > Deadzone)
+ {
+ StartDragging();
+ }
- ///
- /// Invoked every frame when drag is ongoing. Typically implementation should
- /// make the drag shadow follow the mouse position.
- ///
- /// true if drag should continue, false to end.
- public delegate bool OnContinueDrag(float frameTime);
-
- ///
- /// invoked when
- /// the drag drop is ending for any reason. This
- /// should typically just clear the drag shadow.
- ///
- public delegate void OnEndDrag();
+ break;
+ }
+ case DragState.Dragging:
+ {
+ if (!_onContinueDrag.Invoke(frameTime))
+ {
+ EndDrag();
+ }
+ break;
+ }
+ }
+ }
}
+
+///
+/// Invoked when a drag is confirmed and going to be initiated. Implementation should
+/// typically set the drag shadow texture based on the target.
+///
+/// true if drag should begin, false to end.
+public delegate bool OnBeginDrag();
+
+///
+/// Invoked every frame when drag is ongoing. Typically implementation should
+/// make the drag shadow follow the mouse position.
+///
+/// true if drag should continue, false to end.
+public delegate bool OnContinueDrag(float frameTime);
+
+///
+/// invoked when
+/// the drag drop is ending for any reason. This
+/// should typically just clear the drag shadow.
+///
+public delegate void OnEndDrag();
diff --git a/Content.Client/DragDrop/DragDropSystem.cs b/Content.Client/DragDrop/DragDropSystem.cs
index 1e12d53ba5..5be800260d 100644
--- a/Content.Client/DragDrop/DragDropSystem.cs
+++ b/Content.Client/DragDrop/DragDropSystem.cs
@@ -1,10 +1,8 @@
using Content.Client.CombatMode;
using Content.Client.Gameplay;
using Content.Client.Outline;
-using Content.Client.Viewport;
using Content.Shared.ActionBlocker;
using Content.Shared.CCVar;
-using Content.Shared.CombatMode;
using Content.Shared.DragDrop;
using Content.Shared.Interaction;
using Content.Shared.Interaction.Events;
@@ -18,480 +16,538 @@ using Robust.Client.State;
using Robust.Shared.Configuration;
using Robust.Shared.Input;
using Robust.Shared.Input.Binding;
+using Robust.Shared.Map;
+using Robust.Shared.Player;
using Robust.Shared.Prototypes;
using Robust.Shared.Utility;
using System.Linq;
using DrawDepth = Content.Shared.DrawDepth.DrawDepth;
-namespace Content.Client.DragDrop
+namespace Content.Client.DragDrop;
+
+///
+/// Handles clientside drag and drop logic
+///
+[UsedImplicitly]
+public sealed class DragDropSystem : SharedDragDropSystem
{
+ [Dependency] private readonly IStateManager _stateManager = default!;
+ [Dependency] private readonly IInputManager _inputManager = default!;
+ [Dependency] private readonly IEyeManager _eyeManager = default!;
+ [Dependency] private readonly IPlayerManager _playerManager = default!;
+ [Dependency] private readonly IPrototypeManager _prototypeManager = default!;
+ [Dependency] private readonly IConfigurationManager _cfgMan = default!;
+ [Dependency] private readonly InteractionOutlineSystem _outline = default!;
+ [Dependency] private readonly SharedInteractionSystem _interactionSystem = default!;
+ [Dependency] private readonly CombatModeSystem _combatMode = default!;
+ [Dependency] private readonly InputSystem _inputSystem = default!;
+ [Dependency] private readonly ActionBlockerSystem _actionBlockerSystem = default!;
+ [Dependency] private readonly EntityLookupSystem _lookup = default!;
+ [Dependency] private readonly SharedPopupSystem _popup = default!;
+
+ private ISawmill _sawmill = default!;
+
+ // how often to recheck possible targets (prevents calling expensive
+ // check logic each update)
+ private const float TargetRecheckInterval = 0.25f;
+
+ // if a drag ends up being cancelled and it has been under this
+ // amount of time since the mousedown, we will "replay" the original
+ // mousedown event so it can be treated like a regular click
+ private const float MaxMouseDownTimeForReplayingClick = 0.85f;
+
+ private const string ShaderDropTargetInRange = "SelectionOutlineInrange";
+ private const string ShaderDropTargetOutOfRange = "SelectionOutline";
+
///
- /// Handles clientside drag and drop logic
+ /// Current entity being dragged around.
///
- [UsedImplicitly]
- public sealed class DragDropSystem : SharedDragDropSystem
+ private EntityUid? _draggedEntity;
+
+ ///
+ /// If an entity is being dragged is there a drag shadow.
+ ///
+ private EntityUid? _dragShadow;
+
+ ///
+ /// Time since mouse down over the dragged entity
+ ///
+ private float _mouseDownTime;
+
+ ///
+ /// how much time since last recheck of all possible targets
+ ///
+ private float _targetRecheckTime;
+
+ ///
+ /// Reserved initial mousedown event so we can replay it if no drag ends up being performed
+ ///
+ private PointerInputCmdHandler.PointerInputCmdArgs? _savedMouseDown;
+
+ ///
+ /// Whether we are currently replaying the original mouse down, so we
+ /// can ignore any events sent to this system
+ ///
+ private bool _isReplaying;
+
+ private float _deadzone;
+
+ private DragState _state = DragState.NotDragging;
+
+ ///
+ /// screen pos where the mouse down began for the drag
+ ///
+ private ScreenCoordinates? _mouseDownScreenPos;
+
+ private ShaderInstance? _dropTargetInRangeShader;
+ private ShaderInstance? _dropTargetOutOfRangeShader;
+
+ private readonly List _highlightedSprites = new();
+
+ public override void Initialize()
{
- [Dependency] private readonly IStateManager _stateManager = default!;
- [Dependency] private readonly IInputManager _inputManager = default!;
- [Dependency] private readonly IEyeManager _eyeManager = default!;
- [Dependency] private readonly IPlayerManager _playerManager = default!;
- [Dependency] private readonly IPrototypeManager _prototypeManager = default!;
- [Dependency] private readonly IConfigurationManager _cfgMan = default!;
- [Dependency] private readonly InteractionOutlineSystem _outline = default!;
- [Dependency] private readonly SharedInteractionSystem _interactionSystem = default!;
- [Dependency] private readonly CombatModeSystem _combatMode = default!;
- [Dependency] private readonly InputSystem _inputSystem = default!;
- [Dependency] private readonly ActionBlockerSystem _actionBlockerSystem = default!;
- [Dependency] private readonly EntityLookupSystem _lookup = default!;
+ base.Initialize();
+ _sawmill = Logger.GetSawmill("drag_drop");
+ UpdatesOutsidePrediction = true;
+ UpdatesAfter.Add(typeof(EyeUpdateSystem));
- // how often to recheck possible targets (prevents calling expensive
- // check logic each update)
- private const float TargetRecheckInterval = 0.25f;
+ _cfgMan.OnValueChanged(CCVars.DragDropDeadZone, SetDeadZone, true);
- // if a drag ends up being cancelled and it has been under this
- // amount of time since the mousedown, we will "replay" the original
- // mousedown event so it can be treated like a regular click
- private const float MaxMouseDownTimeForReplayingClick = 0.85f;
+ _dropTargetInRangeShader = _prototypeManager.Index(ShaderDropTargetInRange).Instance();
+ _dropTargetOutOfRangeShader = _prototypeManager.Index(ShaderDropTargetOutOfRange).Instance();
+ // needs to fire on mouseup and mousedown so we can detect a drag / drop
+ CommandBinds.Builder
+ .BindBefore(EngineKeyFunctions.Use, new PointerInputCmdHandler(OnUse, false), new[] { typeof(SharedInteractionSystem) })
+ .Register();
+ }
- private const string ShaderDropTargetInRange = "SelectionOutlineInrange";
- private const string ShaderDropTargetOutOfRange = "SelectionOutline";
+ private void SetDeadZone(float deadZone)
+ {
+ _deadzone = deadZone;
+ }
- // entity performing the drag action
+ public override void Shutdown()
+ {
+ _cfgMan.UnsubValueChanged(CCVars.DragDropDeadZone, SetDeadZone);
+ CommandBinds.Unregister();
+ base.Shutdown();
+ }
- private EntityUid _dragger;
- private readonly List _draggables = new();
- private EntityUid _dragShadow;
+ private bool OnUse(in PointerInputCmdHandler.PointerInputCmdArgs args)
+ {
+ // not currently predicted
+ if (_inputSystem.Predicted)
+ return false;
- // time since mouse down over the dragged entity
- private float _mouseDownTime;
- // how much time since last recheck of all possible targets
- private float _targetRecheckTime;
- // reserved initial mousedown event so we can replay it if no drag ends up being performed
- private PointerInputCmdHandler.PointerInputCmdArgs? _savedMouseDown;
- // whether we are currently replaying the original mouse down, so we
- // can ignore any events sent to this system
- private bool _isReplaying;
+ // currently replaying a saved click, don't handle this because
+ // we already decided this click doesn't represent an actual drag attempt
+ if (_isReplaying)
+ return false;
- private DragDropHelper _dragDropHelper = default!;
-
- private ShaderInstance? _dropTargetInRangeShader;
- private ShaderInstance? _dropTargetOutOfRangeShader;
-
- private readonly List _highlightedSprites = new();
-
- public override void Initialize()
+ if (args.State == BoundKeyState.Down)
{
- UpdatesOutsidePrediction = true;
- UpdatesAfter.Add(typeof(EyeUpdateSystem));
-
- _dragDropHelper = new DragDropHelper(OnBeginDrag, OnContinueDrag, OnEndDrag);
- _cfgMan.OnValueChanged(CCVars.DragDropDeadZone, SetDeadZone, true);
-
- _dropTargetInRangeShader = _prototypeManager.Index(ShaderDropTargetInRange).Instance();
- _dropTargetOutOfRangeShader = _prototypeManager.Index(ShaderDropTargetOutOfRange).Instance();
- // needs to fire on mouseup and mousedown so we can detect a drag / drop
- CommandBinds.Builder
- .BindBefore(EngineKeyFunctions.Use, new PointerInputCmdHandler(OnUse, false), new[] { typeof(SharedInteractionSystem) })
- .Register();
+ return OnUseMouseDown(args);
}
- private void SetDeadZone(float deadZone)
+ if (args.State == BoundKeyState.Up)
{
- _dragDropHelper.Deadzone = deadZone;
+ return OnUseMouseUp(args);
}
- public override void Shutdown()
+ return false;
+ }
+
+ private void EndDrag()
+ {
+ if (_state == DragState.NotDragging)
+ return;
+
+ if (_dragShadow != null)
{
- _cfgMan.UnsubValueChanged(CCVars.DragDropDeadZone, SetDeadZone);
- _dragDropHelper.EndDrag();
- CommandBinds.Unregister();
- base.Shutdown();
+ Del(_dragShadow.Value);
+ _dragShadow = null;
}
- private bool OnUse(in PointerInputCmdHandler.PointerInputCmdArgs args)
+ _draggedEntity = null;
+ _state = DragState.NotDragging;
+ _mouseDownScreenPos = null;
+
+ RemoveHighlights();
+ _outline.SetEnabled(true);
+ _mouseDownTime = 0;
+ _savedMouseDown = null;
+ }
+
+ private bool OnUseMouseDown(in PointerInputCmdHandler.PointerInputCmdArgs args)
+ {
+ if (args.Session?.AttachedEntity is not {Valid: true} dragger ||
+ _combatMode.IsInCombatMode())
{
- // not currently predicted
- if (_inputSystem.Predicted) return false;
-
- // currently replaying a saved click, don't handle this because
- // we already decided this click doesn't represent an actual drag attempt
- if (_isReplaying) return false;
-
- if (args.State == BoundKeyState.Down)
- {
- return OnUseMouseDown(args);
- }
- else if (args.State == BoundKeyState.Up)
- {
- return OnUseMouseUp(args);
- }
-
return false;
}
- private bool OnUseMouseDown(in PointerInputCmdHandler.PointerInputCmdArgs args)
+ // cancel any current dragging if there is one (shouldn't be because they would've had to have lifted
+ // the mouse, canceling the drag, but just being cautious)
+ EndDrag();
+
+ // possibly initiating a drag
+ // check if the clicked entity is draggable
+ if (!Exists(args.EntityUid))
{
- if (args.Session?.AttachedEntity is not {Valid: true} dragger ||
- _combatMode.IsInCombatMode())
- {
- return false;
- }
-
- // cancel any current dragging if there is one (shouldn't be because they would've had to have lifted
- // the mouse, canceling the drag, but just being cautious)
- _dragDropHelper.EndDrag();
-
- // possibly initiating a drag
- // check if the clicked entity is draggable
- if (!EntityManager.EntityExists(args.EntityUid))
- {
- return false;
- }
-
- // check if the entity is reachable
- if (!_interactionSystem.InRangeUnobstructed(dragger, args.EntityUid))
- {
- return false;
- }
-
- var canDrag = false;
- foreach (var draggable in EntityManager.GetComponents(args.EntityUid))
- {
- var dragEventArgs = new StartDragDropEvent(dragger, args.EntityUid);
-
- if (!draggable.CanStartDrag(dragEventArgs))
- {
- continue;
- }
-
- _draggables.Add(draggable);
- canDrag = true;
- }
-
- if (!canDrag)
- {
- return false;
- }
-
- // wait to initiate a drag
- _dragDropHelper.MouseDown(args.EntityUid);
- _dragger = dragger;
- _mouseDownTime = 0;
-
- // don't want anything else to process the click,
- // but we will save the event so we can "re-play" it if this drag does
- // not turn into an actual drag so the click can be handled normally
- _savedMouseDown = args;
-
- return true;
-
- }
-
- private bool OnBeginDrag()
- {
- if (_dragDropHelper.Dragged == default || Deleted(_dragDropHelper.Dragged))
- {
- // something happened to the clicked entity or we moved the mouse off the target so
- // we shouldn't replay the original click
- return false;
- }
-
- if (EntityManager.TryGetComponent(_dragDropHelper.Dragged, out var draggedSprite))
- {
- // pop up drag shadow under mouse
- var mousePos = _eyeManager.ScreenToMap(_dragDropHelper.MouseScreenPosition);
- _dragShadow = EntityManager.SpawnEntity("dragshadow", mousePos);
- var dragSprite = EntityManager.GetComponent(_dragShadow);
- dragSprite.CopyFrom(draggedSprite);
- dragSprite.RenderOrder = EntityManager.CurrentTick.Value;
- dragSprite.Color = dragSprite.Color.WithAlpha(0.7f);
- // keep it on top of everything
- dragSprite.DrawDepth = (int) DrawDepth.Overlays;
- if (!dragSprite.NoRotation)
- {
- EntityManager.GetComponent(_dragShadow).WorldRotation = EntityManager.GetComponent(_dragDropHelper.Dragged).WorldRotation;
- }
-
- HighlightTargets();
- _outline.SetEnabled(false);
-
- // drag initiated
- return true;
- }
-
- Logger.Warning("Unable to display drag shadow for {0} because it" +
- " has no sprite component.", EntityManager.GetComponent(_dragDropHelper.Dragged).EntityName);
return false;
}
- private bool OnContinueDrag(float frameTime)
+ // check if the entity is reachable
+ if (!_interactionSystem.InRangeUnobstructed(dragger, args.EntityUid))
{
- if (_dragDropHelper.Dragged == default || Deleted(_dragDropHelper.Dragged) ||
- _combatMode.IsInCombatMode())
- {
- return false;
- }
-
- DebugTools.AssertNotNull(_dragger);
-
- // still in range of the thing we are dragging?
- if (!_interactionSystem.InRangeUnobstructed(_dragger, _dragDropHelper.Dragged))
- {
- return false;
- }
-
- // TODO: would use MapPosition instead if it had a setter, but it has no setter.
- // is that intentional, or should we add a setter for Transform.MapPosition?
- if (_dragShadow == default)
- return false;
-
- _targetRecheckTime += frameTime;
- if (_targetRecheckTime > TargetRecheckInterval)
- {
- HighlightTargets();
- _targetRecheckTime -= TargetRecheckInterval;
- }
-
- return true;
+ return false;
}
- private void OnEndDrag()
- {
- RemoveHighlights();
- if (_dragShadow != default)
- {
- EntityManager.DeleteEntity(_dragShadow);
- }
+ var ev = new CanDragEvent();
- _outline.SetEnabled(true);
- _dragShadow = default;
- _draggables.Clear();
- _dragger = default;
- _mouseDownTime = 0;
- _savedMouseDown = null;
+ RaiseLocalEvent(args.EntityUid, ref ev);
+
+ if (ev.Handled != true)
+ return false;
+
+ _draggedEntity = args.EntityUid;
+ _state = DragState.MouseDown;
+ _mouseDownScreenPos = _inputManager.MouseScreenPosition;
+ _mouseDownTime = 0;
+
+ // don't want anything else to process the click,
+ // but we will save the event so we can "re-play" it if this drag does
+ // not turn into an actual drag so the click can be handled normally
+ _savedMouseDown = args;
+
+ return true;
+
+ }
+
+ private void StartDrag()
+ {
+ if (!Exists(_draggedEntity))
+ {
+ // something happened to the clicked entity or we moved the mouse off the target so
+ // we shouldn't replay the original click
+ return;
}
- private bool OnUseMouseUp(in PointerInputCmdHandler.PointerInputCmdArgs args)
+ _state = DragState.Dragging;
+ DebugTools.Assert(_dragShadow == null);
+ _outline.SetEnabled(false);
+ HighlightTargets();
+
+ if (TryComp(_draggedEntity, out var draggedSprite))
{
- if (_dragDropHelper.IsDragging == false || _dragDropHelper.Dragged == default)
+ // pop up drag shadow under mouse
+ var mousePos = _eyeManager.ScreenToMap(_inputManager.MouseScreenPosition);
+ _dragShadow = EntityManager.SpawnEntity("dragshadow", mousePos);
+ var dragSprite = Comp(_dragShadow.Value);
+ dragSprite.CopyFrom(draggedSprite);
+ dragSprite.RenderOrder = EntityManager.CurrentTick.Value;
+ dragSprite.Color = dragSprite.Color.WithAlpha(0.7f);
+ // keep it on top of everything
+ dragSprite.DrawDepth = (int) DrawDepth.Overlays;
+ if (!dragSprite.NoRotation)
+ {
+ Transform(_dragShadow.Value).WorldRotation = Transform(_draggedEntity.Value).WorldRotation;
+ }
+
+ // drag initiated
+ return;
+ }
+
+ _sawmill.Warning($"Unable to display drag shadow for {ToPrettyString(_draggedEntity.Value)} because it has no sprite component.");
+ }
+
+ private bool UpdateDrag(float frameTime)
+ {
+ if (!Exists(_draggedEntity) || _combatMode.IsInCombatMode())
+ {
+ EndDrag();
+ return false;
+ }
+
+ var player = _playerManager.LocalPlayer?.ControlledEntity;
+
+ // still in range of the thing we are dragging?
+ if (player == null || !_interactionSystem.InRangeUnobstructed(player.Value, _draggedEntity.Value))
+ {
+ return false;
+ }
+
+ if (_dragShadow == null)
+ return false;
+
+ _targetRecheckTime += frameTime;
+
+ if (_targetRecheckTime > TargetRecheckInterval)
+ {
+ HighlightTargets();
+ _targetRecheckTime -= TargetRecheckInterval;
+ }
+
+ return true;
+ }
+
+ private bool OnUseMouseUp(in PointerInputCmdHandler.PointerInputCmdArgs args)
+ {
+ if (_state == DragState.MouseDown)
+ {
+ // haven't started the drag yet, quick mouseup, definitely treat it as a normal click by
+ // replaying the original cmd
+ try
{
- // haven't started the drag yet, quick mouseup, definitely treat it as a normal click by
- // replaying the original cmd
if (_savedMouseDown.HasValue && _mouseDownTime < MaxMouseDownTimeForReplayingClick)
{
var savedValue = _savedMouseDown.Value;
_isReplaying = true;
// adjust the timing info based on the current tick so it appears as if it happened now
var replayMsg = savedValue.OriginalMessage;
- var adjustedInputMsg = new FullInputCmdMessage(args.OriginalMessage.Tick, args.OriginalMessage.SubTick,
- replayMsg.InputFunctionId, replayMsg.State, replayMsg.Coordinates, replayMsg.ScreenCoordinates, replayMsg.Uid);
+
+ var adjustedInputMsg = new FullInputCmdMessage(args.OriginalMessage.Tick,
+ args.OriginalMessage.SubTick,
+ replayMsg.InputFunctionId, replayMsg.State, replayMsg.Coordinates, replayMsg.ScreenCoordinates,
+ replayMsg.Uid);
if (savedValue.Session != null)
{
- _inputSystem.HandleInputCommand(savedValue.Session, EngineKeyFunctions.Use, adjustedInputMsg, true);
+ _inputSystem.HandleInputCommand(savedValue.Session, EngineKeyFunctions.Use, adjustedInputMsg,
+ true);
}
_isReplaying = false;
}
- _dragDropHelper.EndDrag();
- return false;
}
-
- if (_dragger == default)
+ finally
{
- _dragDropHelper.EndDrag();
- return false;
+ EndDrag();
}
- IList entities;
-
- if (_stateManager.CurrentState is GameplayState screen)
- {
- entities = screen.GetClickableEntities(args.Coordinates).ToList();
- }
- else
- {
- entities = Array.Empty();
- }
-
- var outOfRange = false;
-
- foreach (var entity in entities)
- {
- if (entity == _dragDropHelper.Dragged) continue;
-
- // check if it's able to be dropped on by current dragged entity
- var dropArgs = new DragDropEvent(_dragger, args.Coordinates, _dragDropHelper.Dragged, entity);
-
- // TODO: Cache valid CanDragDrops
- if (ValidDragDrop(dropArgs) != true) continue;
-
- if (!_interactionSystem.InRangeUnobstructed(dropArgs.User, dropArgs.Target)
- || !_interactionSystem.InRangeUnobstructed(dropArgs.User, dropArgs.Dragged))
- {
- outOfRange = true;
- continue;
- }
-
- foreach (var draggable in _draggables)
- {
- if (!draggable.CanDrop(dropArgs)) continue;
-
- // tell the server about the drop attempt
- RaiseNetworkEvent(new DragDropRequestEvent(args.Coordinates, _dragDropHelper.Dragged,
- entity));
-
- draggable.Drop(dropArgs);
-
- _dragDropHelper.EndDrag();
- return true;
- }
- }
-
- if (outOfRange &&
- _playerManager.LocalPlayer?.ControlledEntity is { } player &&
- player.IsValid())
- {
- player.PopupMessage(Loc.GetString("drag-drop-system-out-of-range-text"));
- }
-
- _dragDropHelper.EndDrag();
return false;
}
- // TODO make this just use TargetOutlineSystem
- private void HighlightTargets()
+ var localPlayer = _playerManager.LocalPlayer?.ControlledEntity;
+
+ if (localPlayer == null || !Exists(_draggedEntity))
{
- if (_dragDropHelper.Dragged == default || Deleted(_dragDropHelper.Dragged) ||
- _dragShadow == default || Deleted(_dragShadow))
+ EndDrag();
+ return false;
+ }
+
+ IEnumerable entities;
+
+ if (_stateManager.CurrentState is GameplayState screen)
+ {
+ entities = screen.GetClickableEntities(args.Coordinates);
+ }
+ else
+ {
+ entities = Array.Empty();
+ }
+
+ var outOfRange = false;
+ var user = localPlayer.Value;
+
+ foreach (var entity in entities)
+ {
+ if (entity == _draggedEntity)
+ continue;
+
+ // check if it's able to be dropped on by current dragged entity
+ var valid = ValidDragDrop(user, _draggedEntity.Value, entity);
+
+ if (valid != true) continue;
+
+ if (!_interactionSystem.InRangeUnobstructed(user, entity)
+ || !_interactionSystem.InRangeUnobstructed(user, _draggedEntity.Value))
{
- Logger.Warning("Programming error. Can't highlight drag and drop targets, not currently " +
- "dragging anything or dragged entity / shadow was deleted.");
- return;
+ outOfRange = true;
+ continue;
}
- // highlights the possible targets which are visible
- // and able to be dropped on by the current dragged entity
+ // tell the server about the drop attempt
+ RaiseNetworkEvent(new DragDropRequestEvent(_draggedEntity.Value, entity));
+ EndDrag();
+ return true;
+ }
- // remove current highlights
- RemoveHighlights();
+ if (outOfRange)
+ {
+ _popup.PopupEntity(Loc.GetString("drag-drop-system-out-of-range-text"), _draggedEntity.Value, Filter.Local(), true);
+ }
- // find possible targets on screen even if not reachable
- // TODO: Duplicated in SpriteSystem and TargetOutlineSystem. Should probably be cached somewhere for a frame?
- var mousePos = _eyeManager.ScreenToMap(_inputManager.MouseScreenPosition).Position;
- var bounds = new Box2(mousePos - 1.5f, mousePos + 1.5f);
- var pvsEntities = _lookup.GetEntitiesIntersecting(_eyeManager.CurrentMap, bounds, LookupFlags.Approximate | LookupFlags.Static);
- foreach (var pvsEntity in pvsEntities)
+ EndDrag();
+ return false;
+ }
+
+ // TODO make this just use TargetOutlineSystem
+ private void HighlightTargets()
+ {
+ if (!Exists(_draggedEntity) ||
+ !Exists(_dragShadow))
+ {
+ return;
+ }
+
+ var user = _playerManager.LocalPlayer?.ControlledEntity;
+
+ if (user == null)
+ return;
+
+ // highlights the possible targets which are visible
+ // and able to be dropped on by the current dragged entity
+
+ // remove current highlights
+ RemoveHighlights();
+
+ // find possible targets on screen even if not reachable
+ // TODO: Duplicated in SpriteSystem and TargetOutlineSystem. Should probably be cached somewhere for a frame?
+ var mousePos = _eyeManager.ScreenToMap(_inputManager.MouseScreenPosition);
+ var bounds = new Box2(mousePos.Position - 1.5f, mousePos.Position + 1.5f);
+ var pvsEntities = _lookup.GetEntitiesIntersecting(mousePos.MapId, bounds);
+
+ var spriteQuery = GetEntityQuery();
+
+ foreach (var entity in pvsEntities)
+ {
+ if (!spriteQuery.TryGetComponent(entity, out var inRangeSprite) ||
+ !inRangeSprite.Visible ||
+ entity == _draggedEntity)
{
- if (!EntityManager.TryGetComponent(pvsEntity, out SpriteComponent? inRangeSprite) ||
- !inRangeSprite.Visible ||
- pvsEntity == _dragDropHelper.Dragged) continue;
+ continue;
+ }
- // check if it's able to be dropped on by current dragged entity
- var dropArgs = new DragDropEvent(_dragger, EntityManager.GetComponent(pvsEntity).Coordinates, _dragDropHelper.Dragged, pvsEntity);
+ var valid = ValidDragDrop(user.Value, _draggedEntity.Value, entity);
- var valid = ValidDragDrop(dropArgs);
- if (valid == null) continue;
+ // check if it's able to be dropped on by current dragged entity
+ if (valid == null)
+ continue;
- // We'll do a final check given server-side does this before any dragdrop can take place.
- if (valid.Value)
+ // We'll do a final check given server-side does this before any dragdrop can take place.
+ if (valid.Value)
+ {
+ valid = _interactionSystem.InRangeUnobstructed(user.Value, _draggedEntity.Value)
+ && _interactionSystem.InRangeUnobstructed(user.Value, entity);
+ }
+
+ if (inRangeSprite.PostShader != null &&
+ inRangeSprite.PostShader != _dropTargetInRangeShader &&
+ inRangeSprite.PostShader != _dropTargetOutOfRangeShader)
+ {
+ continue;
+ }
+
+ // highlight depending on whether its in or out of range
+ inRangeSprite.PostShader = valid.Value ? _dropTargetInRangeShader : _dropTargetOutOfRangeShader;
+ inRangeSprite.RenderOrder = EntityManager.CurrentTick.Value;
+ _highlightedSprites.Add(inRangeSprite);
+ }
+ }
+
+ private void RemoveHighlights()
+ {
+ foreach (var highlightedSprite in _highlightedSprites)
+ {
+ if (highlightedSprite.PostShader != _dropTargetInRangeShader && highlightedSprite.PostShader != _dropTargetOutOfRangeShader)
+ continue;
+
+ highlightedSprite.PostShader = null;
+ highlightedSprite.RenderOrder = 0;
+ }
+
+ _highlightedSprites.Clear();
+ }
+
+ ///
+ /// Are these args valid for drag-drop?
+ ///
+ ///
+ /// Returns null if no interactions are available or the user / target cannot interact with each other.
+ /// Returns false if interactions exist but are not available currently.
+ ///
+ private bool? ValidDragDrop(EntityUid user, EntityUid dragged, EntityUid target)
+ {
+ if (!_actionBlockerSystem.CanInteract(user, target))
+ return null;
+
+ // CanInteract() doesn't support checking a second "target" entity.
+ // Doing so manually:
+ var ev = new GettingInteractedWithAttemptEvent(user, dragged);
+ RaiseLocalEvent(dragged, ev, true);
+
+ if (ev.Cancelled)
+ return false;
+
+ var dropEv = new CanDropDraggedEvent(user, target);
+
+ RaiseLocalEvent(dragged, ref dropEv);
+
+ if (dropEv.Handled)
+ {
+ if (!dropEv.CanDrop)
+ return false;
+ }
+
+ var dropEv2 = new CanDropTargetEvent(user, dragged);
+
+ RaiseLocalEvent(target, ref dropEv2);
+
+ if (dropEv2.Handled)
+ return dropEv2.CanDrop;
+
+ return null;
+ }
+
+ public override void Update(float frameTime)
+ {
+ base.Update(frameTime);
+
+ switch (_state)
+ {
+ // check if dragging should begin
+ case DragState.MouseDown:
+ {
+ var screenPos = _inputManager.MouseScreenPosition;
+ if ((_mouseDownScreenPos!.Value.Position - screenPos.Position).Length > _deadzone)
{
- valid = _interactionSystem.InRangeUnobstructed(dropArgs.Target, dropArgs.Dragged)
- && _interactionSystem.InRangeUnobstructed(dropArgs.Target, dropArgs.Target);
+ StartDrag();
}
- if (inRangeSprite.PostShader != null &&
- inRangeSprite.PostShader != _dropTargetInRangeShader &&
- inRangeSprite.PostShader != _dropTargetOutOfRangeShader)
- return;
-
- // highlight depending on whether its in or out of range
- inRangeSprite.PostShader = valid.Value ? _dropTargetInRangeShader : _dropTargetOutOfRangeShader;
- inRangeSprite.RenderOrder = EntityManager.CurrentTick.Value;
- _highlightedSprites.Add(inRangeSprite);
- }
- }
-
- private void RemoveHighlights()
- {
- foreach (var highlightedSprite in _highlightedSprites)
- {
- if (highlightedSprite.PostShader != _dropTargetInRangeShader && highlightedSprite.PostShader != _dropTargetOutOfRangeShader)
- continue;
-
- highlightedSprite.PostShader = null;
- highlightedSprite.RenderOrder = 0;
- }
-
- _highlightedSprites.Clear();
- }
-
- ///
- /// Are these args valid for drag-drop?
- ///
- ///
- /// null if the target doesn't support IDragDropOn
- private bool? ValidDragDrop(DragDropEvent eventArgs)
- {
- if (!_actionBlockerSystem.CanInteract(eventArgs.User, eventArgs.Target))
- {
- return false;
- }
-
- // CanInteract() doesn't support checking a second "target" entity.
- // Doing so manually:
- var ev = new GettingInteractedWithAttemptEvent(eventArgs.User, eventArgs.Dragged);
- RaiseLocalEvent(eventArgs.Dragged, ev, true);
- if (ev.Cancelled)
- return false;
-
- var valid = CheckDragDropOn(eventArgs);
-
- foreach (var comp in EntityManager.GetComponents(eventArgs.Target))
- {
- if (!comp.CanDragDropOn(eventArgs))
- {
- valid = false;
- // dragDropOn.Add(comp);
- continue;
- }
-
- valid = true;
break;
}
-
- if (valid != true) return valid;
-
- // Need at least one IDraggable to return true or else we can't do shit
- valid = false;
-
- foreach (var comp in EntityManager.GetComponents(eventArgs.User))
- {
- if (!comp.CanDrop(eventArgs)) continue;
- valid = true;
+ case DragState.Dragging:
+ UpdateDrag(frameTime);
break;
- }
-
- return valid;
}
+ }
- public override void Update(float frameTime)
+ public override void FrameUpdate(float frameTime)
+ {
+ base.FrameUpdate(frameTime);
+
+ // Update position every frame to make it smooth.
+ if (Exists(_dragShadow))
{
- base.Update(frameTime);
-
- _dragDropHelper.Update(frameTime);
- }
-
- public override void FrameUpdate(float frameTime)
- {
- base.FrameUpdate(frameTime);
-
- // Update position every frame to make it smooth.
- if (_dragDropHelper.IsDragging)
- {
- var mousePos = _eyeManager.ScreenToMap(_inputManager.MouseScreenPosition);
- Transform(_dragShadow).WorldPosition = mousePos.Position;
- }
+ var mousePos = _eyeManager.ScreenToMap(_inputManager.MouseScreenPosition);
+ Transform(_dragShadow.Value).WorldPosition = mousePos.Position;
}
}
}
+
+public enum DragState : byte
+{
+ NotDragging,
+
+ ///
+ /// Not dragging yet, waiting to see
+ /// if they hold for long enough
+ ///
+ MouseDown,
+
+ ///
+ /// Currently dragging something
+ ///
+ Dragging,
+}
diff --git a/Content.Client/Kitchen/Components/KitchenSpikeComponent.cs b/Content.Client/Kitchen/Components/KitchenSpikeComponent.cs
index 58f271d63f..375677ef60 100644
--- a/Content.Client/Kitchen/Components/KitchenSpikeComponent.cs
+++ b/Content.Client/Kitchen/Components/KitchenSpikeComponent.cs
@@ -1,15 +1,9 @@
-using Content.Shared.DragDrop;
using Content.Shared.Kitchen.Components;
-using Robust.Shared.GameObjects;
namespace Content.Client.Kitchen.Components
{
- [RegisterComponent]
- internal sealed class KitchenSpikeComponent : SharedKitchenSpikeComponent
+ [RegisterComponent, ComponentReference(typeof(SharedKitchenSpikeComponent))]
+ public sealed class KitchenSpikeComponent : SharedKitchenSpikeComponent
{
- public override bool DragDropOn(DragDropEvent eventArgs)
- {
- return true;
- }
}
}
diff --git a/Content.Client/Kitchen/KitchenSpikeSystem.cs b/Content.Client/Kitchen/KitchenSpikeSystem.cs
new file mode 100644
index 0000000000..3627a29fa9
--- /dev/null
+++ b/Content.Client/Kitchen/KitchenSpikeSystem.cs
@@ -0,0 +1,8 @@
+using Content.Shared.Kitchen;
+
+namespace Content.Client.Kitchen;
+
+public sealed class KitchenSpikeSystem : SharedKitchenSpikeSystem
+{
+
+}
diff --git a/Content.Client/MedicalScanner/MedicalScannerComponent.cs b/Content.Client/MedicalScanner/MedicalScannerComponent.cs
index 49bcbc63a9..1369544cd6 100644
--- a/Content.Client/MedicalScanner/MedicalScannerComponent.cs
+++ b/Content.Client/MedicalScanner/MedicalScannerComponent.cs
@@ -1,16 +1,9 @@
-using Content.Shared.DragDrop;
-using Content.Shared.MedicalScanner;
-using Robust.Shared.GameObjects;
+using Content.Shared.MedicalScanner;
namespace Content.Client.MedicalScanner
{
[RegisterComponent]
- [ComponentReference(typeof(SharedMedicalScannerComponent))]
public sealed class MedicalScannerComponent : SharedMedicalScannerComponent
{
- public override bool DragDropOn(DragDropEvent eventArgs)
- {
- return false;
- }
}
}
diff --git a/Content.Client/Movement/Systems/ClimbSystem.cs b/Content.Client/Movement/Systems/ClimbSystem.cs
index 1f7b757ba4..826c3b0a52 100644
--- a/Content.Client/Movement/Systems/ClimbSystem.cs
+++ b/Content.Client/Movement/Systems/ClimbSystem.cs
@@ -13,6 +13,7 @@ public sealed class ClimbSystem : SharedClimbSystem
{
base.Initialize();
SubscribeLocalEvent(OnClimbingState);
+ SubscribeLocalEvent(OnCanDragDropOn);
}
private static void OnClimbingState(EntityUid uid, ClimbingComponent component, ref ComponentHandleState args)
@@ -24,15 +25,15 @@ public sealed class ClimbSystem : SharedClimbSystem
component.OwnerIsTransitioning = climbModeState.IsTransitioning;
}
- protected override void OnCanDragDropOn(EntityUid uid, ClimbableComponent component, CanDragDropOnEvent args)
+ protected override void OnCanDragDropOn(EntityUid uid, ClimbableComponent component, ref CanDropTargetEvent args)
{
- base.OnCanDragDropOn(uid, component, args);
+ base.OnCanDragDropOn(uid, component, ref args);
if (!args.CanDrop)
return;
var user = args.User;
- var target = args.Target;
+ var target = uid;
var dragged = args.Dragged;
bool Ignored(EntityUid entity) => entity == target || entity == user || entity == dragged;
diff --git a/Content.Client/Strip/StrippableComponent.cs b/Content.Client/Strip/StrippableComponent.cs
deleted file mode 100644
index daad176952..0000000000
--- a/Content.Client/Strip/StrippableComponent.cs
+++ /dev/null
@@ -1,17 +0,0 @@
-using Content.Shared.DragDrop;
-using Content.Shared.Strip.Components;
-using Robust.Shared.GameObjects;
-
-namespace Content.Client.Strip
-{
- [RegisterComponent]
- [ComponentReference(typeof(SharedStrippableComponent))]
- public sealed class StrippableComponent : SharedStrippableComponent
- {
- public override bool Drop(DragDropEvent args)
- {
- // TODO: Prediction
- return false;
- }
- }
-}
diff --git a/Content.Client/Strip/StrippableSystem.cs b/Content.Client/Strip/StrippableSystem.cs
index 59083c4515..bc7e325550 100644
--- a/Content.Client/Strip/StrippableSystem.cs
+++ b/Content.Client/Strip/StrippableSystem.cs
@@ -3,14 +3,16 @@ using Content.Shared.Cuffs.Components;
using Content.Shared.Ensnaring.Components;
using Content.Shared.Hands;
using Content.Shared.Inventory.Events;
+using Content.Shared.Strip;
+using Content.Shared.Strip.Components;
using Robust.Client.GameObjects;
namespace Content.Client.Strip;
///
-/// This is the client-side stripping system, which just triggers UI updates on events.
+/// This is the client-side stripping system, which just triggers UI updates on events.
///
-public sealed class StrippableSystem : EntitySystem
+public sealed class StrippableSystem : SharedStrippableSystem
{
public override void Initialize()
{
diff --git a/Content.Server/Buckle/Systems/BuckleSystem.Buckle.cs b/Content.Server/Buckle/Systems/BuckleSystem.Buckle.cs
index 4ab9439f94..48ec12f9f9 100644
--- a/Content.Server/Buckle/Systems/BuckleSystem.Buckle.cs
+++ b/Content.Server/Buckle/Systems/BuckleSystem.Buckle.cs
@@ -31,8 +31,8 @@ public sealed partial class BuckleSystem
SubscribeLocalEvent(HandleInteractHand);
SubscribeLocalEvent>(AddUnbuckleVerb);
SubscribeLocalEvent(OnEntityStorageInsertAttempt);
- SubscribeLocalEvent(OnBuckleCanDrop);
- SubscribeLocalEvent(OnBuckleDragDrop);
+ SubscribeLocalEvent(OnBuckleCanDrop);
+ SubscribeLocalEvent(OnBuckleDragDrop);
}
private void AddUnbuckleVerb(EntityUid uid, BuckleComponent component, GetVerbsEvent args)
@@ -104,12 +104,12 @@ public sealed partial class BuckleSystem
args.Cancelled = true;
}
- private void OnBuckleCanDrop(EntityUid uid, BuckleComponent component, CanDropEvent args)
+ private void OnBuckleCanDrop(EntityUid uid, BuckleComponent component, ref CanDropDraggedEvent args)
{
args.Handled = HasComp(args.Target);
}
- private void OnBuckleDragDrop(EntityUid uid, BuckleComponent component, DragDropEvent args)
+ private void OnBuckleDragDrop(EntityUid uid, BuckleComponent component, ref DragDropDraggedEvent args)
{
args.Handled = TryBuckle(uid, args.User, args.Target, component);
}
diff --git a/Content.Server/Buckle/Systems/BuckleSystem.Strap.cs b/Content.Server/Buckle/Systems/BuckleSystem.Strap.cs
index 65e15f0fc2..1ca2acdef3 100644
--- a/Content.Server/Buckle/Systems/BuckleSystem.Strap.cs
+++ b/Content.Server/Buckle/Systems/BuckleSystem.Strap.cs
@@ -27,7 +27,7 @@ public sealed partial class BuckleSystem
SubscribeLocalEvent((_,c,_) => StrapRemoveAll(c));
SubscribeLocalEvent((_, c, _) => StrapRemoveAll(c));
SubscribeLocalEvent((_, c, _) => StrapRemoveAll(c));
- SubscribeLocalEvent(OnStrapDragDrop);
+ SubscribeLocalEvent(OnStrapDragDrop);
}
private void OnStrapGetState(EntityUid uid, StrapComponent component, ref ComponentGetState args)
@@ -185,9 +185,9 @@ public sealed partial class BuckleSystem
Dirty(strap);
}
- private void OnStrapDragDrop(EntityUid uid, StrapComponent component, DragDropEvent args)
+ private void OnStrapDragDrop(EntityUid uid, StrapComponent component, ref DragDropTargetEvent args)
{
- if (!StrapCanDragDropOn(uid, args.User, args.Target, args.Dragged, component))
+ if (!StrapCanDragDropOn(uid, args.User, uid, args.Dragged, component))
return;
args.Handled = TryBuckle(args.Dragged, args.User, uid);
diff --git a/Content.Server/Climbing/ClimbSystem.cs b/Content.Server/Climbing/ClimbSystem.cs
index f0c953c99a..6f11cb0351 100644
--- a/Content.Server/Climbing/ClimbSystem.cs
+++ b/Content.Server/Climbing/ClimbSystem.cs
@@ -58,7 +58,7 @@ public sealed class ClimbSystem : SharedClimbSystem
SubscribeLocalEvent(Reset);
SubscribeLocalEvent>(AddClimbableVerb);
- SubscribeLocalEvent(OnClimbableDragDrop);
+ SubscribeLocalEvent(OnClimbableDragDrop);
SubscribeLocalEvent(OnClimbFinished);
SubscribeLocalEvent(OnClimbEndCollide);
@@ -68,17 +68,17 @@ public sealed class ClimbSystem : SharedClimbSystem
SubscribeLocalEvent(OnGlassClimbed);
}
- protected override void OnCanDragDropOn(EntityUid uid, ClimbableComponent component, CanDragDropOnEvent args)
+ protected override void OnCanDragDropOn(EntityUid uid, ClimbableComponent component, ref CanDropTargetEvent args)
{
- base.OnCanDragDropOn(uid, component, args);
+ base.OnCanDragDropOn(uid, component, ref args);
if (!args.CanDrop)
return;
string reason;
var canVault = args.User == args.Dragged
- ? CanVault(component, args.User, args.Target, out reason)
- : CanVault(component, args.User, args.Dragged, args.Target, out reason);
+ ? CanVault(component, args.User, uid, out reason)
+ : CanVault(component, args.User, args.Dragged, uid, out reason);
if (!canVault)
_popupSystem.PopupEntity(reason, args.User, args.User);
@@ -103,9 +103,9 @@ public sealed class ClimbSystem : SharedClimbSystem
});
}
- private void OnClimbableDragDrop(EntityUid uid, ClimbableComponent component, DragDropEvent args)
+ private void OnClimbableDragDrop(EntityUid uid, ClimbableComponent component, ref DragDropTargetEvent args)
{
- TryMoveEntity(component, args.User, args.Dragged, args.Target);
+ TryMoveEntity(component, args.User, args.Dragged, uid);
}
private void TryMoveEntity(ClimbableComponent component, EntityUid user, EntityUid entityToMove,
diff --git a/Content.Server/Disposal/Unit/EntitySystems/DisposalUnitSystem.cs b/Content.Server/Disposal/Unit/EntitySystems/DisposalUnitSystem.cs
index 8439295484..0e7ed86331 100644
--- a/Content.Server/Disposal/Unit/EntitySystems/DisposalUnitSystem.cs
+++ b/Content.Server/Disposal/Unit/EntitySystems/DisposalUnitSystem.cs
@@ -69,7 +69,7 @@ namespace Content.Server.Disposal.Unit.EntitySystems
// Interactions
SubscribeLocalEvent(HandleActivate);
SubscribeLocalEvent(HandleAfterInteractUsing);
- SubscribeLocalEvent(HandleDragDropOn);
+ SubscribeLocalEvent(HandleDragDropOn);
SubscribeLocalEvent(HandleDestruction);
// Verbs
@@ -391,7 +391,7 @@ namespace Content.Server.Disposal.Unit.EntitySystems
TryEjectContents(uid, component);
}
- private void HandleDragDropOn(EntityUid uid, DisposalUnitComponent component, DragDropEvent args)
+ private void HandleDragDropOn(EntityUid uid, DisposalUnitComponent component, ref DragDropTargetEvent args)
{
args.Handled = TryInsert(uid, args.Dragged, args.User);
}
diff --git a/Content.Server/Interaction/InteractionSystem.cs b/Content.Server/Interaction/InteractionSystem.cs
index f4fbafcafc..2433332afc 100644
--- a/Content.Server/Interaction/InteractionSystem.cs
+++ b/Content.Server/Interaction/InteractionSystem.cs
@@ -60,58 +60,38 @@ namespace Content.Server.Interaction
}
#region Drag drop
+
private void HandleDragDropRequestEvent(DragDropRequestEvent msg, EntitySessionEventArgs args)
{
- if (!ValidateClientInput(args.SenderSession, msg.DropLocation, msg.Target, out var userEntity))
- {
- Logger.InfoS("system.interaction", $"DragDropRequestEvent input validation failed");
- return;
- }
-
- if (Deleted(msg.Dropped) || Deleted(msg.Target))
+ if (Deleted(msg.Dragged) || Deleted(msg.Target))
return;
- if (!_actionBlockerSystem.CanInteract(userEntity.Value, msg.Target))
- return;
+ var user = args.SenderSession.AttachedEntity;
- var interactionArgs = new DragDropEvent(userEntity.Value, msg.DropLocation, msg.Dropped, msg.Target);
+ if (user == null || !_actionBlockerSystem.CanInteract(user.Value, msg.Target))
+ return;
// must be in range of both the target and the object they are drag / dropping
// Client also does this check but ya know we gotta validate it.
- if (!InRangeUnobstructed(interactionArgs.User, interactionArgs.Dragged, popup: true)
- || !InRangeUnobstructed(interactionArgs.User, interactionArgs.Target, popup: true))
+ if (!InRangeUnobstructed(user.Value, msg.Dragged, popup: true)
+ || !InRangeUnobstructed(user.Value, msg.Target, popup: true))
+ {
return;
+ }
+
+ var dragArgs = new DragDropDraggedEvent(user.Value, msg.Target);
// trigger dragdrops on the dropped entity
- RaiseLocalEvent(msg.Dropped, interactionArgs, true);
+ RaiseLocalEvent(msg.Dragged, ref dragArgs);
- if (interactionArgs.Handled)
+ if (dragArgs.Handled)
return;
- foreach (var dragDrop in AllComps(msg.Dropped))
- {
- if (dragDrop.CanDrop(interactionArgs) &&
- dragDrop.Drop(interactionArgs))
- {
- return;
- }
- }
+ var dropArgs = new DragDropTargetEvent(user.Value, msg.Dragged);
- // trigger dragdropons on the targeted entity
- RaiseLocalEvent(msg.Target, interactionArgs, false);
-
- if (interactionArgs.Handled)
- return;
-
- foreach (var dragDropOn in AllComps(msg.Target))
- {
- if (dragDropOn.CanDragDropOn(interactionArgs) &&
- dragDropOn.DragDropOn(interactionArgs))
- {
- return;
- }
- }
+ RaiseLocalEvent(msg.Target, ref dropArgs);
}
+
#endregion
}
}
diff --git a/Content.Server/Kitchen/Components/KitchenSpikeComponent.cs b/Content.Server/Kitchen/Components/KitchenSpikeComponent.cs
index 6abea76ec0..6333ca74e2 100644
--- a/Content.Server/Kitchen/Components/KitchenSpikeComponent.cs
+++ b/Content.Server/Kitchen/Components/KitchenSpikeComponent.cs
@@ -1,10 +1,9 @@
using Content.Server.Kitchen.EntitySystems;
-using Content.Shared.DragDrop;
using Content.Shared.Kitchen.Components;
namespace Content.Server.Kitchen.Components
{
- [RegisterComponent, Access(typeof(KitchenSpikeSystem))]
+ [RegisterComponent, Access(typeof(KitchenSpikeSystem)), ComponentReference(typeof(SharedKitchenSpikeComponent))]
public sealed class KitchenSpikeComponent : SharedKitchenSpikeComponent
{
public List? PrototypesToSpawn;
@@ -16,11 +15,5 @@ namespace Content.Server.Kitchen.Components
// Prevents simultaneous spiking of two bodies (could be replaced with CancellationToken, but I don't see any situation where Cancel could be called)
public bool InUse;
-
- // ECS this out!, when DragDropSystem and InteractionSystem refactored
- public override bool DragDropOn(DragDropEvent eventArgs)
- {
- return true;
- }
}
}
diff --git a/Content.Server/Kitchen/EntitySystems/KitchenSpikeSystem.cs b/Content.Server/Kitchen/EntitySystems/KitchenSpikeSystem.cs
index 08ae86cef8..78d4a01deb 100644
--- a/Content.Server/Kitchen/EntitySystems/KitchenSpikeSystem.cs
+++ b/Content.Server/Kitchen/EntitySystems/KitchenSpikeSystem.cs
@@ -3,7 +3,6 @@ using Content.Server.DoAfter;
using Content.Server.Kitchen.Components;
using Content.Server.Nutrition.Components;
using Content.Server.Popups;
-using Content.Shared.Administration.Logs;
using Content.Shared.Database;
using Content.Shared.DragDrop;
using Content.Shared.IdentityManagement;
@@ -15,6 +14,7 @@ using Content.Shared.Storage;
using Robust.Shared.Random;
using static Content.Shared.Kitchen.Components.SharedKitchenSpikeComponent;
using Content.Shared.Interaction.Events;
+using Content.Shared.Kitchen;
using Content.Shared.Mobs.Components;
using Content.Shared.Mobs.Systems;
using Content.Shared.Popups;
@@ -22,7 +22,7 @@ using Robust.Server.GameObjects;
namespace Content.Server.Kitchen.EntitySystems
{
- internal sealed class KitchenSpikeSystem : EntitySystem
+ public sealed class KitchenSpikeSystem : SharedKitchenSpikeSystem
{
[Dependency] private readonly PopupSystem _popupSystem = default!;
[Dependency] private readonly DoAfterSystem _doAfter = default!;
@@ -37,13 +37,21 @@ namespace Content.Server.Kitchen.EntitySystems
SubscribeLocalEvent(OnInteractUsing);
SubscribeLocalEvent(OnInteractHand);
- SubscribeLocalEvent(OnDragDrop);
+ SubscribeLocalEvent(OnDragDrop);
//DoAfter
SubscribeLocalEvent(OnSpikingFinished);
SubscribeLocalEvent(OnSpikingFail);
SubscribeLocalEvent(OnSuicide);
+
+ SubscribeLocalEvent(OnButcherableCanDrop);
+ }
+
+ private void OnButcherableCanDrop(EntityUid uid, ButcherableComponent component, ref CanDropDraggedEvent args)
+ {
+ args.Handled = true;
+ args.CanDrop |= component.Type != ButcheringType.Knife;
}
private void OnSuicide(EntityUid uid, KitchenSpikeComponent component, SuicideEvent args)
@@ -62,7 +70,7 @@ namespace Content.Server.Kitchen.EntitySystems
{
component.InUse = false;
- if (EntityManager.TryGetComponent(args.VictimUid, out var butcherable))
+ if (EntityManager.TryGetComponent(args.VictimUid, out var butcherable))
butcherable.BeingButchered = false;
}
@@ -70,7 +78,7 @@ namespace Content.Server.Kitchen.EntitySystems
{
component.InUse = false;
- if (EntityManager.TryGetComponent(args.VictimUid, out var butcherable))
+ if (EntityManager.TryGetComponent(args.VictimUid, out var butcherable))
butcherable.BeingButchered = false;
if (Spikeable(uid, args.UserUid, args.VictimUid, component, butcherable))
@@ -79,9 +87,9 @@ namespace Content.Server.Kitchen.EntitySystems
}
}
- private void OnDragDrop(EntityUid uid, KitchenSpikeComponent component, DragDropEvent args)
+ private void OnDragDrop(EntityUid uid, KitchenSpikeComponent component, ref DragDropTargetEvent args)
{
- if(args.Handled)
+ if (args.Handled)
return;
args.Handled = true;
@@ -111,7 +119,7 @@ namespace Content.Server.Kitchen.EntitySystems
}
private void Spike(EntityUid uid, EntityUid userUid, EntityUid victimUid,
- KitchenSpikeComponent? component = null, SharedButcherableComponent? butcherable = null)
+ KitchenSpikeComponent? component = null, ButcherableComponent? butcherable = null)
{
if (!Resolve(uid, ref component) || !Resolve(victimUid, ref butcherable))
return;
@@ -177,7 +185,7 @@ namespace Content.Server.Kitchen.EntitySystems
}
private bool Spikeable(EntityUid uid, EntityUid userUid, EntityUid victimUid,
- KitchenSpikeComponent? component = null, SharedButcherableComponent? butcherable = null)
+ KitchenSpikeComponent? component = null, ButcherableComponent? butcherable = null)
{
if (!Resolve(uid, ref component))
return false;
@@ -208,7 +216,7 @@ namespace Content.Server.Kitchen.EntitySystems
}
public bool TrySpike(EntityUid uid, EntityUid userUid, EntityUid victimUid, KitchenSpikeComponent? component = null,
- SharedButcherableComponent? butcherable = null, MobStateComponent? mobState = null)
+ ButcherableComponent? butcherable = null, MobStateComponent? mobState = null)
{
if (!Resolve(uid, ref component) || component.InUse ||
!Resolve(victimUid, ref butcherable) || butcherable.BeingButchered)
diff --git a/Content.Server/Kitchen/EntitySystems/SharpSystem.cs b/Content.Server/Kitchen/EntitySystems/SharpSystem.cs
index 21022bb629..4aceecd419 100644
--- a/Content.Server/Kitchen/EntitySystems/SharpSystem.cs
+++ b/Content.Server/Kitchen/EntitySystems/SharpSystem.cs
@@ -34,7 +34,7 @@ public sealed class SharpSystem : EntitySystem
SubscribeLocalEvent(OnDoafterComplete);
SubscribeLocalEvent(OnDoafterCancelled);
- SubscribeLocalEvent>(OnGetInteractionVerbs);
+ SubscribeLocalEvent>(OnGetInteractionVerbs);
}
private void OnAfterInteract(EntityUid uid, SharpComponent component, AfterInteractEvent args)
@@ -47,7 +47,7 @@ public sealed class SharpSystem : EntitySystem
private void TryStartButcherDoafter(EntityUid knife, EntityUid target, EntityUid user)
{
- if (!TryComp(target, out var butcher))
+ if (!TryComp(target, out var butcher))
return;
if (!TryComp(knife, out var sharp))
@@ -79,7 +79,7 @@ public sealed class SharpSystem : EntitySystem
private void OnDoafterComplete(SharpButcherDoafterComplete ev)
{
- if (!TryComp(ev.Entity, out var butcher))
+ if (!TryComp(ev.Entity, out var butcher))
return;
if (!TryComp(ev.Sharp, out var sharp))
@@ -123,7 +123,7 @@ public sealed class SharpSystem : EntitySystem
sharp.Butchering.Remove(ev.Entity);
}
- private void OnGetInteractionVerbs(EntityUid uid, SharedButcherableComponent component, GetVerbsEvent args)
+ private void OnGetInteractionVerbs(EntityUid uid, ButcherableComponent component, GetVerbsEvent args)
{
if (component.Type != ButcheringType.Knife || args.Hands == null)
return;
diff --git a/Content.Server/Medical/BiomassReclaimer/BiomassReclaimerSystem.cs b/Content.Server/Medical/BiomassReclaimer/BiomassReclaimerSystem.cs
index 9ec1b3a290..7d35105930 100644
--- a/Content.Server/Medical/BiomassReclaimer/BiomassReclaimerSystem.cs
+++ b/Content.Server/Medical/BiomassReclaimer/BiomassReclaimerSystem.cs
@@ -228,7 +228,7 @@ namespace Content.Server.Medical.BiomassReclaimer
{
component.BloodReagent = stream.BloodReagent;
}
- if (TryComp(toProcess, out var butcherableComponent))
+ if (TryComp(toProcess, out var butcherableComponent))
{
component.SpawnedEntities = butcherableComponent.SpawnedEntities;
}
diff --git a/Content.Server/Medical/Components/MedicalScannerComponent.cs b/Content.Server/Medical/Components/MedicalScannerComponent.cs
index 1c6606ea84..165eb17d20 100644
--- a/Content.Server/Medical/Components/MedicalScannerComponent.cs
+++ b/Content.Server/Medical/Components/MedicalScannerComponent.cs
@@ -21,11 +21,5 @@ namespace Content.Server.Medical.Components
[DataField("partRatingCloningFailChanceMultiplier")]
public float PartRatingFailMultiplier = 0.75f;
-
- // ECS this out!, when DragDropSystem and InteractionSystem refactored
- public override bool DragDropOn(DragDropEvent eventArgs)
- {
- return true;
- }
}
}
diff --git a/Content.Server/Medical/CryoPodSystem.cs b/Content.Server/Medical/CryoPodSystem.cs
index 694ff77b59..b789031044 100644
--- a/Content.Server/Medical/CryoPodSystem.cs
+++ b/Content.Server/Medical/CryoPodSystem.cs
@@ -20,7 +20,6 @@ using Content.Shared.Chemistry;
using Content.Shared.Chemistry.Components;
using Content.Shared.Chemistry.Reagent;
using Content.Shared.Containers.ItemSlots;
-using Content.Shared.Destructible;
using Content.Shared.DragDrop;
using Content.Shared.Emag.Systems;
using Content.Shared.Examine;
@@ -54,6 +53,7 @@ public sealed partial class CryoPodSystem: SharedCryoPodSystem
{
base.Initialize();
+ SubscribeLocalEvent(OnCryoPodCanDropOn);
SubscribeLocalEvent(OnComponentInit);
SubscribeLocalEvent>(AddAlternativeVerbs);
SubscribeLocalEvent(OnEmagged);
@@ -63,7 +63,7 @@ public sealed partial class CryoPodSystem: SharedCryoPodSystem
SubscribeLocalEvent(OnCryoPodPryInterrupted);
SubscribeLocalEvent(OnCryoPodUpdateAtmosphere);
- SubscribeLocalEvent(HandleDragDropOn);
+ SubscribeLocalEvent(HandleDragDropOn);
SubscribeLocalEvent(OnInteractUsing);
SubscribeLocalEvent(OnExamined);
SubscribeLocalEvent(OnPowerChanged);
@@ -127,7 +127,7 @@ public sealed partial class CryoPodSystem: SharedCryoPodSystem
#region Interaction
- private void HandleDragDropOn(EntityUid uid, CryoPodComponent cryoPodComponent, DragDropEvent args)
+ private void HandleDragDropOn(EntityUid uid, CryoPodComponent cryoPodComponent, ref DragDropTargetEvent args)
{
if (cryoPodComponent.BodyContainer.ContainedEntity != null)
{
diff --git a/Content.Server/Medical/MedicalScannerSystem.cs b/Content.Server/Medical/MedicalScannerSystem.cs
index 979ce061f1..d468cb0417 100644
--- a/Content.Server/Medical/MedicalScannerSystem.cs
+++ b/Content.Server/Medical/MedicalScannerSystem.cs
@@ -12,6 +12,8 @@ using Content.Server.MachineLinking.System;
using Content.Server.MachineLinking.Events;
using Content.Server.Cloning.Components;
using Content.Server.Construction;
+using Content.Server.Power.EntitySystems;
+using Content.Shared.Body.Components;
using Content.Shared.Mobs.Components;
using Content.Shared.Mobs.Systems;
using Robust.Server.Containers;
@@ -42,11 +44,26 @@ namespace Content.Server.Medical
SubscribeLocalEvent>(AddInsertOtherVerb);
SubscribeLocalEvent>(AddAlternativeVerbs);
SubscribeLocalEvent(OnDestroyed);
- SubscribeLocalEvent(HandleDragDropOn);
+ SubscribeLocalEvent(OnDragDropOn);
SubscribeLocalEvent(OnPortDisconnected);
SubscribeLocalEvent(OnAnchorChanged);
SubscribeLocalEvent(OnRefreshParts);
SubscribeLocalEvent(OnUpgradeExamine);
+ SubscribeLocalEvent(OnCanDragDropOn);
+ }
+
+ private void OnCanDragDropOn(EntityUid uid, MedicalScannerComponent component, ref CanDropTargetEvent args)
+ {
+ args.Handled = true;
+ args.CanDrop |= CanScannerInsert(uid, args.Dragged, component);
+ }
+
+ public bool CanScannerInsert(EntityUid uid, EntityUid target, MedicalScannerComponent? component = null)
+ {
+ if (!Resolve(uid, ref component))
+ return false;
+
+ return HasComp(target);
}
private void OnComponentInit(EntityUid uid, MedicalScannerComponent scannerComponent, ComponentInit args)
@@ -58,7 +75,7 @@ namespace Content.Server.Medical
private void OnRelayMovement(EntityUid uid, MedicalScannerComponent scannerComponent, ref ContainerRelayMovementEntityEvent args)
{
- if (!_blocker.CanInteract(args.Entity, scannerComponent.Owner))
+ if (!_blocker.CanInteract(args.Entity, uid))
return;
EjectBody(uid, scannerComponent);
@@ -70,7 +87,7 @@ namespace Content.Server.Medical
!args.CanAccess ||
!args.CanInteract ||
IsOccupied(component) ||
- !component.CanInsert(args.Using.Value))
+ !CanScannerInsert(uid, args.Using.Value, component))
return;
string name = "Unknown";
@@ -79,7 +96,7 @@ namespace Content.Server.Medical
InteractionVerb verb = new()
{
- Act = () => InsertBody(component.Owner, args.Target, component),
+ Act = () => InsertBody(uid, args.Target, component),
Category = VerbCategory.Insert,
Text = name
};
@@ -104,11 +121,11 @@ namespace Content.Server.Medical
// Self-insert verb
if (!IsOccupied(component) &&
- component.CanInsert(args.User) &&
+ CanScannerInsert(uid, args.User, component) &&
_blocker.CanMove(args.User))
{
AlternativeVerb verb = new();
- verb.Act = () => InsertBody(component.Owner, args.User, component);
+ verb.Act = () => InsertBody(uid, args.User, component);
verb.Text = Loc.GetString("medical-scanner-verb-enter");
args.Verbs.Add(verb);
}
@@ -119,7 +136,7 @@ namespace Content.Server.Medical
EjectBody(uid, scannerComponent);
}
- private void HandleDragDropOn(EntityUid uid, MedicalScannerComponent scannerComponent, DragDropEvent args)
+ private void OnDragDropOn(EntityUid uid, MedicalScannerComponent scannerComponent, ref DragDropTargetEvent args)
{
InsertBody(uid, args.Dragged, scannerComponent);
}
@@ -141,9 +158,9 @@ namespace Content.Server.Medical
}
_cloningConsoleSystem.UpdateUserInterface(console);
}
- private MedicalScannerStatus GetStatus(MedicalScannerComponent scannerComponent)
+ private MedicalScannerStatus GetStatus(EntityUid uid, MedicalScannerComponent scannerComponent)
{
- if (TryComp(scannerComponent.Owner, out var power) && power.Powered)
+ if (this.IsPowered(uid, EntityManager))
{
var body = scannerComponent.BodyContainer.ContainedEntity;
if (body == null)
@@ -180,9 +197,9 @@ namespace Content.Server.Medical
private void UpdateAppearance(EntityUid uid, MedicalScannerComponent scannerComponent)
{
- if (TryComp(scannerComponent.Owner, out var appearance))
+ if (TryComp(uid, out var appearance))
{
- _appearance.SetData(uid, MedicalScannerVisuals.Status, GetStatus(scannerComponent), appearance);
+ _appearance.SetData(uid, MedicalScannerVisuals.Status, GetStatus(uid, scannerComponent), appearance);
}
}
@@ -210,11 +227,11 @@ namespace Content.Server.Medical
if (scannerComponent.BodyContainer.ContainedEntity != null)
return;
- if (!TryComp(user, out var comp))
+ if (!HasComp(user))
return;
scannerComponent.BodyContainer.Insert(user);
- UpdateAppearance(scannerComponent.Owner, scannerComponent);
+ UpdateAppearance(uid, scannerComponent);
}
public void EjectBody(EntityUid uid, MedicalScannerComponent? scannerComponent)
@@ -222,11 +239,12 @@ namespace Content.Server.Medical
if (!Resolve(uid, ref scannerComponent))
return;
- if (scannerComponent.BodyContainer.ContainedEntity is not {Valid: true} contained) return;
+ if (scannerComponent.BodyContainer.ContainedEntity is not {Valid: true} contained)
+ return;
scannerComponent.BodyContainer.Remove(contained);
_climbSystem.ForciblySetClimbing(contained, uid);
- UpdateAppearance(scannerComponent.Owner, scannerComponent);
+ UpdateAppearance(uid, scannerComponent);
}
private void OnRefreshParts(EntityUid uid, MedicalScannerComponent component, RefreshPartsEvent args)
diff --git a/Content.Server/Strip/StrippableComponent.cs b/Content.Server/Strip/StrippableComponent.cs
deleted file mode 100644
index 141dddec00..0000000000
--- a/Content.Server/Strip/StrippableComponent.cs
+++ /dev/null
@@ -1,26 +0,0 @@
-using System.Threading;
-using Content.Shared.DragDrop;
-using Content.Shared.Strip.Components;
-
-namespace Content.Server.Strip
-{
- [RegisterComponent]
- [ComponentReference(typeof(SharedStrippableComponent))]
- [Access(typeof(StrippableSystem))]
- public sealed class StrippableComponent : SharedStrippableComponent
- {
- ///
- /// The strip delay for hands.
- ///
- [DataField("handDelay")]
- public float HandStripDelay = 4f;
-
- public override bool Drop(DragDropEvent args)
- {
- IoCManager.Resolve().GetEntitySystem().StartOpeningStripper(args.User, this);
- return true;
- }
-
- public Dictionary CancelTokens = new();
- }
-}
diff --git a/Content.Server/Strip/StrippableSystem.cs b/Content.Server/Strip/StrippableSystem.cs
index 4acc65fba2..d70d374f69 100644
--- a/Content.Server/Strip/StrippableSystem.cs
+++ b/Content.Server/Strip/StrippableSystem.cs
@@ -17,10 +17,11 @@ using Content.Server.Administration.Logs;
using Content.Shared.Database;
using Content.Shared.Ensnaring.Components;
using Content.Shared.Interaction;
+using Content.Shared.Strip;
namespace Content.Server.Strip
{
- public sealed class StrippableSystem : EntitySystem
+ public sealed class StrippableSystem : SharedStrippableSystem
{
[Dependency] private readonly SharedHandsSystem _handsSystem = default!;
[Dependency] private readonly InventorySystem _inventorySystem = default!;
@@ -104,8 +105,10 @@ namespace Content.Server.Strip
TakeItemFromHands(user, handId, component);
}
- public void StartOpeningStripper(EntityUid user, StrippableComponent component, bool openInCombat = false)
+ public override void StartOpeningStripper(EntityUid user, StrippableComponent component, bool openInCombat = false)
{
+ base.StartOpeningStripper(user, component, openInCombat);
+
if (TryComp(user, out var mode) && mode.IsInCombatMode && !openInCombat)
return;
@@ -446,25 +449,5 @@ namespace Content.Server.Strip
// hand update will trigger strippable update
_adminLogger.Add(LogType.Stripping, LogImpact.Medium, $"{ToPrettyString(user):user} has stripped the item {ToPrettyString(held):item} from {ToPrettyString(component.Owner):target}");
}
-
- private sealed class OpenStrippingCompleteEvent
- {
- public readonly EntityUid User;
-
- public OpenStrippingCompleteEvent(EntityUid user)
- {
- User = user;
- }
- }
-
- private sealed class OpenStrippingCancelledEvent
- {
- public readonly EntityUid User;
-
- public OpenStrippingCancelledEvent(EntityUid user)
- {
- User = user;
- }
- }
}
}
diff --git a/Content.Shared/ActionBlocker/ActionBlockerSystem.cs b/Content.Shared/ActionBlocker/ActionBlockerSystem.cs
index 12310ce0f5..e0d772c718 100644
--- a/Content.Shared/ActionBlocker/ActionBlockerSystem.cs
+++ b/Content.Shared/ActionBlocker/ActionBlockerSystem.cs
@@ -1,6 +1,7 @@
using Content.Shared.Body.Events;
using Content.Shared.DragDrop;
using Content.Shared.Emoting;
+using Content.Shared.Hands;
using Content.Shared.Interaction;
using Content.Shared.Interaction.Events;
using Content.Shared.Item;
@@ -115,7 +116,7 @@ namespace Content.Shared.ActionBlocker
public bool CanDrop(EntityUid uid)
{
- var ev = new DropAttemptEvent(uid);
+ var ev = new DropAttemptEvent();
RaiseLocalEvent(uid, ev);
return !ev.Cancelled;
diff --git a/Content.Shared/Body/Components/BodyComponent.cs b/Content.Shared/Body/Components/BodyComponent.cs
index 022d3a7799..312f37f251 100644
--- a/Content.Shared/Body/Components/BodyComponent.cs
+++ b/Content.Shared/Body/Components/BodyComponent.cs
@@ -1,7 +1,6 @@
using Content.Shared.Body.Part;
using Content.Shared.Body.Prototypes;
using Content.Shared.Body.Systems;
-using Content.Shared.DragDrop;
using Robust.Shared.Audio;
using Robust.Shared.GameStates;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
@@ -10,7 +9,7 @@ namespace Content.Shared.Body.Components;
[RegisterComponent, NetworkedComponent]
[Access(typeof(SharedBodySystem))]
-public sealed class BodyComponent : Component, IDraggable
+public sealed class BodyComponent : Component
{
[DataField("prototype", customTypeSerializer: typeof(PrototypeIdSerializer))]
public readonly string? Prototype;
@@ -27,14 +26,4 @@ public sealed class BodyComponent : Component, IDraggable
///
[DataField("requiredLegs")]
public int RequiredLegs;
-
- bool IDraggable.CanStartDrag(StartDragDropEvent args)
- {
- return true;
- }
-
- bool IDraggable.CanDrop(CanDropEvent args)
- {
- return true;
- }
}
diff --git a/Content.Shared/Body/Systems/SharedBodySystem.Body.cs b/Content.Shared/Body/Systems/SharedBodySystem.Body.cs
index 92a0c88a2a..3b464ca115 100644
--- a/Content.Shared/Body/Systems/SharedBodySystem.Body.cs
+++ b/Content.Shared/Body/Systems/SharedBodySystem.Body.cs
@@ -5,6 +5,7 @@ using Content.Shared.Body.Organ;
using Content.Shared.Body.Part;
using Content.Shared.Body.Prototypes;
using Content.Shared.Coordinates;
+using Content.Shared.DragDrop;
using Robust.Shared.Containers;
using Robust.Shared.GameStates;
@@ -18,6 +19,12 @@ public partial class SharedBodySystem
SubscribeLocalEvent(OnBodyGetState);
SubscribeLocalEvent(OnBodyHandleState);
+ SubscribeLocalEvent(OnBodyCanDrag);
+ }
+
+ private void OnBodyCanDrag(EntityUid uid, BodyComponent component, ref CanDragEvent args)
+ {
+ args.Handled = true;
}
private void OnBodyInit(EntityUid bodyId, BodyComponent body, ComponentInit args)
diff --git a/Content.Shared/Buckle/SharedBuckleSystem.Strap.cs b/Content.Shared/Buckle/SharedBuckleSystem.Strap.cs
index 8e54bd384e..9e9ffa1583 100644
--- a/Content.Shared/Buckle/SharedBuckleSystem.Strap.cs
+++ b/Content.Shared/Buckle/SharedBuckleSystem.Strap.cs
@@ -13,7 +13,7 @@ public abstract partial class SharedBuckleSystem
{
SubscribeLocalEvent(OnStrapRotate);
SubscribeLocalEvent(OnStrapHandleState);
- SubscribeLocalEvent(OnStrapCanDragDropOn);
+ SubscribeLocalEvent(OnStrapCanDropOn);
}
private void OnStrapHandleState(EntityUid uid, StrapComponent component, ref ComponentHandleState args)
@@ -85,9 +85,9 @@ public abstract partial class SharedBuckleSystem
return _interactions.InRangeUnobstructed(target, buckleId, buckle.Range, predicate: Ignored);
}
- private void OnStrapCanDragDropOn(EntityUid uid, StrapComponent strap, CanDragDropOnEvent args)
+ private void OnStrapCanDropOn(EntityUid uid, StrapComponent strap, ref CanDropTargetEvent args)
{
- args.CanDrop = StrapCanDragDropOn(args.Target, args.User, args.Target, args.Dragged, strap);
+ args.CanDrop = StrapCanDragDropOn(uid, args.User, uid, args.Dragged, strap);
args.Handled = true;
}
}
diff --git a/Content.Shared/Climbing/BonkSystem.cs b/Content.Shared/Climbing/BonkSystem.cs
index 9774f59751..dcf534058d 100644
--- a/Content.Shared/Climbing/BonkSystem.cs
+++ b/Content.Shared/Climbing/BonkSystem.cs
@@ -22,7 +22,7 @@ public sealed class BonkSystem : EntitySystem
public override void Initialize()
{
base.Initialize();
- SubscribeLocalEvent(OnDragDrop);
+ SubscribeLocalEvent(OnDragDrop);
}
public bool TryBonk(EntityUid user, EntityUid bonkableUid, BonkableComponent? bonkableComponent = null)
@@ -56,8 +56,8 @@ public sealed class BonkSystem : EntitySystem
return false;
}
- private void OnDragDrop(EntityUid user, BonkableComponent bonkableComponent, DragDropEvent args)
+ private void OnDragDrop(EntityUid uid, BonkableComponent bonkableComponent, ref DragDropTargetEvent args)
{
- TryBonk(args.Dragged, args.Target);
+ TryBonk(args.Dragged, uid);
}
}
diff --git a/Content.Shared/Climbing/SharedClimbSystem.cs b/Content.Shared/Climbing/SharedClimbSystem.cs
index 1d9ff5f606..6521599f54 100644
--- a/Content.Shared/Climbing/SharedClimbSystem.cs
+++ b/Content.Shared/Climbing/SharedClimbSystem.cs
@@ -1,5 +1,4 @@
using Content.Shared.DragDrop;
-using Content.Shared.Movement;
using Content.Shared.Movement.Events;
namespace Content.Shared.Climbing;
@@ -10,7 +9,6 @@ public abstract class SharedClimbSystem : EntitySystem
{
base.Initialize();
SubscribeLocalEvent(HandleMoveAttempt);
- SubscribeLocalEvent(OnCanDragDropOn);
}
private static void HandleMoveAttempt(EntityUid uid, ClimbingComponent component, UpdateCanMoveEvent args)
@@ -22,7 +20,7 @@ public abstract class SharedClimbSystem : EntitySystem
args.Cancel();
}
- protected virtual void OnCanDragDropOn(EntityUid uid, ClimbableComponent component, CanDragDropOnEvent args)
+ protected virtual void OnCanDragDropOn(EntityUid uid, ClimbableComponent component, ref CanDropTargetEvent args)
{
args.CanDrop = HasComp(args.Dragged);
}
diff --git a/Content.Shared/Cuffs/SharedCuffableSystem.cs b/Content.Shared/Cuffs/SharedCuffableSystem.cs
index db17972ac8..b5cf8a5868 100644
--- a/Content.Shared/Cuffs/SharedCuffableSystem.cs
+++ b/Content.Shared/Cuffs/SharedCuffableSystem.cs
@@ -2,6 +2,7 @@ using Content.Shared.ActionBlocker;
using Content.Shared.Alert;
using Content.Shared.Cuffs.Components;
using Content.Shared.DragDrop;
+using Content.Shared.Hands;
using Content.Shared.Hands.Components;
using Content.Shared.Interaction.Events;
using Content.Shared.Inventory.Events;
diff --git a/Content.Shared/Disposal/SharedDisposalUnitSystem.cs b/Content.Shared/Disposal/SharedDisposalUnitSystem.cs
index e0312a7af3..e0f0faf1a2 100644
--- a/Content.Shared/Disposal/SharedDisposalUnitSystem.cs
+++ b/Content.Shared/Disposal/SharedDisposalUnitSystem.cs
@@ -27,7 +27,7 @@ namespace Content.Shared.Disposal
{
base.Initialize();
SubscribeLocalEvent(OnPreventCollide);
- SubscribeLocalEvent(OnCanDragDropOn);
+ SubscribeLocalEvent(OnCanDragDropOn);
}
private void OnPreventCollide(EntityUid uid, SharedDisposalUnitComponent component, ref PreventCollideEvent args)
@@ -48,9 +48,10 @@ namespace Content.Shared.Disposal
}
}
- private void OnCanDragDropOn(EntityUid uid, SharedDisposalUnitComponent component, CanDragDropOnEvent args)
+ private void OnCanDragDropOn(EntityUid uid, SharedDisposalUnitComponent component, ref CanDropTargetEvent args)
{
- if (args.Handled) return;
+ if (args.Handled)
+ return;
args.CanDrop = CanInsert(component, args.Dragged);
args.Handled = true;
diff --git a/Content.Shared/DragDrop/CanDragDropOnEvent.cs b/Content.Shared/DragDrop/CanDragDropOnEvent.cs
deleted file mode 100644
index 9667bb7659..0000000000
--- a/Content.Shared/DragDrop/CanDragDropOnEvent.cs
+++ /dev/null
@@ -1,36 +0,0 @@
-namespace Content.Shared.DragDrop;
-
-///
-/// Event that gets send to the target of a drag drop action
-/// Mark this event as handled to specify that the entity can be dropped on
-/// and set CanDrop to true or false, depending on whether dropping the entity onto the target is actually possible.
-///
-public sealed class CanDragDropOnEvent : HandledEntityEventArgs
-{
- ///
- /// Entity doing the drag and drop.
- ///
- public EntityUid User { get; }
-
- ///
- /// Entity that is being dragged.
- ///
- public EntityUid Dragged { get; }
-
- ///
- /// Entity that is being dropped on.
- ///
- public EntityUid Target { get; }
-
- ///
- /// If the dragged entity can be dropped on the target.
- ///
- public bool CanDrop { get; set; } = false;
-
- public CanDragDropOnEvent(EntityUid user, EntityUid dragged, EntityUid target)
- {
- User = user;
- Dragged = dragged;
- Target = target;
- }
-}
diff --git a/Content.Shared/DragDrop/DragDropRequestEvent.cs b/Content.Shared/DragDrop/DragDropRequestEvent.cs
index b48e3889e6..af32997942 100644
--- a/Content.Shared/DragDrop/DragDropRequestEvent.cs
+++ b/Content.Shared/DragDrop/DragDropRequestEvent.cs
@@ -1,33 +1,26 @@
-using Robust.Shared.Map;
using Robust.Shared.Serialization;
namespace Content.Shared.DragDrop
{
///
- /// Requests a drag / drop interaction to be performed
+ /// Raised on the client to the server requesting a drag-drop.
///
[Serializable, NetSerializable]
public sealed class DragDropRequestEvent : EntityEventArgs
{
- ///
- /// Location that the entity was dropped.
- ///
- public EntityCoordinates DropLocation { get; }
-
///
/// Entity that was dragged and dropped.
///
- public EntityUid Dropped { get; }
+ public EntityUid Dragged { get; }
///
/// Entity that was drag dropped on.
///
public EntityUid Target { get; }
- public DragDropRequestEvent(EntityCoordinates dropLocation, EntityUid dropped, EntityUid target)
+ public DragDropRequestEvent(EntityUid dragged, EntityUid target)
{
- DropLocation = dropLocation;
- Dropped = dropped;
+ Dragged = dragged;
Target = target;
}
}
diff --git a/Content.Shared/DragDrop/DraggableEvents.cs b/Content.Shared/DragDrop/DraggableEvents.cs
new file mode 100644
index 0000000000..288a269e19
--- /dev/null
+++ b/Content.Shared/DragDrop/DraggableEvents.cs
@@ -0,0 +1,67 @@
+namespace Content.Shared.DragDrop;
+
+///
+/// Raised directed on an entity when attempting to start a drag.
+///
+[ByRefEvent]
+public record struct CanDragEvent
+{
+ ///
+ /// False if we are unable to drag this entity.
+ ///
+ public bool Handled;
+}
+
+///
+/// Raised directed on a dragged entity to indicate whether it has interactions with the target entity.
+///
+[ByRefEvent]
+public record struct CanDropDraggedEvent(EntityUid User, EntityUid Target)
+{
+ public readonly EntityUid User = User;
+ public readonly EntityUid Target = Target;
+ public bool Handled = false;
+
+ ///
+ /// Can we drop the entity onto the target? If the event is not handled then there is no supported interactions.
+ ///
+ public bool CanDrop = false;
+}
+
+///
+/// Raised directed on the target entity to indicate whether it has interactions with the dragged entity.
+///
+[ByRefEvent]
+public record struct CanDropTargetEvent(EntityUid User, EntityUid Dragged)
+{
+ public readonly EntityUid User = User;
+ public readonly EntityUid Dragged = Dragged;
+ public bool Handled = false;
+
+ ///
+ ///
+ ///
+ public bool CanDrop = false;
+}
+
+///
+/// Raised directed on a dragged entity when it is dropped on a target entity.
+///
+[ByRefEvent]
+public record struct DragDropDraggedEvent(EntityUid User, EntityUid Target)
+{
+ public readonly EntityUid User = User;
+ public readonly EntityUid Target = Target;
+ public bool Handled = false;
+}
+
+///
+/// Raised directed on the target entity when a dragged entity is dragged onto it.
+///
+[ByRefEvent]
+public record struct DragDropTargetEvent(EntityUid User, EntityUid Dragged)
+{
+ public readonly EntityUid User = User;
+ public readonly EntityUid Dragged = Dragged;
+ public bool Handled = false;
+}
diff --git a/Content.Shared/DragDrop/DropAttemptEvent.cs b/Content.Shared/DragDrop/DropAttemptEvent.cs
deleted file mode 100644
index 033a14215f..0000000000
--- a/Content.Shared/DragDrop/DropAttemptEvent.cs
+++ /dev/null
@@ -1,12 +0,0 @@
-namespace Content.Shared.DragDrop
-{
- public sealed class DropAttemptEvent : CancellableEntityEventArgs
- {
- public DropAttemptEvent(EntityUid uid)
- {
- Uid = uid;
- }
-
- public EntityUid Uid { get; }
- }
-}
diff --git a/Content.Shared/DragDrop/IDragDropOn.cs b/Content.Shared/DragDrop/IDragDropOn.cs
deleted file mode 100644
index 0fca993bc9..0000000000
--- a/Content.Shared/DragDrop/IDragDropOn.cs
+++ /dev/null
@@ -1,32 +0,0 @@
-namespace Content.Shared.DragDrop
-{
- ///
- /// This interface allows the component's entity to be dragged and dropped
- /// onto by another entity and gives it behavior when that occurs.
- ///
- [RequiresExplicitImplementation]
- public interface IDragDropOn
- {
- ///
- /// Invoked when another entity is being dragged and dropped
- /// onto this one before invoking .
- /// Note that other drag and drop interactions may be attempted if
- /// this one fails.
- ///
- ///
- /// true if is valid, false otherwise.
- bool CanDragDropOn(DragDropEvent eventArgs);
-
- ///
- /// Invoked server-side when another entity is being dragged and dropped
- /// onto this one before invoking
- /// Note that other drag and drop interactions may be attempted if
- /// this one fails.
- ///
- ///
- /// true if an interaction occurred and no further interaction should
- /// be processed for this drop.
- ///
- bool DragDropOn(DragDropEvent eventArgs);
- }
-}
diff --git a/Content.Shared/DragDrop/IDraggable.cs b/Content.Shared/DragDrop/IDraggable.cs
deleted file mode 100644
index f4940426a8..0000000000
--- a/Content.Shared/DragDrop/IDraggable.cs
+++ /dev/null
@@ -1,124 +0,0 @@
-using Robust.Shared.Map;
-
-namespace Content.Shared.DragDrop
-{
- ///
- /// This interface allows a local client to initiate dragging of the component's
- /// entity by mouse, for drag and drop interactions.
- ///
- [RequiresExplicitImplementation]
- public interface IDraggable
- {
- ///
- /// Invoked when an user is attempting to initiate a drag with
- /// this component's entity in range. It's fine to return true even if there
- /// wouldn't be any valid targets - just return true if this entity is in a
- /// "draggable" state.
- ///
- ///
- /// The information about the drag, such as who is doing it.
- ///
- /// True if the drag should be initiated, false otherwise.
- bool CanStartDrag(StartDragDropEvent args)
- {
- return true;
- }
-
- ///
- /// Invoked on entities visible to the user to check if this component's
- /// entity can be dropped on the indicated target entity.
- /// No need to check range / reachability in here.
- /// Returning true will cause the target entity to be highlighted as
- /// a potential target and allow dropping when in range.
- ///
- ///
- /// True if target is a valid target to be dropped on by this component's
- /// entity, false otherwise.
- ///
- bool CanDrop(CanDropEvent args);
-
- ///
- /// Invoked when this component's entity is being dropped on another.
- /// Other drag and drop interactions may be attempted if this one fails.
- ///
- ///
- /// The information about the drag, such as who is doing it.
- ///
- ///
- /// True if an interaction occurred and no further interaction should
- /// be processed for this drop, false otherwise.
- ///
- bool Drop(DragDropEvent args)
- {
- return false;
- }
- }
-
- [Virtual]
- public class StartDragDropEvent : HandledEntityEventArgs
- {
- ///
- /// Entity doing the drag and drop.
- ///
- public EntityUid User { get; }
-
- ///
- /// Entity that is being dragged.
- ///
- public EntityUid Dragged { get; }
-
- ///
- /// Creates a new instance of .
- ///
- /// The entity doing the drag and drop.
- /// The entity that is being dragged and dropped.
- public StartDragDropEvent(EntityUid user, EntityUid dragged)
- {
- User = user;
- Dragged = dragged;
- }
- }
-
- [Virtual]
- public class CanDropEvent : StartDragDropEvent
- {
- ///
- /// The entity uid that
- /// is being dropped onto.
- ///
- public EntityUid Target { get; }
-
- ///
- /// Creates a new instance of .
- ///
- /// The entity doing the drag and drop.
- /// The entity that is being dragged and dropped.
- /// The entity that is being dropped onto.
- public CanDropEvent(EntityUid user, EntityUid dragged, EntityUid target) : base(user, dragged)
- {
- Target = target;
- }
- }
-
- [Virtual]
- public class DragDropEvent : CanDropEvent
- {
- ///
- /// The location where
- /// is being dropped.
- ///
- public EntityCoordinates DropLocation { get; }
-
- ///
- /// Creates a new instance of .
- ///
- /// The entity doing the drag and drop.
- /// The location where is being dropped.
- /// The entity that is being dragged and dropped.
- /// The entity that is being dropped onto.
- public DragDropEvent(EntityUid user, EntityCoordinates dropLocation, EntityUid dragged, EntityUid target) : base(user, dragged, target)
- {
- DropLocation = dropLocation;
- }
- }
-}
diff --git a/Content.Shared/DragDrop/SharedDragDropSystem.cs b/Content.Shared/DragDrop/SharedDragDropSystem.cs
index d6fab4b6ff..7f1f6c23f7 100644
--- a/Content.Shared/DragDrop/SharedDragDropSystem.cs
+++ b/Content.Shared/DragDrop/SharedDragDropSystem.cs
@@ -2,12 +2,5 @@
public abstract class SharedDragDropSystem : EntitySystem
{
- protected bool? CheckDragDropOn(DragDropEvent eventArgs)
- {
- var canDragDropOnEvent = new CanDragDropOnEvent(eventArgs.User, eventArgs.Dragged, eventArgs.Target);
- RaiseLocalEvent(eventArgs.Target, canDragDropOnEvent, false);
-
- return canDragDropOnEvent.Handled ? canDragDropOnEvent.CanDrop : null;
- }
}
diff --git a/Content.Shared/Ghost/SharedGhostSystem.cs b/Content.Shared/Ghost/SharedGhostSystem.cs
index b480906f97..fa91d5e2ff 100644
--- a/Content.Shared/Ghost/SharedGhostSystem.cs
+++ b/Content.Shared/Ghost/SharedGhostSystem.cs
@@ -1,5 +1,6 @@
using Content.Shared.DragDrop;
using Content.Shared.Emoting;
+using Content.Shared.Hands;
using Content.Shared.Interaction.Events;
using Content.Shared.Item;
using Robust.Shared.Serialization;
@@ -56,7 +57,7 @@ namespace Content.Shared.Ghost
DisplayName = displayName;
IsWarpPoint = isWarpPoint;
}
-
+
///
/// The entity representing the warp point.
/// This is passed back to the server in
diff --git a/Content.Shared/Hands/HandEvents.cs b/Content.Shared/Hands/HandEvents.cs
index 3d5f64986a..29f4b2cad8 100644
--- a/Content.Shared/Hands/HandEvents.cs
+++ b/Content.Shared/Hands/HandEvents.cs
@@ -7,6 +7,14 @@ using static Robust.Shared.GameObjects.SharedSpriteComponent;
namespace Content.Shared.Hands
{
+ ///
+ /// Raised directed on an entity when attempting to drop its hand items.
+ ///
+ public sealed class DropAttemptEvent : CancellableEntityEventArgs
+ {
+ public readonly EntityUid Uid;
+ }
+
///
/// Raised directed at an item that needs to update its in-hand sprites/layers.
///
diff --git a/Content.Shared/Inventory/InventorySystem.Equip.cs b/Content.Shared/Inventory/InventorySystem.Equip.cs
index e545ef84a8..cd305bbf96 100644
--- a/Content.Shared/Inventory/InventorySystem.Equip.cs
+++ b/Content.Shared/Inventory/InventorySystem.Equip.cs
@@ -243,8 +243,8 @@ public abstract partial class InventorySystem
// that requires server/client specific code.
// Uhhh TODO, fix this. This doesn't even fucking check if the target item is IN the targets inventory.
return actor != target &&
- HasComp(target) &&
- HasComp(actor) &&
+ HasComp(target) &&
+ HasComp(actor) &&
HasComp(actor);
}
diff --git a/Content.Shared/Kitchen/Components/SharedKitchenSpikeComponent.cs b/Content.Shared/Kitchen/Components/SharedKitchenSpikeComponent.cs
index cee5232073..1428ef8bb6 100644
--- a/Content.Shared/Kitchen/Components/SharedKitchenSpikeComponent.cs
+++ b/Content.Shared/Kitchen/Components/SharedKitchenSpikeComponent.cs
@@ -1,11 +1,11 @@
-using Content.Shared.DragDrop;
-using Content.Shared.Nutrition.Components;
using Robust.Shared.Audio;
+using Robust.Shared.GameStates;
using Robust.Shared.Serialization;
namespace Content.Shared.Kitchen.Components
{
- public abstract class SharedKitchenSpikeComponent : Component, IDragDropOn
+ [NetworkedComponent]
+ public abstract class SharedKitchenSpikeComponent : Component
{
[DataField("delay")]
public float SpikeDelay = 7.0f;
@@ -14,19 +14,6 @@ namespace Content.Shared.Kitchen.Components
[DataField("sound")]
public SoundSpecifier SpikeSound = new SoundPathSpecifier("/Audio/Effects/Fluids/splat.ogg");
- bool IDragDropOn.CanDragDropOn(DragDropEvent eventArgs)
- {
- if (!IoCManager.Resolve().HasComponent(eventArgs.Dragged))
- {
- return false;
- }
-
- // TODO: Once we get silicons need to check organic
- return true;
- }
-
- public abstract bool DragDropOn(DragDropEvent eventArgs);
-
[Serializable, NetSerializable]
public enum KitchenSpikeVisuals : byte
{
diff --git a/Content.Shared/Kitchen/SharedKitchenSpikeSystem.cs b/Content.Shared/Kitchen/SharedKitchenSpikeSystem.cs
new file mode 100644
index 0000000000..fa8d7a9e85
--- /dev/null
+++ b/Content.Shared/Kitchen/SharedKitchenSpikeSystem.cs
@@ -0,0 +1,31 @@
+using Content.Shared.DragDrop;
+using Content.Shared.Kitchen.Components;
+using Content.Shared.Nutrition.Components;
+
+namespace Content.Shared.Kitchen;
+
+public abstract class SharedKitchenSpikeSystem : EntitySystem
+{
+ public override void Initialize()
+ {
+ base.Initialize();
+ SubscribeLocalEvent(OnCanDrop);
+ }
+
+ private void OnCanDrop(EntityUid uid, SharedKitchenSpikeComponent component, ref CanDropTargetEvent args)
+ {
+ if (args.Handled)
+ return;
+
+ args.Handled = true;
+
+ if (!HasComp(args.Dragged))
+ {
+ args.CanDrop = false;
+ return;
+ }
+
+ // TODO: Once we get silicons need to check organic
+ args.CanDrop = true;
+ }
+}
diff --git a/Content.Shared/Medical/Cryogenics/SharedCryoPodComponent.cs b/Content.Shared/Medical/Cryogenics/SharedCryoPodComponent.cs
index b10a929879..3a9c76111c 100644
--- a/Content.Shared/Medical/Cryogenics/SharedCryoPodComponent.cs
+++ b/Content.Shared/Medical/Cryogenics/SharedCryoPodComponent.cs
@@ -9,7 +9,7 @@ using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
namespace Content.Shared.Medical.Cryogenics;
[NetworkedComponent]
-public abstract class SharedCryoPodComponent: Component, IDragDropOn
+public abstract class SharedCryoPodComponent: Component
{
///
/// Specifies the name of the atmospherics port to draw gas from.
@@ -87,19 +87,4 @@ public abstract class SharedCryoPodComponent: Component, IDragDropOn
ContainsEntity,
IsOn
}
-
- public bool CanInsert(EntityUid entity)
- {
- return IoCManager.Resolve().HasComponent(entity);
- }
-
- bool IDragDropOn.CanDragDropOn(DragDropEvent eventArgs)
- {
- return CanInsert(eventArgs.Dragged);
- }
-
- bool IDragDropOn.DragDropOn(DragDropEvent eventArgs)
- {
- return false;
- }
}
diff --git a/Content.Shared/Medical/Cryogenics/SharedCryoPodSystem.cs b/Content.Shared/Medical/Cryogenics/SharedCryoPodSystem.cs
index 3c41cec3cd..502669dc5c 100644
--- a/Content.Shared/Medical/Cryogenics/SharedCryoPodSystem.cs
+++ b/Content.Shared/Medical/Cryogenics/SharedCryoPodSystem.cs
@@ -1,4 +1,6 @@
using Content.Server.Medical.Components;
+using Content.Shared.Body.Components;
+using Content.Shared.DragDrop;
using Content.Shared.Emag.Systems;
using Content.Shared.Mobs.Components;
using Content.Shared.Mobs.Systems;
@@ -26,6 +28,12 @@ public abstract partial class SharedCryoPodSystem: EntitySystem
InitializeInsideCryoPod();
}
+ protected void OnCryoPodCanDropOn(EntityUid uid, SharedCryoPodComponent component, ref CanDropTargetEvent args)
+ {
+ args.CanDrop = args.CanDrop && HasComp(args.Dragged);
+ args.Handled = true;
+ }
+
protected void OnComponentInit(EntityUid uid, SharedCryoPodComponent cryoPodComponent, ComponentInit args)
{
cryoPodComponent.BodyContainer = _containerSystem.EnsureContainer(uid, "scanner-body");
diff --git a/Content.Shared/MedicalScanner/SharedMedicalScannerComponent.cs b/Content.Shared/MedicalScanner/SharedMedicalScannerComponent.cs
index 1b1805a1f1..848370c1d0 100644
--- a/Content.Shared/MedicalScanner/SharedMedicalScannerComponent.cs
+++ b/Content.Shared/MedicalScanner/SharedMedicalScannerComponent.cs
@@ -1,19 +1,18 @@
-using Content.Shared.Body.Components;
using Content.Shared.DragDrop;
using Robust.Shared.Serialization;
namespace Content.Shared.MedicalScanner
{
- public abstract class SharedMedicalScannerComponent : Component, IDragDropOn
+ public abstract class SharedMedicalScannerComponent : Component
{
[Serializable, NetSerializable]
- public enum MedicalScannerVisuals
+ public enum MedicalScannerVisuals : byte
{
Status
}
[Serializable, NetSerializable]
- public enum MedicalScannerStatus
+ public enum MedicalScannerStatus : byte
{
Off,
Open,
@@ -22,17 +21,5 @@ namespace Content.Shared.MedicalScanner
Green,
Yellow,
}
-
- public bool CanInsert(EntityUid entity)
- {
- return IoCManager.Resolve().HasComponent(entity);
- }
-
- bool IDragDropOn.CanDragDropOn(DragDropEvent eventArgs)
- {
- return CanInsert(eventArgs.Dragged);
- }
-
- public abstract bool DragDropOn(DragDropEvent eventArgs);
}
}
diff --git a/Content.Shared/Mobs/Systems/MobStateSystem.Subscribers.cs b/Content.Shared/Mobs/Systems/MobStateSystem.Subscribers.cs
index 82b183e519..6515ba41a8 100644
--- a/Content.Shared/Mobs/Systems/MobStateSystem.Subscribers.cs
+++ b/Content.Shared/Mobs/Systems/MobStateSystem.Subscribers.cs
@@ -2,6 +2,7 @@
using Content.Shared.Disease.Events;
using Content.Shared.DragDrop;
using Content.Shared.Emoting;
+using Content.Shared.Hands;
using Content.Shared.Interaction.Events;
using Content.Shared.Inventory.Events;
using Content.Shared.Item;
diff --git a/Content.Shared/Nutrition/Components/SharedButcherableComponent.cs b/Content.Shared/Nutrition/Components/ButcherableComponent.cs
similarity index 51%
rename from Content.Shared/Nutrition/Components/SharedButcherableComponent.cs
rename to Content.Shared/Nutrition/Components/ButcherableComponent.cs
index 9f7794b30a..ab8e40b4d4 100644
--- a/Content.Shared/Nutrition/Components/SharedButcherableComponent.cs
+++ b/Content.Shared/Nutrition/Components/ButcherableComponent.cs
@@ -1,38 +1,31 @@
-using Content.Shared.DragDrop;
using Content.Shared.Storage;
+using Robust.Shared.GameStates;
namespace Content.Shared.Nutrition.Components
{
///
/// Indicates that the entity can be thrown on a kitchen spike for butchering.
///
- [RegisterComponent]
- public sealed class SharedButcherableComponent : Component, IDraggable
+ [RegisterComponent, NetworkedComponent]
+ public sealed class ButcherableComponent : Component
{
[DataField("spawned", required: true)]
public List SpawnedEntities = new();
- [DataField("butcherDelay")]
+ [ViewVariables(VVAccess.ReadWrite), DataField("butcherDelay")]
public float ButcherDelay = 8.0f;
- [DataField("butcheringType")]
+ [ViewVariables(VVAccess.ReadWrite), DataField("butcheringType")]
public ButcheringType Type = ButcheringType.Knife;
///
/// Prevents butchering same entity on two and more spikes simultaneously and multiple doAfters on the same Spike
///
+ [ViewVariables]
public bool BeingButchered;
-
- // TODO: ECS this out!, my guess CanDropEvent should be client side only and then "ValidDragDrop" in the DragDropSystem needs a little touch
- // But this may lead to creating client-side systems for every Draggable component subbed to CanDrop. Actually those systems could control
- // CanDropOn behaviors as well (IDragDropOn)
- bool IDraggable.CanDrop(CanDropEvent args)
- {
- return Type != ButcheringType.Knife;
- }
}
- public enum ButcheringType
+ public enum ButcheringType : byte
{
Knife, // e.g. goliaths
Spike, // e.g. monkeys
diff --git a/Content.Shared/PAI/SharedPAISystem.cs b/Content.Shared/PAI/SharedPAISystem.cs
index 0e25d83824..a29c7bba01 100644
--- a/Content.Shared/PAI/SharedPAISystem.cs
+++ b/Content.Shared/PAI/SharedPAISystem.cs
@@ -1,6 +1,7 @@
using Content.Shared.ActionBlocker;
using Content.Shared.Actions;
using Content.Shared.DragDrop;
+using Content.Shared.Hands;
using Content.Shared.Interaction.Events;
using Content.Shared.Item;
using Content.Shared.Movement;
diff --git a/Content.Shared/Strip/Components/SharedStrippingComponent.cs b/Content.Shared/Strip/Components/SharedStrippingComponent.cs
deleted file mode 100644
index ef4c8b241f..0000000000
--- a/Content.Shared/Strip/Components/SharedStrippingComponent.cs
+++ /dev/null
@@ -1,29 +0,0 @@
-using Content.Shared.ActionBlocker;
-using Content.Shared.DragDrop;
-using Content.Shared.Hands.Components;
-
-namespace Content.Shared.Strip.Components
-{
- ///
- /// Give to an entity to say they can strip another entity.
- ///
- [RegisterComponent]
- public sealed class SharedStrippingComponent : Component, IDragDropOn
- {
- bool IDragDropOn.CanDragDropOn(DragDropEvent eventArgs)
- {
- var ent = IoCManager.Resolve();
- return eventArgs.Target != eventArgs.Dragged &&
- eventArgs.Target == eventArgs.User &&
- ent.HasComponent(eventArgs.Dragged) &&
- ent.HasComponent(eventArgs.User) &&
- ent.EntitySysManager.GetEntitySystem().CanInteract(eventArgs.User, eventArgs.Dragged);
- }
-
- bool IDragDropOn.DragDropOn(DragDropEvent eventArgs)
- {
- // Handled by StrippableComponent
- return true;
- }
- }
-}
diff --git a/Content.Shared/Strip/Components/SharedStrippableComponent.cs b/Content.Shared/Strip/Components/StrippableComponent.cs
similarity index 72%
rename from Content.Shared/Strip/Components/SharedStrippableComponent.cs
rename to Content.Shared/Strip/Components/StrippableComponent.cs
index ad8f83b5d6..597795473e 100644
--- a/Content.Shared/Strip/Components/SharedStrippableComponent.cs
+++ b/Content.Shared/Strip/Components/StrippableComponent.cs
@@ -1,24 +1,17 @@
-using Content.Shared.ActionBlocker;
-using Content.Shared.DragDrop;
-using Content.Shared.Hands.Components;
using Content.Shared.Inventory;
+using Robust.Shared.GameStates;
using Robust.Shared.Serialization;
namespace Content.Shared.Strip.Components
{
- public abstract class SharedStrippableComponent : Component, IDraggable
+ [RegisterComponent, NetworkedComponent]
+ public sealed class StrippableComponent : Component
{
- bool IDraggable.CanDrop(CanDropEvent args)
- {
- var ent = IoCManager.Resolve();
- return args.Target != args.Dragged &&
- args.Target == args.User &&
- ent.HasComponent(args.User) &&
- ent.HasComponent(args.User) &&
- ent.EntitySysManager.GetEntitySystem().CanInteract(args.User, args.Dragged);
- }
-
- public abstract bool Drop(DragDropEvent args);
+ ///
+ /// The strip delay for hands.
+ ///
+ [ViewVariables(VVAccess.ReadWrite), DataField("handDelay")]
+ public float HandStripDelay = 4f;
}
[NetSerializable, Serializable]
diff --git a/Content.Shared/Strip/Components/StrippingComponent.cs b/Content.Shared/Strip/Components/StrippingComponent.cs
new file mode 100644
index 0000000000..6893e28d94
--- /dev/null
+++ b/Content.Shared/Strip/Components/StrippingComponent.cs
@@ -0,0 +1,10 @@
+using Robust.Shared.GameStates;
+
+namespace Content.Shared.Strip.Components
+{
+ ///
+ /// Give to an entity to say they can strip another entity.
+ ///
+ [RegisterComponent, NetworkedComponent]
+ public sealed class StrippingComponent : Component {}
+}
diff --git a/Content.Shared/Strip/SharedStrippableSystem.cs b/Content.Shared/Strip/SharedStrippableSystem.cs
new file mode 100644
index 0000000000..ec707b51fc
--- /dev/null
+++ b/Content.Shared/Strip/SharedStrippableSystem.cs
@@ -0,0 +1,49 @@
+using Content.Shared.DragDrop;
+using Content.Shared.Hands.Components;
+using Content.Shared.Strip.Components;
+
+namespace Content.Shared.Strip;
+
+public abstract class SharedStrippableSystem : EntitySystem
+{
+ public override void Initialize()
+ {
+ base.Initialize();
+ SubscribeLocalEvent(OnCanDropOn);
+ SubscribeLocalEvent(OnCanDrop);
+ SubscribeLocalEvent(OnDragDrop);
+ }
+
+ private void OnDragDrop(EntityUid uid, StrippableComponent component, ref DragDropDraggedEvent args)
+ {
+ // If the user drags a strippable thing onto themselves.
+ if (args.Handled || args.Target != args.User)
+ return;
+
+ StartOpeningStripper(args.User, component);
+ args.Handled = true;
+ }
+
+ public virtual void StartOpeningStripper(EntityUid user, StrippableComponent component, bool openInCombat = false)
+ {
+
+ }
+
+ private void OnCanDropOn(EntityUid uid, StrippingComponent component, ref CanDropTargetEvent args)
+ {
+ args.Handled = true;
+ args.CanDrop |= uid == args.User &&
+ HasComp(args.Dragged) &&
+ HasComp(args.User);
+ }
+
+ private void OnCanDrop(EntityUid uid, StrippableComponent component, ref CanDropDraggedEvent args)
+ {
+ args.CanDrop |= args.Target == args.User &&
+ HasComp(args.User) &&
+ HasComp(args.User);
+
+ if (args.CanDrop)
+ args.Handled = true;
+ }
+}
diff --git a/Content.Shared/Stunnable/SharedStunSystem.cs b/Content.Shared/Stunnable/SharedStunSystem.cs
index 530b0252be..458d28dbf9 100644
--- a/Content.Shared/Stunnable/SharedStunSystem.cs
+++ b/Content.Shared/Stunnable/SharedStunSystem.cs
@@ -8,6 +8,7 @@ using Content.Shared.Inventory.Events;
using Content.Shared.Item;
using Content.Shared.Bed.Sleep;
using Content.Shared.Database;
+using Content.Shared.Hands;
using Content.Shared.Mobs;
using Content.Shared.Mobs.Components;
using Content.Shared.Mobs.Systems;