Remove floating points from map generation

Removes all use of floating point from the RaMapGenerator map generator
and its dependencies.

Floating point behavior is potentially non-portable across client
hardware. Removing them should make the map generation logic
consistent even across clients with different floating point hardware
or compiler behavior. This may be useful for sync-safe multiplayer map
generation where clients independently generate the map from settings.

Most previously fractional public-facing settings are now represented
as numbers out of 1000, with some exceptions using 1000000. Most
internal logic which relies on fixed-point concepts now uses 1024ths,
though some floating point mechanisms have been replaced with
alternative discrete approximations (e.g. gaussian to binomial).
This commit is contained in:
Ashley Newson
2025-01-26 16:45:46 +00:00
committed by Gustas Kažukauskas
parent 04e9cef38e
commit 037326024b
17 changed files with 847 additions and 827 deletions

View File

@@ -44,26 +44,26 @@ namespace OpenRA.Mods.Common.MapGenerator
/// Mirrors a (zero-area) point around a given center.
/// </para>
/// <para>
/// For example, if using a center of (4.0, 4.0) a point at (0.1, 0.1) could be projected
/// to (0.1, 0.1), (0.1, 7.9), (7.9, 0.1), or (7.9, 7.9).
/// For example, if using a center of (40, 40) a point at (1, 1) could be projected
/// to (1, 1), (1, 79), (79, 1), or (79, 79).
/// </para>
/// </summary>
public static float2 MirrorPointAround(Mirror mirror, float2 original, float2 center)
public static int2 MirrorPointAround(Mirror mirror, int2 original, int2 center)
{
switch (mirror)
{
case Mirror.None:
throw new ArgumentException("Mirror.None has no transformed point");
case Mirror.LeftMatchesRight:
return new float2(2.0f * center.X - original.X, original.Y);
return new int2(2 * center.X - original.X, original.Y);
case Mirror.TopLeftMatchesBottomRight:
return new float2(
return new int2(
center.Y - original.Y + center.X,
center.X - original.X + center.Y);
case Mirror.TopMatchesBottom:
return new float2(original.X, 2.0f * center.Y - original.Y);
return new int2(original.X, 2 * center.Y - original.Y);
case Mirror.TopRightMatchesBottomLeft:
return new float2(
return new int2(
center.X + original.Y - center.Y,
center.Y + original.X - center.X);
default:
@@ -73,27 +73,11 @@ namespace OpenRA.Mods.Common.MapGenerator
public static WPos MirrorWPosAround(Mirror mirror, WPos original, WPos center)
{
switch (mirror)
{
case Mirror.None:
throw new ArgumentException("Mirror.None has no transformed point");
case Mirror.LeftMatchesRight:
return new WPos(2 * center.X - original.X, original.Y, original.Z);
case Mirror.TopLeftMatchesBottomRight:
return new WPos(
center.Y - original.Y + center.X,
center.X - original.X + center.Y,
original.Z);
case Mirror.TopMatchesBottom:
return new WPos(original.X, 2 * center.Y - original.Y, original.Z);
case Mirror.TopRightMatchesBottomLeft:
return new WPos(
center.X + original.Y - center.Y,
center.Y + original.X - center.X,
original.Z);
default:
throw new ArgumentException("Bad mirror");
}
var result = MirrorPointAround(
mirror,
new int2(original.X, original.Y),
new int2(center.X, center.Y));
return new WPos(result.X, result.Y, original.Z);
}
/// <summary>
@@ -199,17 +183,17 @@ namespace OpenRA.Mods.Common.MapGenerator
/// functions. This may be slightly imprecise for non-trivial rotations.
/// </para>
/// <para>
/// For example, if using a center of (4.0, 4.0) a point at (0.1, 0.1) could be projected
/// to (0.1, 0.1), (0.1, 7.9), (7.9, 0.1), and (7.9, 7.9).
/// For example, if using a center of (40, 40) a point at (1, 1) could be projected
/// to (1, 1), (1, 79), (79, 1), and (79, 79).
/// </para>
/// </summary>
public static float2[] RotateAndMirrorPointAround(
float2 original,
float2 center,
public static int2[] RotateAndMirrorPointAround(
int2 original,
int2 center,
int rotations,
Mirror mirror)
{
var projections = new float2[RotateAndMirrorProjectionCount(rotations, mirror)];
var projections = new int2[RotateAndMirrorProjectionCount(rotations, mirror)];
var projectionIndex = 0;
for (var rotation = 0; rotation < rotations; rotation++)
@@ -217,12 +201,12 @@ namespace OpenRA.Mods.Common.MapGenerator
// This could be made more accurate using dedicated, higher precision
// rotation count to cos and sin lookup tables.
var wangle = new WAngle(rotation * 1024 / rotations);
var cos = wangle.Cos() / 1024.0f;
var sin = wangle.Sin() / 1024.0f;
long cos = wangle.Cos();
long sin = wangle.Sin();
var relOrig = original - center;
var projX = relOrig.X * cos - relOrig.Y * sin + center.X;
var projY = relOrig.X * sin + relOrig.Y * cos + center.Y;
var projection = new float2(projX, projY);
var projX = (relOrig.X * cos - relOrig.Y * sin) / 1024 + center.X;
var projY = (relOrig.X * sin + relOrig.Y * cos) / 1024 + center.Y;
var projection = new int2((int)projX, (int)projY);
projections[projectionIndex++] = projection;
if (mirror != Mirror.None)
@@ -303,7 +287,7 @@ namespace OpenRA.Mods.Common.MapGenerator
public static bool IsCPosNearCenter<T>(
CPos cpos,
CellLayer<T> cellLayer,
float reservationRadius,
int reservationRadius,
Mirror mirror)
{
CPos[] testPoints;
@@ -313,7 +297,7 @@ namespace OpenRA.Mods.Common.MapGenerator
testPoints = RotateAndMirrorCPos(cpos, cellLayer, 1, mirror);
var separation = (testPoints[1] - testPoints[0]).LengthSquared;
return separation <= reservationRadius * reservationRadius * 4.0f;
return separation <= reservationRadius * reservationRadius * 4;
}
}
}