Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Physics Based Air Throws #342

Open
wants to merge 31 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
4212fbb
Physics based air throws
VMSolidus Apr 29, 2024
bddb87b
Update base_structureclosets.yml
VMSolidus Apr 29, 2024
162c284
Updates for review
VMSolidus Apr 29, 2024
3374757
Hello, this is an asymptote. Divide by zero must be an exit condition.
VMSolidus Apr 29, 2024
3dc71fb
Adding the clamp back in
VMSolidus Apr 29, 2024
b3c503c
I found another small optimization
VMSolidus May 1, 2024
68e0510
Another one
VMSolidus May 1, 2024
9e7aa5d
New Cvar
VMSolidus May 4, 2024
3d03262
Update comments for documentation
VMSolidus May 4, 2024
67fdaff
Apply suggestions from code review
VMSolidus May 6, 2024
6cc4704
MORE
VMSolidus May 16, 2024
54ca8ce
Update AtmosphereSystem.HighPressureDelta.cs
VMSolidus May 16, 2024
7500efd
guh, last push
VMSolidus May 16, 2024
3440636
Merge branch 'Simple-Station:master' into Atmos-optimization-test
VMSolidus May 16, 2024
7470ba7
Fix for objects getting stuck on walls, new CVar for more expensive a…
VMSolidus May 16, 2024
b328725
Update animals.yml
VMSolidus May 16, 2024
f7e2f70
Fix tiny mobs boiling themselves to death
VMSolidus May 16, 2024
53d221f
Merge branch 'master' into Atmos-optimization-test
VMSolidus May 29, 2024
eba2d1d
Merge branch 'master' into Atmos-optimization-test
VMSolidus May 29, 2024
7c1ba29
Merge branch 'master' into Atmos-optimization-test
VMSolidus Jun 11, 2024
9d81e24
Initial Beta for Rip Tile Rework
VMSolidus Jun 12, 2024
70a9345
Tentative fixes for wall quantum tunneling
VMSolidus Jun 12, 2024
4d1cf7d
More fixes
VMSolidus Jun 12, 2024
c9286a5
Update CCVars.cs
VMSolidus Jun 12, 2024
9c00871
Update CCVars.cs
VMSolidus Jun 12, 2024
adf3745
Apply suggestions from code review
VMSolidus Jun 16, 2024
351c4ec
Add System for making Humanoids get thrown harder
VMSolidus Jun 25, 2024
9b544bf
Update CCVars.cs
VMSolidus Jun 25, 2024
c9eadac
1984 move by pressure, reroute to ThrowingSystem because its more adv…
VMSolidus Jun 25, 2024
bc25b78
This is significantly smoother
VMSolidus Jun 25, 2024
c5946ee
Update AtmosphereSystem.HighPressureDelta.cs
VMSolidus Jul 2, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions Content.Server/Atmos/EntitySystems/AtmosphereSystem.CVars.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,14 @@ public sealed partial class AtmosphereSystem
public float SpaceWindPressureForceDivisorPush { get; private set; }
public float SpaceWindMaxVelocity { get; private set; }
public float SpaceWindMaxPushForce { get; private set; }
public float SpaceWindMinimumCalculatedMass { get; private set; }
public float SpaceWindMaximumCalculatedInverseMass { get; private set; }
public bool MonstermosUseExpensiveAirflow { get; private set; }
public bool MonstermosEqualization { get; private set; }
public bool MonstermosDepressurization { get; private set; }
public bool MonstermosRipTiles { get; private set; }
public float MonstermosRipTilesMinimumPressure { get; private set; }
public float MonstermosRipTilesPressureOffset { get; private set; }
public bool GridImpulse { get; private set; }
public float SpacingEscapeRatio { get; private set; }
public float SpacingMinGas { get; private set; }
Expand All @@ -26,6 +31,7 @@ public sealed partial class AtmosphereSystem
public float AtmosTickRate { get; private set; }
public float Speedup { get; private set; }
public float HeatScale { get; private set; }
public float HumanoidThrowMultiplier { get; private set; }

