Minor atmos optimisations (#6625)

This commit is contained in:
metalgearsloth
2022-02-20 17:43:20 +11:00
committed by GitHub
parent 5b53b69191
commit 07b38e5acd
9 changed files with 172 additions and 112 deletions

View File

@@ -1,30 +1,22 @@
using System; using Content.Server.Atmos.EntitySystems;
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;
namespace Content.Server.Atmos.Components namespace Content.Server.Atmos.Components
{ {
// Unfortunately can't be friends yet due to magboots.
[RegisterComponent] [RegisterComponent]
public sealed class MovedByPressureComponent : Component public sealed class MovedByPressureComponent : Component
{ {
[Dependency] private readonly IRobustRandom _robustRandom = default!; public const float MoveForcePushRatio = 1f;
[Dependency] private readonly IEntityManager _entMan = default!; 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; /// <summary>
private const float MoveForceForcePushRatio = 1f; /// Accumulates time when yeeted by high pressure deltas.
private const float ProbabilityOffset = 25f; /// </summary>
private const float ProbabilityBasePercent = 10f; [ViewVariables]
private const float ThrowForce = 100f; public float Accumulator = 0f;
[ViewVariables(VVAccess.ReadWrite)] [ViewVariables(VVAccess.ReadWrite)]
[DataField("enabled")] [DataField("enabled")]
@@ -37,75 +29,5 @@ namespace Content.Server.Atmos.Components
public float MoveResist { get; set; } = 100f; public float MoveResist { get; set; } = 100f;
[ViewVariables(VVAccess.ReadWrite)] [ViewVariables(VVAccess.ReadWrite)]
public int LastHighPressureMovementAirCycle { get; set; } = 0; 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<TransformComponent>(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<MobStateComponent>(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<MobStateComponent>(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;
}
}
}
} }
} }

View File

@@ -1493,6 +1493,11 @@ namespace Content.Server.Atmos.EntitySystems
#region Position Helpers #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) public bool TryGetGridAndTile(MapCoordinates coordinates, [NotNullWhen(true)] out (GridId Grid, Vector2i Tile)? tuple)
{ {
if (!_mapManager.TryFindGridAt(coordinates, out var grid)) if (!_mapManager.TryFindGridAt(coordinates, out var grid))

View File

@@ -1,11 +1,16 @@
using Content.Server.Atmos.Components; using Content.Server.Atmos.Components;
using Content.Shared.Atmos; using Content.Shared.Atmos;
using Content.Shared.Audio; using Content.Shared.Audio;
using Content.Shared.MobState.Components;
using Content.Shared.Physics;
using Robust.Shared.Audio; using Robust.Shared.Audio;
using Robust.Shared.GameObjects; using Robust.Shared.GameObjects;
using Robust.Shared.Map; using Robust.Shared.Map;
using Robust.Shared.Maths; using Robust.Shared.Maths;
using Robust.Shared.Physics;
using Robust.Shared.Player; using Robust.Shared.Player;
using Robust.Shared.Random;
using Robust.Shared.Utility;
using Robust.Shared.ViewVariables; using Robust.Shared.ViewVariables;
namespace Content.Server.Atmos.EntitySystems namespace Content.Server.Atmos.EntitySystems
@@ -19,6 +24,71 @@ namespace Content.Server.Atmos.EntitySystems
[ViewVariables(VVAccess.ReadWrite)] [ViewVariables(VVAccess.ReadWrite)]
public string? SpaceWindSound { get; private set; } = "/Audio/Effects/space_wind.ogg"; public string? SpaceWindSound { get; private set; } = "/Audio/Effects/space_wind.ogg";
private HashSet<MovedByPressureComponent> _activePressures = new(8);
private void UpdateHighPressure(float frameTime)
{
var toRemove = new RemQueue<MovedByPressureComponent>();
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<MobStateComponent>(comp.Owner) &&
TryComp<PhysicsComponent>(comp.Owner, out var body))
{
body.BodyStatus = BodyStatus.OnGround;
}
if (TryComp<FixturesComponent>(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<FixturesComponent>(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<PhysicsComponent> bodies, EntityQuery<TransformComponent> xforms, EntityQuery<MovedByPressureComponent> pressureQuery) private void HighPressureMovements(GridAtmosphereComponent gridAtmosphere, TileAtmosphere tile, EntityQuery<PhysicsComponent> bodies, EntityQuery<TransformComponent> xforms, EntityQuery<MovedByPressureComponent> pressureQuery)
{ {
// TODO ATMOS finish this // TODO ATMOS finish this
@@ -37,15 +107,28 @@ namespace Content.Server.Atmos.EntitySystems
foreach (var entity in _lookup.GetEntitiesIntersecting(tile.GridIndex, tile.GridIndices)) 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<T> anyway. // Ideally containers would have their own EntityQuery internally or something given recursively it may need to slam GetComp<T> anyway.
if (!bodies.HasComponent(entity) // Also, don't care about static bodies (but also due to collisionwakestate can't query dynamic directly atm).
|| !pressureQuery.TryGetComponent(entity, out var pressure) || !pressure.Enabled if (!bodies.TryGetComponent(entity, out var body) ||
|| _containers.IsEntityInContainer(entity, xforms.GetComponent(entity))) !pressureQuery.TryGetComponent(entity, out var pressure) ||
!pressure.Enabled)
continue; continue;
var xform = xforms.GetComponent(entity);
if (_containers.IsEntityInContainer(entity, xform)) continue;
var pressureMovements = EnsureComp<MovedByPressureComponent>(entity); var pressureMovements = EnsureComp<MovedByPressureComponent>(entity);
if (pressure.LastHighPressureMovementAirCycle < gridAtmosphere.UpdateCounter) 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(); 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<MobStateComponent>(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;
}
}
}
} }
} }

View File

@@ -170,7 +170,7 @@ namespace Content.Server.Atmos.EntitySystems
foreach (var entity in _lookup.GetEntitiesIntersecting(tile.GridIndex, tile.GridIndices)) foreach (var entity in _lookup.GetEntitiesIntersecting(tile.GridIndex, tile.GridIndices))
{ {
RaiseLocalEvent(entity, fireEvent, false); RaiseLocalEvent(entity, ref fireEvent, false);
} }
} }
} }

