Порт атмоса с ЕЕ + пара фиксво (#491)
* fix a lot of spaces in shuttle call reason * fix tts fatal without api url * Physics Based Air Throws (#342) I've made it so that when a room is explosively depressurized(or when a body of high pressure air flows into one of lower pressure air), that entities inside are launched by the air pressure with effects according to their mass. An entity's mass is now used as an innate resistance to forced movement by airflow, and more massive entities are both less likely to be launched, and will launch less far than others. While lighter entities are launched far more easily, and will shoot off into space quite quickly! Spacing departments has never been so exciting! This can be made extraordinarily fun if more objects are given the ability to injure people when colliding with them at high speeds. As a note, Humans are very unlikely to be sucked into space at a typical force generated from a 101kpa room venting into 0kpa, unless they happened to be standing right next to the opening to space when it was created. The same cannot be said for "Lighter-Than-Human" species such as Felinids and Harpies. I guess that's just the price to pay for being cute. :) On a plus side, because the math behind this is simplified even further than it was before, this actually runs more efficiently than the previous system. Nothing, this is basically done. I've spent a good 6 hours straight finely tuning the system until I was satisfied that it reflects something close to reality. **Before the Space Wind Rework:** https://github.com/Simple-Station/Einstein-Engines/assets/16548818/0bf56c50-58e6-4aef-97f8-027fbe62331e **With this Rework:** https://github.com/Simple-Station/Einstein-Engines/assets/16548818/6be507a9-e9de-4bb8-9d46-8b7c83ed5f1d 🆑 VMSolidus - add: Atmospheric "Throws" are now calculated using object mass, and behave accordingly. Tiny objects will shoot out of rooms quite fast! --------- Signed-off-by: VMSolidus <evilexecutive@gmail.com> Co-authored-by: DEATHB4DEFEAT <77995199+DEATHB4DEFEAT@users.noreply.github.com> * fixes --------- Signed-off-by: VMSolidus <evilexecutive@gmail.com> Co-authored-by: VMSolidus <evilexecutive@gmail.com> Co-authored-by: DEATHB4DEFEAT <77995199+DEATHB4DEFEAT@users.noreply.github.com>
This commit is contained in:
@@ -12,9 +12,14 @@ namespace Content.Server.Atmos.EntitySystems
|
||||
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; }
|
||||
@@ -26,6 +31,7 @@ namespace Content.Server.Atmos.EntitySystems
|
||||
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
|
||||
@@ -41,9 +47,14 @@ namespace Content.Server.Atmos.EntitySystems
|
||||
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);
|
||||
@@ -55,6 +66,7 @@ namespace Content.Server.Atmos.EntitySystems
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
@@ -49,8 +50,7 @@ namespace Content.Server.Atmos.EntitySystems
|
||||
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);
|
||||
}
|
||||
@@ -70,27 +70,10 @@ namespace Content.Server.Atmos.EntitySystems
|
||||
}
|
||||
}
|
||||
|
||||
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...
|
||||
@@ -120,7 +103,8 @@ namespace Content.Server.Atmos.EntitySystems
|
||||
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.
|
||||
@@ -160,7 +144,7 @@ namespace Content.Server.Atmos.EntitySystems
|
||||
(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),
|
||||
@@ -181,12 +165,29 @@ namespace Content.Server.Atmos.EntitySystems
|
||||
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,
|
||||
EntityCoordinates throwTarget,
|
||||
Angle gridWorldRotation,
|
||||
TransformComponent? xform = null,
|
||||
@@ -199,50 +200,28 @@ namespace Content.Server.Atmos.EntitySystems
|
||||
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)
|
||||
{
|
||||
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;
|
||||
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;
|
||||
|
||||
@@ -5,11 +5,13 @@ using Content.Server.Doors.Systems;
|
||||
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
|
||||
@@ -137,7 +139,7 @@ namespace Content.Server.Atmos.EntitySystems
|
||||
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);
|
||||
@@ -550,7 +552,8 @@ namespace Content.Server.Atmos.EntitySystems
|
||||
}
|
||||
|
||||
InvalidateVisuals(ent, otherTile);
|
||||
HandleDecompressionFloorRip(mapGrid, otherTile, otherTile.MonstermosInfo.CurrentTransferAmount);
|
||||
if (MonstermosRipTiles && otherTile.PressureDifference > MonstermosRipTilesMinimumPressure)
|
||||
HandleDecompressionFloorRip(mapGrid, otherTile, otherTile.PressureDifference);
|
||||
}
|
||||
|
||||
if (GridImpulse && tileCount > 0)
|
||||
@@ -682,14 +685,14 @@ namespace Content.Server.Atmos.EntitySystems
|
||||
adj.MonstermosInfo[idx.ToOppositeDir()] -= 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);
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ using Content.Server.NodeContainer.EntitySystems;
|
||||
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;
|
||||
@@ -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;
|
||||
|
||||
@@ -171,8 +171,9 @@ public sealed class TemperatureSystem : EntitySystem
|
||||
{
|
||||
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)
|
||||
|
||||
@@ -63,9 +63,10 @@ public sealed class TTSManager
|
||||
{
|
||||
var url = _cfg.GetCVar(WhiteCVars.TtsApiUrl);
|
||||
var maxCacheSize = _cfg.GetCVar(WhiteCVars.TtsMaxCacheSize);
|
||||
if (string.IsNullOrWhiteSpace(url))
|
||||
if (string.IsNullOrWhiteSpace(url)) // zaebal padat
|
||||
{
|
||||
throw new Exception("TTS Api url not specified");
|
||||
_sawmill.Log(LogLevel.Error, nameof(TTSManager), "TTS Api url not specified");
|
||||
return null;
|
||||
}
|
||||
|
||||
WantedCount.Inc();
|
||||
@@ -193,4 +194,4 @@ public sealed class TTSManager
|
||||
[JsonPropertyName("audio")]
|
||||
public string Audio { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user