/// <summary>
/// Time between each atmos sub-update. If you are writing an atmos device, use AtmosDeviceUpdateEvent.dt
Expand All @@ -41,9 +47,14 @@ private void InitializeCVars()
Subs.CVar(_cfg, CCVars.SpaceWindPressureForceDivisorPush, value => SpaceWindPressureForceDivisorPush = value, true);
Subs.CVar(_cfg, CCVars.SpaceWindMaxVelocity, value => SpaceWindMaxVelocity = value, true);
Subs.CVar(_cfg, CCVars.SpaceWindMaxPushForce, value => SpaceWindMaxPushForce = value, true);
Subs.CVar(_cfg, CCVars.SpaceWindMinimumCalculatedMass, value => SpaceWindMinimumCalculatedMass = value, true);
Subs.CVar(_cfg, CCVars.SpaceWindMaximumCalculatedInverseMass, value => SpaceWindMaximumCalculatedInverseMass = value, true);
Subs.CVar(_cfg, CCVars.MonstermosUseExpensiveAirflow, value => MonstermosUseExpensiveAirflow = value, true);
Subs.CVar(_cfg, CCVars.MonstermosEqualization, value => MonstermosEqualization = value, true);
Subs.CVar(_cfg, CCVars.MonstermosDepressurization, value => MonstermosDepressurization = value, true);
Subs.CVar(_cfg, CCVars.MonstermosRipTiles, value => MonstermosRipTiles = value, true);
Subs.CVar(_cfg, CCVars.MonstermosRipTilesMinimumPressure, value => MonstermosRipTilesMinimumPressure = value, true);
Subs.CVar(_cfg, CCVars.MonstermosRipTilesPressureOffset, value => MonstermosRipTilesPressureOffset = value, true);
Subs.CVar(_cfg, CCVars.AtmosGridImpulse, value => GridImpulse = value, true);
Subs.CVar(_cfg, CCVars.AtmosSpacingEscapeRatio, value => SpacingEscapeRatio = value, true);
Subs.CVar(_cfg, CCVars.AtmosSpacingMinGas, value => SpacingMinGas = value, true);
Expand All @@ -55,6 +66,7 @@ private void InitializeCVars()
Subs.CVar(_cfg, CCVars.AtmosHeatScale, value => { HeatScale = value; InitializeGases(); }, true);
Subs.CVar(_cfg, CCVars.ExcitedGroups, value => ExcitedGroups = value, true);
Subs.CVar(_cfg, CCVars.ExcitedGroupsSpaceIsAllConsuming, value => ExcitedGroupsSpaceIsAllConsuming = value, true);
Subs.CVar(_cfg, CCVars.AtmosHumanoidThrowMultiplier, value => HumanoidThrowMultiplier = value, true);
}
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using Content.Server.Atmos.Components;
using Content.Shared.Atmos;
using Content.Shared.Humanoid;
using Content.Shared.Mobs.Components;
using Content.Shared.Physics;
using Robust.Shared.Audio;
Expand Down Expand Up @@ -49,8 +50,7 @@ private void UpdateHighPressure(float frameTime)
comp.Accumulator = 0f;
toRemove.Add(ent);

if (HasComp<MobStateComponent>(uid) &&
TryComp<PhysicsComponent>(uid, out var body))
if (TryComp<PhysicsComponent>(uid, out var body))
{
_physics.SetBodyStatus(uid, body, BodyStatus.OnGround);
}
Expand All @@ -70,27 +70,10 @@ private void UpdateHighPressure(float frameTime)
}
}

private void AddMobMovedByPressure(EntityUid uid, MovedByPressureComponent component, PhysicsComponent body)
{
if (!TryComp<FixturesComponent>(uid, out var fixtures))
return;

_physics.SetBodyStatus(uid, body, BodyStatus.InAir);

foreach (var (id, fixture) in fixtures.Fixtures)
{
_physics.RemoveCollisionMask(uid, id, fixture, (int) CollisionGroup.TableLayer, manager: fixtures);
}

// 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((uid, component));
}

