Mob movement rewrite (#35931)

* Conveyor optimisations

- Optimise movement for moving stuff. Better flags + less resolves + slapped parallelrobustjob on it.
- Sleeping for entities getting conveyed into walls.

* Blocker version

* Finish

* Final

* Fix conveyor power mispredict

* Bagel save

* Revert "Bagel save"

This reverts commit 1b93fda81fb852d89b89b0beae0b80f8a61165f2.

* Conveyor resave

* Fix prediction

* Mob movement rewrite

* Bandaid

* Working version

* Tentatively working

* Friction to fix cornering

* More fixes

* Revert bagel

* Revert this

* a

* Reviewed

* Funky re-save

* Fix velocity

* Table fix

* Review

* a
This commit is contained in:
metalgearsloth
2025-03-28 09:29:02 +11:00
committed by GitHub
parent e98df217e2
commit 948588399c
8 changed files with 360 additions and 131 deletions

View File

@@ -155,7 +155,6 @@ public abstract partial class SharedMoverController : VirtualController
return;
}
UsedMobMovement[uid] = true;
// Specifically don't use mover.Owner because that may be different to the actual physics body being moved.
var weightless = _gravity.IsWeightless(physicsUid, physicsComponent, xform);
@@ -203,20 +202,21 @@ public abstract partial class SharedMoverController : VirtualController
var total = walkDir * walkSpeed + sprintDir * sprintSpeed;
var parentRotation = GetParentGridAngle(mover);
var worldTotal = _relativeMovement ? parentRotation.RotateVec(total) : total;
var wishDir = _relativeMovement ? parentRotation.RotateVec(total) : total;
DebugTools.Assert(MathHelper.CloseToPercent(total.Length(), worldTotal.Length()));
DebugTools.Assert(MathHelper.CloseToPercent(total.Length(), wishDir.Length()));
var velocity = physicsComponent.LinearVelocity;
float friction;
float weightlessModifier;
float accel;
var velocity = physicsComponent.LinearVelocity;
// Whether we use weightless friction or not.
if (weightless)
{
if (gridComp == null && !MapGridQuery.HasComp(xform.GridUid))
friction = moveSpeedComponent?.OffGridFriction ?? MovementSpeedModifierComponent.DefaultOffGridFriction;
else if (worldTotal != Vector2.Zero && touching)
else if (wishDir != Vector2.Zero && touching)
friction = moveSpeedComponent?.WeightlessFriction ?? MovementSpeedModifierComponent.DefaultWeightlessFriction;
else
friction = moveSpeedComponent?.WeightlessFrictionNoInput ?? MovementSpeedModifierComponent.DefaultWeightlessFrictionNoInput;
@@ -226,7 +226,7 @@ public abstract partial class SharedMoverController : VirtualController
}
else
{
if (worldTotal != Vector2.Zero || moveSpeedComponent?.FrictionNoInput == null)
if (wishDir != Vector2.Zero || moveSpeedComponent?.FrictionNoInput == null)
{
friction = tileDef?.MobFriction ?? moveSpeedComponent?.Friction ?? MovementSpeedModifierComponent.DefaultFriction;
}
@@ -242,14 +242,27 @@ public abstract partial class SharedMoverController : VirtualController
var minimumFrictionSpeed = moveSpeedComponent?.MinimumFrictionSpeed ?? MovementSpeedModifierComponent.DefaultMinimumFrictionSpeed;
Friction(minimumFrictionSpeed, frameTime, friction, ref velocity);
if (worldTotal != Vector2.Zero)
wishDir *= weightlessModifier;
if (!weightless || touching)
Accelerate(ref velocity, in wishDir, accel, frameTime);
SetWishDir((uid, mover), wishDir);
PhysicsSystem.SetLinearVelocity(physicsUid, velocity, body: physicsComponent);
// Ensures that players do not spiiiiiiin
PhysicsSystem.SetAngularVelocity(physicsUid, 0, body: physicsComponent);
// Handle footsteps at the end
if (total != Vector2.Zero)
{
if (!NoRotateQuery.HasComponent(uid))
{
// TODO apparently this results in a duplicate move event because "This should have its event run during
// island solver"??. So maybe SetRotation needs an argument to avoid raising an event?
var worldRot = _transform.GetWorldRotation(xform);
_transform.SetLocalRotation(xform, xform.LocalRotation + worldTotal.ToWorldAngle() - worldRot);
_transform.SetLocalRotation(xform, xform.LocalRotation + wishDir.ToWorldAngle() - worldRot);
}
if (!weightless && MobMoverQuery.TryGetComponent(uid, out var mobMover) &&
@@ -272,16 +285,23 @@ public abstract partial class SharedMoverController : VirtualController
}
}
}
}
worldTotal *= weightlessModifier;
public Vector2 GetWishDir(Entity<InputMoverComponent?> mover)
{
if (!MoverQuery.Resolve(mover.Owner, ref mover.Comp, false))
return Vector2.Zero;
if (!weightless || touching)
Accelerate(ref velocity, in worldTotal, accel, frameTime);
return mover.Comp.WishDir;
}
PhysicsSystem.SetLinearVelocity(physicsUid, velocity, body: physicsComponent);
public void SetWishDir(Entity<InputMoverComponent> mover, Vector2 wishDir)
{
if (mover.Comp.WishDir.Equals(wishDir))
return;
// Ensures that players do not spiiiiiiin
PhysicsSystem.SetAngularVelocity(physicsUid, 0, body: physicsComponent);
mover.Comp.WishDir = wishDir;
Dirty(mover);
}
public void LerpRotation(EntityUid uid, InputMoverComponent mover, float frameTime)
@@ -317,7 +337,7 @@ public abstract partial class SharedMoverController : VirtualController
}
}
private void Friction(float minimumFrictionSpeed, float frameTime, float friction, ref Vector2 velocity)
public void Friction(float minimumFrictionSpeed, float frameTime, float friction, ref Vector2 velocity)
{
var speed = velocity.Length();
@@ -338,7 +358,10 @@ public abstract partial class SharedMoverController : VirtualController
velocity *= newSpeed;
}
private void Accelerate(ref Vector2 currentVelocity, in Vector2 velocity, float accel, float frameTime)
/// <summary>
/// Adjusts the current velocity to the target velocity based on the specified acceleration.
/// </summary>
public static void Accelerate(ref Vector2 currentVelocity, in Vector2 velocity, float accel, float frameTime)
{
var wishDir = velocity != Vector2.Zero ? velocity.Normalized() : Vector2.Zero;
var wishSpeed = velocity.Length();