* Added atmos sprites from CEV-Eris * Moved canister sprites to appropriate dir * Removed unnecessary sprites, edited canisters prototype * Created Gas Canister UI and release pressure buttons * Changed GasMixture's pressure calculation (convert liters to cube meters) * Added relabeling Canisters * Reverted changes on GasMixture * Changed my name in the credits * Added valve opening on canisters * Change canister visual state when connected to a port * Added nullable to SharedGasCanisterComponent * Replaced nullable contexts * Changed again nullable annotation context * Moved name in the credits to correct alphabetical order * Canisters: Fix the most blatant issues with this PR (the added project interdependencies for no reason whatsoever) * Canisters: Stop crashes when canisters leave atmosphere * Canisters: Gas released into no atmosphere gets transferred "into space" (deleted) * Atmos: Nullability annotations on TileAtmosphere, explaination of the states of TileAtmosphere.Air * Canisters: If in an airblocked tile, do NOT release gas * Scrubbers: Fix typo leading to them not connecting properly. * Revert manual changes to credits file (sorry!) (1/2) This reverts commit 94f3b0e5df8d9c2fa189866a17a231920f99bdaf. * Revert manual changes to credits file (sorry!) (2/2) This reverts commit 1986fb094dfaa44060f08d280f36b755258d17a6. * Canisters: Apply @Zumorica 's reviews * Canisters: Add missing localization as suggested by PJB Co-authored-by: Pieter-Jan Briers <pieterjan.briers@gmail.com> * Canisters: Pressure lights! * Canisters: Light is now unshaded. * Canisters: Now using IActivate * Gas canisters (& air canister), now with their numbers properly calibrated (hopefully) * Canisters: Refactor how their layers are added to be more like ApcVisualizer * Canisters: Clean up of the tile invalidation/air release logic * Canisters: Some gas canister window improvements * Canisters: Clean up release pressure change button label code Co-authored-by: Clement-O <topy72.mine@gmail.com> Co-authored-by: Clément <clement.orlandini@gmail.com> Co-authored-by: Pieter-Jan Briers <pieterjan.briers@gmail.com>
This commit is contained in:
@@ -1,4 +1,6 @@
|
||||
using Content.Server.Atmos;
|
||||
#nullable enable
|
||||
using System;
|
||||
using Content.Server.Atmos;
|
||||
using Content.Server.GameObjects.Components.Atmos.Piping;
|
||||
using Content.Server.Interfaces;
|
||||
using Robust.Shared.GameObjects;
|
||||
@@ -6,36 +8,83 @@ using Robust.Shared.GameObjects.Components;
|
||||
using Robust.Shared.GameObjects.Components.Transform;
|
||||
using Robust.Shared.Serialization;
|
||||
using Robust.Shared.ViewVariables;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Content.Server.GameObjects.EntitySystems;
|
||||
using Content.Server.Interfaces.GameObjects.Components.Items;
|
||||
using Content.Server.Utility;
|
||||
using Content.Shared.GameObjects.Components.Atmos;
|
||||
using Content.Shared.GameObjects.EntitySystems;
|
||||
using Content.Shared.Interfaces;
|
||||
using Content.Shared.Interfaces.GameObjects.Components;
|
||||
using Content.Shared.Atmos;
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Server.GameObjects.Components.UserInterface;
|
||||
using Robust.Server.Interfaces.GameObjects;
|
||||
using Robust.Shared.Containers;
|
||||
using Robust.Shared.GameObjects.Systems;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
using Robust.Shared.Localization;
|
||||
|
||||
namespace Content.Server.GameObjects.Components.Atmos
|
||||
{
|
||||
/// <summary>
|
||||
/// Component that manages gas mixtures temperature, pressure and output.
|
||||
/// </summary>
|
||||
[RegisterComponent]
|
||||
public class GasCanisterComponent : Component, IGasMixtureHolder
|
||||
[ComponentReference(typeof(IActivate))]
|
||||
public class GasCanisterComponent : Component, IGasMixtureHolder, IActivate
|
||||
{
|
||||
public override string Name => "GasCanister";
|
||||
|
||||
[ViewVariables]
|
||||
public GasMixture Air { get; set; }
|
||||
private const int MaxLabelLength = 32;
|
||||
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public string Label { get; set; } = "Gas Canister";
|
||||
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public bool ValveOpened { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// What <see cref="GasMixture"/> the canister contains.
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public GasMixture Air { get; set; } = default!;
|
||||
|
||||
[ViewVariables]
|
||||
public bool Anchored => !Owner.TryGetComponent<IPhysicsComponent>(out var physics) || physics.Anchored;
|
||||
|
||||
/// <summary>
|
||||
/// The floor connector port that the canister is attached to.
|
||||
/// </summary>
|
||||
[ViewVariables]
|
||||
public GasCanisterPortComponent ConnectedPort { get; private set; }
|
||||
public GasCanisterPortComponent? ConnectedPort { get; private set; }
|
||||
|
||||
[ViewVariables]
|
||||
public bool ConnectedToPort => ConnectedPort != null;
|
||||
|
||||
private const float DefaultVolume = 10;
|
||||
|
||||
[ViewVariables(VVAccess.ReadWrite)] public float ReleasePressure { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The user interface bound to the canister.
|
||||
/// </summary>
|
||||
private BoundUserInterface? UserInterface => Owner.GetUIOrNull(SharedGasCanisterComponent.GasCanisterUiKey.Key);
|
||||
|
||||
/// <summary>
|
||||
/// Stores the last ui state after it's been casted into <see cref="GasCanisterBoundUserInterface"/>
|
||||
/// </summary>
|
||||
private GasCanisterBoundUserInterfaceState? _lastUiState;
|
||||
|
||||
private AppearanceComponent? _appearance;
|
||||
|
||||
public override void ExposeData(ObjectSerializer serializer)
|
||||
{
|
||||
base.ExposeData(serializer);
|
||||
serializer.DataField(this, x => Air, "gasMixture", new GasMixture(DefaultVolume));
|
||||
}
|
||||
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
@@ -44,8 +93,21 @@ namespace Content.Server.GameObjects.Components.Atmos
|
||||
AnchorUpdate();
|
||||
physics.AnchoredChanged += AnchorUpdate;
|
||||
}
|
||||
if (UserInterface != null)
|
||||
{
|
||||
UserInterface.OnReceiveMessage += OnUiReceiveMessage;
|
||||
}
|
||||
|
||||
// Init some variables
|
||||
Label = Owner.Name;
|
||||
Owner.TryGetComponent(out _appearance);
|
||||
|
||||
UpdateUserInterface();
|
||||
UpdateAppearance();
|
||||
}
|
||||
|
||||
#region Connector port methods
|
||||
|
||||
public override void OnRemove()
|
||||
{
|
||||
base.OnRemove();
|
||||
@@ -53,23 +115,27 @@ namespace Content.Server.GameObjects.Components.Atmos
|
||||
{
|
||||
physics.AnchoredChanged -= AnchorUpdate;
|
||||
}
|
||||
if (UserInterface != null)
|
||||
{
|
||||
UserInterface.OnReceiveMessage -= OnUiReceiveMessage;
|
||||
}
|
||||
DisconnectFromPort();
|
||||
}
|
||||
|
||||
|
||||
public void TryConnectToPort()
|
||||
{
|
||||
if (!Owner.TryGetComponent<SnapGridComponent>(out var snapGrid)) return;
|
||||
var port = snapGrid.GetLocal()
|
||||
.Select(entity => entity.TryGetComponent<GasCanisterPortComponent>(out var port) ? port : null)
|
||||
.Where(port => port != null)
|
||||
.Where(port => !port.ConnectedToCanister)
|
||||
.Where(port => !port!.ConnectedToCanister)
|
||||
.FirstOrDefault();
|
||||
if (port == null) return;
|
||||
ConnectedPort = port;
|
||||
ConnectedPort.ConnectGasCanister(this);
|
||||
}
|
||||
|
||||
|
||||
public void DisconnectFromPort()
|
||||
{
|
||||
ConnectedPort?.DisconnectGasCanister();
|
||||
@@ -86,6 +152,181 @@ namespace Content.Server.GameObjects.Components.Atmos
|
||||
{
|
||||
DisconnectFromPort();
|
||||
}
|
||||
UpdateAppearance();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
void IActivate.Activate(ActivateEventArgs eventArgs)
|
||||
{
|
||||
if (!eventArgs.User.TryGetComponent(out IActorComponent? actor))
|
||||
return;
|
||||
|
||||
UserInterface?.Open(actor.playerSession);
|
||||
}
|
||||
|
||||
private void OnUiReceiveMessage(ServerBoundUserInterfaceMessage obj)
|
||||
{
|
||||
if (obj.Session.AttachedEntity == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!PlayerCanUse(obj.Session.AttachedEntity))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// If the label has been changed by a client
|
||||
if (obj.Message is CanisterLabelChangedMessage canLabelMessage)
|
||||
{
|
||||
var newLabel = canLabelMessage.NewLabel;
|
||||
if (newLabel.Length > MaxLabelLength)
|
||||
newLabel = newLabel.Substring(0, MaxLabelLength);
|
||||
Label = newLabel;
|
||||
Owner.Name = Label;
|
||||
UpdateUserInterface();
|
||||
return;
|
||||
}
|
||||
|
||||
// If the release pressure has been adjusted by the client on the gas canister
|
||||
if (obj.Message is ReleasePressureButtonPressedMessage rPMessage)
|
||||
{
|
||||
ReleasePressure += rPMessage.ReleasePressure;
|
||||
ReleasePressure = Math.Clamp(ReleasePressure, 0, 1000);
|
||||
ReleasePressure = MathF.Round(ReleasePressure, 2);
|
||||
UpdateUserInterface();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (obj.Message is UiButtonPressedMessage btnPressedMessage)
|
||||
{
|
||||
switch (btnPressedMessage.Button)
|
||||
{
|
||||
case UiButton.ValveToggle:
|
||||
ToggleValve();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Update the user interface if relevant
|
||||
/// </summary>
|
||||
private void UpdateUserInterface()
|
||||
{
|
||||
var state = GetUserInterfaceState();
|
||||
|
||||
if (_lastUiState != null && _lastUiState.Equals(state))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_lastUiState = state;
|
||||
UserInterface?.SetState(state);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Update the canister's sprite
|
||||
/// </summary>
|
||||
private void UpdateAppearance()
|
||||
{
|
||||
_appearance?.SetData(GasCanisterVisuals.ConnectedState, ConnectedToPort);
|
||||
// The Eris canisters are being used, so best to use the Eris light logic unless someone else has a better idea.
|
||||
// https://github.com/discordia-space/CEV-Eris/blob/fdd6ee7012f46838a6711adb1737cd90c48ae448/code/game/machinery/atmoalter/canister.dm#L129
|
||||
if (Air.Pressure < 10)
|
||||
{
|
||||
_appearance?.SetData(GasCanisterVisuals.PressureState, 0);
|
||||
}
|
||||
else if (Air.Pressure < Atmospherics.OneAtmosphere)
|
||||
{
|
||||
_appearance?.SetData(GasCanisterVisuals.PressureState, 1);
|
||||
}
|
||||
else if (Air.Pressure < (15 * Atmospherics.OneAtmosphere))
|
||||
{
|
||||
_appearance?.SetData(GasCanisterVisuals.PressureState, 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
_appearance?.SetData(GasCanisterVisuals.PressureState, 3);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the current interface state from server data
|
||||
/// </summary>
|
||||
/// <returns>The state</returns>
|
||||
private GasCanisterBoundUserInterfaceState GetUserInterfaceState()
|
||||
{
|
||||
// We round the pressure for ease of reading
|
||||
return new GasCanisterBoundUserInterfaceState(Label,
|
||||
MathF.Round(Air.Pressure, 2),
|
||||
ReleasePressure,
|
||||
ValveOpened);
|
||||
}
|
||||
|
||||
public void AirWasUpdated()
|
||||
{
|
||||
UpdateUserInterface();
|
||||
UpdateAppearance();
|
||||
}
|
||||
|
||||
#region Check methods
|
||||
|
||||
private bool PlayerCanUse(IEntity? player)
|
||||
{
|
||||
if (player == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!ActionBlockerSystem.CanInteract(player) ||
|
||||
!ActionBlockerSystem.CanUse(player))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Called when the canister's valve is toggled
|
||||
/// </summary>
|
||||
private void ToggleValve()
|
||||
{
|
||||
ValveOpened = !ValveOpened;
|
||||
UpdateUserInterface();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called every frame
|
||||
/// </summary>
|
||||
/// <param name="frameTime"></param>
|
||||
public void Update(in float frameTime)
|
||||
{
|
||||
if (ValveOpened)
|
||||
{
|
||||
var tileAtmosphere = Owner.Transform.Coordinates.GetTileAtmosphere();
|
||||
if (tileAtmosphere != null)
|
||||
{
|
||||
// If tileAtmosphere.Air is null, then we're airblocked, so DON'T release
|
||||
if (tileAtmosphere.Air != null)
|
||||
{
|
||||
Air.ReleaseGasTo(tileAtmosphere.Air, ReleasePressure);
|
||||
tileAtmosphere.Invalidate();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Air.ReleaseGasTo(null, ReleasePressure);
|
||||
}
|
||||
|
||||
AirWasUpdated();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user