From 914d0f025150c82e017324ab2e9d25832e7d74ed Mon Sep 17 00:00:00 2001 From: VMSolidus Date: Mon, 20 Jan 2025 18:08:30 -0500 Subject: [PATCH 1/2] Port And Fix Wizden PR23372 --- .../Components/GravityWellComponent.cs | 12 +++ .../EntitySystems/EventHorizonSystem.cs | 16 +++- .../EntitySystems/GravityWellSystem.cs | 78 +++++++++++++------ .../Components/EventHorizonComponent.cs | 6 ++ .../Generation/Singularity/singularity.yml | 6 +- .../Power/Generation/Tesla/energyball.yml | 2 +- 6 files changed, 91 insertions(+), 29 deletions(-) diff --git a/Content.Server/Singularity/Components/GravityWellComponent.cs b/Content.Server/Singularity/Components/GravityWellComponent.cs index 58a314fa8bb..f16327ad1a8 100644 --- a/Content.Server/Singularity/Components/GravityWellComponent.cs +++ b/Content.Server/Singularity/Components/GravityWellComponent.cs @@ -67,5 +67,17 @@ public sealed partial class GravityWellComponent : Component [Access(typeof(GravityWellSystem))] public TimeSpan LastPulseTime { get; internal set; } = default!; + /// + /// Whether to also apply Newton's third law. + /// + [DataField] + public bool ApplyCounterforce; + + /// + /// If is true, how much to pull self to static objects. Does not pull static objects if null. + /// + [DataField] + public float? StaticAttraction = null; + #endregion Update Timing } diff --git a/Content.Server/Singularity/EntitySystems/EventHorizonSystem.cs b/Content.Server/Singularity/EntitySystems/EventHorizonSystem.cs index e57a59475f2..157e8258c61 100644 --- a/Content.Server/Singularity/EntitySystems/EventHorizonSystem.cs +++ b/Content.Server/Singularity/EntitySystems/EventHorizonSystem.cs @@ -11,9 +11,11 @@ using Robust.Shared.Containers; using Robust.Shared.Map; using Robust.Shared.Map.Components; +using Robust.Shared.Physics.Components; using Robust.Shared.Physics.Events; +using Robust.Shared.Physics.Systems; using Robust.Shared.Timing; -using Content.Shared.Abilities.Psionics; //Nyano - Summary: for the telegnostic projection. +using Content.Shared.Abilities.Psionics; namespace Content.Server.Singularity.EntitySystems; @@ -29,6 +31,7 @@ public sealed class EventHorizonSystem : SharedEventHorizonSystem [Dependency] private readonly IMapManager _mapMan = default!; [Dependency] private readonly IAdminLogManager _adminLogger = default!; [Dependency] private readonly SharedContainerSystem _containerSystem = default!; + [Dependency] private readonly SharedPhysicsSystem _physics = default!; [Dependency] private readonly SharedTransformSystem _xformSystem = default!; [Dependency] private readonly TagSystem _tagSystem = default!; #endregion Dependencies @@ -39,7 +42,7 @@ public override void Initialize() SubscribeLocalEvent(PreventConsume); SubscribeLocalEvent(PreventConsume); - SubscribeLocalEvent(PreventConsume); ///Nyano - Summary: the telegnositic projection has the same trait as ghosts. + SubscribeLocalEvent(PreventConsume); ///Nyano - Summary: the telegnositic projection has the same trait as ghosts. SubscribeLocalEvent(PreventConsume); SubscribeLocalEvent(OnHorizonMapInit); SubscribeLocalEvent(OnStartCollide); @@ -127,6 +130,15 @@ public void ConsumeEntity(EntityUid hungry, EntityUid morsel, EventHorizonCompon } EntityManager.QueueDeleteEntity(morsel); + + if (eventHorizon.InheritMomentum && TryComp(hungry, out var thisPhysics) && TryComp(morsel, out var otherPhysics)) + { + var impulse = (otherPhysics.LinearVelocity - thisPhysics.LinearVelocity) + * otherPhysics.FixturesMass + * thisPhysics.FixturesMass / (thisPhysics.FixturesMass + otherPhysics.FixturesMass); // accounts for the expected mass change from consuming the object + _physics.ApplyLinearImpulse(hungry, impulse, body: thisPhysics); + } + var evSelf = new EntityConsumedByEventHorizonEvent(morsel, hungry, eventHorizon, outerContainer); var evEaten = new EventHorizonConsumedEntityEvent(morsel, hungry, eventHorizon, outerContainer); RaiseLocalEvent(hungry, ref evSelf); diff --git a/Content.Server/Singularity/EntitySystems/GravityWellSystem.cs b/Content.Server/Singularity/EntitySystems/GravityWellSystem.cs index f53d658ebd7..d0df7d7a209 100644 --- a/Content.Server/Singularity/EntitySystems/GravityWellSystem.cs +++ b/Content.Server/Singularity/EntitySystems/GravityWellSystem.cs @@ -99,7 +99,10 @@ private void Update(EntityUid uid, TimeSpan frameTime, GravityWellComponent? gra return; var scale = (float)frameTime.TotalSeconds; - GravPulse(uid, gravWell.MaxRange, gravWell.MinRange, gravWell.BaseRadialAcceleration * scale, gravWell.BaseTangentialAcceleration * scale, xform); + GravPulse(uid, out var appliedImpulse, gravWell.MaxRange, gravWell.MinRange, gravWell.BaseRadialAcceleration * scale, gravWell.BaseTangentialAcceleration * scale, xform, gravWell.StaticAttraction); + + if (gravWell.ApplyCounterforce && TryComp(uid, out var physics)) + _physics.ApplyLinearImpulse(uid, -appliedImpulse, body: physics); } #region GravPulse @@ -123,29 +126,36 @@ private bool CanGravPulseAffect(EntityUid entity) /// Greates a gravitational pulse, shoving around all entities within some distance of an epicenter. /// /// The entity at the epicenter of the gravity pulse. + /// The state of the gravity well that is pulsing. /// The maximum distance at which entities can be affected by the gravity pulse. /// The minimum distance at which entities can be affected by the gravity pulse. /// The base velocity added to any entities within affected by the gravity pulse scaled by the displacement of those entities from the epicenter. /// (optional) The transform of the entity at the epicenter of the gravitational pulse. - public void GravPulse(EntityUid uid, float maxRange, float minRange, in Matrix3x2 baseMatrixDeltaV, TransformComponent? xform = null) + public void GravPulse(EntityUid uid, out Vector2 appliedImpulse, float maxRange, float minRange, in Matrix3x2 baseMatrixDeltaV, TransformComponent? xform = null, float? staticImpulse = null) { if (Resolve(uid, ref xform)) - GravPulse(xform.Coordinates, maxRange, minRange, in baseMatrixDeltaV); + GravPulse(uid, out appliedImpulse, xform.Coordinates, maxRange, minRange, in baseMatrixDeltaV, staticImpulse); + else + appliedImpulse = new Vector2(0f, 0f); } + /// /// Greates a gravitational pulse, shoving around all entities within some distance of an epicenter. /// /// The entity at the epicenter of the gravity pulse. + /// The state of the gravity well that is pulsing. /// The maximum distance at which entities can be affected by the gravity pulse. /// The minimum distance at which entities can be affected by the gravity pulse. /// The base radial velocity that will be added to entities within range towards the center of the gravitational pulse. /// The base tangential velocity that will be added to entities within countrclockwise around the center of the gravitational pulse. /// (optional) The transform of the entity at the epicenter of the gravitational pulse. - public void GravPulse(EntityUid uid, float maxRange, float minRange, float baseRadialDeltaV = 0.0f, float baseTangentialDeltaV = 0.0f, TransformComponent? xform = null) + public void GravPulse(EntityUid uid, out Vector2 appliedImpulse, float maxRange, float minRange, float baseRadialDeltaV = 0.0f, float baseTangentialDeltaV = 0.0f, TransformComponent? xform = null, float? staticImpulse = null) { if (Resolve(uid, ref xform)) - GravPulse(xform.Coordinates, maxRange, minRange, baseRadialDeltaV, baseTangentialDeltaV); + GravPulse(uid, out appliedImpulse, xform.Coordinates, maxRange, minRange, baseRadialDeltaV, baseTangentialDeltaV, staticImpulse); + else + appliedImpulse = new Vector2(0f, 0f); } /// @@ -155,8 +165,8 @@ public void GravPulse(EntityUid uid, float maxRange, float minRange, float baseR /// The maximum distance at which entities can be affected by the gravity pulse. /// The minimum distance at which entities can be affected by the gravity pulse. /// The base velocity added to any entities within affected by the gravity pulse scaled by the displacement of those entities from the epicenter. - public void GravPulse(EntityCoordinates entityPos, float maxRange, float minRange, in Matrix3x2 baseMatrixDeltaV) - => GravPulse(entityPos.ToMap(EntityManager, _transform), maxRange, minRange, in baseMatrixDeltaV); + public void GravPulse(EntityUid uid, out Vector2 appliedImpulse, EntityCoordinates entityPos, float maxRange, float minRange, in Matrix3x2 baseMatrixDeltaV, float? staticImpulse = null) + => GravPulse(uid, out appliedImpulse, _transform.ToMapCoordinates(entityPos), maxRange, minRange, in baseMatrixDeltaV, staticImpulse); /// /// Greates a gravitational pulse, shoving around all entities within some distance of an epicenter. @@ -166,18 +176,22 @@ public void GravPulse(EntityCoordinates entityPos, float maxRange, float minRang /// The minimum distance at which entities can be affected by the gravity pulse. /// The base radial velocity that will be added to entities within range towards the center of the gravitational pulse. /// The base tangential velocity that will be added to entities within countrclockwise around the center of the gravitational pulse. - public void GravPulse(EntityCoordinates entityPos, float maxRange, float minRange, float baseRadialDeltaV = 0.0f, float baseTangentialDeltaV = 0.0f) - => GravPulse(entityPos.ToMap(EntityManager, _transform), maxRange, minRange, baseRadialDeltaV, baseTangentialDeltaV); + public void GravPulse(EntityUid uid, out Vector2 appliedImpulse, EntityCoordinates entityPos, float maxRange, float minRange, float baseRadialDeltaV = 0.0f, float baseTangentialDeltaV = 0.0f, float? staticImpulse = null) + => GravPulse(uid, out appliedImpulse, _transform.ToMapCoordinates(entityPos), maxRange, minRange, baseRadialDeltaV, baseTangentialDeltaV, staticImpulse); /// /// Causes a gravitational pulse, shoving around all entities within some distance of an epicenter. /// + /// The entity at the epicenter of the gravity pulse. + /// The state of the gravity well that is pulsing. /// The epicenter of the gravity pulse. /// The maximum distance at which entities can be affected by the gravity pulse. /// The minimum distance at which entities can be affected by the gravity pulse. Exists to prevent div/0 errors. /// The base velocity added to any entities within affected by the gravity pulse scaled by the displacement of those entities from the epicenter. - public void GravPulse(MapCoordinates mapPos, float maxRange, float minRange, in Matrix3x2 baseMatrixDeltaV) + public void GravPulse(EntityUid uid, out Vector2 appliedImpulse, MapCoordinates mapPos, float maxRange, float minRange, in Matrix3x2 baseMatrixDeltaV, float? staticImpulse = null) { + appliedImpulse = new Vector2(0f, 0f); + if (mapPos == MapCoordinates.Nullspace) return; // No gravpulses in nullspace please. @@ -186,43 +200,57 @@ public void GravPulse(MapCoordinates mapPos, float maxRange, float minRange, in var bodyQuery = GetEntityQuery(); var xformQuery = GetEntityQuery(); - foreach(var entity in _lookup.GetEntitiesInRange(mapPos.MapId, epicenter, maxRange, flags: LookupFlags.Dynamic | LookupFlags.Sundries)) + var countStatic = staticImpulse is not null; + + var flags = LookupFlags.Dynamic | LookupFlags.Sundries; + if (countStatic) + flags |= LookupFlags.Static; + + foreach(var entity in _lookup.GetEntitiesInRange(mapPos.MapId, epicenter, maxRange, flags: flags)) { - if (!bodyQuery.TryGetComponent(entity, out var physics) - || physics.BodyType == BodyType.Static) - { + if (!bodyQuery.TryGetComponent(entity, out var physics)) continue; - } - - if (TryComp(entity, out var movedPressure) && !movedPressure.Enabled) //Ignore magboots users + bool isStatic = physics.BodyType == BodyType.Static; + if (!countStatic && isStatic) continue; - if(!CanGravPulseAffect(entity)) + if (!CanGravPulseAffect(entity)) continue; + isStatic |= TryComp(entity, out var movedPressure) && !movedPressure.Enabled; //Treat magboots users as static + var displacement = epicenter - _transform.GetWorldPosition(entity, xformQuery); var distance2 = displacement.LengthSquared(); if (distance2 < minRange2) continue; - var scaling = (1f / distance2) * physics.Mass; // TODO: Variable falloff gradiants. - _physics.ApplyLinearImpulse(entity, Vector2.Transform(displacement, baseMatrixDeltaV) * scaling, body: physics); + var scaling = (1f / distance2) * physics.FixturesMass; // TODO: Variable falloff gradiants. + if (isStatic) + scaling *= staticImpulse ?? 1f; + + var impulse = Vector2.Transform(displacement, baseMatrixDeltaV) * scaling; + if (!isStatic) // impulse shouldn't be applied to static entities + _physics.ApplyLinearImpulse(entity, impulse, body: physics); + + appliedImpulse += impulse; } } /// /// Causes a gravitational pulse, shoving around all entities within some distance of an epicenter. /// + /// The entity at the epicenter of the gravity pulse. + /// The state of the gravity well that is pulsing. /// The epicenter of the gravity pulse. /// The maximum distance at which entities can be affected by the gravity pulse. /// The minimum distance at which entities can be affected by the gravity pulse. Exists to prevent div/0 errors. /// The base amount of velocity that will be added to entities in range towards the epicenter of the pulse. /// The base amount of velocity that will be added to entities in range counterclockwise relative to the epicenter of the pulse. - public void GravPulse(MapCoordinates mapPos, float maxRange, float minRange = 0.0f, float baseRadialDeltaV = 0.0f, float baseTangentialDeltaV = 0.0f) - => GravPulse(mapPos, maxRange, minRange, new Matrix3x2( - baseRadialDeltaV, -baseTangentialDeltaV, 0.0f, - +baseTangentialDeltaV, baseRadialDeltaV, 0.0f - )); + public void GravPulse(EntityUid uid, out Vector2 appliedImpulse, MapCoordinates mapPos, float maxRange, float minRange = 0.0f, float baseRadialDeltaV = 0.0f, float baseTangentialDeltaV = 0.0f, float? staticImpulse = null) + => GravPulse(uid, out appliedImpulse, mapPos, maxRange, minRange, new Matrix3x2( + baseRadialDeltaV, +baseTangentialDeltaV, 0.0f, + -baseTangentialDeltaV, baseRadialDeltaV, 0.0f + ), staticImpulse); #endregion GravPulse diff --git a/Content.Shared/Singularity/Components/EventHorizonComponent.cs b/Content.Shared/Singularity/Components/EventHorizonComponent.cs index 106d790ccb6..22c80cce6ad 100644 --- a/Content.Shared/Singularity/Components/EventHorizonComponent.cs +++ b/Content.Shared/Singularity/Components/EventHorizonComponent.cs @@ -81,5 +81,11 @@ public sealed partial class EventHorizonComponent : Component [AutoPausedField] public TimeSpan NextConsumeWaveTime; + /// + /// Whether to inherit the momentum of consumed objects. + /// + [DataField] + public bool InheritMomentum; + #endregion Update Timing } diff --git a/Resources/Prototypes/Entities/Structures/Power/Generation/Singularity/singularity.yml b/Resources/Prototypes/Entities/Structures/Power/Generation/Singularity/singularity.yml index b8d66c61e38..39a5c97c320 100644 --- a/Resources/Prototypes/Entities/Structures/Power/Generation/Singularity/singularity.yml +++ b/Resources/Prototypes/Entities/Structures/Power/Generation/Singularity/singularity.yml @@ -17,11 +17,14 @@ - type: EventHorizon # To make the singularity consume things. radius: 0.5 canBreachContainment: false + inheritMomentum: true colliderFixtureId: EventHorizonCollider consumerFixtureId: EventHorizonConsumer - type: GravityWell # To make the singularity attract things. baseRadialAcceleration: 10 maxRange: 4 + applyCounterforce: true + staticAttraction: 0.3 - type: Fixtures fixtures: EventHorizonCollider: @@ -30,7 +33,7 @@ radius: 0.35 hard: true restitution: 0.8 - density: 99999 + density: 2000 mask: - AllMask layer: @@ -52,6 +55,7 @@ - type: RandomWalk # To make the singularity move around. maxSpeed: 2.5 minSpeed: 1.875 + accumulatorRatio: 0.7 - type: SingularityDistortion falloffPower: 2.529822 intensity: 3645 diff --git a/Resources/Prototypes/Entities/Structures/Power/Generation/Tesla/energyball.yml b/Resources/Prototypes/Entities/Structures/Power/Generation/Tesla/energyball.yml index 1cfdb9256a5..228285094d2 100644 --- a/Resources/Prototypes/Entities/Structures/Power/Generation/Tesla/energyball.yml +++ b/Resources/Prototypes/Entities/Structures/Power/Generation/Tesla/energyball.yml @@ -46,7 +46,7 @@ radius: 0.55 hard: true restitution: 0.8 - density: 99999 + density: 2000 mask: - Opaque layer: From 0653462957beab61edb4cf932004971b0a3153ae Mon Sep 17 00:00:00 2001 From: VMSolidus Date: Mon, 20 Jan 2025 18:28:14 -0500 Subject: [PATCH 2/2] Apply suggestions from code review Co-authored-by: DEATHB4DEFEAT <77995199+DEATHB4DEFEAT@users.noreply.github.com> Signed-off-by: VMSolidus --- .../Singularity/EntitySystems/EventHorizonSystem.cs | 4 ++-- .../Singularity/EntitySystems/GravityWellSystem.cs | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Content.Server/Singularity/EntitySystems/EventHorizonSystem.cs b/Content.Server/Singularity/EntitySystems/EventHorizonSystem.cs index 157e8258c61..a7ac664f9ed 100644 --- a/Content.Server/Singularity/EntitySystems/EventHorizonSystem.cs +++ b/Content.Server/Singularity/EntitySystems/EventHorizonSystem.cs @@ -134,8 +134,8 @@ public void ConsumeEntity(EntityUid hungry, EntityUid morsel, EventHorizonCompon if (eventHorizon.InheritMomentum && TryComp(hungry, out var thisPhysics) && TryComp(morsel, out var otherPhysics)) { var impulse = (otherPhysics.LinearVelocity - thisPhysics.LinearVelocity) - * otherPhysics.FixturesMass - * thisPhysics.FixturesMass / (thisPhysics.FixturesMass + otherPhysics.FixturesMass); // accounts for the expected mass change from consuming the object + * otherPhysics.FixturesMass + * thisPhysics.FixturesMass / (thisPhysics.FixturesMass + otherPhysics.FixturesMass); // Accounts for the expected mass change from consuming the object _physics.ApplyLinearImpulse(hungry, impulse, body: thisPhysics); } diff --git a/Content.Server/Singularity/EntitySystems/GravityWellSystem.cs b/Content.Server/Singularity/EntitySystems/GravityWellSystem.cs index d0df7d7a209..cb34c0bb49f 100644 --- a/Content.Server/Singularity/EntitySystems/GravityWellSystem.cs +++ b/Content.Server/Singularity/EntitySystems/GravityWellSystem.cs @@ -217,19 +217,19 @@ public void GravPulse(EntityUid uid, out Vector2 appliedImpulse, MapCoordinates if (!CanGravPulseAffect(entity)) continue; - isStatic |= TryComp(entity, out var movedPressure) && !movedPressure.Enabled; //Treat magboots users as static + isStatic |= TryComp(entity, out var movedPressure) && !movedPressure.Enabled; // Treat magboots users as static var displacement = epicenter - _transform.GetWorldPosition(entity, xformQuery); var distance2 = displacement.LengthSquared(); if (distance2 < minRange2) continue; - var scaling = (1f / distance2) * physics.FixturesMass; // TODO: Variable falloff gradiants. + var scaling = (1f / distance2) * physics.FixturesMass; // TODO: Variable falloff gradients if (isStatic) scaling *= staticImpulse ?? 1f; var impulse = Vector2.Transform(displacement, baseMatrixDeltaV) * scaling; - if (!isStatic) // impulse shouldn't be applied to static entities + if (!isStatic) // Impulse shouldn't be applied to static entities _physics.ApplyLinearImpulse(entity, impulse, body: physics); appliedImpulse += impulse;