Files
tbd-station-14/Content.Server/Access/Components/IdCardConsoleComponent.cs
collinlunn f2816e8081 Moves Hands to shared, some prediction (#3829)
* HandsGuiState

* Gui state setting methods

* code cleanup

* Removes TryGetHands

* ClientHand

* Gui Hands

* Refactor WIP 1

* Hand index

* refactors 2

* wip 3

* wip 4

* wiip 4

* wip 5

* wip 6

* wip 7

* wip 8

* wip 9

* wip 11

* Hand ui mostly looks fine

* hands gui cleanup 1

* cleanup 2

* wip 13

* hand enabled

* stuff

* Hands gui gap fix

* onpressed test

* hand gui buttons events work

* bag activation works

* fix item use

* todo comment

* hands activate fix

* Moves Client Hands back to using strings to identify active hand

* fixes action hand highlighting

* diff fix

* serverhand

* SharedHand

* SharedHand, IReadOnlyHand

* Client Hands only stores SharedHand

* cleanup server hands

* server hand container shutdown

* misc renames, refactors of serverhand

* stuff 1

* stuff 3

* server hand refactor 1

* Undo API changes to remove massive diff

* More API name fixes

* server hands cleanup 2

* cleanup 3

* dropping cleanup

* Cleanup 4

* MoveItemFromHand

* Stuff

* region sorting

* Hand Putter methods cleanup

* stuff 2

* Merges all of serverhand and clienthand into sharedhand

* Other hands systems, hack to make inhands update (gui state set every frame, visualzier updated every frame)

* GetFinalDropCoordinates cleanup

* SwapHands cleanup

* Moves server hands code to shared hands

* Fixed hand selected and deselected

* Naming fixes

* Server hands system cleanup

* Hands privacy fixes

* Client hand updates when containers are modified

* HeldItemVisualizer

* Fixes hand gui item status panel

* method name fix

* Swap hands prediction

* Dropping prediction

* Fixes pickup entity animation

* Fixes HeldItemsVisualizer

* moves item pickup to shared

* PR cleanup

* fixes hand enabling/disabling

* build fix

* Conflict fixes

* Fixes pickup animation

* Uses component directed message subscriptions

* event unsubscriptions in hand system

* unsubscribe fix

* CanInsertEntityIntoHand checks if hand is enabled

* Moving items from one hand to another checks if the hands can pick up and drop

* Fixes stop pulling not re-enabling hand

* Fixes pickup animation for entities containers on the floor

* Fixes using held items

* Fixes multiple hands guis appearing

* test fix

* removes obsolete system sunsubscribes

* Checks IsFirstTimePredicted before playing drop animation

* fixes hand item deleted crash

* Uses Get to get other system

* Replaces AppearanceComponent with SharedAppearanceComponent

* Replaces EnsureComponent with TryGetComponent

* Improves event class names

* Moves property up to top of class

* Moves code for determining the hand visualizer rsi state into the visualizer instead of being determined on hand component

* Eventbus todo comment

* Yaml fix for changed visualizer name

* Makes HandsVisuals a byte

* Removes state from HandsVisualizer

* Fixes hand using interaction method name

* Namespace changes fixes

* Fix for changed hand interaction method

* missing }

* conflict build fix

* Moves cleint HandsSystem to correct folder

* Moved namespace fix for interaction test

* Moves Handsvisualizer ot correct folder

* Moves SharedHandsSystem to correct folder

* Fixes errors from moving namespace of hand systems

* Fixes PDA component changes

* Fixes ActionsComponent diff

* Fixes inventory component diff

* fixes null ref

* Replaces obsolete Loc.GetString usage with fluent translations

* Fluent for hands disarming

* SwapHands and Drop user input specify to the server which hand

* Pickup animation WorldPosiiton todo

* Cleans up hands gui subscription handling

* Fixes change in ActionBlockerSystem access

* Namespace references fixes

* HandsComponent PlayerAttached/Detached messages are handled through eventbus

* Fixes GasCanisterSystem drop method usage

* Fix gameticker equipping method at new location

Co-authored-by: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com>
2021-06-21 19:21:20 +10:00

320 lines
12 KiB
C#

