diff --git a/Content.Server/Atmos/Components/MovedByPressureComponent.cs b/Content.Server/Atmos/Components/MovedByPressureComponent.cs
index b92d2bd3ea..bae12d67bd 100644
--- a/Content.Server/Atmos/Components/MovedByPressureComponent.cs
+++ b/Content.Server/Atmos/Components/MovedByPressureComponent.cs
@@ -1,30 +1,22 @@
-using System;
-using System.Diagnostics.CodeAnalysis;
-using Content.Shared.Atmos;
-using Content.Shared.MobState.Components;
-using Content.Shared.Physics;
-using Robust.Shared.GameObjects;
-using Robust.Shared.IoC;
-using Robust.Shared.Map;
-using Robust.Shared.Maths;
-using Robust.Shared.Physics;
-using Robust.Shared.Random;
-using Robust.Shared.Serialization.Manager.Attributes;
-using Robust.Shared.ViewVariables;
+using Content.Server.Atmos.EntitySystems;
namespace Content.Server.Atmos.Components
{
+ // Unfortunately can't be friends yet due to magboots.
[RegisterComponent]
public sealed class MovedByPressureComponent : Component
{
- [Dependency] private readonly IRobustRandom _robustRandom = default!;
- [Dependency] private readonly IEntityManager _entMan = default!;
+ public const float MoveForcePushRatio = 1f;
+ public const float MoveForceForcePushRatio = 1f;
+ public const float ProbabilityOffset = 25f;
+ public const float ProbabilityBasePercent = 10f;
+ public const float ThrowForce = 100f;
- private const float MoveForcePushRatio = 1f;
- private const float MoveForceForcePushRatio = 1f;
- private const float ProbabilityOffset = 25f;
- private const float ProbabilityBasePercent = 10f;
- private const float ThrowForce = 100f;
+ ///
+ /// Accumulates time when yeeted by high pressure deltas.
+ ///
+ [ViewVariables]
+ public float Accumulator = 0f;
[ViewVariables(VVAccess.ReadWrite)]
[DataField("enabled")]
@@ -37,75 +29,5 @@ namespace Content.Server.Atmos.Components
public float MoveResist { get; set; } = 100f;
[ViewVariables(VVAccess.ReadWrite)]
public int LastHighPressureMovementAirCycle { get; set; } = 0;
-
- public void ExperiencePressureDifference(int cycle, float pressureDifference, AtmosDirection direction,
- float pressureResistanceProbDelta, EntityCoordinates throwTarget)
- {
- if (!_entMan.TryGetComponent(Owner, out PhysicsComponent? physics))
- return;
- if (!_entMan.TryGetComponent(Owner, out FixturesComponent? fixtureComponent))
- return;
-
- // TODO ATMOS stuns?
-
- var transform = _entMan.GetComponent(physics.Owner);
- var maxForce = MathF.Sqrt(pressureDifference) * 2.25f;
- var moveProb = 100f;
-
- if (PressureResistance > 0)
- moveProb = MathF.Abs((pressureDifference / PressureResistance * ProbabilityBasePercent) -
- ProbabilityOffset);
-
- if (moveProb > ProbabilityOffset && _robustRandom.Prob(MathF.Min(moveProb / 100f, 1f))
- && !float.IsPositiveInfinity(MoveResist)
- && (physics.BodyType != BodyType.Static
- && (maxForce >= (MoveResist * MoveForcePushRatio)))
- || (physics.BodyType == BodyType.Static && (maxForce >= (MoveResist * MoveForceForcePushRatio))))
- {
- if (_entMan.HasComponent(physics.Owner))
- {
- physics.BodyStatus = BodyStatus.InAir;
- foreach (var fixture in fixtureComponent.Fixtures.Values)
- {
- fixture.CollisionMask &= ~(int) CollisionGroup.VaultImpassable;
- }
-
- Owner.SpawnTimer(2000, () =>
- {
- if (Deleted || !_entMan.TryGetComponent(Owner, out PhysicsComponent? physicsComponent)) return;
-
- // Uhh if you get race conditions good luck buddy.
- if (_entMan.HasComponent(physicsComponent.Owner))
- {
- physicsComponent.BodyStatus = BodyStatus.OnGround;
- }
-
- foreach (var fixture in physics.Fixtures)
- {
- fixture.CollisionMask |= (int) CollisionGroup.VaultImpassable;
- }
- });
- }
-
- if (maxForce > ThrowForce)
- {
- // Vera please fix ;-;
- if (throwTarget != EntityCoordinates.Invalid)
- {
- var moveForce = maxForce * MathHelper.Clamp(moveProb, 0, 100) / 15f;
- var pos = ((throwTarget.Position - transform.Coordinates.Position).Normalized + direction.ToDirection().ToVec()).Normalized;
- physics.ApplyLinearImpulse(pos * moveForce);
- }
-
- else
- {
- var moveForce = MathF.Min(maxForce * MathHelper.Clamp(moveProb, 0, 100) / 2500f, 20f);
- physics.ApplyLinearImpulse(direction.ToDirection().ToVec() * moveForce);
- }
-
- LastHighPressureMovementAirCycle = cycle;
- }
- }
- }
}
}
diff --git a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Grid.cs b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Grid.cs
index 23331cf089..4c6746dfc7 100644
--- a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Grid.cs
+++ b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Grid.cs
@@ -1493,6 +1493,11 @@ namespace Content.Server.Atmos.EntitySystems
#region Position Helpers
+ private TileRef? GetTile(TileAtmosphere tile)
+ {
+ return tile.GridIndices.GetTileRef(tile.GridIndex, _mapManager);
+ }
+
public bool TryGetGridAndTile(MapCoordinates coordinates, [NotNullWhen(true)] out (GridId Grid, Vector2i Tile)? tuple)
{
if (!_mapManager.TryFindGridAt(coordinates, out var grid))
diff --git a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.HighPressureDelta.cs b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.HighPressureDelta.cs
index 5d8382500d..4a05623129 100644
--- a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.HighPressureDelta.cs
+++ b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.HighPressureDelta.cs
@@ -1,11 +1,16 @@
using Content.Server.Atmos.Components;
using Content.Shared.Atmos;
using Content.Shared.Audio;
+using Content.Shared.MobState.Components;
+using Content.Shared.Physics;
using Robust.Shared.Audio;
using Robust.Shared.GameObjects;
using Robust.Shared.Map;
using Robust.Shared.Maths;
+using Robust.Shared.Physics;
using Robust.Shared.Player;
+using Robust.Shared.Random;
+using Robust.Shared.Utility;
using Robust.Shared.ViewVariables;
namespace Content.Server.Atmos.EntitySystems
@@ -19,6 +24,71 @@ namespace Content.Server.Atmos.EntitySystems
[ViewVariables(VVAccess.ReadWrite)]
public string? SpaceWindSound { get; private set; } = "/Audio/Effects/space_wind.ogg";
+ private HashSet _activePressures = new(8);
+
+ private void UpdateHighPressure(float frameTime)
+ {
+ var toRemove = new RemQueue();
+
+ foreach (var comp in _activePressures)
+ {
+ MetaDataComponent? metadata = null;
+
+ if (Deleted(comp.Owner, metadata))
+ {
+ toRemove.Add(comp);
+ continue;
+ }
+
+ if (Paused(comp.Owner, metadata)) continue;
+
+ comp.Accumulator += frameTime;
+
+ if (comp.Accumulator < 2f) continue;
+
+ // Reset it just for VV reasons even though it doesn't matter
+ comp.Accumulator = 0f;
+ toRemove.Add(comp);
+
+ if (HasComp(comp.Owner) &&
+ TryComp(comp.Owner, out var body))
+ {
+ body.BodyStatus = BodyStatus.OnGround;
+ }
+
+ if (TryComp(comp.Owner, out var fixtures))
+ {
+ foreach (var (_, fixture) in fixtures.Fixtures)
+ {
+ _physics.AddCollisionMask(fixtures, fixture, (int) CollisionGroup.VaultImpassable);
+ }
+ }
+ }
+
+ foreach (var comp in toRemove)
+ {
+ _activePressures.Remove(comp);
+ }
+ }
+
+ private void AddMobMovedByPressure(MovedByPressureComponent component, PhysicsComponent body)
+ {
+ if (!TryComp(component.Owner, out var fixtures)) return;
+
+ body.BodyStatus = BodyStatus.InAir;
+
+ foreach (var fixture in fixtures.Fixtures.Values)
+ {
+ _physics.RemoveCollisionMask(fixtures, fixture, (int) CollisionGroup.VaultImpassable);
+ }
+
+ // TODO: Make them dynamic type? Ehh but they still want movement so uhh make it non-predicted like weightless?
+ // idk it's hard.
+
+ component.Accumulator = 0f;
+ _activePressures.Add(component);
+ }
+
private void HighPressureMovements(GridAtmosphereComponent gridAtmosphere, TileAtmosphere tile, EntityQuery bodies, EntityQuery xforms, EntityQuery pressureQuery)
{
// TODO ATMOS finish this
@@ -37,15 +107,28 @@ namespace Content.Server.Atmos.EntitySystems
foreach (var entity in _lookup.GetEntitiesIntersecting(tile.GridIndex, tile.GridIndices))
{
// Ideally containers would have their own EntityQuery internally or something given recursively it may need to slam GetComp anyway.
- if (!bodies.HasComponent(entity)
- || !pressureQuery.TryGetComponent(entity, out var pressure) || !pressure.Enabled
- || _containers.IsEntityInContainer(entity, xforms.GetComponent(entity)))
+ // Also, don't care about static bodies (but also due to collisionwakestate can't query dynamic directly atm).
+ if (!bodies.TryGetComponent(entity, out var body) ||
+ !pressureQuery.TryGetComponent(entity, out var pressure) ||
+ !pressure.Enabled)
continue;
+ var xform = xforms.GetComponent(entity);
+
+ if (_containers.IsEntityInContainer(entity, xform)) continue;
+
var pressureMovements = EnsureComp(entity);
if (pressure.LastHighPressureMovementAirCycle < gridAtmosphere.UpdateCounter)
{
- pressureMovements.ExperiencePressureDifference(gridAtmosphere.UpdateCounter, tile.PressureDifference, tile.PressureDirection, 0, tile.PressureSpecificTarget?.GridIndices.ToEntityCoordinates(tile.GridIndex, _mapManager) ?? EntityCoordinates.Invalid);
+ // tl;dr YEET
+ ExperiencePressureDifference(
+ pressureMovements,
+ gridAtmosphere.UpdateCounter,
+ tile.PressureDifference,
+ tile.PressureDirection, 0,
+ tile.PressureSpecificTarget?.GridIndices.ToEntityCoordinates(tile.GridIndex, _mapManager) ?? EntityCoordinates.Invalid,
+ xform,
+ body);
}
}
@@ -68,5 +151,62 @@ namespace Content.Server.Atmos.EntitySystems
tile.PressureDirection = (tile.GridIndices - other.GridIndices).GetDir().ToAtmosDirection();
}
}
+
+ public void ExperiencePressureDifference(
+ MovedByPressureComponent component,
+ int cycle,
+ float pressureDifference,
+ AtmosDirection direction,
+ float pressureResistanceProbDelta,
+ EntityCoordinates throwTarget,
+ TransformComponent? xform = null,
+ PhysicsComponent? physics = null)
+ {
+ if (!Resolve(component.Owner, ref physics, false))
+ return;
+
+ if (!Resolve(component.Owner, ref xform)) return;
+
+ // TODO ATMOS stuns?
+
+ var maxForce = MathF.Sqrt(pressureDifference) * 2.25f;
+ var moveProb = 100f;
+
+ if (component.PressureResistance > 0)
+ moveProb = MathF.Abs((pressureDifference / component.PressureResistance * MovedByPressureComponent.ProbabilityBasePercent) -
+ MovedByPressureComponent.ProbabilityOffset);
+
+ // Can we yeet the thing (due to probability, strength, etc.)
+ if (moveProb > MovedByPressureComponent.ProbabilityOffset && _robustRandom.Prob(MathF.Min(moveProb / 100f, 1f))
+ && !float.IsPositiveInfinity(component.MoveResist)
+ && (physics.BodyType != BodyType.Static
+ && (maxForce >= (component.MoveResist * MovedByPressureComponent.MoveForcePushRatio)))
+ || (physics.BodyType == BodyType.Static && (maxForce >= (component.MoveResist * MovedByPressureComponent.MoveForceForcePushRatio))))
+ {
+ if (HasComp(physics.Owner))
+ {
+ AddMobMovedByPressure(component, physics);
+ }
+
+ if (maxForce > MovedByPressureComponent.ThrowForce)
+ {
+ // TODO: Technically these directions won't be correct but uhh I'm just here for optimisations buddy not to fix my old bugs.
+ if (throwTarget != EntityCoordinates.Invalid)
+ {
+ var moveForce = maxForce * MathHelper.Clamp(moveProb, 0, 100) / 15f;
+ var pos = ((throwTarget.Position - xform.Coordinates.Position).Normalized + direction.ToDirection().ToVec()).Normalized;
+ physics.ApplyLinearImpulse(pos * moveForce);
+ }
+
+ else
+ {
+ var moveForce = MathF.Min(maxForce * MathHelper.Clamp(moveProb, 0, 100) / 2500f, 20f);
+ physics.ApplyLinearImpulse(direction.ToDirection().ToVec() * moveForce);
+ }
+
+ component.LastHighPressureMovementAirCycle = cycle;
+ }
+ }
+ }
}
}
diff --git a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Hotspot.cs b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Hotspot.cs
index 6fbb47c574..9e78f4acb6 100644
--- a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Hotspot.cs
+++ b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Hotspot.cs
@@ -170,7 +170,7 @@ namespace Content.Server.Atmos.EntitySystems
foreach (var entity in _lookup.GetEntitiesIntersecting(tile.GridIndex, tile.GridIndices))
{
- RaiseLocalEvent(entity, fireEvent, false);
+ RaiseLocalEvent(entity, ref fireEvent, false);
}
}
}
diff --git a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Processing.cs b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Processing.cs
index bb13f8a423..bae1c044b8 100644
--- a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Processing.cs
+++ b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Processing.cs
@@ -112,7 +112,7 @@ namespace Content.Server.Atmos.EntitySystems
AddActiveTile(atmosphere, tile);
// TODO ATMOS: Query all the contents of this tile (like walls) and calculate the correct thermal conductivity and heat capacity
- var tileDef = tile.Tile?.Tile.GetContentTileDefinition();
+ var tileDef = GetTile(tile)?.Tile.GetContentTileDefinition(_tileDefinitionManager);
tile.ThermalConductivity = tileDef?.ThermalConductivity ?? 0.5f;
tile.HeatCapacity = tileDef?.HeatCapacity ?? float.PositiveInfinity;
InvalidateVisuals(mapGrid.Index, indices);
diff --git a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.cs b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.cs
index cef954fe00..d8c34f1ce6 100644
--- a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.cs
+++ b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.cs
@@ -1,18 +1,10 @@
-using Content.Server.Administration;
using Content.Server.Administration.Logs;
using Content.Server.Atmos.Components;
-using Content.Server.Database;
using Content.Server.NodeContainer.EntitySystems;
-using Content.Server.Temperature.Components;
-using Content.Server.Temperature.Systems;
-using Content.Shared.Administration;
using Content.Shared.Atmos.EntitySystems;
using Content.Shared.Maps;
using JetBrains.Annotations;
-using Robust.Shared.Console;
using Robust.Shared.Containers;
-using Robust.Shared.GameObjects;
-using Robust.Shared.IoC;
using Robust.Shared.Map;
namespace Content.Server.Atmos.EntitySystems
@@ -26,6 +18,7 @@ namespace Content.Server.Atmos.EntitySystems
[Dependency] private readonly IMapManager _mapManager = default!;
[Dependency] private readonly AdminLogSystem _adminLog = default!;
[Dependency] private readonly SharedContainerSystem _containers = default!;
+ [Dependency] private readonly SharedPhysicsSystem _physics = default!;
private const float ExposedUpdateDelay = 1f;
private float _exposedTimer = 0f;
@@ -77,6 +70,7 @@ namespace Content.Server.Atmos.EntitySystems
base.Update(frameTime);
UpdateProcessing(frameTime);
+ UpdateHighPressure(frameTime);
_exposedTimer += frameTime;
diff --git a/Content.Server/Atmos/EntitySystems/FlammableSystem.cs b/Content.Server/Atmos/EntitySystems/FlammableSystem.cs
index d657b0d081..a92a95294d 100644
--- a/Content.Server/Atmos/EntitySystems/FlammableSystem.cs
+++ b/Content.Server/Atmos/EntitySystems/FlammableSystem.cs
@@ -111,7 +111,7 @@ namespace Content.Server.Atmos.EntitySystems
args.IsHot = flammable.OnFire;
}
- private void OnTileFireEvent(EntityUid uid, FlammableComponent flammable, TileFireEvent args)
+ private void OnTileFireEvent(EntityUid uid, FlammableComponent flammable, ref TileFireEvent args)
{
var tempDelta = args.Temperature - MinIgnitionTemperature;
diff --git a/Content.Server/Atmos/Monitor/Systems/AtmosMonitoringSystem.cs b/Content.Server/Atmos/Monitor/Systems/AtmosMonitoringSystem.cs
index 17f222922f..28a3d05539 100644
--- a/Content.Server/Atmos/Monitor/Systems/AtmosMonitoringSystem.cs
+++ b/Content.Server/Atmos/Monitor/Systems/AtmosMonitoringSystem.cs
@@ -237,7 +237,7 @@ namespace Content.Server.Atmos.Monitor.Systems
}
}
- private void OnFireEvent(EntityUid uid, AtmosMonitorComponent component, TileFireEvent args)
+ private void OnFireEvent(EntityUid uid, AtmosMonitorComponent component, ref TileFireEvent args)
{
if (!TryComp(uid, out var powerReceiverComponent)
|| !powerReceiverComponent.Powered)
diff --git a/Content.Server/Atmos/TileFireEvent.cs b/Content.Server/Atmos/TileFireEvent.cs
index d9085ce015..5dad4e8fc0 100644
--- a/Content.Server/Atmos/TileFireEvent.cs
+++ b/Content.Server/Atmos/TileFireEvent.cs
@@ -1,14 +1,13 @@
-using Robust.Shared.GameObjects;
-
-namespace Content.Server.Atmos
+namespace Content.Server.Atmos
{
///
/// Event raised directed to an entity when it is standing on a tile that's on fire.
///
- public sealed class TileFireEvent : EntityEventArgs
+ [ByRefEvent]
+ public readonly struct TileFireEvent
{
- public float Temperature { get; }
- public float Volume { get; }
+ public readonly float Temperature;
+ public readonly float Volume;
public TileFireEvent(float temperature, float volume)
{