Convert Direction.cs to enums and extensions

- Converts OpenRA.Mods.Common/MapGenerator/Direction.cs over to using
  Direction and DirectionMask enums
- Moves direction-related utilities into Exts classes.
- Simplifies some direction utility logic.

Only very small numerical precision behavioral changes.
This commit is contained in:
Ashley Newson
2025-05-21 00:16:38 +01:00
committed by Gustas Kažukauskas
parent 99253702c5
commit 7538943f59
7 changed files with 205 additions and 231 deletions

View File

@@ -112,10 +112,10 @@ namespace OpenRA.Mods.Common.Widgets
.FirstOrDefault(0);
var isStartDirector =
plan.AutoStart != Direction.None
&& cpos == plan.FirstPoint - Direction.ToCVec(plan.AutoStart);
&& cpos == plan.FirstPoint - plan.AutoStart.ToCVec();
var isEndDirector =
plan.AutoEnd != Direction.None
&& cpos == plan.LastPoint + Direction.ToCVec(plan.AutoEnd);
&& cpos == plan.LastPoint + plan.AutoEnd.ToCVec();
return (isInside, isRally, rallyIndex, isStartDirector, isEndDirector);
}
@@ -131,7 +131,7 @@ namespace OpenRA.Mods.Common.Widgets
var offset = plan.FirstPoint - to;
var direction =
offset != CVec.Zero
? Direction.FromCVecRounding(offset)
? DirectionExts.ClosestFromCVec(offset)
: Direction.None;
UpdatePlan(plan.WithStart(direction), true);
}
@@ -140,7 +140,7 @@ namespace OpenRA.Mods.Common.Widgets
var offset = to - plan.LastPoint;
var direction =
offset != CVec.Zero
? Direction.FromCVecRounding(offset)
? DirectionExts.ClosestFromCVec(offset)
: Direction.None;
UpdatePlan(plan.WithEnd(direction), true);
}
@@ -248,7 +248,7 @@ namespace OpenRA.Mods.Common.Widgets
if (plan.AutoEnd != Direction.None)
yield return new CircleAnnotationRenderable(
CornerOfCell(plan.LastPoint) + Direction.ToWVec(plan.AutoEnd) * 768,
CornerOfCell(plan.LastPoint) + plan.AutoEnd.ToWVec() * 768,
new WDist(256),
2,
plan.End != Direction.None ? Color.Magenta : Color.Gray,
@@ -256,7 +256,7 @@ namespace OpenRA.Mods.Common.Widgets
if (plan.AutoStart != Direction.None)
yield return new CircleAnnotationRenderable(
CornerOfCell(plan.FirstPoint) - Direction.ToWVec(plan.AutoStart) * 768,
CornerOfCell(plan.FirstPoint) - plan.AutoStart.ToWVec() * 768,
new WDist(256),
2,
plan.Start != Direction.None ? Color.Magenta : Color.Gray,

View File

@@ -19,71 +19,80 @@ namespace OpenRA.Mods.Common.MapGenerator
/// Utilities for simple directions and adjacency. Note that coordinate systems might not agree
/// as to which directions are conceptually left/right or up/down.
/// </summary>
public static class Direction
public enum Direction
{
/// <summary>No direction.</summary>
public const int None = -1;
None = -1,
/// <summary>+X ("right").</summary>
public const int R = 0;
R = 0,
/// <summary>+X+Y ("right down").</summary>
public const int RD = 1;
RD = 1,
/// <summary>+Y ("down").</summary>
public const int D = 2;
D = 2,
/// <summary>-X+Y ("left down").</summary>
public const int LD = 3;
LD = 3,
/// <summary>-X ("left").</summary>
public const int L = 4;
L = 4,
/// <summary>-X-Y ("left up").</summary>
public const int LU = 5;
LU = 5,
/// <summary>-Y ("up").</summary>
public const int U = 6;
U = 6,
/// <summary>+X-Y ("right up").</summary>
public const int RU = 7;
RU = 7,
}
[Flags]
public enum DirectionMask
{
None = 0,
/// <summary>Bitmask right.</summary>
public const int MR = 1 << R;
MR = 1 << Direction.R,
/// <summary>Bitmask right-down.</summary>
public const int MRD = 1 << RD;
MRD = 1 << Direction.RD,
/// <summary>Bitmask down.</summary>
public const int MD = 1 << D;
MD = 1 << Direction.D,
/// <summary>Bitmask left-down.</summary>
public const int MLD = 1 << LD;
MLD = 1 << Direction.LD,
/// <summary>Bitmask left.</summary>
public const int ML = 1 << L;
ML = 1 << Direction.L,
/// <summary>Bitmask left-up.</summary>
public const int MLU = 1 << LU;
MLU = 1 << Direction.LU,
/// <summary>Bitmask up.</summary>
public const int MU = 1 << U;
MU = 1 << Direction.U,
/// <summary>Bitmask right-up.</summary>
public const int MRU = 1 << RU;
MRU = 1 << Direction.RU,
}
public static class DirectionExts
{
/// <summary>Adjacent offsets with directions, excluding diagonals.</summary>
public static readonly ImmutableArray<(int2, int)> Spread4D =
public static readonly ImmutableArray<(int2, Direction)> Spread4D =
[
(new int2(1, 0), R),
(new int2(0, 1), D),
(new int2(-1, 0), L),
(new int2(0, -1), U)
(new int2(1, 0), Direction.R),
(new int2(0, 1), Direction.D),
(new int2(-1, 0), Direction.L),
(new int2(0, -1), Direction.U)
];
/// <summary>Adjacent offsets, excluding diagonals.</summary>
public static readonly ImmutableArray<int2> Spread4 =
Spread4D.Select(((int2 XY, int _) v) => v.XY).ToImmutableArray();
Spread4D.Select(((int2 XY, Direction _) v) => v.XY).ToImmutableArray();
/// <summary>
/// Adjacent offsets, excluding diagonals. Assumes that CVec(1, 0)
@@ -93,21 +102,21 @@ namespace OpenRA.Mods.Common.MapGenerator
Spread4.Select(xy => new CVec(xy.X, xy.Y)).ToImmutableArray();
/// <summary>Adjacent offsets with directions, including diagonals.</summary>
public static readonly ImmutableArray<(int2, int)> Spread8D =
public static readonly ImmutableArray<(int2, Direction)> Spread8D =
[
(new int2(1, 0), R),
(new int2(1, 1), RD),
(new int2(0, 1), D),
(new int2(-1, 1), LD),
(new int2(-1, 0), L),
(new int2(-1, -1), LU),
(new int2(0, -1), U),
(new int2(1, -1), RU)
(new int2(1, 0), Direction.R),
(new int2(1, 1), Direction.RD),
(new int2(0, 1), Direction.D),
(new int2(-1, 1), Direction.LD),
(new int2(-1, 0), Direction.L),
(new int2(-1, -1), Direction.LU),
(new int2(0, -1), Direction.U),
(new int2(1, -1), Direction.RU)
];
/// <summary>Adjacent offsets, including diagonals.</summary>
public static readonly ImmutableArray<int2> Spread8 =
Spread8D.Select(((int2 XY, int _) v) => v.XY).ToImmutableArray();
Spread8D.Select(((int2 XY, Direction _) v) => v.XY).ToImmutableArray();
/// <summary>
/// Adjacent offsets, including diagonals. Assumes that CVec(1, 0)
@@ -117,34 +126,22 @@ namespace OpenRA.Mods.Common.MapGenerator
Spread8.Select(xy => new CVec(xy.X, xy.Y)).ToImmutableArray();
/// <summary>Convert a non-none direction to an int2 offset.</summary>
public static int2 ToInt2(int d)
public static int2 ToInt2(this Direction direction)
{
if (d >= 0 && d < 8)
return Spread8[d];
if (direction >= Direction.R && direction <= Direction.RU)
return Spread8[(int)direction];
else
throw new ArgumentException("bad direction");
}
static readonly ImmutableArray<int2> KiloVectors =
[
new(1024, 0),
new(724, 724),
new(0, 1024),
new(-724, 724),
new(-1024, 0),
new(-724, -724),
new(0, -1024),
new(724, -724),
];
/// <summary>
/// Convert a non-none direction to a CVec offset. Assumes that
/// CVec(1, 0) corresponds to Direction.R.
/// </summary>
public static CVec ToCVec(int d)
public static CVec ToCVec(this Direction direction)
{
if (d >= 0 && d < 8)
return Spread8CVec[d];
if (direction >= Direction.R && direction <= Direction.RU)
return Spread8CVec[(int)direction];
else
throw new ArgumentException("bad direction");
}
@@ -153,10 +150,10 @@ namespace OpenRA.Mods.Common.MapGenerator
/// Convert a non-none direction to a WVec offset. Assumes that
/// WVec(1, 0, 0) corresponds to Direction.R.
/// </summary>
public static WVec ToWVec(int d)
public static WVec ToWVec(this Direction direction)
{
if (d >= 0 && d < 8)
return new WVec(Spread8[d].X, Spread8[d].Y, 0);
if (direction >= Direction.R && direction <= Direction.RU)
return new WVec(Spread8[(int)direction].X, Spread8[(int)direction].Y, 0);
else
throw new ArgumentException("bad direction");
}
@@ -166,32 +163,32 @@ namespace OpenRA.Mods.Common.MapGenerator
/// The direction is based purely on the signs of the inputs.
/// Supplying a zero-offset will throw.
/// </summary>
public static int FromOffset(int dx, int dy)
public static Direction FromOffset(int dx, int dy)
{
if (dx > 0)
{
if (dy > 0)
return RD;
return Direction.RD;
else if (dy < 0)
return RU;
return Direction.RU;
else
return R;
return Direction.R;
}
else if (dx < 0)
{
if (dy > 0)
return LD;
return Direction.LD;
else if (dy < 0)
return LU;
return Direction.LU;
else
return L;
return Direction.L;
}
else
{
if (dy > 0)
return D;
return Direction.D;
else if (dy < 0)
return U;
return Direction.U;
else
throw new ArgumentException("Bad direction");
}
@@ -202,32 +199,37 @@ namespace OpenRA.Mods.Common.MapGenerator
/// The direction with the closest angle wins. Keep inputs to 1000000 or less.
/// Supplying a zero-offset will throw.
/// </summary>
public static int FromOffsetRounding(int dx, int dy)
public static Direction ClosestFrom(int dx, int dy)
{
if (dx == 0 && dy == 0)
throw new ArgumentException("Bad direction");
throw new ArgumentException("bad direction");
var d = new int2(dx, dy);
var direction = None;
var best = 0;
for (var i = 0; i < KiloVectors.Length; i++)
var absX = Math.Abs(dx);
var absY = Math.Abs(dy);
var min = Math.Min(absX, absY);
var max = Math.Max(absX, absY);
// 408 / 985 is an approximation of tan(Pi / 8 radians), or tan(22.5 degrees)
if (408 * max < 985 * min)
{
var score = int2.Dot(d, KiloVectors[i]);
if (score > best)
{
best = score;
direction = i;
}
// Diagonal
return FromOffset(dx, dy);
}
else
{
// Cardinal
if (absX > absY)
return FromOffsetNonDiagonal(dx, 0);
else
return FromOffsetNonDiagonal(0, dy);
}
return direction;
}
/// <summary>
/// Convert an offset (of arbitrary non-zero magnitude) to a direction.
/// Supplying a zero-offset will throw.
/// </summary>
public static int FromInt2(int2 delta)
public static Direction FromInt2(int2 delta)
=> FromOffset(delta.X, delta.Y);
/// <summary>
@@ -235,7 +237,7 @@ namespace OpenRA.Mods.Common.MapGenerator
/// Supplying a zero-offset will throw. Assumes that CVec(1, 0)
/// corresponds to Direction.R.
/// </summary>
public static int FromCVec(CVec delta)
public static Direction FromCVec(CVec delta)
=> FromOffset(delta.X, delta.Y);
/// <summary>
@@ -243,23 +245,23 @@ namespace OpenRA.Mods.Common.MapGenerator
/// Supplying a zero-offset will throw. Assumes that CVec(1, 0)
/// corresponds to Direction.R.
/// </summary>
public static int FromCVecRounding(CVec delta)
=> FromOffsetRounding(delta.X, delta.Y);
public static Direction ClosestFromCVec(CVec delta)
=> ClosestFrom(delta.X, delta.Y);
/// <summary>
/// Convert an offset (of arbitrary non-zero magnitude) to a non-diagonal direction.
/// Supplying a zero-offset will throw.
/// </summary>
public static int FromOffsetNonDiagonal(int dx, int dy)
public static Direction FromOffsetNonDiagonal(int dx, int dy)
{
if (dx - dy > 0 && dx + dy >= 0)
return R;
return Direction.R;
if (dy + dx > 0 && dy - dx >= 0)
return D;
return Direction.D;
if (-dx + dy > 0 && -dx - dy >= 0)
return L;
return Direction.L;
if (-dy - dx > 0 && -dy + dx >= 0)
return U;
return Direction.U;
throw new ArgumentException("bad direction");
}
@@ -267,7 +269,7 @@ namespace OpenRA.Mods.Common.MapGenerator
/// Convert an offset (of arbitrary non-zero magnitude) to a
/// non-diagonal direction. Supplying a zero-offset will throw.
/// </summary>
public static int FromInt2NonDiagonal(int2 delta)
public static Direction FromInt2NonDiagonal(int2 delta)
=> FromOffsetNonDiagonal(delta.X, delta.Y);
/// <summary>
@@ -275,81 +277,53 @@ namespace OpenRA.Mods.Common.MapGenerator
/// non-diagonal direction. Supplying a zero-offset will throw. Assumes
/// that CVec(1, 0) corresponds to Direction.R.
/// </summary>
public static int FromCVecNonDiagonal(CVec delta)
public static Direction FromCVecNonDiagonal(CVec delta)
=> FromOffsetNonDiagonal(delta.X, delta.Y);
/// <summary>Return the opposite direction.</summary>
public static int Reverse(int direction)
public static Direction Reverse(this Direction direction)
{
if (direction == None)
return None;
return direction ^ 4;
if (direction != Direction.None)
return (Direction)((int)direction ^ 4);
else
return Direction.None;
}
/// <summary>Convert a direction to a short string, like "None", "R", "RD", etc.</summary>
public static string ToString(int direction)
/// <summary>Converts the direction to a mask value.</summary>
public static DirectionMask ToMask(this Direction direction)
{
switch (direction)
{
case None: return "None";
case R: return "R";
case RD: return "RD";
case D: return "D";
case LD: return "LD";
case L: return "L";
case LU: return "LU";
case U: return "U";
case RU: return "RU";
default: throw new ArgumentException("bad direction");
}
if (direction >= Direction.R && direction <= Direction.RU)
return (DirectionMask)(1 << (int)direction);
else
return DirectionMask.None;
}
}
public static class DirectionMaskExts
{
/// <summary>Count the number of set bits (directions) in a direction mask.</summary>
public static int Count(this DirectionMask mask)
{
return int.PopCount((int)mask);
}
/// <summary>Count the number of set bits in a direction mask.</summary>
public static int Count(int dm)
/// <summary>Finds the only direction set in a direction mask or returns None.</summary>
public static Direction ToDirection(this DirectionMask mask)
{
var count = 0;
for (var m = dm; m != 0; m >>= 1)
if ((m & 1) == 1)
count++;
return count;
}
/// <summary>Finds the only direction set in a direction mask or returns NONE.</summary>
public static int FromMask(int mask)
{
switch (mask)
{
case MR: return R;
case MRD: return RD;
case MD: return D;
case MLD: return LD;
case ML: return L;
case MLU: return LU;
case MU: return U;
case MRU: return RU;
default: return None;
}
var d = int.Log2((int)mask);
if (1 << d == (int)mask)
return (Direction)d;
else
return Direction.None;
}
/// <summary>True if diagonal, false if horizontal/vertical, throws otherwise.</summary>
public static bool IsDiagonal(int direction)
public static bool IsDiagonal(this Direction direction)
{
switch (direction)
{
case R:
case D:
case L:
case U:
return false;
case RD:
case LD:
case LU:
case RU:
return true;
default:
throw new ArgumentException("NONE or bad direction");
}
if (direction >= Direction.R && direction <= Direction.RU)
return ((int)direction & 1) == 1;
else
throw new ArgumentException("None or bad direction");
}
}
}

View File

@@ -189,7 +189,7 @@ namespace OpenRA.Mods.Common.MapGenerator
output[xy] = distance;
unprocessed[i] = int.MaxValue;
foreach (var (offset, direction) in Direction.Spread8D)
foreach (var (offset, direction) in DirectionExts.Spread8D)
{
var nextXY = xy + offset;
if (!passable.ContainsXY(nextXY))
@@ -199,7 +199,7 @@ namespace OpenRA.Mods.Common.MapGenerator
if (output[nextXY] != int.MaxValue)
continue;
int nextDistance;
if (Direction.IsDiagonal(direction))
if (direction.IsDiagonal())
nextDistance = distance + Diagonal;
else
nextDistance = distance + Straight;
@@ -250,7 +250,7 @@ namespace OpenRA.Mods.Common.MapGenerator
}
}
FloodFill(space.Size, [(new int2(x, y), holeCount)], Filler, Direction.Spread4);
FloodFill(space.Size, [(new int2(x, y), holeCount)], Filler, DirectionExts.Spread4);
}
const int UNASSIGNED = int.MaxValue;
@@ -322,7 +322,7 @@ namespace OpenRA.Mods.Common.MapGenerator
}
}
FloodFill(size, seeds, Filler, Direction.Spread4);
FloodFill(size, seeds, Filler, DirectionExts.Spread4);
}
var deflatedSize = size + new int2(1, 1);
@@ -346,10 +346,10 @@ namespace OpenRA.Mods.Common.MapGenerator
}
deflated[cx, cy] = (byte)(
(neighborhood[0] != neighborhood[1] ? Direction.MU : 0) |
(neighborhood[1] != neighborhood[3] ? Direction.MR : 0) |
(neighborhood[3] != neighborhood[2] ? Direction.MD : 0) |
(neighborhood[2] != neighborhood[0] ? Direction.ML : 0));
(neighborhood[0] != neighborhood[1] ? DirectionMask.MU : 0) |
(neighborhood[1] != neighborhood[3] ? DirectionMask.MR : 0) |
(neighborhood[3] != neighborhood[2] ? DirectionMask.MD : 0) |
(neighborhood[2] != neighborhood[0] ? DirectionMask.ML : 0));
}
return deflated;
@@ -776,7 +776,7 @@ namespace OpenRA.Mods.Common.MapGenerator
roominess.Size,
seeds,
Filler,
Direction.Spread8);
DirectionExts.Spread8);
return roominess;
}
@@ -813,7 +813,7 @@ namespace OpenRA.Mods.Common.MapGenerator
{
var from = pointArray[i - 1];
var to = pointArray[i];
var direction = Direction.FromInt2(to - from);
var direction = DirectionExts.FromInt2(to - from);
var fx = from.X;
var fy = from.Y;
switch (direction)
@@ -850,7 +850,7 @@ namespace OpenRA.Mods.Common.MapGenerator
return prop;
}
FloodFill(size, seeds, FillChirality, Direction.Spread4);
FloodFill(size, seeds, FillChirality, DirectionExts.Spread4);
return chirality;
}
@@ -898,7 +898,7 @@ namespace OpenRA.Mods.Common.MapGenerator
// Looping paths contain the start/end point twice.
var paths = new List<int2[]>();
void TracePath(int sx, int sy, int direction)
void TracePath(int sx, int sy, Direction direction)
{
var points = new List<int2>();
var x = sx;
@@ -1214,18 +1214,18 @@ namespace OpenRA.Mods.Common.MapGenerator
for (var cx = 0; cx < matrix.Size.X; cx++)
{
var fromPos = new int2(cx, cy);
var fromDm = matrix[fromPos];
foreach (var (offset, d) in Direction.Spread8D)
var fromDm = (DirectionMask)matrix[fromPos];
foreach (var (offset, d) in DirectionExts.Spread8D)
{
if ((fromDm & (1 << d)) == 0)
if ((fromDm & d.ToMask()) == DirectionMask.None)
continue;
var dr = Direction.Reverse(d);
var dr = d.Reverse();
var toPos = new int2(cx + offset.X, cy + offset.Y);
if (matrix.ContainsXY(toPos) && (matrix[toPos] & (1 << dr)) != 0)
if (matrix.ContainsXY(toPos) && ((DirectionMask)matrix[toPos] & dr.ToMask()) != DirectionMask.None)
continue;
matrix[fromPos] = (byte)(output[fromPos] & ~(1 << d));
matrix[fromPos] = (byte)((DirectionMask)output[fromPos] & ~d.ToMask());
}
}
}
@@ -1236,17 +1236,17 @@ namespace OpenRA.Mods.Common.MapGenerator
for (var cy = 0; cy < input.Size.Y; cy++)
for (var cx = 0; cx < input.Size.X; cx++)
{
var dm = input[cx, cy];
if (Direction.Count(dm) > 2)
var dm = (DirectionMask)input[cx, cy];
if (dm.Count() > 2)
{
output[cx, cy] = 0;
foreach (var (offset, d) in Direction.Spread8D)
foreach (var (offset, d) in DirectionExts.Spread8D)
{
var xy = new int2(cx + offset.X, cy + offset.Y);
if (!input.ContainsXY(xy))
continue;
var dr = Direction.Reverse(d);
output[xy] = (byte)(output[xy] & ~(1 << dr));
var dr = d.Reverse();
output[xy] = (byte)((DirectionMask)output[xy] & ~dr.ToMask());
}
}
}
@@ -1266,20 +1266,20 @@ namespace OpenRA.Mods.Common.MapGenerator
// Find non-loops, starting at terminals.
var pointArrays = new List<int2[]>();
void TracePoints(int2 xy, int reverseDm)
void TracePoints(int2 xy, DirectionMask reverseDm)
{
var points = new List<int2>();
bool AddPoint()
{
points.Add(xy);
var dm = links[xy] & ~reverseDm;
var dm = (DirectionMask)links[xy] & ~reverseDm;
links[xy] = 0;
foreach (var (offset, d) in Direction.Spread8D)
if ((dm & (1 << d)) != 0)
foreach (var (offset, d) in DirectionExts.Spread8D)
if ((dm & d.ToMask()) != DirectionMask.None)
{
xy += offset;
reverseDm = 1 << Direction.Reverse(d);
reverseDm = d.Reverse().ToMask();
return true;
}
@@ -1294,7 +1294,7 @@ namespace OpenRA.Mods.Common.MapGenerator
for (var sy = 0; sy < links.Size.Y; sy++)
for (var sx = 0; sx < links.Size.X; sx++)
if (Direction.FromMask(links[sx, sy]) != Direction.None)
if (((DirectionMask)links[sx, sy]).ToDirection() != Direction.None)
TracePoints(new int2(sx, sy), 0);
// All non-loops have been removed, leaving only loops left.
@@ -1303,7 +1303,7 @@ namespace OpenRA.Mods.Common.MapGenerator
if (links[sx, sy] != 0)
{
// Choose direction with most-significant bit
var reverseDm = links[sx, sy] & (links[sx, sy] - 1);
var reverseDm = (DirectionMask)(links[sx, sy] & (links[sx, sy] - 1));
TracePoints(new int2(sx, sy), reverseDm);
}
@@ -1351,8 +1351,8 @@ namespace OpenRA.Mods.Common.MapGenerator
{
toDelete.Add(point);
if (pointArray.Length < minimumJunctionSeparation)
foreach (var (offset, d) in Direction.Spread8D)
if ((links[point] & (1 << d)) != 0)
foreach (var (offset, d) in DirectionExts.Spread8D)
if (((DirectionMask)links[point] & d.ToMask()) != DirectionMask.None)
toDelete.Add(point + offset);
}

View File

@@ -123,7 +123,7 @@ namespace OpenRA.Mods.Common.MapGenerator
playable,
[(start, true)],
Filler,
Direction.Spread4CVec);
DirectionExts.Spread4CVec);
}
foreach (var mpos in map.AllCells.MapCoords)