#nullable enable
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Content.Server.Hands.Components;
using Content.Server.Items;
using Content.Server.Power.Components;
using Content.Server.UserInterface;
using Content.Shared.Access;
using Content.Shared.ActionBlocker;
using Content.Shared.Acts;
using Content.Shared.Interaction;
using Content.Shared.Interaction.Events;
using Content.Shared.Notification.Managers;
using Content.Shared.Verbs;
using Robust.Server.GameObjects;
using Robust.Shared.Containers;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Localization;
using Robust.Shared.Log;
using Robust.Shared.Prototypes;
using Robust.Shared.ViewVariables;
namespace Content.Server.Access.Components
{
[RegisterComponent]
[ComponentReference(typeof(IActivate))]
public class IdCardConsoleComponent : SharedIdCardConsoleComponent, IActivate, IInteractUsing, IBreakAct
{
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
private ContainerSlot _privilegedIdContainer = default!;
private ContainerSlot _targetIdContainer = default!;
[ViewVariables] private BoundUserInterface? UserInterface => Owner.GetUIOrNull(IdCardConsoleUiKey.Key);
[ViewVariables] private bool Powered => !Owner.TryGetComponent(out PowerReceiverComponent? receiver) || receiver.Powered;
private bool PrivilegedIDEmpty => _privilegedIdContainer.ContainedEntities.Count < 1;
private bool TargetIDEmpty => _targetIdContainer.ContainedEntities.Count < 1;
protected override void Initialize()
{
base.Initialize();
_privilegedIdContainer = ContainerHelpers.EnsureContainer<ContainerSlot>(Owner, $"{Name}-privilegedId");
_targetIdContainer = ContainerHelpers.EnsureContainer<ContainerSlot>(Owner, $"{Name}-targetId");
Owner.EnsureComponentWarn<AccessReader>();
Owner.EnsureComponentWarn<ServerUserInterfaceComponent>();
if (UserInterface != null)
{
UserInterface.OnReceiveMessage += OnUiReceiveMessage;
}
UpdateUserInterface();
}
private void OnUiReceiveMessage(ServerBoundUserInterfaceMessage obj)
{
if (obj.Session.AttachedEntity == null)
{
return;
}
switch (obj.Message)
{
case IdButtonPressedMessage msg:
switch (msg.Button)
{
case UiButton.PrivilegedId:
HandleId(obj.Session.AttachedEntity, _privilegedIdContainer);
break;
case UiButton.TargetId:
HandleId(obj.Session.AttachedEntity, _targetIdContainer);
break;
}
break;
case WriteToTargetIdMessage msg:
TryWriteToTargetId(msg.FullName, msg.JobTitle, msg.AccessList);
break;
}
UpdateUserInterface();
}
/// <summary>
/// Returns true if there is an ID in <see cref="_privilegedIdContainer"/> and said ID satisfies the requirements of <see cref="AccessReader"/>.
/// </summary>
private bool PrivilegedIdIsAuthorized()
{
if (!Owner.TryGetComponent(out AccessReader? reader))
{
return true;
}
var privilegedIdEntity = _privilegedIdContainer.ContainedEntity;
return privilegedIdEntity != null && reader.IsAllowed(privilegedIdEntity);
}
/// <summary>
/// Called when the "Submit" button in the UI gets pressed.
/// Writes data passed from the UI into the ID stored in <see cref="_targetIdContainer"/>, if present.
/// </summary>
private void TryWriteToTargetId(string newFullName, string newJobTitle, List<string> newAccessList)
{
if (!PrivilegedIdIsAuthorized() || _targetIdContainer.ContainedEntity == null)
{
return;
}
var targetIdEntity = _targetIdContainer.ContainedEntity;
var targetIdComponent = targetIdEntity.GetComponent<IdCardComponent>();
targetIdComponent.FullName = newFullName;
targetIdComponent.JobTitle = newJobTitle;
if (!newAccessList.TrueForAll(x => _prototypeManager.HasIndex<AccessLevelPrototype>(x)))
{
Logger.Warning("Tried to write unknown access tag.");
return;
}
var targetIdAccess = targetIdEntity.GetComponent<AccessComponent>();
targetIdAccess.SetTags(newAccessList);
}
/// <summary>
/// Called when one of the insert/remove ID buttons gets pressed.
/// </summary>
private void HandleId(IEntity user, ContainerSlot container)
{
if (!user.TryGetComponent(out IHandsComponent? hands))
{
Owner.PopupMessage(user, Loc.GetString("access-id-card-console-component-no-hands-error"));
return;
}
if (container.ContainedEntity == null)
{
InsertIdFromHand(user, container, hands);
}
else
{
PutIdInHand(container, hands);
}
}
private void InsertIdFromHand(IEntity user, ContainerSlot container, IHandsComponent hands)
{
var isId = hands.GetActiveHand?.Owner.HasComponent<IdCardComponent>();
if (isId != true)
{
return;
}
if (hands.ActiveHand == null)
{
return;
}
if (!hands.TryPutHandIntoContainer(hands.ActiveHand, container))
{
Owner.PopupMessage(user, Loc.GetString("access-id-card-console-component-cannot-let-go-error"));
return;
}
UpdateUserInterface();
}
private void PutIdInHand(ContainerSlot container, IHandsComponent hands)
{
var idEntity = container.ContainedEntity;
if (idEntity == null || !container.Remove(idEntity))
{
return;
}
UpdateUserInterface();
hands.PutInHand(idEntity.GetComponent<ItemComponent>());
}
private void UpdateUserInterface()
{
var isPrivilegedIdPresent = _privilegedIdContainer.ContainedEntity != null;
var targetIdEntity = _targetIdContainer.ContainedEntity;
IdCardConsoleBoundUserInterfaceState newState;
// this could be prettier
if (targetIdEntity == null)
{
newState = new IdCardConsoleBoundUserInterfaceState(
isPrivilegedIdPresent,
PrivilegedIdIsAuthorized(),
false,
null,
null,
null,
_privilegedIdContainer.ContainedEntity?.Name ?? string.Empty,
_targetIdContainer.ContainedEntity?.Name ?? string.Empty);
}
else
{
var targetIdComponent = targetIdEntity.GetComponent<IdCardComponent>();
var targetAccessComponent = targetIdEntity.GetComponent<AccessComponent>();
newState = new IdCardConsoleBoundUserInterfaceState(
isPrivilegedIdPresent,
PrivilegedIdIsAuthorized(),
true,
targetIdComponent.FullName,
targetIdComponent.JobTitle,
targetAccessComponent.Tags.ToArray(),
_privilegedIdContainer.ContainedEntity?.Name ?? string.Empty,
_targetIdContainer.ContainedEntity?.Name ?? string.Empty);
}
UserInterface?.SetState(newState);
}
void IActivate.Activate(ActivateEventArgs eventArgs)
{
if (!eventArgs.User.TryGetComponent(out ActorComponent? actor))
{
return;
}
if (!Powered) return;
UserInterface?.Open(actor.PlayerSession);
}
async Task<bool> IInteractUsing.InteractUsing(InteractUsingEventArgs eventArgs)
{
var item = eventArgs.Using;
var user = eventArgs.User;
if (!PrivilegedIDEmpty && !TargetIDEmpty)
{
return false;
}
if (!item.HasComponent<IdCardComponent>() || !user.TryGetComponent(out IHandsComponent? hand))
{
return false;
}
if (PrivilegedIDEmpty)
{
InsertIdFromHand(user, _privilegedIdContainer, hand);
}
else if (TargetIDEmpty)
{
InsertIdFromHand(user, _targetIdContainer, hand);
}
UpdateUserInterface();
return true;
}
[Verb]
public sealed class EjectPrivilegedIDVerb : Verb<IdCardConsoleComponent>
{
protected override void GetData(IEntity user, IdCardConsoleComponent component, VerbData data)
{
if (!EntitySystem.Get<ActionBlockerSystem>().CanInteract(user))
{
data.Visibility = VerbVisibility.Invisible;
return;
}
data.Text = Loc.GetString("access-eject-privileged-id-verb-get-data-text");
data.IconTexture = "/Textures/Interface/VerbIcons/eject.svg.192dpi.png";
data.Visibility = component.PrivilegedIDEmpty ? VerbVisibility.Invisible : VerbVisibility.Visible;
}
protected override void Activate(IEntity user, IdCardConsoleComponent component)
{
if (!user.TryGetComponent(out IHandsComponent? hand))
{
return;
}
component.PutIdInHand(component._privilegedIdContainer, hand);
}
}
public sealed class EjectTargetIDVerb : Verb<IdCardConsoleComponent>
{
protected override void GetData(IEntity user, IdCardConsoleComponent component, VerbData data)
{
if (!EntitySystem.Get<ActionBlockerSystem>().CanInteract(user))
{
data.Visibility = VerbVisibility.Invisible;
return;
}
data.Text = Loc.GetString("access-eject-target-id-verb-get-data-text");
data.Visibility = component.TargetIDEmpty ? VerbVisibility.Invisible : VerbVisibility.Visible;
data.IconTexture = "/Textures/Interface/VerbIcons/eject.svg.192dpi.png";
}
protected override void Activate(IEntity user, IdCardConsoleComponent component)
{
if (!user.TryGetComponent(out IHandsComponent? hand))
{
return;
}
component.PutIdInHand(component._targetIdContainer, hand);
}
}
public void OnBreak(BreakageEventArgs eventArgs)
{
var privileged = _privilegedIdContainer.ContainedEntity;
if (privileged != null)
_privilegedIdContainer.Remove(privileged);
var target = _targetIdContainer.ContainedEntity;
if (target != null)
_targetIdContainer.Remove(target);
}
}
}