Files
tbd-station-14/Content.Server/Interaction/InteractionSystem.cs
TNE 52ef8f9b70 Allow drag-and-drop insertion of reagents into the ChemMaster (#19796)
* Add DumpableSolutionComponent

Separates out the component from "DrainComponent" that allows one to drag a bucket/any reagent container onto a drain/sink/toilet to empty it and allows other reagent containers to reuse the code effortlessly.

* Give the ChemMaster 4000 the DumpableSolution Component

Allows drag and dropping solutions into the ChemMaster much like you used to be able to do exclusively with drains. This also allows dumping jugs into them.
2023-09-04 15:53:13 +03:00

114 lines
3.8 KiB
C#

using Content.Server.Administration.Logs;
using Content.Server.Pulling;
using Content.Server.Storage.Components;
using Content.Shared.ActionBlocker;
using Content.Shared.DragDrop;
using Content.Shared.Input;
using Content.Shared.Interaction;
using Content.Shared.Pulling.Components;
using Content.Shared.Storage;
using JetBrains.Annotations;
using Robust.Server.GameObjects;
using Robust.Shared.Containers;
using Robust.Shared.Input.Binding;
using Robust.Shared.Map;
using Robust.Shared.Players;
using Robust.Shared.Random;
namespace Content.Server.Interaction
{
/// <summary>
/// Governs interactions during clicking on entities
/// </summary>
[UsedImplicitly]
public sealed partial class InteractionSystem : SharedInteractionSystem
{
[Dependency] private readonly ActionBlockerSystem _actionBlockerSystem = default!;
[Dependency] private readonly SharedContainerSystem _container = default!;
[Dependency] private readonly UserInterfaceSystem _uiSystem = default!;
public override void Initialize()
{
base.Initialize();
SubscribeNetworkEvent<DragDropRequestEvent>(HandleDragDropRequestEvent);
SubscribeLocalEvent<BoundUserInterfaceCheckRangeEvent>(HandleUserInterfaceRangeCheck);
}
public override bool CanAccessViaStorage(EntityUid user, EntityUid target)
{
if (Deleted(target))
return false;
if (!_container.TryGetContainingContainer(target, out var container))
return false;
if (!TryComp(container.Owner, out ServerStorageComponent? storage))
return false;
if (storage.Storage?.ID != container.ID)
return false;
if (!TryComp(user, out ActorComponent? actor))
return false;
// we don't check if the user can access the storage entity itself. This should be handed by the UI system.
return _uiSystem.SessionHasOpenUi(container.Owner, SharedStorageComponent.StorageUiKey.Key, actor.PlayerSession);
}
#region Drag drop
private void HandleDragDropRequestEvent(DragDropRequestEvent msg, EntitySessionEventArgs args)
{
if (Deleted(msg.Dragged) || Deleted(msg.Target))
return;
var user = args.SenderSession.AttachedEntity;
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(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.Dragged, ref dragArgs);
if (dragArgs.Handled)
return;
var dropArgs = new DragDropTargetEvent(user.Value, msg.Dragged);
// trigger dragdrops on the target entity (what you are dropping onto)
RaiseLocalEvent(msg.Target, ref dropArgs);
}
#endregion
private void HandleUserInterfaceRangeCheck(ref BoundUserInterfaceCheckRangeEvent ev)
{
if (ev.Player.AttachedEntity is not { } user)
return;
if (InRangeUnobstructed(user, ev.Target, ev.UserInterface.InteractionRange))
{
ev.Result = BoundUserInterfaceRangeResult.Pass;
}
else
{
ev.Result = BoundUserInterfaceRangeResult.Fail;
}
}
}
}