View File

@@ -31,7 +31,7 @@ namespace OpenRA.Mods.Common.MapGenerator
/// Direction to use for this terminal.
/// If the direction here is null, it will be determined automatically later.
/// </summary>
public int? Direction;
public Direction? Direction;
/// <summary>
/// A string which can match the format used by MultiBrushSegment's Start or End.
@@ -42,11 +42,11 @@ namespace OpenRA.Mods.Common.MapGenerator
{
var direction =
Direction ?? throw new InvalidOperationException("Direction is null");
return $"{Type}.{MapGenerator.Direction.ToString(direction)}";
return $"{Type}.{direction}";
}
}
public Terminal(string type, int? direction)
public Terminal(string type, Direction? direction)
{
Type = type;
Direction = direction;
@@ -249,9 +249,9 @@ namespace OpenRA.Mods.Common.MapGenerator
public readonly CVec Offset;
public readonly CVec Moves;
public readonly CVec[] RelativePoints;
public readonly int[] Directions;
public readonly int[] DirectionMasks;
public readonly int[] ReverseDirectionMasks;
public readonly Direction[] Directions;
public readonly DirectionMask[] DirectionMasks;
public readonly DirectionMask[] ReverseDirectionMasks;
public TilingSegment(MultiBrush multiBrush, int startId, int endId)
{
@@ -264,9 +264,9 @@ namespace OpenRA.Mods.Common.MapGenerator
.Select(p => p - multiBrush.Segment.Points[0])
.ToArray();
Directions = new int[RelativePoints.Length];
DirectionMasks = new int[RelativePoints.Length];
ReverseDirectionMasks = new int[RelativePoints.Length];
Directions = new Direction[RelativePoints.Length];
DirectionMasks = new DirectionMask[RelativePoints.Length];
ReverseDirectionMasks = new DirectionMask[RelativePoints.Length];
// Last point has no direction.
Directions[^1] = Direction.None;
@@ -274,12 +274,12 @@ namespace OpenRA.Mods.Common.MapGenerator
ReverseDirectionMasks[^1] = 0;
for (var i = 0; i < RelativePoints.Length - 1; i++)
{
var direction = Direction.FromCVec(RelativePoints[i + 1] - RelativePoints[i]);
var direction = DirectionExts.FromCVec(RelativePoints[i + 1] - RelativePoints[i]);
if (direction == Direction.None)
throw new ArgumentException("MultiBrushSegment has duplicate points in sequence");
Directions[i] = direction;
DirectionMasks[i] = 1 << direction;
ReverseDirectionMasks[i] = 1 << Direction.Reverse(direction);
DirectionMasks[i] = direction.ToMask();
ReverseDirectionMasks[i] = direction.Reverse().ToMask();
}
}
}
@@ -349,8 +349,8 @@ namespace OpenRA.Mods.Common.MapGenerator
var start = Start;
var end = End;
start.Direction ??= Direction.FromCVec(Points[1] - Points[0]);
end.Direction ??= Direction.FromCVec(IsLoop ? Points[1] - Points[0] : Points[^1] - Points[^2]);
start.Direction ??= DirectionExts.FromCVec(Points[1] - Points[0]);
end.Direction ??= DirectionExts.FromCVec(IsLoop ? Points[1] - Points[0] : Points[^1] - Points[^2]);
var maxSkip = MaxSkip > 0 ? MaxSkip : (2 * MaxDeviation + 1);
@@ -472,7 +472,7 @@ namespace OpenRA.Mods.Common.MapGenerator
lows.Clear();
highs.Clear();
foreach (var offset in Direction.Spread8)
foreach (var offset in DirectionExts.Spread8)
{
var neighbor = xy + offset;
if (!deviations.ContainsXY(neighbor) ||
@@ -502,7 +502,7 @@ namespace OpenRA.Mods.Common.MapGenerator
size,
progressSeeds,
ProgressFiller,
Direction.Spread8);
DirectionExts.Spread8);
var separationSeeds = new List<(int2, int)>();
@@ -521,7 +521,7 @@ namespace OpenRA.Mods.Common.MapGenerator
if (MinSeparation > 0)
{
foreach (var offset in Direction.Spread8)
foreach (var offset in DirectionExts.Spread8)
{
var neighbor = xy + offset;
if (!deviations.ContainsXY(neighbor) ||
@@ -553,7 +553,7 @@ namespace OpenRA.Mods.Common.MapGenerator
size,
separationSeeds,
SeparationFiller,
Direction.Spread8);
DirectionExts.Spread8);
}
var pathStart = points[0];
@@ -861,7 +861,7 @@ namespace OpenRA.Mods.Common.MapGenerator
fallbackDistances.Size,
[(new int2(maxEndDeviation, maxEndDeviation), 0)],
FallbacksFiller,
Direction.Spread4);
DirectionExts.Spread4);
var bestDistance = fallbackDistances.Data.Min();
if (bestDistance == Unreached || bestDistance == Unsolved)
@@ -943,17 +943,17 @@ namespace OpenRA.Mods.Common.MapGenerator
if (inertialRange > points.Length - 1)
inertialRange = points.Length - 1;
var sd = Direction.FromCVecNonDiagonal(points[inertialRange] - points[0]);
var ed = Direction.FromCVecNonDiagonal(points[^1] - points[^(inertialRange + 1)]);
var sd = DirectionExts.FromCVecNonDiagonal(points[inertialRange] - points[0]);
var ed = DirectionExts.FromCVecNonDiagonal(points[^1] - points[^(inertialRange + 1)]);
var newPoints = new CPos[points.Length + extensionLength * 2];
for (var i = 0; i < extensionLength; i++)
newPoints[i] = points[0] - Direction.ToCVec(sd) * (extensionLength - i);
newPoints[i] = points[0] - sd.ToCVec() * (extensionLength - i);
Array.Copy(points, 0, newPoints, extensionLength, points.Length);
for (var i = 0; i < extensionLength; i++)
newPoints[extensionLength + points.Length + i] = points[^1] + Direction.ToCVec(ed) * (i + 1);
newPoints[extensionLength + points.Length + i] = points[^1] + ed.ToCVec() * (i + 1);
return newPoints;
}
@@ -1341,7 +1341,7 @@ namespace OpenRA.Mods.Common.MapGenerator
for (var i = 1; i < points.Length; i++)
{
var offset = lastPoint - points[i];
if (Direction.ToCVec(Direction.FromCVecNonDiagonal(offset)) != offset)
if (DirectionExts.FromCVecNonDiagonal(offset).ToCVec() != offset)
return false;
lastPoint = points[i];

View File

@@ -1049,7 +1049,7 @@ namespace OpenRA.Mods.Common.Traits
regionMask,
map.AllCells.Where(cpos => regionMask[cpos] == largest.Id).Select(cpos => (cpos, true)),
AdoptPartiallyPlayableIntoLargest,
Direction.Spread4CVec);
DirectionExts.Spread4CVec);
if (param.DenyWalledAreas)
{
@@ -1086,7 +1086,7 @@ namespace OpenRA.Mods.Common.Traits
map.Tiles,
unplayableWater.Select(cpos => (cpos, false)),
ClearWaterBody,
Direction.Spread4CVec);
DirectionExts.Spread4CVec);
}
var replaceable = IdentifyReplaceableTiles(map, replaceabilityMap, actorPlans);

