* 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>
245 lines
10 KiB
C#
245 lines
10 KiB
C#
using System;
|
|
using Content.Server.Atmos.Components;
|
|
using Content.Server.Atmos.Piping.Binary.Components;
|
|
using Content.Server.Atmos.Piping.Components;
|
|
using Content.Server.GameObjects.Components.NodeContainer.Nodes;
|
|
using Content.Server.Hands.Components;
|
|
using Content.Server.NodeContainer;
|
|
using Content.Server.UserInterface;
|
|
using Content.Shared.ActionBlocker;
|
|
using Content.Shared.Atmos;
|
|
using Content.Shared.Atmos.Piping.Binary.Components;
|
|
using Content.Shared.Interaction;
|
|
using Content.Shared.Interaction.Helpers;
|
|
using JetBrains.Annotations;
|
|
using Robust.Server.GameObjects;
|
|
using Robust.Shared.Containers;
|
|
using Robust.Shared.GameObjects;
|
|
using Robust.Shared.Maths;
|
|
|
|
namespace Content.Server.Atmos.Piping.Binary.EntitySystems
|
|
{
|
|
[UsedImplicitly]
|
|
public class GasCanisterSystem : EntitySystem
|
|
{
|
|
public override void Initialize()
|
|
{
|
|
base.Initialize();
|
|
|
|
SubscribeLocalEvent<GasCanisterComponent, ComponentStartup>(OnCanisterStartup);
|
|
SubscribeLocalEvent<GasCanisterComponent, AtmosDeviceUpdateEvent>(OnCanisterUpdated);
|
|
SubscribeLocalEvent<GasCanisterComponent, ActivateInWorldEvent>(OnCanisterActivate);
|
|
SubscribeLocalEvent<GasCanisterComponent, InteractHandEvent>(OnCanisterInteractHand);
|
|
SubscribeLocalEvent<GasCanisterComponent, InteractUsingEvent>(OnCanisterInteractUsing);
|
|
SubscribeLocalEvent<GasCanisterComponent, EntInsertedIntoContainerMessage>(OnCanisterContainerInserted);
|
|
SubscribeLocalEvent<GasCanisterComponent, EntRemovedFromContainerMessage>(OnCanisterContainerRemoved);
|
|
}
|
|
|
|
private void OnCanisterStartup(EntityUid uid, GasCanisterComponent canister, ComponentStartup args)
|
|
{
|
|
// TODO ATMOS: Don't use Owner to get the UI.
|
|
if(canister.Owner.GetUIOrNull(GasCanisterUiKey.Key) is {} ui)
|
|
ui.OnReceiveMessage += msg => OnCanisterUIMessage(uid, canister, msg);
|
|
|
|
if (!ComponentManager.TryGetComponent(uid, out NodeContainerComponent? nodeContainer))
|
|
return;
|
|
|
|
if (!nodeContainer.TryGetNode(canister.PortName, out PipeNode? portNode))
|
|
return;
|
|
|
|
// Create a pipenet if we don't have one already.
|
|
portNode.TryAssignGroupIfNeeded();
|
|
portNode.Air.Merge(canister.InitialMixture);
|
|
portNode.Air.Temperature = canister.InitialMixture.Temperature;
|
|
portNode.Volume = canister.InitialMixture.Volume;
|
|
}
|
|
|
|
private void DirtyUI(EntityUid uid)
|
|
{
|
|
if (!ComponentManager.TryGetComponent(uid, out IMetaDataComponent? metadata)
|
|
|| !ComponentManager.TryGetComponent(uid, out GasCanisterComponent? canister)
|
|
|| !ComponentManager.TryGetComponent(uid, out GasPassiveGateComponent? passiveGate)
|
|
|| !ComponentManager.TryGetComponent(uid, out NodeContainerComponent? nodeContainer)
|
|
|| !nodeContainer.TryGetNode(canister.PortName, out PipeNode? portNode)
|
|
|| !nodeContainer.TryGetNode(canister.TankName, out PipeNode? tankNode)
|
|
|| !ComponentManager.TryGetComponent(uid, out ServerUserInterfaceComponent? userInterfaceComponent)
|
|
|| !userInterfaceComponent.TryGetBoundUserInterface(GasCanisterUiKey.Key, out var ui))
|
|
return;
|
|
|
|
string? tankLabel = null;
|
|
var tankPressure = 0f;
|
|
|
|
if (ComponentManager.TryGetComponent(uid, out ContainerManagerComponent? containerManager) && containerManager.TryGetContainer(canister.ContainerName, out var tankContainer) && tankContainer.ContainedEntities.Count > 0)
|
|
{
|
|
var tank = tankContainer.ContainedEntities[0];
|
|
tankLabel = tank.Name;
|
|
tankPressure = tankNode.Air.Pressure;
|
|
}
|
|
|
|
ui.SetState(new GasCanisterBoundUserInterfaceState(metadata.EntityName, portNode.Air.Pressure,
|
|
portNode.NodeGroup.Nodes.Count > 1, tankLabel, tankPressure,
|
|
passiveGate.TargetPressure, passiveGate.Enabled,
|
|
canister.MinReleasePressure, canister.MaxReleasePressure));
|
|
}
|
|
|
|
private void OnCanisterUIMessage(EntityUid uid, GasCanisterComponent canister, ServerBoundUserInterfaceMessage msg)
|
|
{
|
|
if (msg.Session.AttachedEntity is not {} entity
|
|
|| !Get<ActionBlockerSystem>().CanInteract(entity)
|
|
|| !Get<ActionBlockerSystem>().CanUse(entity))
|
|
return;
|
|
|
|
|
|
if (!ComponentManager.TryGetComponent(uid, out GasPassiveGateComponent? passiveGate)
|
|
|| !ComponentManager.TryGetComponent(uid, out ContainerManagerComponent? containerManager)
|
|
|| !containerManager.TryGetContainer(canister.ContainerName, out var container))
|
|
return;
|
|
|
|
switch (msg.Message)
|
|
{
|
|
case GasCanisterHoldingTankEjectMessage:
|
|
if (container.ContainedEntities.Count == 0)
|
|
break;
|
|
|
|
container.Remove(container.ContainedEntities[0]);
|
|
break;
|
|
|
|
case GasCanisterChangeReleasePressureMessage changeReleasePressure:
|
|
var pressure = Math.Clamp(changeReleasePressure.Pressure, canister.MinReleasePressure, canister.MaxReleasePressure);
|
|
|
|
passiveGate.TargetPressure = pressure;
|
|
DirtyUI(uid);
|
|
break;
|
|
|
|
case GasCanisterChangeReleaseValveMessage changeReleaseValve:
|
|
passiveGate.Enabled = changeReleaseValve.Valve;
|
|
DirtyUI(uid);
|
|
break;
|
|
}
|
|
}
|
|
|
|
private void OnCanisterUpdated(EntityUid uid, GasCanisterComponent canister, AtmosDeviceUpdateEvent args)
|
|
{
|
|
if (!ComponentManager.TryGetComponent(uid, out NodeContainerComponent? nodeContainer)
|
|
|| !ComponentManager.TryGetComponent(uid, out AppearanceComponent? appearance))
|
|
return;
|
|
|
|
if (!nodeContainer.TryGetNode(canister.PortName, out PipeNode? portNode))
|
|
return;
|
|
|
|
DirtyUI(uid);
|
|
|
|
// Nothing to do here.
|
|
if (MathHelper.CloseTo(portNode.Air.Pressure, canister.LastPressure))
|
|
return;
|
|
|
|
canister.LastPressure = portNode.Air.Pressure;
|
|
|
|
if (portNode.Air.Pressure < 10)
|
|
{
|
|
appearance.SetData(GasCanisterVisuals.PressureState, 0);
|
|
}
|
|
else if (portNode.Air.Pressure < Atmospherics.OneAtmosphere)
|
|
{
|
|
appearance.SetData(GasCanisterVisuals.PressureState, 1);
|
|
}
|
|
else if (portNode.Air.Pressure < (15 * Atmospherics.OneAtmosphere))
|
|
{
|
|
appearance.SetData(GasCanisterVisuals.PressureState, 2);
|
|
}
|
|
else
|
|
{
|
|
appearance.SetData(GasCanisterVisuals.PressureState, 3);
|
|
}
|
|
}
|
|
|
|
private void OnCanisterActivate(EntityUid uid, GasCanisterComponent component, ActivateInWorldEvent args)
|
|
{
|
|
if (!args.User.TryGetComponent(out ActorComponent? actor))
|
|
return;
|
|
|
|
component.Owner.GetUIOrNull(GasCanisterUiKey.Key)?.Open(actor.PlayerSession);
|
|
args.Handled = true;
|
|
}
|
|
|
|
|
|
private void OnCanisterInteractHand(EntityUid uid, GasCanisterComponent component, InteractHandEvent args)
|
|
{
|
|
if (!args.User.TryGetComponent(out ActorComponent? actor))
|
|
return;
|
|
|
|
component.Owner.GetUIOrNull(GasCanisterUiKey.Key)?.Open(actor.PlayerSession);
|
|
args.Handled = true;
|
|
}
|
|
|
|
private void OnCanisterInteractUsing(EntityUid uid, GasCanisterComponent component, InteractUsingEvent args)
|
|
{
|
|
var canister = EntityManager.GetEntity(uid);
|
|
var container = canister.EnsureContainer<ContainerSlot>(component.ContainerName);
|
|
|
|
// Container full.
|
|
if (container.ContainedEntity != null)
|
|
return;
|
|
|
|
// Check the used item is valid...
|
|
if (!args.Used.TryGetComponent(out GasTankComponent? _)
|
|
|| !args.Used.TryGetComponent(out NodeContainerComponent? _))
|
|
return;
|
|
|
|
// Check the user has hands.
|
|
if (!args.User.TryGetComponent(out HandsComponent? hands))
|
|
return;
|
|
|
|
if (!args.User.InRangeUnobstructed(canister, SharedInteractionSystem.InteractionRange, popup: true))
|
|
return;
|
|
|
|
if (!hands.TryPutEntityIntoContainer(args.Used, container))
|
|
return;
|
|
|
|
args.Handled = true;
|
|
}
|
|
|
|
private void OnCanisterContainerInserted(EntityUid uid, GasCanisterComponent component, EntInsertedIntoContainerMessage args)
|
|
{
|
|
if (args.Container.ID != component.ContainerName)
|
|
return;
|
|
|
|
DirtyUI(uid);
|
|
|
|
if (!ComponentManager.TryGetComponent(uid, out NodeContainerComponent? nodeContainer)
|
|
|| !nodeContainer.TryGetNode(component.TankName, out PipeNode? tankNode))
|
|
return;
|
|
|
|
tankNode.EnvironmentalAir = false;
|
|
tankNode.ConnectToContainedEntities = true;
|
|
tankNode.NodeGroup.RemakeGroup();
|
|
|
|
if (!ComponentManager.TryGetComponent(uid, out AppearanceComponent? appearance))
|
|
return;
|
|
|
|
appearance.SetData(GasCanisterVisuals.TankInserted, true);
|
|
}
|
|
|
|
private void OnCanisterContainerRemoved(EntityUid uid, GasCanisterComponent component, EntRemovedFromContainerMessage args)
|
|
{
|
|
if (args.Container.ID != component.ContainerName)
|
|
return;
|
|
|
|
DirtyUI(uid);
|
|
|
|
if (!ComponentManager.TryGetComponent(uid, out NodeContainerComponent? nodeContainer)
|
|
|| !nodeContainer.TryGetNode(component.TankName, out PipeNode? tankNode))
|
|
return;
|
|
|
|
tankNode.NodeGroup.RemakeGroup();
|
|
tankNode.ConnectToContainedEntities = false;
|
|
tankNode.EnvironmentalAir = true;
|
|
|
|
if (!ComponentManager.TryGetComponent(uid, out AppearanceComponent? appearance))
|
|
return;
|
|
|
|
appearance.SetData(GasCanisterVisuals.TankInserted, false);
|
|
}
|
|
}
|
|
}
|