private void HighPressureMovements(Entity<GridAtmosphereComponent> gridAtmosphere, TileAtmosphere tile, EntityQuery<PhysicsComponent> bodies, EntityQuery<TransformComponent> xforms, EntityQuery<MovedByPressureComponent> pressureQuery, EntityQuery<MetaDataComponent> metas)
{
if (tile.PressureDifference < SpaceWindMinimumCalculatedMass * SpaceWindMinimumCalculatedMass)
return;
// TODO ATMOS finish this

// Don't play the space wind sound on tiles that are on fire...
Expand Down Expand Up @@ -120,7 +103,8 @@ private void HighPressureMovements(Entity<GridAtmosphereComponent> gridAtmospher
var gridWorldRotation = xforms.GetComponent(gridAtmosphere).WorldRotation;

// If we're using monstermos, smooth out the yeet direction to follow the flow
if (MonstermosEqualization)
//TODO This is bad, don't run this. It just makes the throws worse by somehow rounding them to orthogonal
if (!MonstermosEqualization)
{
// We step through tiles according to the pressure direction on the current tile.
// The goal is to get a general direction of the airflow in the area.
Expand Down Expand Up @@ -160,7 +144,7 @@ private void HighPressureMovements(Entity<GridAtmosphereComponent> gridAtmospher
(entity, pressureMovements),
gridAtmosphere.Comp.UpdateCounter,
tile.PressureDifference,
tile.PressureDirection, 0,
tile.PressureDirection,
tile.PressureSpecificTarget != null ? _mapSystem.ToCenterCoordinates(tile.GridIndex, tile.PressureSpecificTarget.GridIndices) : EntityCoordinates.Invalid,
gridWorldRotation,
xforms.GetComponent(entity),
Expand All @@ -181,12 +165,29 @@ private void ConsiderPressureDifference(GridAtmosphereComponent gridAtmosphere,
tile.PressureDirection = differenceDirection;
}

//INFO The EE version of this function drops pressureResistanceProbDelta, since it's not needed. If you are for whatever reason calling this function
//INFO And if it isn't working, you've probably still got the pressureResistanceProbDelta line included.
/// <notes>
/// EXPLANATION:
/// pressureDifference = Force of Air Flow on a given tile
/// physics.Mass = Mass of the object potentially being thrown
/// physics.InvMass = 1 divided by said Mass. More CPU efficient way to do division.
///
/// Objects can only be thrown if the force of air flow is greater than the SQUARE of their mass or {SpaceWindMinimumCalculatedMass}, whichever is heavier
/// This means that the heavier an object is, the exponentially more force is required to move it
/// The force of a throw is equal to the force of air pressure, divided by an object's mass. So not only are heavier objects
/// less likely to be thrown, they are also harder to throw,
/// while lighter objects are yeeted easily, and from great distance.
///
/// For a human sized entity with a standard weight of 80kg and a spacing between a hard vacuum and a room pressurized at 101kpa,
/// The human shall only be moved if he is either very close to the hole, or is standing in a region of high airflow
/// </notes>

public void ExperiencePressureDifference(
Entity<MovedByPressureComponent> ent,
int cycle,
float pressureDifference,
AtmosDirection direction,
float pressureResistanceProbDelta,
VMSolidus marked this conversation as resolved.
Show resolved Hide resolved
EntityCoordinates throwTarget,
Angle gridWorldRotation,
TransformComponent? xform = null,
Expand All @@ -199,50 +200,28 @@ private void ConsiderPressureDifference(GridAtmosphereComponent gridAtmosphere,
if (!Resolve(uid, 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 (physics.BodyType != BodyType.Static
&& !float.IsPositiveInfinity(component.MoveResist))
{
if (HasComp<MobStateComponent>(uid))
var moveForce = pressureDifference * MathF.Max(physics.InvMass, SpaceWindMaximumCalculatedInverseMass);
if (HasComp<HumanoidAppearanceComponent>(ent))
moveForce *= HumanoidThrowMultiplier;
if (moveForce > physics.Mass)
{
AddMobMovedByPressure(uid, component, physics);
}

if (maxForce > MovedByPressureComponent.ThrowForce)
VMSolidus marked this conversation as resolved.
Show resolved Hide resolved
{
var moveForce = maxForce;
moveForce /= (throwTarget != EntityCoordinates.Invalid) ? SpaceWindPressureForceDivisorThrow : SpaceWindPressureForceDivisorPush;
moveForce *= MathHelper.Clamp(moveProb, 0, 100);

// Apply a sanity clamp to prevent being thrown through objects.
var maxSafeForceForObject = SpaceWindMaxVelocity * physics.Mass;
VMSolidus marked this conversation as resolved.
Show resolved Hide resolved
moveForce = MathF.Min(moveForce, maxSafeForceForObject);

// Grid-rotation adjusted direction
var dirVec = (direction.ToAngle() + gridWorldRotation).ToWorldVec();
moveForce *= MathF.Max(physics.InvMass, SpaceWindMaximumCalculatedInverseMass);

// TODO: Technically these directions won't be correct but uhh I'm just here for optimisations buddy not to fix my old bugs.
//TODO Consider replacing throw target with proper trigonometry angles.
if (throwTarget != EntityCoordinates.Invalid)
{
var pos = ((throwTarget.ToMap(EntityManager, _transformSystem).Position - xform.WorldPosition).Normalized() + dirVec).Normalized();
_physics.ApplyLinearImpulse(uid, pos * moveForce, body: physics);
var pos = throwTarget.ToMap(EntityManager, _transformSystem).Position - xform.WorldPosition + dirVec;
_throwing.TryThrow(uid, pos.Normalized() * MathF.Min(moveForce, SpaceWindMaxVelocity), moveForce);
}
else
{
moveForce = MathF.Min(moveForce, SpaceWindMaxPushForce);
_physics.ApplyLinearImpulse(uid, dirVec * moveForce, body: physics);
_throwing.TryThrow(uid, dirVec.Normalized() * MathF.Min(moveForce, SpaceWindMaxVelocity), moveForce);
}

component.LastHighPressureMovementAirCycle = cycle;
Expand Down
19 changes: 11 additions & 8 deletions Content.Server/Atmos/EntitySystems/AtmosphereSystem.Monstermos.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,13 @@
using Content.Shared.Atmos;
using Content.Shared.Atmos.Components;
using Content.Shared.Database;
using Content.Shared.Maps;
using Robust.Shared.Map;
using Robust.Shared.Map.Components;
using Robust.Shared.Physics.Components;
using Robust.Shared.Prototypes;
using Robust.Shared.Random;
using Robust.Shared.Utility;

namespace Content.Server.Atmos.EntitySystems
{
public sealed partial class AtmosphereSystem
Expand Down Expand Up @@ -137,7 +139,7 @@ public sealed partial class AtmosphereSystem
var logN = MathF.Log2(tileCount);

// Optimization - try to spread gases using an O(n log n) algorithm that has a chance of not working first to avoid O(n^2)
if (giverTilesLength > logN && takerTilesLength > logN)
if (!MonstermosUseExpensiveAirflow && giverTilesLength > logN && takerTilesLength > logN)
{
// Even if it fails, it will speed up the next part.
Array.Sort(_equalizeTiles, 0, tileCount, _monstermosComparer);
Expand Down Expand Up @@ -550,7 +552,8 @@ public sealed partial class AtmosphereSystem
}

InvalidateVisuals(otherTile.GridIndex, otherTile.GridIndices, visuals);
HandleDecompressionFloorRip(mapGrid, otherTile, otherTile.MonstermosInfo.CurrentTransferAmount);
if (MonstermosRipTiles && otherTile.PressureDifference > MonstermosRipTilesMinimumPressure)
HandleDecompressionFloorRip(mapGrid, otherTile, otherTile.PressureDifference);
}

if (GridImpulse && tileCount > 0)
Expand Down Expand Up @@ -676,14 +679,14 @@ private void AdjustEqMovement(TileAtmosphere tile, AtmosDirection direction, flo
adj.MonstermosInfo[direction.GetOpposite()] -= amount;
}

private void HandleDecompressionFloorRip(MapGridComponent mapGrid, TileAtmosphere tile, float sum)
private void HandleDecompressionFloorRip(MapGridComponent mapGrid, TileAtmosphere tile, float delta)
{
if (!MonstermosRipTiles)
if (!mapGrid.TryGetTileRef(tile.GridIndices, out var tileRef))
return;
var tileref = tileRef.Tile;

var chance = MathHelper.Clamp(0.01f + (sum / SpacingMaxWind) * 0.3f, 0.003f, 0.3f);

if (sum > 20 && _robustRandom.Prob(chance))
var tileDef = (ContentTileDefinition) _tileDefinitionManager[tileref.TypeId];
if (!tileDef.Reinforced && tileDef.TileRipResistance < delta * MonstermosRipTilesPressureOffset)
PryTile(mapGrid, tile.GridIndices);
}

Expand Down
2 changes: 2 additions & 0 deletions Content.Server/Atmos/EntitySystems/AtmosphereSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using Content.Shared.Atmos.EntitySystems;
using Content.Shared.Doors.Components;
using Content.Shared.Maps;
using Content.Shared.Throwing;
using JetBrains.Annotations;
using Robust.Server.GameObjects;
using Robust.Shared.Audio.Systems;
Expand Down Expand Up @@ -37,6 +38,7 @@ public sealed partial class AtmosphereSystem : SharedAtmosphereSystem
[Dependency] private readonly TileSystem _tile = default!;
[Dependency] private readonly MapSystem _map = default!;
[Dependency] public readonly PuddleSystem Puddle = default!;
[Dependency] private readonly ThrowingSystem _throwing = default!;

private const float ExposedUpdateDelay = 1f;
private float _exposedTimer = 0f;
Expand Down
5 changes: 3 additions & 2 deletions Content.Server/Temperature/Systems/TemperatureSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -163,8 +163,9 @@ public float GetHeatCapacity(EntityUid uid, TemperatureComponent? comp = null, P
{
return Atmospherics.MinimumHeatCapacity;
}

return comp.SpecificHeat * physics.FixturesMass;
if (physics.Mass < 1)
return comp.SpecificHeat;
else return comp.SpecificHeat * physics.FixturesMass;
}

private void OnInit(EntityUid uid, InternalTemperatureComponent comp, MapInitEvent args)
Expand Down
Loading
Loading