mirror of
https://github.com/WWhiteDreamProject/wwdpublic.git
synced 2026-04-18 14:07:53 +03:00
# Description This PR ports some fixes to the order of operations for air pressure processing, which will help fix issues with temperature not correctly diffusing, as well as errors in the order of operations processing that made it so that Space Wind was receiving wildly incorrect pressure values. Additionally, this fixes a math error that made it so that the diagonal airflows were contributing 41% more to airflows, making diagonal motion unusually harsh. There's still two more bugs I need to fix though.
192 lines
8.7 KiB
C#
192 lines
8.7 KiB
C#
using Content.Server.Atmos.Components;
|
|
using Content.Shared.Atmos;
|
|
using Content.Shared.Atmos.Components;
|
|
using Content.Shared.Humanoid;
|
|
using Content.Shared.Maps;
|
|
using Content.Shared.Projectiles;
|
|
using Content.Shared.Throwing;
|
|
using Robust.Shared.Audio;
|
|
using Robust.Shared.Map.Components;
|
|
using Robust.Shared.Physics;
|
|
using Robust.Shared.Physics.Components;
|
|
using Robust.Shared.Prototypes;
|
|
using System.Numerics;
|
|
|
|
namespace Content.Server.Atmos.EntitySystems;
|
|
|
|
public sealed partial class AtmosphereSystem
|
|
{
|
|
private EntProtoId _spaceWindProto = "SpaceWindVisual";
|
|
private readonly HashSet<Entity<MovedByPressureComponent>> _activePressures = new();
|
|
private void UpdateHighPressure(float frameTime)
|
|
{
|
|
foreach (var ent in _activePressures)
|
|
{
|
|
if (!ent.Comp.Throwing || _gameTiming.CurTime < ent.Comp.ThrowingCutoffTarget
|
|
|| !TryComp(ent.Owner, out PhysicsComponent? physics))
|
|
continue;
|
|
|
|
if (TryComp(ent.Owner, out ThrownItemComponent? thrown))
|
|
{
|
|
_thrown.LandComponent(ent.Owner, thrown, physics, true);
|
|
_thrown.StopThrow(ent.Owner, thrown);
|
|
}
|
|
|
|
_physics.SetBodyStatus(ent.Owner, physics, BodyStatus.OnGround);
|
|
_physics.SetSleepingAllowed(ent.Owner, physics, true);
|
|
|
|
ent.Comp.Throwing = false;
|
|
_activePressures.Remove(ent);
|
|
}
|
|
}
|
|
|
|
private void HighPressureMovements(Entity<GridAtmosphereComponent> gridAtmosphere,
|
|
TileAtmosphere tile,
|
|
EntityQuery<PhysicsComponent> bodies,
|
|
EntityQuery<TransformComponent> xforms,
|
|
EntityQuery<MovedByPressureComponent> pressureQuery,
|
|
EntityQuery<MetaDataComponent> metas,
|
|
EntityQuery<ProjectileComponent> projectileQuery,
|
|
double gravity)
|
|
{
|
|
var atmosComp = gridAtmosphere.Comp;
|
|
var oneAtmos = Atmospherics.OneAtmosphere;
|
|
|
|
// No atmos yeets, return early.
|
|
if (!SpaceWind
|
|
|| !gridAtmosphere.Comp.SpaceWindSimulation // Is the grid marked as exempt from space wind?)
|
|
|| tile.Space) // No Air Checks. Pressure differentials can't exist in a hard vacuum.
|
|
return;
|
|
|
|
var pressure = tile.AirArchived?.Pressure;
|
|
if (pressure is null
|
|
|| pressure <= atmosComp.PressureCutoff // Below 5kpa(can't throw a base item)
|
|
|| oneAtmos - atmosComp.PressureCutoff <= pressure
|
|
&& pressure <= oneAtmos + atmosComp.PressureCutoff // Check within 5kpa of default pressure.
|
|
|| !TryComp(gridAtmosphere.Owner, out MapGridComponent? mapGrid)
|
|
|| !_mapSystem.TryGetTileRef(gridAtmosphere.Owner, mapGrid, tile.GridIndices, out var tileRef))
|
|
return;
|
|
|
|
var tileDef = (ContentTileDefinition) _tileDefinitionManager[tileRef.Tile.TypeId];
|
|
if (!tileDef.SimulatedTurf)
|
|
return;
|
|
|
|
var partialFrictionComposition = gravity * tileDef.MobFrictionNoInput ?? 0.2f;
|
|
|
|
var pressureVector = GetPressureVectorFromTile(gridAtmosphere, tile);
|
|
if (!pressureVector.IsValid())
|
|
return;
|
|
tile.LastPressureDirection = pressureVector;
|
|
|
|
// Calculate this HERE so that we aren't running the square root of a whole Newton vector per item.
|
|
var pVecLength = pressureVector.Length();
|
|
if (pVecLength <= 1) // Then guard against extremely small vectors.
|
|
return;
|
|
|
|
pressureVector *= SpaceWindStrengthMultiplier;
|
|
|
|
if (SpaceWindVisuals && atmosComp.SpaceWindSoundCooldown == 0)
|
|
{
|
|
var location = _mapSystem.GridTileToLocal(gridAtmosphere.Owner, mapGrid, tile.GridIndices);
|
|
var visualEnt = SpawnAtPosition(_spaceWindProto, location);
|
|
_transformSystem.SetLocalRotation(visualEnt, pressureVector.ToAngle() - MathF.PI / 2);
|
|
}
|
|
|
|
if (pVecLength > 15 && !tile.Hotspot.Valid && atmosComp.SpaceWindSoundCooldown == 0)
|
|
{
|
|
var coordinates = _mapSystem.ToCenterCoordinates(tile.GridIndex, tile.GridIndices);
|
|
var volume = Math.Clamp(pVecLength / atmosComp.SpaceWindSoundDenominator, atmosComp.SpaceWindSoundMinVolume, atmosComp.SpaceWindSoundMaxVolume);
|
|
_audio.PlayPvs(atmosComp.SpaceWindSound, coordinates, AudioParams.Default.WithVariation(0.125f).WithVolume(volume));
|
|
}
|
|
|
|
if (atmosComp.SpaceWindSoundCooldown++ > atmosComp.SpaceWindSoundCooldownCycles)
|
|
atmosComp.SpaceWindSoundCooldown = 0;
|
|
|
|
// TODO: Deprecated for now, it sucks ass and I'm disassembling monstermos because it sucks. This'll be handled by Space Wind after I'm done whiteboarding better equations for it.
|
|
// - TCJ
|
|
// HandleDecompressionFloorRip(mapGrid, otherTile, otherTile.PressureDifference);
|
|
|
|
_entSet.Clear();
|
|
_lookup.GetLocalEntitiesIntersecting(tile.GridIndex, tile.GridIndices, _entSet, 0f);
|
|
|
|
foreach (var entity in _entSet)
|
|
{
|
|
// Ideally containers would have their own EntityQuery internally or something given recursively it may need to slam GetComp<T> anyway.
|
|
// 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 pressureComp)
|
|
|| !pressureComp.Enabled
|
|
|| _containers.IsEntityInContainer(entity, metas.GetComponent(entity))
|
|
|| pressureComp.LastHighPressureMovementAirCycle >= gridAtmosphere.Comp.UpdateCounter)
|
|
continue;
|
|
|
|
// tl;dr YEET
|
|
ExperiencePressureDifference(
|
|
(entity, pressureComp),
|
|
gridAtmosphere.Comp.UpdateCounter,
|
|
pressureVector,
|
|
pVecLength,
|
|
partialFrictionComposition,
|
|
projectileQuery,
|
|
xforms.GetComponent(entity),
|
|
body);
|
|
}
|
|
}
|
|
|
|
// Called from AtmosphereSystem.LINDA.cs with SpaceWind CVar check handled there.
|
|
private void ConsiderPressureDifference(GridAtmosphereComponent gridAtmosphere, TileAtmosphere tile) => gridAtmosphere.HighPressureDelta.Add(tile);
|
|
|
|
public void ExperiencePressureDifference(Entity<MovedByPressureComponent> ent,
|
|
int cycle,
|
|
Vector2 pressureVector,
|
|
float pVecLength,
|
|
double partialFrictionComposition,
|
|
EntityQuery<ProjectileComponent> projectileQuery,
|
|
TransformComponent? xform = null,
|
|
PhysicsComponent? physics = null)
|
|
{
|
|
var (uid, component) = ent;
|
|
if (!Resolve(uid, ref physics, false)
|
|
|| !Resolve(uid, ref xform)
|
|
|| physics.BodyType == BodyType.Static
|
|
|| physics.LinearVelocity.Length() >= SpaceWindMaxForce)
|
|
return;
|
|
|
|
var alwaysThrow = partialFrictionComposition == 0 || physics.BodyStatus == BodyStatus.InAir;
|
|
|
|
// Coefficient of static friction in Newtons (kg * m/s^2), which might not apply under certain conditions.
|
|
var coefficientOfFriction = partialFrictionComposition * physics.Mass;
|
|
coefficientOfFriction *= _standingSystem.IsDown(uid) ? 3 : 1;
|
|
|
|
if (TryComp(ent.Owner, out HumanoidAppearanceComponent? humanoidAppearance))
|
|
{
|
|
pressureVector *= HumanoidThrowMultiplier;
|
|
|
|
if (SpaceWindAllowKnockdown)
|
|
{
|
|
// Torque threshold for a humanoid shaped object is 1/3rd mass * height squared. Ignore the 3, it's not a magic number in this context.
|
|
// Same with 1.75f, we're quick and dirty shorthanding for the standard height of a human (in meters).
|
|
var heightSquared = MathF.Pow(humanoidAppearance.Height * 1.75f, 2);
|
|
var knockdownThreshold = heightSquared / 3;
|
|
if (knockdownThreshold <= pVecLength)
|
|
_sharedStunSystem.TryKnockdown(uid, TimeSpan.FromSeconds(SpaceWindKnockdownTime), true);
|
|
}
|
|
}
|
|
|
|
if (!alwaysThrow && pVecLength < coefficientOfFriction)
|
|
return;
|
|
|
|
// Yes this technically increases the magnitude by a small amount... I detest having to swap between "World" and "Local" vectors.
|
|
// ThrowingSystem increments linear velocity by a given vector, but we have to do this anyways because reasons.
|
|
var velocity = _transformSystem.GetWorldRotation(uid).ToWorldVec() + pressureVector;
|
|
|
|
_throwing.TryThrow(uid, velocity, physics, xform, projectileQuery,
|
|
1, doSpin: physics.AngularVelocity < SpaceWindMaxAngularVelocity);
|
|
|
|
component.LastHighPressureMovementAirCycle = cycle;
|
|
component.Throwing = true;
|
|
component.ThrowingCutoffTarget = _gameTiming.CurTime + component.CutoffTime;
|
|
_activePressures.Add(ent);
|
|
}
|
|
}
|