Delete AetheriaMath in favour of CultMath

AetheriaMath predates the CultMath swap and re-implemented helpers CultMath
now owns. Callers use CultMath directly: decay (Ship, AetherDrive, Entity),
damp (VelocityConversion, FieldTester, FieldDriver), first_order_intercept
(TurretController, Combat, GuidedProjectile), quadratic_bezier (FieldDriver)
and smootherstep (Ship). Parameter order matches in every case, and those
formulas have the same float evaluation order, so behaviour is unchanged.
Galaxy's commented-out segment check names distance_to_segment.

The other overloads had no callers and are dropped without a CultMath
counterpart being needed: the double Damp overloads, FindDistanceToSegment,
GetCatmullRomPosition, GetCubicSplinePosition, Smoothstep(x), and the
Deg2Rad/Rad2Deg constants.

AetherDb census, factions and hardpoint-fit are byte-identical to the
pre-cut captures.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Meta Vens 2026-09-14 18:02:41 +02:00
commit 55c3fc6a49
12 changed files with 19 additions and 273 deletions

View file

@ -233,7 +233,7 @@ public class FieldDriver : MonoBehaviour
if (_grabObject != null)
{
_tendrilBasePos = AetheriaMath.Damp(_tendrilBasePos.ToCultMath(), _grabObject.position.ToCultMath(), TendrilBaseDamping, Time.deltaTime).ToUnity();
_tendrilBasePos = damp(_tendrilBasePos.ToCultMath(), _grabObject.position.ToCultMath(), TendrilBaseDamping, Time.deltaTime).ToUnity();
switch (_grabPhase)
{
case GrabPhase.Extend:
@ -292,7 +292,7 @@ public class FieldDriver : MonoBehaviour
for (int i = 1; i <= GIZMO_STEPS; i++)
{
var l = (float)i / GIZMO_STEPS;
var next = AetheriaMath.GetQuadraticSplinePosition(_tendrilBasePos.ToCultMath(), _tendrilBendTarget.ToCultMath(), _tendrilTargetPos.ToCultMath(), l).ToUnity();
var next = quadratic_bezier(_tendrilBasePos.ToCultMath(), _tendrilBendTarget.ToCultMath(), _tendrilTargetPos.ToCultMath(), l).ToUnity();
Gizmos.DrawLine(previous, next);
previous = next;
}

View file

@ -77,7 +77,7 @@ public class GuidedProjectile : MonoBehaviour
var targetPosition = TargetPosition?.Invoke() ?? Target.position;
_targetVelocity = lerp(_targetVelocity.ToCultMath(), (targetPosition - _previousTargetPosition).ToCultMath(), saturate(Time.deltaTime * 5)).ToUnity();
_previousTargetPosition = targetPosition;
targetPosition = AetheriaMath.FirstOrderIntercept(position,float3.zero, TopSpeed, targetPosition.ToCultMath(), _targetVelocity.ToCultMath()).ToUnity();
targetPosition = first_order_intercept(position,float3.zero, TopSpeed, targetPosition.ToCultMath(), _targetVelocity.ToCultMath()).ToUnity();
var diff = targetPosition - transform.position;
var targetDist = diff.magnitude;

View file

@ -1,243 +0,0 @@
using System.Collections;
using System.Collections.Generic;
using CultMath;
using static CultMath.math;
public static class AetheriaMath
{
public const float Deg2Rad = 0.01745329f;
public const float Rad2Deg = 57.29578f;
public static float Decay(float source, float lambda, float dt)
{
return source * exp(-lambda * dt);
}
public static float3 Decay(float3 source, float lambda, float dt)
{
return source * exp(-lambda * dt);
}
public static float3 Decay(float3 source, float3 lambda, float dt)
{
return source * exp(-lambda * dt);
}
public static float Damp(float a, float b, float lambda, float dt)
{
return lerp(a, b, 1 - exp(-lambda * dt));
}
public static float2 Damp(float2 a, float2 b, float lambda, float dt)
{
return lerp(a, b, 1 - exp(-lambda * dt));
}
public static float3 Damp(float3 a, float3 b, float lambda, float dt)
{
return lerp(a, b, 1 - exp(-lambda * dt));
}
public static double Damp(double a, double b, double lambda, double dt)
{
return lerp(a, b, 1 - exp(-lambda * dt));
}
public static double2 Damp(double2 a, double2 b, double2 lambda, double2 dt)
{
return lerp(a, b, 1 - exp(-lambda * dt));
}
public static double3 Damp(double3 a, double3 b, double3 lambda, double3 dt)
{
return lerp(a, b, 1 - exp(-lambda * dt));
}
//first-order intercept using absolute target position
public static float3 FirstOrderIntercept
(
float3 shooterPosition,
float3 shooterVelocity,
float shotSpeed,
float3 targetPosition,
float3 targetVelocity
) {
float3 targetRelativePosition = targetPosition - shooterPosition;
float3 targetRelativeVelocity = targetVelocity - shooterVelocity;
float t = FirstOrderInterceptTime
(
shotSpeed,
targetRelativePosition,
targetRelativeVelocity
);
return targetPosition + t*targetRelativeVelocity;
}
//first-order intercept using relative target position
public static float FirstOrderInterceptTime
(
float shotSpeed,
float3 targetRelativePosition,
float3 targetRelativeVelocity
) {
float velocitySquared = lengthsq(targetRelativeVelocity);
if(velocitySquared < 0.001f)
return 0f;
float a = velocitySquared - shotSpeed*shotSpeed;
//handle similar velocities
if (abs(a) < 0.001f)
{
float t = -lengthsq(targetRelativePosition)/ (2f*dot(targetRelativeVelocity, targetRelativePosition));
return max(t, 0f); //don't shoot back in time
}
float b = 2f*dot(targetRelativeVelocity, targetRelativePosition);
float c = lengthsq(targetRelativePosition);
float determinant = b*b - 4f*a*c;
if (determinant > 0f) { //determinant > 0; two intercept paths (most common)
float t1 = (-b + sqrt(determinant))/(2f*a),
t2 = (-b - sqrt(determinant))/(2f*a);
if (t1 > 0f) {
if (t2 > 0f)
return min(t1, t2); //both are positive
else
return t1; //only t1 is positive
} else
return max(t2, 0f); //don't shoot back in time
} else if (determinant < 0f) //determinant < 0; no intercept path
return 0f;
else //determinant = 0; one intercept path, pretty much never happens
return max(-b/(2f*a), 0f); //don't shoot back in time
}
// http://csharphelper.com/blog/2016/09/find-the-shortest-distance-between-a-point-and-a-line-segment-in-c/
// Calculate the distance between
// point pt and the segment p1 --> p2.
public static float FindDistanceToSegment(
float2 pt, float2 p1, float2 p2, out float2 closest)
{
float dx = p2.x - p1.x;
float dy = p2.y - p1.y;
if (dx == 0 && dy == 0)
{
// It's a point not a line segment.
closest = p1;
dx = pt.x - p1.x;
dy = pt.y - p1.y;
return sqrt(dx * dx + dy * dy);
}
// Calculate the t that minimizes the distance.
float t = ((pt.x - p1.x) * dx + (pt.y - p1.y) * dy) /
(dx * dx + dy * dy);
// See if this represents one of the segment's
// end points or a point in the middle.
if (t < 0)
{
closest = float2(p1.x, p1.y);
dx = pt.x - p1.x;
dy = pt.y - p1.y;
}
else if (t > 1)
{
closest = float2(p2.x, p2.y);
dx = pt.x - p2.x;
dy = pt.y - p2.y;
}
else
{
closest = float2(p1.x + t * dx, p1.y + t * dy);
dx = pt.x - closest.x;
dy = pt.y - closest.y;
}
return sqrt(dx * dx + dy * dy);
}
//Returns a position between 4 float3s with Catmull-Rom spline algorithm
//http://www.iquilezles.org/www/articles/minispline/minispline.htm
public static float GetCatmullRomPosition(float p0, float p1, float p2, float p3, float t)
{
//The coefficients of the cubic polynomial (except the 0.5f * which I added later for performance)
var a = 2f * p1;
var b = p2 - p0;
var c = 2f * p0 - 5f * p1 + 4f * p2 - p3;
var d = -p0 + 3f * p1 - 3f * p2 + p3;
//The cubic polynomial: a + b * t + c * t^2 + d * t^3
var pos = 0.5f * (a + (b * t) + (c * t * t) + (d * t * t * t));
return pos;
}
public static float3 GetCatmullRomPosition(float3 p0, float3 p1, float3 p2, float3 p3, float t)
{
//The coefficients of the cubic polynomial (except the 0.5f * which I added later for performance)
var a = 2f * p1;
var b = p2 - p0;
var c = 2f * p0 - 5f * p1 + 4f * p2 - p3;
var d = -p0 + 3f * p1 - 3f * p2 + p3;
//The cubic polynomial: a + b * t + c * t^2 + d * t^3
var pos = 0.5f * (a + (b * t) + (c * t * t) + (d * t * t * t));
return pos;
}
// https://catlikecoding.com/unity/tutorials/curves-and-splines/
public static float GetQuadraticSplinePosition(float p0, float p1, float p2, float t)
{
t = saturate(t);
var oneMinusT = 1f - t;
return
oneMinusT * oneMinusT * p0 +
2f * oneMinusT * t * p1 +
t * t * p2;
}
public static float3 GetQuadraticSplinePosition(float3 p0, float3 p1, float3 p2, float t)
{
t = saturate(t);
var oneMinusT = 1f - t;
return
oneMinusT * oneMinusT * p0 +
2f * oneMinusT * t * p1 +
t * t * p2;
}
public static float3 GetCubicSplinePosition (float p0, float p1, float p2, float p3, float t) {
t = saturate(t);
var oneMinusT = 1f - t;
return
oneMinusT * oneMinusT * oneMinusT * p0 +
3f * oneMinusT * oneMinusT * t * p1 +
3f * oneMinusT * t * t * p2 +
t * t * t * p3;
}
public static float3 GetCubicSplinePosition (float3 p0, float3 p1, float3 p2, float3 p3, float t) {
t = saturate(t);
var oneMinusT = 1f - t;
return
oneMinusT * oneMinusT * oneMinusT * p0 +
3f * oneMinusT * oneMinusT * t * p1 +
3f * oneMinusT * t * t * p2 +
t * t * t * p3;
}
public static float Smoothstep(float x)
{
x = saturate(x);
return x * x * (3 - 2 * x);
}
public static float Smootherstep(float x)
{
x = saturate(x);
return x * x * x * (x * (x * 6 - 15) + 10);
}
}

View file

@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 70c5f24f81c803248a4f682e6eb12ef2
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -86,7 +86,7 @@ public class CombatState : BaseState
var targetHullData = _agent.ItemManager.GetData(target.Hull) as HullData;
var targetVelocity = float3(target.Velocity.x, 0, target.Velocity.y);
var shipVelocity = float3(_agent.Ship.Velocity.x, 0, _agent.Ship.Velocity.y);
var predictedPosition = AetheriaMath.FirstOrderIntercept(
var predictedPosition = first_order_intercept(
_agent.Ship.Position,
float3.zero,
testWeapon.Velocity,

View file

@ -99,11 +99,11 @@ public class AetherDrive : Behavior
var couplingEfficiency = Evaluate(_data.CouplingEfficiency);
var efficiency = float3(saturate(1 - speed / max(rotorSpeed.xy, 1) * sign(_axis.xy)) * couplingEfficiency, 1);
Thrust = (Rpm - AetheriaMath.Decay(Rpm, _data.CouplingLambda, dt)) * _data.RotorMass * efficiency;
Thrust = (Rpm - decay(Rpm, _data.CouplingLambda, dt)) * _data.RotorMass * efficiency;
var couplingLambda = _data.CouplingLambda * Item.Evaluate(_data.LambdaMultiplier) * max(abs(_axis), Evaluate(_data.PassiveCoupling));
var previousRpm = Rpm;
Rpm = AetheriaMath.Decay(Rpm, couplingLambda, dt);
Rpm = decay(Rpm, couplingLambda, dt);
var rpmLoss = previousRpm - Rpm;
var force = rpmLoss * _data.RotorMass * efficiency;

View file

@ -64,7 +64,7 @@ public class TurretController : Behavior, IInitializableBehavior
{
var targetHullData = Entity.ItemManager.GetData(Entity.Target.Value.Hull) as HullData;
var targetVelocity = float3(Entity.Target.Value.Velocity.x, 0, Entity.Target.Value.Velocity.y);
var predictedPosition = AetheriaMath.FirstOrderIntercept(
var predictedPosition = first_order_intercept(
Entity.Position, float3.zero, _shotSpeed,
Entity.Target.Value.Position, targetVelocity
);

View file

@ -38,7 +38,7 @@ public class VelocityConversion : Behavior
public override bool Execute(float dt)
{
Entity.Velocity = AetheriaMath.Damp(Entity.Velocity, Entity.Direction * length(Entity.Velocity), Evaluate(_data.Lambda), dt);
Entity.Velocity = damp(Entity.Velocity, Entity.Direction * length(Entity.Velocity), Evaluate(_data.Lambda), dt);
return true;
}
}

View file

@ -855,7 +855,7 @@ public abstract class Entity
foreach (var v in VisibilitySources.Keys.ToArray())
{
VisibilitySources[v] = AetheriaMath.Decay(VisibilitySources[v], ItemManager.GameplaySettings.VisibilityDecay, delta);
VisibilitySources[v] = decay(VisibilitySources[v], ItemManager.GameplaySettings.VisibilityDecay, delta);
if (VisibilitySources[v] < 0.1f) VisibilitySources.Remove(v);
}

View file

@ -381,7 +381,7 @@ public class Galaxy
// foreach (var zone in Zones)
// {
// if(zone != link.Item1 && zone != link.Item2)
// if (AetheriaMath.FindDistanceToSegment(zone.Position, link.Item1.Position, link.Item2.Position, out _) < minLineSeparation)
// if (distance_to_segment(zone.Position, link.Item1.Position, link.Item2.Position, out _) < minLineSeparation)
// links.Remove(link);
// }
// }

View file

@ -293,7 +293,7 @@ public class Ship : Entity
var velocityMagnitude = length(Velocity);
if(velocityMagnitude > .01f)
Velocity = normalize(Velocity) * AetheriaMath.Decay(velocityMagnitude, HullData.Drag, delta);
Velocity = normalize(Velocity) * decay(velocityMagnitude, HullData.Drag, delta);
Position.xz += Velocity * delta;
@ -325,7 +325,7 @@ public class Ship : Entity
{
var exitLerp = (_wormholeAnimationProgress - ItemManager.GameplaySettings.WormholeExitCurveStart) /
(1 - ItemManager.GameplaySettings.WormholeExitCurveStart);
exitLerp = AetheriaMath.Smootherstep(exitLerp); // Square the interpolation variable to produce curve with zero slope at start
exitLerp = smootherstep(exitLerp); // Square the interpolation variable to produce curve with zero slope at start
Position.xz = _wormholePosition + normalize(_wormholeExitVelocity) * exitLerp * ItemManager.GameplaySettings.WormholeExitRadius;
Rotation = quaternion.LookRotation(
lerp(float3(0, 1, 0), forward, exitLerp),
@ -351,7 +351,7 @@ public class Ship : Entity
if (_wormholeAnimationProgress < 1 - ItemManager.GameplaySettings.WormholeExitCurveStart)
{
var enterLerp = _wormholeAnimationProgress / (1 - ItemManager.GameplaySettings.WormholeExitCurveStart);
enterLerp = AetheriaMath.Smootherstep(enterLerp); // Square the interpolation variable to produce curve with zero slope at vertical
enterLerp = smootherstep(enterLerp); // Square the interpolation variable to produce curve with zero slope at vertical
Position.xz = lerp(_wormholeEntryPosition, _wormholePosition, enterLerp);
Rotation = quaternion.LookRotation(
lerp(forward, float3(0, -1, 0), enterLerp),

View file

@ -81,21 +81,21 @@ public class FieldTester : MonoBehaviour
var turn = _input.Player.Turn.ReadValue<float>();
if (_directionalPush)
{
TestField.Push = AetheriaMath.Damp(TestField.Push, move, _throttleDecay, Time.deltaTime);
TestField.FrontTwist = AetheriaMath.Damp(TestField.FrontTwist,
TestField.Push = damp(TestField.Push, move, _throttleDecay, Time.deltaTime);
TestField.FrontTwist = damp(TestField.FrontTwist,
turn,
_throttleDecay, Time.deltaTime);
TestField.RearTwist = AetheriaMath.Damp(TestField.RearTwist,
TestField.RearTwist = damp(TestField.RearTwist,
turn,
_throttleDecay, Time.deltaTime);
}
else
{
TestField.Push = AetheriaMath.Damp(TestField.Push, float2(0,move.y), _throttleDecay, Time.deltaTime);
TestField.FrontTwist = AetheriaMath.Damp(TestField.FrontTwist,
TestField.Push = damp(TestField.Push, float2(0,move.y), _throttleDecay, Time.deltaTime);
TestField.FrontTwist = damp(TestField.FrontTwist,
clamp(turn + move.x, -1, 1) * (1+min(move.y,0)),
_throttleDecay, Time.deltaTime);
TestField.RearTwist = AetheriaMath.Damp(TestField.RearTwist,
TestField.RearTwist = damp(TestField.RearTwist,
clamp(turn - move.x, -1, 1) * (1+min(-move.y,0)),
_throttleDecay, Time.deltaTime);
}