Atmos pipe rework (#3833)
* Initial * Cleanup a bunch of things * some changes dunno * RequireAnchored * a * stuff * more work * Lots of progress * delete pipe visualizer * a * b * pipenet and pipenode cleanup * Fixes * Adds GasValve * Adds GasMiner * Fix stuff, maybe? * More fixes * Ignored components on the client * Adds thermomachine behavior, change a bunch of stuff * Remove Anchored * some work, but it's shitcode * significantly more ECS * ECS AtmosDevices * Cleanup * fix appearance * when the pipe direction is sus * Gas tanks and canisters * pipe anchoring and stuff * coding is my passion * Unsafe pipes take longer to unanchor * turns out we're no longer using eris canisters * Gas canister inserted tank appearance, improvements * Work on a bunch of appearances * Scrubber appearance * Reorganize AtmosphereSystem.Piping into a bunch of different systems * Appearance for vent/scrubber/pump turns off when leaving atmosphere * ThermoMachine appearance * Cleanup gas tanks * Remove passive gate unused imports * remove old canister UI functionality * PipeNode environment air, make everything use AssumeAir instead of merging manually * a * Reorganize atmos to follow new structure * ????? * Canister UI, restructure client * Restructure shared * Fix build tho * listen, at least the canister UI works entirely... * fix build : ) * Atmos device prototypes have names and descriptions * gas canister ui slider doesn't jitter * trinary prototypes * sprite for miners * ignore components * fix YAML * Fix port system doing useless thing * Fix build * fix thinking moment * fix build again because * canister direction * pipenode is a word * GasTank Air will throw on invalid states * fix build.... * Unhardcode volume pump thresholds * Volume pump and filter take time into account * Rename Join/Leave atmosphere events to AtmosDeviceEnabled/Disabled Event * Gas tank node volume is set by initial mixtuer * I love node container
This commit is contained in:
committed by
GitHub
parent
cfc3f2e7fc
commit
a2b737d945
287
Content.Server/Atmos/Components/GasAnalyzerComponent.cs
Normal file
287
Content.Server/Atmos/Components/GasAnalyzerComponent.cs
Normal file
@@ -0,0 +1,287 @@
|
||||
#nullable enable
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Content.Server.Atmos.EntitySystems;
|
||||
using Content.Server.Hands.Components;
|
||||
using Content.Server.UserInterface;
|
||||
using Content.Shared.Atmos;
|
||||
using Content.Shared.Atmos.Components;
|
||||
using Content.Shared.DragDrop;
|
||||
using Content.Shared.Interaction;
|
||||
using Content.Shared.Notification.Managers;
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Server.Player;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Localization;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Players;
|
||||
using Robust.Shared.ViewVariables;
|
||||
|
||||
namespace Content.Server.Atmos.Components
|
||||
{
|
||||
[RegisterComponent]
|
||||
public class GasAnalyzerComponent : SharedGasAnalyzerComponent, IAfterInteract, IDropped, IUse
|
||||
{
|
||||
private GasAnalyzerDanger _pressureDanger;
|
||||
private float _timeSinceSync;
|
||||
private const float TimeBetweenSyncs = 2f;
|
||||
private bool _checkPlayer = false; // Check at the player pos or at some other tile?
|
||||
private EntityCoordinates? _position; // The tile that we scanned
|
||||
private AppearanceComponent? _appearance;
|
||||
|
||||
[ViewVariables] private BoundUserInterface? UserInterface => Owner.GetUIOrNull(GasAnalyzerUiKey.Key);
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
if (UserInterface != null)
|
||||
{
|
||||
UserInterface.OnReceiveMessage += UserInterfaceOnReceiveMessage;
|
||||
UserInterface.OnClosed += UserInterfaceOnClose;
|
||||
}
|
||||
|
||||
Owner.TryGetComponent(out _appearance);
|
||||
}
|
||||
|
||||
public override ComponentState GetComponentState(ICommonSession player)
|
||||
{
|
||||
return new GasAnalyzerComponentState(_pressureDanger);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Call this from other components to open the gas analyzer UI.
|
||||
/// Uses the player position.
|
||||
/// </summary>
|
||||
/// <param name="session">The session to open the ui for</param>
|
||||
public void OpenInterface(IPlayerSession session)
|
||||
{
|
||||
_checkPlayer = true;
|
||||
_position = null;
|
||||
UserInterface?.Open(session);
|
||||
UpdateUserInterface();
|
||||
UpdateAppearance(true);
|
||||
Resync();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Call this from other components to open the gas analyzer UI.
|
||||
/// Uses a given position.
|
||||
/// </summary>
|
||||
/// <param name="session">The session to open the ui for</param>
|
||||
/// <param name="pos">The position to analyze the gas</param>
|
||||
public void OpenInterface(IPlayerSession session, EntityCoordinates pos)
|
||||
{
|
||||
_checkPlayer = false;
|
||||
_position = pos;
|
||||
UserInterface?.Open(session);
|
||||
UpdateUserInterface();
|
||||
UpdateAppearance(true);
|
||||
Resync();
|
||||
}
|
||||
|
||||
public void ToggleInterface(IPlayerSession session)
|
||||
{
|
||||
if (UserInterface == null)
|
||||
return;
|
||||
|
||||
if (UserInterface.SessionHasOpen(session))
|
||||
CloseInterface(session);
|
||||
else
|
||||
OpenInterface(session);
|
||||
}
|
||||
|
||||
public void CloseInterface(IPlayerSession session)
|
||||
{
|
||||
_position = null;
|
||||
UserInterface?.Close(session);
|
||||
// Our OnClose will do the appearance stuff
|
||||
Resync();
|
||||
}
|
||||
|
||||
private void UserInterfaceOnClose(IPlayerSession obj)
|
||||
{
|
||||
UpdateAppearance(false);
|
||||
}
|
||||
|
||||
private void UpdateAppearance(bool open)
|
||||
{
|
||||
_appearance?.SetData(GasAnalyzerVisuals.VisualState,
|
||||
open ? GasAnalyzerVisualState.Working : GasAnalyzerVisualState.Off);
|
||||
}
|
||||
|
||||
public void Update(float frameTime)
|
||||
{
|
||||
_timeSinceSync += frameTime;
|
||||
if (_timeSinceSync > TimeBetweenSyncs)
|
||||
{
|
||||
Resync();
|
||||
UpdateUserInterface();
|
||||
}
|
||||
}
|
||||
|
||||
private void Resync()
|
||||
{
|
||||
// Already get the pressure before Dirty(), because we can't get the EntitySystem in that thread or smth
|
||||
var pressure = 0f;
|
||||
var gam = EntitySystem.Get<AtmosphereSystem>().GetGridAtmosphere(Owner.Transform.Coordinates);
|
||||
var tile = gam?.GetTile(Owner.Transform.Coordinates)?.Air;
|
||||
if (tile != null)
|
||||
{
|
||||
pressure = tile.Pressure;
|
||||
}
|
||||
|
||||
if (pressure >= Atmospherics.HazardHighPressure || pressure <= Atmospherics.HazardLowPressure)
|
||||
{
|
||||
_pressureDanger = GasAnalyzerDanger.Hazard;
|
||||
}
|
||||
else if (pressure >= Atmospherics.WarningHighPressure || pressure <= Atmospherics.WarningLowPressure)
|
||||
{
|
||||
_pressureDanger = GasAnalyzerDanger.Warning;
|
||||
}
|
||||
else
|
||||
{
|
||||
_pressureDanger = GasAnalyzerDanger.Nominal;
|
||||
}
|
||||
|
||||
Dirty();
|
||||
_timeSinceSync = 0f;
|
||||
}
|
||||
|
||||
private void UpdateUserInterface()
|
||||
{
|
||||
if (UserInterface == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
string? error = null;
|
||||
|
||||
// Check if the player is still holding the gas analyzer => if not, don't update
|
||||
foreach (var session in UserInterface.SubscribedSessions)
|
||||
{
|
||||
if (session.AttachedEntity == null)
|
||||
return;
|
||||
|
||||
if (!session.AttachedEntity.TryGetComponent(out IHandsComponent? handsComponent))
|
||||
return;
|
||||
|
||||
var activeHandEntity = handsComponent?.GetActiveHand?.Owner;
|
||||
if (activeHandEntity == null || !activeHandEntity.TryGetComponent(out GasAnalyzerComponent? gasAnalyzer))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
var pos = Owner.Transform.Coordinates;
|
||||
if (!_checkPlayer && _position.HasValue)
|
||||
{
|
||||
// Check if position is out of range => don't update
|
||||
if (!_position.Value.InRange(Owner.EntityManager, pos, SharedInteractionSystem.InteractionRange))
|
||||
return;
|
||||
|
||||
pos = _position.Value;
|
||||
}
|
||||
|
||||
var atmosSystem = EntitySystem.Get<AtmosphereSystem>();
|
||||
var gam = atmosSystem.GetGridAtmosphere(pos);
|
||||
var tile = gam.GetTile(pos)?.Air;
|
||||
if (tile == null)
|
||||
{
|
||||
error = "No Atmosphere!";
|
||||
UserInterface.SetState(
|
||||
new GasAnalyzerBoundUserInterfaceState(
|
||||
0,
|
||||
0,
|
||||
null,
|
||||
error));
|
||||
return;
|
||||
}
|
||||
|
||||
var gases = new List<GasEntry>();
|
||||
|
||||
for (var i = 0; i < Atmospherics.TotalNumberOfGases; i++)
|
||||
{
|
||||
var gas = atmosSystem.GetGas(i);
|
||||
|
||||
if (tile.Gases[i] <= Atmospherics.GasMinMoles) continue;
|
||||
|
||||
gases.Add(new GasEntry(gas.Name, tile.Gases[i], gas.Color));
|
||||
}
|
||||
|
||||
UserInterface.SetState(
|
||||
new GasAnalyzerBoundUserInterfaceState(
|
||||
tile.Pressure,
|
||||
tile.Temperature,
|
||||
gases.ToArray(),
|
||||
error));
|
||||
}
|
||||
|
||||
private void UserInterfaceOnReceiveMessage(ServerBoundUserInterfaceMessage serverMsg)
|
||||
{
|
||||
var message = serverMsg.Message;
|
||||
switch (message)
|
||||
{
|
||||
case GasAnalyzerRefreshMessage msg:
|
||||
var player = serverMsg.Session.AttachedEntity;
|
||||
if (player == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!player.TryGetComponent(out IHandsComponent? handsComponent))
|
||||
{
|
||||
Owner.PopupMessage(player, Loc.GetString("You have no hands."));
|
||||
return;
|
||||
}
|
||||
|
||||
var activeHandEntity = handsComponent.GetActiveHand?.Owner;
|
||||
if (activeHandEntity == null || !activeHandEntity.TryGetComponent(out GasAnalyzerComponent? gasAnalyzer))
|
||||
{
|
||||
serverMsg.Session.AttachedEntity?.PopupMessage(Loc.GetString("You need a Gas Analyzer in your hand!"));
|
||||
return;
|
||||
}
|
||||
|
||||
UpdateUserInterface();
|
||||
Resync();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
async Task<bool> IAfterInteract.AfterInteract(AfterInteractEventArgs eventArgs)
|
||||
{
|
||||
if (!eventArgs.CanReach)
|
||||
{
|
||||
eventArgs.User.PopupMessage(Loc.GetString("You can't reach there!"));
|
||||
return true;
|
||||
}
|
||||
|
||||
if (eventArgs.User.TryGetComponent(out ActorComponent? actor))
|
||||
{
|
||||
OpenInterface(actor.PlayerSession, eventArgs.ClickLocation);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void IDropped.Dropped(DroppedEventArgs eventArgs)
|
||||
{
|
||||
if (eventArgs.User.TryGetComponent(out ActorComponent? actor))
|
||||
{
|
||||
CloseInterface(actor.PlayerSession);
|
||||
}
|
||||
}
|
||||
|
||||
bool IUse.UseEntity(UseEntityEventArgs eventArgs)
|
||||
{
|
||||
if (eventArgs.User.TryGetComponent(out ActorComponent? actor))
|
||||
{
|
||||
ToggleInterface(actor.PlayerSession);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user