From 0b9482518216bcd6380f141a159d42f2ccbc6185 Mon Sep 17 00:00:00 2001 From: router Date: Mon, 4 Sep 2023 22:33:47 +0300 Subject: [PATCH] Fix thrusters, add new max velocity calculation (#19688) --- .../Physics/Controllers/MoverController.cs | 51 +++++++++++++++---- .../Shuttles/Components/ShuttleComponent.cs | 12 ++++- .../Shuttles/Systems/ThrusterSystem.cs | 10 ++++ 3 files changed, 62 insertions(+), 11 deletions(-) diff --git a/Content.Server/Physics/Controllers/MoverController.cs b/Content.Server/Physics/Controllers/MoverController.cs index c6bb5fa6cc..5c8968dd98 100644 --- a/Content.Server/Physics/Controllers/MoverController.cs +++ b/Content.Server/Physics/Controllers/MoverController.cs @@ -232,6 +232,29 @@ namespace Content.Server.Physics.Controllers component.CurTickBraking += brake * fraction; } + /// + /// Helper function to extrapolate max velocity for a given Vector2 (really, its angle) and shuttle. + /// + private Vector2 ObtainMaxVel(Vector2 vel, ShuttleComponent shuttle) + { + if (vel.Length() == 0f) + return Vector2.Zero; + + // this math could PROBABLY be simplified for performance + // probably + // __________________________________ + // / / __ __ \2 / __ __ \2 + // O = I : _ / |I * | 1/H | | + |I * | 0 | | + // V \ |_ 0 _| / \ |_1/V_| / + + var horizIndex = vel.X > 0 ? 1 : 3; // east else west + var vertIndex = vel.Y > 0 ? 2 : 0; // north else south + var horizComp = MathF.Pow(Vector2.Dot(vel, new (shuttle.BaseLinearThrust[horizIndex] / shuttle.LinearThrust[horizIndex], 0f)), 2); + var vertComp = MathF.Pow(Vector2.Dot(vel, new (0f, shuttle.BaseLinearThrust[vertIndex] / shuttle.LinearThrust[vertIndex])), 2); + + return shuttle.BaseMaxLinearVelocity * vel * MathF.ReciprocalSqrtEstimate(horizComp + vertComp); + } + private void HandleShuttleMovement(float frameTime) { var newPilots = new Dictionary)>(); @@ -478,19 +501,27 @@ namespace Content.Server.Physics.Controllers totalForce += impulse; } - totalForce = shuttleNorthAngle.RotateVec(totalForce); - var forceMul = frameTime * body.InvMass; - var maxVelocity = (ShuttleComponent.MaxLinearVelocity - body.LinearVelocity.Length()) / forceMul; - if (maxVelocity != 0f) - { - // Don't overshoot - if (totalForce.Length() > maxVelocity) - totalForce = totalForce.Normalized() * maxVelocity; + var localVel = (-shuttleNorthAngle).RotateVec(body.LinearVelocity); + var maxVelocity = ObtainMaxVel(localVel, shuttle); // max for current travel dir + var maxWishVelocity = ObtainMaxVel(totalForce, shuttle); + var properAccel = (maxWishVelocity - localVel) / forceMul; - PhysicsSystem.ApplyForce(shuttleUid, totalForce, body: body); - } + var finalForce = Vector2.Dot(totalForce, properAccel.Normalized()) * properAccel.Normalized(); + + if (localVel.Length() >= maxVelocity.Length() && Vector2.Dot(totalForce, localVel) > 0f) + finalForce = Vector2.Zero; // burn would be faster if used as such + + if (finalForce.Length() > properAccel.Length()) + finalForce = properAccel; // don't overshoot + + //Logger.Info($"shuttle: maxVelocity {maxVelocity} totalForce {totalForce} finalForce {finalForce} forceMul {forceMul} properAccel {properAccel}"); + + finalForce = shuttleNorthAngle.RotateVec(finalForce); + + if (finalForce.Length() > 0f) + PhysicsSystem.ApplyForce(shuttleUid, finalForce, body: body); } if (MathHelper.CloseTo(angularInput, 0f)) diff --git a/Content.Server/Shuttles/Components/ShuttleComponent.cs b/Content.Server/Shuttles/Components/ShuttleComponent.cs index 25415636e0..488f1d3a21 100644 --- a/Content.Server/Shuttles/Components/ShuttleComponent.cs +++ b/Content.Server/Shuttles/Components/ShuttleComponent.cs @@ -16,7 +16,11 @@ namespace Content.Server.Shuttles.Components /// public const float BrakeCoefficient = 1.5f; - public const float MaxLinearVelocity = 20f; + /// + /// Maximum velocity assuming unupgraded, tier 1 thrusters + /// + [ViewVariables(VVAccess.ReadWrite)] + public float BaseMaxLinearVelocity = 20f; public const float MaxAngularVelocity = 4f; @@ -26,6 +30,12 @@ namespace Content.Server.Shuttles.Components [ViewVariables] public readonly float[] LinearThrust = new float[4]; + /// + /// The cached thrust available for each cardinal direction, if all thrusters are T1 + /// + [ViewVariables] + public readonly float[] BaseLinearThrust = new float[4]; + /// /// The thrusters contributing to each direction for impulse. /// diff --git a/Content.Server/Shuttles/Systems/ThrusterSystem.cs b/Content.Server/Shuttles/Systems/ThrusterSystem.cs index a9bc0f4e71..24d326c94e 100644 --- a/Content.Server/Shuttles/Systems/ThrusterSystem.cs +++ b/Content.Server/Shuttles/Systems/ThrusterSystem.cs @@ -173,10 +173,12 @@ public sealed class ThrusterSystem : EntitySystem var direction = (int) args.NewRotation.GetCardinalDir() / 2; shuttleComponent.LinearThrust[oldDirection] -= component.Thrust; + shuttleComponent.BaseLinearThrust[oldDirection] -= component.BaseThrust; DebugTools.Assert(shuttleComponent.LinearThrusters[oldDirection].Contains(uid)); shuttleComponent.LinearThrusters[oldDirection].Remove(uid); shuttleComponent.LinearThrust[direction] += component.Thrust; + shuttleComponent.BaseLinearThrust[direction] += component.BaseThrust; DebugTools.Assert(!shuttleComponent.LinearThrusters[direction].Contains(uid)); shuttleComponent.LinearThrusters[direction].Add(uid); } @@ -257,6 +259,7 @@ public sealed class ThrusterSystem : EntitySystem var direction = (int) xform.LocalRotation.GetCardinalDir() / 2; shuttleComponent.LinearThrust[direction] += component.Thrust; + shuttleComponent.BaseLinearThrust[direction] += component.BaseThrust; DebugTools.Assert(!shuttleComponent.LinearThrusters[direction].Contains(uid)); shuttleComponent.LinearThrusters[direction].Add(uid); @@ -355,6 +358,7 @@ public sealed class ThrusterSystem : EntitySystem var direction = (int) angle.Value.GetCardinalDir() / 2; shuttleComponent.LinearThrust[direction] -= component.Thrust; + shuttleComponent.BaseLinearThrust[direction] -= component.BaseThrust; DebugTools.Assert(shuttleComponent.LinearThrusters[direction].Contains(uid)); shuttleComponent.LinearThrusters[direction].Remove(uid); break; @@ -552,9 +556,15 @@ public sealed class ThrusterSystem : EntitySystem private void OnRefreshParts(EntityUid uid, ThrusterComponent component, RefreshPartsEvent args) { + if (component.IsOn) // safely disable thruster to prevent negative thrust + DisableThruster(uid, component); + var thrustRating = args.PartRatings[component.MachinePartThrust]; component.Thrust = component.BaseThrust * MathF.Pow(component.PartRatingThrustMultiplier, thrustRating - 1); + + if (component.Enabled && CanEnable(uid, component)) + EnableThruster(uid, component); } private void OnUpgradeExamine(EntityUid uid, ThrusterComponent component, UpgradeExamineEvent args)