View File

@@ -112,7 +112,7 @@ namespace Content.Server.Atmos.EntitySystems
AddActiveTile(atmosphere, tile); AddActiveTile(atmosphere, tile);
// TODO ATMOS: Query all the contents of this tile (like walls) and calculate the correct thermal conductivity and heat capacity // 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.ThermalConductivity = tileDef?.ThermalConductivity ?? 0.5f;
tile.HeatCapacity = tileDef?.HeatCapacity ?? float.PositiveInfinity; tile.HeatCapacity = tileDef?.HeatCapacity ?? float.PositiveInfinity;
InvalidateVisuals(mapGrid.Index, indices); InvalidateVisuals(mapGrid.Index, indices);

View File

@@ -1,18 +1,10 @@
using Content.Server.Administration;
using Content.Server.Administration.Logs; using Content.Server.Administration.Logs;
using Content.Server.Atmos.Components; using Content.Server.Atmos.Components;
using Content.Server.Database;
using Content.Server.NodeContainer.EntitySystems; 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.Atmos.EntitySystems;
using Content.Shared.Maps; using Content.Shared.Maps;
using JetBrains.Annotations; using JetBrains.Annotations;
using Robust.Shared.Console;
using Robust.Shared.Containers; using Robust.Shared.Containers;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Map; using Robust.Shared.Map;
namespace Content.Server.Atmos.EntitySystems namespace Content.Server.Atmos.EntitySystems
@@ -26,6 +18,7 @@ namespace Content.Server.Atmos.EntitySystems
[Dependency] private readonly IMapManager _mapManager = default!; [Dependency] private readonly IMapManager _mapManager = default!;
[Dependency] private readonly AdminLogSystem _adminLog = default!; [Dependency] private readonly AdminLogSystem _adminLog = default!;
[Dependency] private readonly SharedContainerSystem _containers = default!; [Dependency] private readonly SharedContainerSystem _containers = default!;
[Dependency] private readonly SharedPhysicsSystem _physics = default!;
private const float ExposedUpdateDelay = 1f; private const float ExposedUpdateDelay = 1f;
private float _exposedTimer = 0f; private float _exposedTimer = 0f;
@@ -77,6 +70,7 @@ namespace Content.Server.Atmos.EntitySystems
base.Update(frameTime); base.Update(frameTime);
UpdateProcessing(frameTime); UpdateProcessing(frameTime);
UpdateHighPressure(frameTime);
_exposedTimer += frameTime; _exposedTimer += frameTime;

View File

@@ -111,7 +111,7 @@ namespace Content.Server.Atmos.EntitySystems
args.IsHot = flammable.OnFire; 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; var tempDelta = args.Temperature - MinIgnitionTemperature;

View File

@@ -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<ApcPowerReceiverComponent>(uid, out var powerReceiverComponent) if (!TryComp<ApcPowerReceiverComponent>(uid, out var powerReceiverComponent)
|| !powerReceiverComponent.Powered) || !powerReceiverComponent.Powered)

View File

@@ -1,14 +1,13 @@
using Robust.Shared.GameObjects; namespace Content.Server.Atmos
namespace Content.Server.Atmos
{ {
/// <summary> /// <summary>
/// Event raised directed to an entity when it is standing on a tile that's on fire. /// Event raised directed to an entity when it is standing on a tile that's on fire.
/// </summary> /// </summary>
public sealed class TileFireEvent : EntityEventArgs [ByRefEvent]
public readonly struct TileFireEvent
{ {
public float Temperature { get; } public readonly float Temperature;
public float Volume { get; } public readonly float Volume;
public TileFireEvent(float temperature, float volume) public TileFireEvent(float temperature, float volume)
{ {