diff --git a/OpenRA.Mods.Common/MapGenerator/NoiseUtils.cs b/OpenRA.Mods.Common/MapGenerator/NoiseUtils.cs index b0b02edcf2..c02faeaa73 100644 --- a/OpenRA.Mods.Common/MapGenerator/NoiseUtils.cs +++ b/OpenRA.Mods.Common/MapGenerator/NoiseUtils.cs @@ -189,7 +189,7 @@ namespace OpenRA.Mods.Common.MapGenerator MersenneTwister random, CellLayer cellLayer, int rotations, - Symmetry.Mirror mirror, + Symmetry.WMirror wmirror, int featureSize, Func ampFunc) { @@ -199,7 +199,7 @@ namespace OpenRA.Mods.Common.MapGenerator random, size, rotations, - mirror, + wmirror.ForCPos(), featureSize, ampFunc); CellLayerUtils.FromMatrix(cellLayer, noise); diff --git a/OpenRA.Mods.Common/MapGenerator/Symmetry.cs b/OpenRA.Mods.Common/MapGenerator/Symmetry.cs index b69ecc82af..dc8c029c47 100644 --- a/OpenRA.Mods.Common/MapGenerator/Symmetry.cs +++ b/OpenRA.Mods.Common/MapGenerator/Symmetry.cs @@ -18,25 +18,66 @@ namespace OpenRA.Mods.Common.MapGenerator { public static class Symmetry { - /// Trivial mirroring configurations defined in world space. + /// + /// Trivial mirroring configurations. These are not tied to a specific coordinate system. + /// public enum Mirror { /// No mirror. None = 0, - /// Match low X with high X in WPos space. + /// Match low X with high X. LeftMatchesRight = 1, - /// Match low X, low Y with high X, high Y in WPos space. + /// Match low X, low Y with high X, high Y. TopLeftMatchesBottomRight = 2, - /// Match low Y with high Y in WPos space. + /// Match low Y with high Y. TopMatchesBottom = 3, - /// Match low X, high Y with high X, low Y in WPos space. + /// Match low X, high Y with high X, low Y. TopRightMatchesBottomLeft = 4, } + /// + /// Wraps a mirror defined in terms of WPos space and provides conversions to appropriate + /// coordinate systems. + /// + public readonly struct WMirror + { + readonly Mirror mirror; + readonly MapGridType gridType; + + /// Create a WMirror. + /// Mirror relative to WPos space. + /// Map grid type used for conversions. + public WMirror(Mirror mirror, MapGridType gridType) + { + this.mirror = mirror; + this.gridType = gridType; + } + + public bool HasMirror => mirror != Mirror.None; + + /// Return a Mirror relative to the WPos coordinate system. + public Mirror ForWPos() + { + return mirror; + } + + /// Return a Mirror relative to the CPos coordinate system. + public Mirror ForCPos() + { + if (mirror == Mirror.None) + return Mirror.None; + + if (gridType == MapGridType.RectangularIsometric) + return (Mirror)((((int)mirror + 2) & 0b11) + 1); + + return mirror; + } + } + public static bool TryParseMirror(string s, out Mirror mirror) => Enum.TryParse(s, out mirror); /// @@ -71,10 +112,10 @@ namespace OpenRA.Mods.Common.MapGenerator } } - public static WPos MirrorWPosAround(Mirror mirror, WPos original, WPos center) + public static WPos MirrorWPosAround(WMirror wmirror, WPos original, WPos center) { var result = MirrorPointAround( - mirror, + wmirror.ForWPos(), new int2(original.X, original.Y), new int2(center.X, center.Y)); return new WPos(result.X, result.Y, original.Z); @@ -91,9 +132,9 @@ namespace OpenRA.Mods.Common.MapGenerator WPos original, WPos center, int rotations, - Mirror mirror) + WMirror wmirror) { - var projections = new WPos[RotateAndMirrorProjectionCount(rotations, mirror)]; + var projections = new WPos[RotateAndMirrorProjectionCount(rotations, wmirror.ForWPos())]; var projectionIndex = 0; for (var rotation = 0; rotation < rotations; rotation++) @@ -109,8 +150,8 @@ namespace OpenRA.Mods.Common.MapGenerator var projection = new WPos(projX, projY, original.Z); projections[projectionIndex++] = projection; - if (mirror != Mirror.None) - projections[projectionIndex++] = MirrorWPosAround(mirror, projection, center); + if (wmirror.HasMirror) + projections[projectionIndex++] = MirrorWPosAround(wmirror, projection, center); } return projections; @@ -120,24 +161,24 @@ namespace OpenRA.Mods.Common.MapGenerator WPos original, CellLayer cellLayer, int rotations, - Mirror mirror) + WMirror wmirror) { return RotateAndMirrorWPosAround( original, CellLayerUtils.Center(cellLayer), rotations, - mirror); + wmirror); } public static CPos[] RotateAndMirrorCPos( CPos original, CellLayer cellLayer, int rotations, - Mirror mirror) + WMirror wmirror) { - var cposProjections = new CPos[RotateAndMirrorProjectionCount(rotations, mirror)]; + var cposProjections = new CPos[RotateAndMirrorProjectionCount(rotations, wmirror.ForWPos())]; var wpos = CellLayerUtils.CPosToWPos(original, cellLayer.GridType); - var wposProjections = RotateAndMirrorWPos(wpos, cellLayer, rotations, mirror); + var wposProjections = RotateAndMirrorWPos(wpos, cellLayer, rotations, wmirror); for (var i = 0; i < wposProjections.Length; i++) cposProjections[i] = CellLayerUtils.WPosToCPos(wposProjections[i], cellLayer.GridType); return cposProjections; @@ -222,12 +263,12 @@ namespace OpenRA.Mods.Common.MapGenerator public static ImmutableArray RotateAndMirrorActorPlans( IReadOnlyList originals, int rotations, - Mirror mirror) + WMirror wmirror) { var projections = new List( - originals.Count * RotateAndMirrorProjectionCount(rotations, mirror)); + originals.Count * RotateAndMirrorProjectionCount(rotations, wmirror.ForWPos())); foreach (var original in originals) - projections.AddRange(RotateAndMirrorActorPlan(original, rotations, mirror)); + projections.AddRange(RotateAndMirrorActorPlan(original, rotations, wmirror)); return projections.ToImmutableArray(); } @@ -239,14 +280,14 @@ namespace OpenRA.Mods.Common.MapGenerator public static ImmutableArray RotateAndMirrorActorPlan( ActorPlan original, int rotations, - Mirror mirror) + WMirror wmirror) { - var projections = new List(RotateAndMirrorProjectionCount(rotations, mirror)); + var projections = new List(RotateAndMirrorProjectionCount(rotations, wmirror.ForWPos())); var points = RotateAndMirrorWPos( original.WPosCenterLocation, original.Map.Tiles, rotations, - mirror); + wmirror); foreach (var point in points) { var plan = original.Clone(); @@ -266,7 +307,7 @@ namespace OpenRA.Mods.Common.MapGenerator public static void RotateAndMirrorOverCPos( CellLayer cellLayer, int rotations, - Mirror mirror, + WMirror wmirror, Action action) { var size = cellLayer.Size; @@ -274,7 +315,7 @@ namespace OpenRA.Mods.Common.MapGenerator for (var u = 0; u < size.Width; u++) { var original = new MPos(u, v).ToCPos(cellLayer.GridType); - var projections = RotateAndMirrorCPos(original, cellLayer, rotations, mirror); + var projections = RotateAndMirrorCPos(original, cellLayer, rotations, wmirror); action(projections, original); } } diff --git a/OpenRA.Mods.Common/MapGenerator/Terraformer.cs b/OpenRA.Mods.Common/MapGenerator/Terraformer.cs index 75ca8e2ffe..2d49309c3c 100644 --- a/OpenRA.Mods.Common/MapGenerator/Terraformer.cs +++ b/OpenRA.Mods.Common/MapGenerator/Terraformer.cs @@ -106,7 +106,7 @@ namespace OpenRA.Mods.Common.MapGenerator public readonly Map Map; public readonly ModData ModData; public readonly List ActorPlans; - public readonly Symmetry.Mirror Mirror; + public readonly Symmetry.WMirror WMirror; public readonly int Rotations; readonly ITerrainInfo terrainInfo; @@ -128,7 +128,7 @@ namespace OpenRA.Mods.Common.MapGenerator Map = map; ModData = modData; ActorPlans = actorPlans; - Mirror = mirror; + WMirror = new Symmetry.WMirror(mirror, map.Grid.Type); Rotations = rotations; terrainInfo = modData.DefaultTerrainInfo[map.Tileset]; @@ -222,7 +222,7 @@ namespace OpenRA.Mods.Common.MapGenerator Symmetry.RotateAndMirrorOverCPos( layer, Rotations, - Mirror, + WMirror, (sources, destination) => newLayer[destination] = sources .Select(source => layer.TryGetValue(source, out var value) ? value : outsideValue) @@ -371,7 +371,7 @@ namespace OpenRA.Mods.Common.MapGenerator if (mask != null) zoneable = CellLayerUtils.Intersect([zoneable, mask]); - if (Rotations > 1 || Mirror != Symmetry.Mirror.None) + if (Rotations > 1 || WMirror.HasMirror) { // Reserve the center of the map - otherwise it will mess with symmetries CellLayerUtils.OverCircle( @@ -411,7 +411,7 @@ namespace OpenRA.Mods.Common.MapGenerator Symmetry.RotateAndMirrorOverCPos( projectionSpacing, Rotations, - Mirror, + WMirror, (projections, cpos) => projectionSpacing[cpos] = Symmetry.ProjectionProximity(projections) / 2); return projectionSpacing; @@ -443,7 +443,7 @@ namespace OpenRA.Mods.Common.MapGenerator Symmetry.RotateAndMirrorOverCPos( incompatibilities, Rotations, - Mirror, + WMirror, (sources, destination) => { if (!dominant[destination]) @@ -545,7 +545,7 @@ namespace OpenRA.Mods.Common.MapGenerator Symmetry.RotateAndMirrorOverCPos( regionMask, Rotations, - Mirror, + WMirror, TestSymmetry); for (var id = 0; id < symmetryScore.Length; id++) @@ -726,7 +726,7 @@ namespace OpenRA.Mods.Common.MapGenerator { CheckHasMapShapeOrNull(zoneable); var projections = Symmetry.RotateAndMirrorActorPlan( - actorPlan, Rotations, Mirror); + actorPlan, Rotations, WMirror); ActorPlans.AddRange(projections); if (zoneable != null) foreach (var projection in projections) @@ -998,7 +998,7 @@ namespace OpenRA.Mods.Common.MapGenerator random, noise, Rotations, - Mirror, + WMirror, noiseFeatureSize, wavelength => NoiseUtils.ClumpinessAmplitude(wavelength, clumpiness)); @@ -1021,7 +1021,7 @@ namespace OpenRA.Mods.Common.MapGenerator random, CellLayerUtils.CellBounds(Map).Size.ToInt2(), Rotations, - Mirror, + WMirror.ForCPos(), noiseFeatureSize, NoiseUtils.PinkAmplitude); MatrixUtils.NormalizeRangeInPlace(elevation, 1024); @@ -1050,7 +1050,7 @@ namespace OpenRA.Mods.Common.MapGenerator random, pattern, Rotations, - Mirror, + WMirror, noiseFeatureSize, wavelength => NoiseUtils.ClumpinessAmplitude(wavelength, clumpiness)); { @@ -1764,7 +1764,7 @@ namespace OpenRA.Mods.Common.MapGenerator chosenMPos.ToCPos(Map), space, Rotations, - Mirror); + WMirror); foreach (var projection in projections) { if (space.Contains(projection)) @@ -1811,7 +1811,7 @@ namespace OpenRA.Mods.Common.MapGenerator // For awkward symmetries, we try harder to make sure roads are fairer. // This can degrade the quantity of roads, though. var imperfectSymmetry = - Mirror != Symmetry.Mirror.None || + WMirror.HasMirror || Rotations == 3 || Rotations >= 5; var gridType = Map.Grid.Type; @@ -1890,7 +1890,7 @@ namespace OpenRA.Mods.Common.MapGenerator { var cposPath = CellLayerUtils.FromMatrixPoints([path], space)[0]; var projectedPoints = cposPath - .SelectMany(p => Symmetry.RotateAndMirrorCPos(p, space, Rotations, Mirror)) + .SelectMany(p => Symmetry.RotateAndMirrorCPos(p, space, Rotations, WMirror)) .ToArray(); var matrixPoints = CellLayerUtils.ToMatrixPoints([projectedPoints], space)[0]; if (!matrixPoints.All(p => !nearPath.ContainsXY(p) || nearPath[p])) @@ -2140,7 +2140,7 @@ namespace OpenRA.Mods.Common.MapGenerator var chosenMPos = PriorityMPos(n); var chosenCPos = chosenMPos.ToCPos(gridType); - foreach (var cpos in Symmetry.RotateAndMirrorCPos(chosenCPos, plan, Rotations, Mirror)) + foreach (var cpos in Symmetry.RotateAndMirrorCPos(chosenCPos, plan, Rotations, WMirror)) if (Map.Resources.Contains(cpos)) remaining -= AddResource(cpos); } @@ -2186,7 +2186,7 @@ namespace OpenRA.Mods.Common.MapGenerator random, decorationNoise, Rotations, - Mirror, + WMirror, featureSize, NoiseUtils.WhiteAmplitude); @@ -2195,7 +2195,7 @@ namespace OpenRA.Mods.Common.MapGenerator random, densityNoise, Rotations, - Mirror, + WMirror, 1024, NoiseUtils.PinkAmplitude); var densityMask = CellLayerUtils.CalibratedBooleanThreshold(