View File

@@ -54,11 +54,11 @@ namespace OpenRA.Mods.Common.Traits
/// </summary>
public sealed class PathPlan
{
public readonly int Start;
public readonly int End;
public readonly Direction Start;
public readonly Direction End;
public readonly bool Loop;
public readonly ImmutableArray<CPos> Rallies;
public int AutoStart
public Direction AutoStart
{
get
{
@@ -69,14 +69,14 @@ namespace OpenRA.Mods.Common.Traits
else
{
if (Rallies.Length >= 2)
return Direction.FromCVecRounding(Rallies[1] - Rallies[0]);
return DirectionExts.ClosestFromCVec(Rallies[1] - Rallies[0]);
else
return Direction.None;
}
}
}
public int AutoEnd
public Direction AutoEnd
{
get
{
@@ -91,7 +91,7 @@ namespace OpenRA.Mods.Common.Traits
else
{
if (Rallies.Length >= 2)
return Direction.FromCVecRounding(Rallies[^1] - Rallies[^2]);
return DirectionExts.ClosestFromCVec(Rallies[^1] - Rallies[^2]);
else
return Direction.None;
}
@@ -101,7 +101,7 @@ namespace OpenRA.Mods.Common.Traits
public CPos FirstPoint => Rallies[0];
public CPos LastPoint => Loop ? Rallies[0] : Rallies[^1];
PathPlan(int start, int end, bool loop, ImmutableArray<CPos> rallies)
PathPlan(Direction start, Direction end, bool loop, ImmutableArray<CPos> rallies)
{
if (rallies == null || rallies.Length == 0)
throw new ArgumentException("rallies must have at least one point");
@@ -122,13 +122,13 @@ namespace OpenRA.Mods.Common.Traits
}
/// <summary>Return a copy, modifying the start direction.</summary>
public PathPlan WithStart(int start)
public PathPlan WithStart(Direction start)
{
return new PathPlan(start, End, Loop, Rallies);
}
/// <summary>Return a copy, modifying the end direction.</summary>
public PathPlan WithEnd(int end)
public PathPlan WithEnd(Direction end)
{
return new PathPlan(Start, end, Loop, Rallies);
}
@@ -191,16 +191,16 @@ namespace OpenRA.Mods.Common.Traits
}
return new PathPlan(
Direction.Reverse(reversedStart),
Direction.Reverse(reversedEnd),
reversedStart.Reverse(),
reversedEnd.Reverse(),
Loop,
Rallies.Skip(1).Append(Rallies[0]).Reverse().ToImmutableArray());
}
else
{
return new PathPlan(
Direction.Reverse(End),
Direction.Reverse(Start),
End.Reverse(),
Start.Reverse(),
Loop,
Rallies.Reverse().ToImmutableArray());
}
@@ -228,7 +228,7 @@ namespace OpenRA.Mods.Common.Traits
var points = new List<(CPos CPos, int RallyIndex)>();
var cpos = Rallies[0];
points.Add((cpos, 0));
var inertia = Direction.ToCVec(AutoStart);
var inertia = AutoStart.ToCVec();
if (inertia.X != 0 && inertia.Y != 0)
inertia = new CVec(inertia.X, 0);
@@ -267,9 +267,9 @@ namespace OpenRA.Mods.Common.Traits
inertia = new CVec(0, yStep);
else
inertia =
Direction.ToCVec(
Direction.FromCVecNonDiagonal(
inertia + new CVec(xStep * 2, yStep * 2)));
DirectionExts.FromCVecNonDiagonal(
inertia + new CVec(xStep * 2, yStep * 2))
.ToCVec();
while (cpos != target)
{