Add atmos tick time to atmos device update event (#18781)

This commit is contained in:
Kevin Zheng
2023-08-07 10:36:43 -07:00
committed by GitHub
parent e64e613a62
commit 57bf21cb6a
4 changed files with 45 additions and 34 deletions

View File

@@ -21,6 +21,12 @@ namespace Content.Server.Atmos.EntitySystems
public bool ExcitedGroupsSpaceIsAllConsuming { get; private set; } public bool ExcitedGroupsSpaceIsAllConsuming { get; private set; }
public float AtmosMaxProcessTime { get; private set; } public float AtmosMaxProcessTime { get; private set; }
public float AtmosTickRate { get; private set; } public float AtmosTickRate { get; private set; }
/// <summary>
/// Time between each atmos sub-update. If you are writing an atmos device, use AtmosDeviceUpdateEvent.dt
/// instead of this value, because atmos devices do not update each are sub-update and sometimes are skipped to
/// meet the tick deadline.
/// </summary>
public float AtmosTime => 1f / AtmosTickRate; public float AtmosTime => 1f / AtmosTickRate;
private void InitializeCVars() private void InitializeCVars()

View File

@@ -14,7 +14,6 @@ namespace Content.Server.Atmos.EntitySystems
{ {
[Dependency] private readonly IGameTiming _gameTiming = default!; [Dependency] private readonly IGameTiming _gameTiming = default!;
private readonly AtmosDeviceUpdateEvent _updateEvent = new();
private readonly Stopwatch _simulationStopwatch = new(); private readonly Stopwatch _simulationStopwatch = new();
/// <summary> /// <summary>
@@ -337,7 +336,7 @@ namespace Content.Server.Atmos.EntitySystems
var number = 0; var number = 0;
while (atmosphere.CurrentRunAtmosDevices.TryDequeue(out var device)) while (atmosphere.CurrentRunAtmosDevices.TryDequeue(out var device))
{ {
RaiseLocalEvent(device.Owner, _updateEvent, false); RaiseLocalEvent(device.Owner, new AtmosDeviceUpdateEvent(AtmosTime * (int)AtmosphereProcessingState.NumStates), false);
device.LastProcess = time; device.LastProcess = time;
if (number++ < LagCheckIterations) continue; if (number++ < LagCheckIterations) continue;
@@ -509,5 +508,6 @@ namespace Content.Server.Atmos.EntitySystems
Superconductivity, Superconductivity,
PipeNet, PipeNet,
AtmosDevices, AtmosDevices,
NumStates
} }
} }

View File

@@ -7,32 +7,50 @@ namespace Content.Server.Atmos.Piping.Components
public sealed class AtmosDeviceComponent : Component public sealed class AtmosDeviceComponent : Component
{ {
/// <summary> /// <summary>
/// Whether this device requires being anchored to join an atmosphere. /// If true, this device must be anchored before it will receive any AtmosDeviceUpdateEvents.
/// </summary> /// </summary>
[ViewVariables(VVAccess.ReadWrite)] [ViewVariables(VVAccess.ReadWrite)]
[DataField("requireAnchored")] [DataField("requireAnchored")]
public bool RequireAnchored { get; private set; } = true; public bool RequireAnchored { get; private set; } = true;
/// <summary> /// <summary>
/// Whether this device will join an entity system to process when not in a grid. /// If true, update even when there is no grid atmosphere. Normally, atmos devices only
/// update when inside a grid atmosphere, because they work with gases in the environment
/// and won't do anything useful if there is no environment. This is useful for devices
/// like gas canisters whose contents can still react if the canister itself is not inside
/// a grid atmosphere.
/// </summary> /// </summary>
[DataField("joinSystem")] [DataField("joinSystem")]
public bool JoinSystem { get; } = false; public bool JoinSystem { get; } = false;
/// <summary> /// <summary>
/// Whether we have joined an entity system to process. /// If non-null, the grid that this device is part of.
/// </summary>
public EntityUid? JoinedGrid { get; set; }
/// <summary>
/// Indicates that a device is not on a grid atmosphere but still being updated.
/// </summary> /// </summary>
[ViewVariables] [ViewVariables]
public bool JoinedSystem { get; set; } = false; public bool JoinedSystem { get; set; } = false;
[ViewVariables] [ViewVariables]
public TimeSpan LastProcess { get; set; } = TimeSpan.Zero; public TimeSpan LastProcess { get; set; } = TimeSpan.Zero;
public EntityUid? JoinedGrid { get; set; }
} }
public sealed class AtmosDeviceUpdateEvent : EntityEventArgs public sealed class AtmosDeviceUpdateEvent : EntityEventArgs
{} {
/// <summary>
/// Time elapsed since last update, in seconds. Multiply values used in the update handler
/// by this number to make them tickrate-invariant. Use this number instead of AtmosphereSystem.AtmosTime.
/// </summary>
public float dt;
public AtmosDeviceUpdateEvent(float dt)
{
this.dt = dt;
}
}
public sealed class AtmosDeviceEnabledEvent : EntityEventArgs public sealed class AtmosDeviceEnabledEvent : EntityEventArgs
{} {}

View File

@@ -11,9 +11,9 @@ namespace Content.Server.Atmos.Piping.EntitySystems
[Dependency] private readonly IGameTiming _gameTiming = default!; [Dependency] private readonly IGameTiming _gameTiming = default!;
[Dependency] private readonly AtmosphereSystem _atmosphereSystem = default!; [Dependency] private readonly AtmosphereSystem _atmosphereSystem = default!;
private readonly AtmosDeviceUpdateEvent _updateEvent = new();
private float _timer = 0f; private float _timer = 0f;
// Set of atmos devices that are off-grid but have JoinSystem set.
private readonly HashSet<AtmosDeviceComponent> _joinedDevices = new(); private readonly HashSet<AtmosDeviceComponent> _joinedDevices = new();
public override void Initialize() public override void Initialize()
@@ -27,40 +27,23 @@ namespace Content.Server.Atmos.Piping.EntitySystems
SubscribeLocalEvent<AtmosDeviceComponent, AnchorStateChangedEvent>(OnDeviceAnchorChanged); SubscribeLocalEvent<AtmosDeviceComponent, AnchorStateChangedEvent>(OnDeviceAnchorChanged);
} }
private bool CanJoinAtmosphere(AtmosDeviceComponent component, TransformComponent transform)
{
return (!component.RequireAnchored || transform.Anchored) && transform.GridUid != null;
}
public void JoinAtmosphere(AtmosDeviceComponent component) public void JoinAtmosphere(AtmosDeviceComponent component)
{ {
var transform = Transform(component.Owner); var transform = Transform(component.Owner);
if (!CanJoinAtmosphere(component, transform)) if (component.RequireAnchored && !transform.Anchored)
{
return; return;
}
// TODO: low-hanging fruit for perf improvements around here // Attempt to add device to a grid atmosphere.
bool onGrid = (transform.GridUid != null) && _atmosphereSystem.AddAtmosDevice(transform.GridUid!.Value, component);
// GridUid is not null because we can join atmosphere. if (!onGrid && component.JoinSystem)
// We try to add the device to a valid atmosphere, and if we can't, try to add it to the entity system.
if (!_atmosphereSystem.AddAtmosDevice(transform.GridUid!.Value, component))
{
if (component.JoinSystem)
{ {
_joinedDevices.Add(component); _joinedDevices.Add(component);
component.JoinedSystem = true; component.JoinedSystem = true;
} }
else
{
return;
}
}
component.LastProcess = _gameTiming.CurTime; component.LastProcess = _gameTiming.CurTime;
RaiseLocalEvent(component.Owner, new AtmosDeviceEnabledEvent(), false); RaiseLocalEvent(component.Owner, new AtmosDeviceEnabledEvent(), false);
} }
@@ -117,6 +100,10 @@ namespace Content.Server.Atmos.Piping.EntitySystems
RejoinAtmosphere(component); RejoinAtmosphere(component);
} }
/// <summary>
/// Update atmos devices that are off-grid but have JoinSystem set. For devices updates when
/// a device is on a grid, see AtmosphereSystem:UpdateProcessing().
/// </summary>
public override void Update(float frameTime) public override void Update(float frameTime)
{ {
_timer += frameTime; _timer += frameTime;
@@ -129,7 +116,7 @@ namespace Content.Server.Atmos.Piping.EntitySystems
var time = _gameTiming.CurTime; var time = _gameTiming.CurTime;
foreach (var device in _joinedDevices) foreach (var device in _joinedDevices)
{ {
RaiseLocalEvent(device.Owner, _updateEvent, false); RaiseLocalEvent(device.Owner, new AtmosDeviceUpdateEvent(_atmosphereSystem.AtmosTime), false);
device.LastProcess = time; device.LastProcess = time;
} }
} }