diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml
index 31268537..d4b86779 100644
--- a/.idea/inspectionProfiles/Project_Default.xml
+++ b/.idea/inspectionProfiles/Project_Default.xml
@@ -536,7 +536,9 @@
-
+
+
+
@@ -974,14 +976,19 @@
-
+
+
+
+
-
+
+
+
@@ -991,7 +998,11 @@
-
+
+
+
+
+
@@ -2211,7 +2222,10 @@
-
+
+
+
+
diff --git a/generator/src/main/java/com/faforever/neroxis/generator/terrain/BasicTerrainGenerator.java b/generator/src/main/java/com/faforever/neroxis/generator/terrain/BasicTerrainGenerator.java
index 9c2fc7f0..603b826e 100644
--- a/generator/src/main/java/com/faforever/neroxis/generator/terrain/BasicTerrainGenerator.java
+++ b/generator/src/main/java/com/faforever/neroxis/generator/terrain/BasicTerrainGenerator.java
@@ -3,12 +3,16 @@
import com.faforever.neroxis.brushes.Brushes;
import com.faforever.neroxis.generator.GeneratorParameters;
import com.faforever.neroxis.map.SCMap;
+import com.faforever.neroxis.map.Spawn;
import com.faforever.neroxis.map.SymmetrySettings;
import com.faforever.neroxis.mask.BooleanMask;
import com.faforever.neroxis.mask.FloatMask;
import com.faforever.neroxis.mask.MapMaskMethods;
+import com.faforever.neroxis.util.vector.Vector2;
import com.faforever.neroxis.util.vector.Vector3;
+import java.util.List;
+
public class BasicTerrainGenerator extends TerrainGenerator {
protected BooleanMask spawnLandMask;
protected BooleanMask spawnPlateauMask;
@@ -143,9 +147,18 @@ protected void teamConnectionsSetup() {
int numTeammateConnections = 1;
connections.setSize(map.getSize() + 1);
- MapMaskMethods.connectTeamsAroundCenter(map, random.nextLong(), connections, minMiddlePoints, maxMiddlePoints,
+ List team0SpawnLocations = map.getSpawns()
+ .stream()
+ .filter(spawn -> spawn.getTeamID() == 0)
+ .map(Spawn::getPosition)
+ .map(Vector2::new)
+ .toList();
+
+ MapMaskMethods.connectTeamsAroundCenter(team0SpawnLocations, random.nextLong(), connections, minMiddlePoints,
+ maxMiddlePoints,
numTeamConnections, maxStepSize, 32);
- MapMaskMethods.connectTeammates(map, random.nextLong(), connections, maxMiddlePoints, numTeammateConnections,
+ MapMaskMethods.connectTeammates(team0SpawnLocations, random.nextLong(), connections, maxMiddlePoints,
+ numTeammateConnections,
maxStepSize);
}
diff --git a/generator/src/main/java/com/faforever/neroxis/generator/terrain/BigIslandsTerrainGenerator.java b/generator/src/main/java/com/faforever/neroxis/generator/terrain/BigIslandsTerrainGenerator.java
index e5fedf95..f2a4fd18 100644
--- a/generator/src/main/java/com/faforever/neroxis/generator/terrain/BigIslandsTerrainGenerator.java
+++ b/generator/src/main/java/com/faforever/neroxis/generator/terrain/BigIslandsTerrainGenerator.java
@@ -1,8 +1,12 @@
package com.faforever.neroxis.generator.terrain;
import com.faforever.neroxis.generator.ParameterConstraints;
+import com.faforever.neroxis.map.Spawn;
import com.faforever.neroxis.mask.BooleanMask;
import com.faforever.neroxis.mask.MapMaskMethods;
+import com.faforever.neroxis.util.vector.Vector2;
+
+import java.util.List;
public class BigIslandsTerrainGenerator extends PathedTerrainGenerator {
@@ -24,7 +28,16 @@ protected void landSetup() {
BooleanMask islands = new BooleanMask(mapSize / 4, random.nextLong(), symmetrySettings, "islands", true);
land.setSize(mapSize + 1);
- MapMaskMethods.pathAroundSpawns(map, random.nextLong(), land, maxStepSize, numPaths, maxMiddlePoints, bound,
+
+ List team0SpawnLocations = map.getSpawns()
+ .stream()
+ .filter(spawn -> spawn.getTeamID() == 0)
+ .map(Spawn::getPosition)
+ .map(Vector2::new)
+ .toList();
+
+ MapMaskMethods.pathAroundSpawns(team0SpawnLocations, random.nextLong(), land, maxStepSize, numPaths,
+ maxMiddlePoints, bound,
(float) StrictMath.PI / 2);
land.inflate(maxStepSize).setSize(mapSize / 4);
diff --git a/generator/src/main/java/com/faforever/neroxis/generator/terrain/DropPlateauTerrainGenerator.java b/generator/src/main/java/com/faforever/neroxis/generator/terrain/DropPlateauTerrainGenerator.java
index 04d40b99..cf5d6e6d 100644
--- a/generator/src/main/java/com/faforever/neroxis/generator/terrain/DropPlateauTerrainGenerator.java
+++ b/generator/src/main/java/com/faforever/neroxis/generator/terrain/DropPlateauTerrainGenerator.java
@@ -2,8 +2,12 @@
import com.faforever.neroxis.generator.GeneratorParameters;
import com.faforever.neroxis.map.SCMap;
+import com.faforever.neroxis.map.Spawn;
import com.faforever.neroxis.map.SymmetrySettings;
import com.faforever.neroxis.mask.MapMaskMethods;
+import com.faforever.neroxis.util.vector.Vector2;
+
+import java.util.List;
public class DropPlateauTerrainGenerator extends PathedTerrainGenerator {
@@ -31,9 +35,18 @@ protected void teamConnectionsSetup() {
connections.setSize(mapSize + 1);
- MapMaskMethods.connectTeamsAroundCenter(map, random.nextLong(), connections, minMiddlePoints, maxMiddlePoints,
+ List team0SpawnLocations = map.getSpawns()
+ .stream()
+ .filter(spawn -> spawn.getTeamID() == 0)
+ .map(Spawn::getPosition)
+ .map(Vector2::new)
+ .toList();
+
+ MapMaskMethods.connectTeamsAroundCenter(team0SpawnLocations, random.nextLong(), connections, minMiddlePoints,
+ maxMiddlePoints,
numTeamConnections, maxStepSize, 32);
- MapMaskMethods.connectTeammates(map, random.nextLong(), connections, maxMiddlePoints, numTeammateConnections,
+ MapMaskMethods.connectTeammates(team0SpawnLocations, random.nextLong(), connections, maxMiddlePoints,
+ numTeammateConnections,
maxStepSize);
}
diff --git a/generator/src/main/java/com/faforever/neroxis/generator/terrain/LandBridgeTerrainGenerator.java b/generator/src/main/java/com/faforever/neroxis/generator/terrain/LandBridgeTerrainGenerator.java
index 272ad01c..c600e8a0 100644
--- a/generator/src/main/java/com/faforever/neroxis/generator/terrain/LandBridgeTerrainGenerator.java
+++ b/generator/src/main/java/com/faforever/neroxis/generator/terrain/LandBridgeTerrainGenerator.java
@@ -1,7 +1,11 @@
package com.faforever.neroxis.generator.terrain;
import com.faforever.neroxis.generator.ParameterConstraints;
+import com.faforever.neroxis.map.Spawn;
import com.faforever.neroxis.mask.MapMaskMethods;
+import com.faforever.neroxis.util.vector.Vector2;
+
+import java.util.List;
public class LandBridgeTerrainGenerator extends PathedTerrainGenerator {
@@ -20,9 +24,18 @@ protected void landSetup() {
int numPaths = 32 / generatorParameters.spawnCount();
land.setSize(mapSize + 1);
- MapMaskMethods.connectTeammates(map, random.nextLong(), land, 8, 2, maxStepSize);
- MapMaskMethods.connectTeams(map, random.nextLong(), land, 0, 2, 1, maxStepSize);
- MapMaskMethods.pathAroundSpawns(map, random.nextLong(), land, maxStepSize, numPaths, 4, mapSize / 6,
+
+ List team0SpawnLocations = map.getSpawns()
+ .stream()
+ .filter(spawn -> spawn.getTeamID() == 0)
+ .map(Spawn::getPosition)
+ .map(Vector2::new)
+ .toList();
+
+ MapMaskMethods.connectTeammates(team0SpawnLocations, random.nextLong(), land, 8, 2, maxStepSize);
+ MapMaskMethods.connectTeams(team0SpawnLocations, random.nextLong(), land, 0, 2, 1, maxStepSize);
+ MapMaskMethods.pathAroundSpawns(team0SpawnLocations, random.nextLong(), land, maxStepSize, numPaths, 4,
+ mapSize / 6,
(float) (StrictMath.PI / 2f));
land.inflate(maxStepSize);
land.setSize(mapSize / 8);
diff --git a/generator/src/main/java/com/faforever/neroxis/generator/terrain/OneIslandTerrainGenerator.java b/generator/src/main/java/com/faforever/neroxis/generator/terrain/OneIslandTerrainGenerator.java
index ada02955..ce70fc3e 100644
--- a/generator/src/main/java/com/faforever/neroxis/generator/terrain/OneIslandTerrainGenerator.java
+++ b/generator/src/main/java/com/faforever/neroxis/generator/terrain/OneIslandTerrainGenerator.java
@@ -3,8 +3,12 @@
import com.faforever.neroxis.generator.GeneratorParameters;
import com.faforever.neroxis.generator.ParameterConstraints;
import com.faforever.neroxis.map.SCMap;
+import com.faforever.neroxis.map.Spawn;
import com.faforever.neroxis.map.SymmetrySettings;
import com.faforever.neroxis.mask.MapMaskMethods;
+import com.faforever.neroxis.util.vector.Vector2;
+
+import java.util.List;
public class OneIslandTerrainGenerator extends PathedTerrainGenerator {
@@ -31,9 +35,18 @@ protected void teamConnectionsSetup() {
int numTeammateConnections = 1;
connections.setSize(map.getSize() + 1);
- MapMaskMethods.connectTeams(map, random.nextLong(), connections, minMiddlePoints, maxMiddlePoints,
+ List team0SpawnLocations = map.getSpawns()
+ .stream()
+ .filter(spawn -> spawn.getTeamID() == 0)
+ .map(Spawn::getPosition)
+ .map(Vector2::new)
+ .toList();
+
+ MapMaskMethods.connectTeams(team0SpawnLocations, random.nextLong(), connections, minMiddlePoints,
+ maxMiddlePoints,
numTeamConnections, maxStepSize);
- MapMaskMethods.connectTeammates(map, random.nextLong(), connections, maxMiddlePoints, numTeammateConnections,
+ MapMaskMethods.connectTeammates(team0SpawnLocations, random.nextLong(), connections, maxMiddlePoints,
+ numTeammateConnections,
maxStepSize);
}
@@ -58,9 +71,19 @@ protected void landSetup() {
.fillEdge((int) (mapSize / 8 * (1 - landDensity) + mapSize / 8), false)
.inflate(mapSize / 64f)
.blur(12, .125f));
- MapMaskMethods.connectTeamsAroundCenter(map, random.nextLong(), land, minMiddlePoints, maxMiddlePoints,
+
+ List team0SpawnLocations = map.getSpawns()
+ .stream()
+ .filter(spawn -> spawn.getTeamID() == 0)
+ .map(Spawn::getPosition)
+ .map(Vector2::new)
+ .toList();
+
+ MapMaskMethods.connectTeamsAroundCenter(team0SpawnLocations, random.nextLong(), land, minMiddlePoints,
+ maxMiddlePoints,
numTeamConnections, maxStepSize, 32);
- MapMaskMethods.connectTeammates(map, random.nextLong(), land, maxMiddlePoints, numTeammateConnections,
+ MapMaskMethods.connectTeammates(team0SpawnLocations, random.nextLong(), land, maxMiddlePoints,
+ numTeammateConnections,
maxStepSize);
land.inflate(mapSize / 128f).setSize(mapSize / 8);
land.dilute(.5f, 8).erode(.5f, 6);
diff --git a/generator/src/main/java/com/faforever/neroxis/generator/terrain/SmallIslandsTerrainGenerator.java b/generator/src/main/java/com/faforever/neroxis/generator/terrain/SmallIslandsTerrainGenerator.java
index 21f5841d..5697675a 100644
--- a/generator/src/main/java/com/faforever/neroxis/generator/terrain/SmallIslandsTerrainGenerator.java
+++ b/generator/src/main/java/com/faforever/neroxis/generator/terrain/SmallIslandsTerrainGenerator.java
@@ -3,9 +3,13 @@
import com.faforever.neroxis.generator.GeneratorParameters;
import com.faforever.neroxis.generator.ParameterConstraints;
import com.faforever.neroxis.map.SCMap;
+import com.faforever.neroxis.map.Spawn;
import com.faforever.neroxis.map.SymmetrySettings;
import com.faforever.neroxis.mask.BooleanMask;
import com.faforever.neroxis.mask.MapMaskMethods;
+import com.faforever.neroxis.util.vector.Vector2;
+
+import java.util.List;
public class SmallIslandsTerrainGenerator extends PathedTerrainGenerator {
@Override
@@ -28,13 +32,22 @@ protected void landSetup() {
int maxMiddlePoints = 4;
int numPaths = (int) (4 * landDensity + 4) / symmetrySettings.spawnSymmetry().getNumSymPoints();
- int bound = ((int) (mapSize / 16 * (random.nextFloat() * .25f + landDensity * .75f)) + mapSize / 16);
+ int bound = ((int) (mapSize / 16f * (random.nextFloat() * .25f + landDensity * .75f)) + mapSize / 16);
float maxStepSize = mapSize / 128f;
BooleanMask islands = new BooleanMask(mapSize / 4, random.nextLong(), symmetrySettings, "islands", true);
land.setSize(mapSize + 1);
- MapMaskMethods.pathAroundSpawns(map, random.nextLong(), land, maxStepSize, numPaths, maxMiddlePoints, bound,
+
+ List team0SpawnLocations = map.getSpawns()
+ .stream()
+ .filter(spawn -> spawn.getTeamID() == 0)
+ .map(Spawn::getPosition)
+ .map(Vector2::new)
+ .toList();
+
+ MapMaskMethods.pathAroundSpawns(team0SpawnLocations, random.nextLong(), land, maxStepSize, numPaths,
+ maxMiddlePoints, bound,
(float) StrictMath.PI / 2);
land.inflate(maxStepSize).setSize(mapSize / 4);
diff --git a/settings.gradle b/settings.gradle
index 9fea44e3..09657287 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -2,7 +2,5 @@ rootProject.name = 'NeroxisGen'
include 'shared'
include 'generator'
include 'toolsuite'
-include 'mapgeneditor'
include 'utilities'
-include 'ngraph'
diff --git a/shared/src/main/java/com/faforever/neroxis/map/SymmetrySettings.java b/shared/src/main/java/com/faforever/neroxis/map/SymmetrySettings.java
index 6d19b5c4..77a4e3be 100644
--- a/shared/src/main/java/com/faforever/neroxis/map/SymmetrySettings.java
+++ b/shared/src/main/java/com/faforever/neroxis/map/SymmetrySettings.java
@@ -5,6 +5,21 @@ public record SymmetrySettings(
Symmetry teamSymmetry,
Symmetry spawnSymmetry
) {
+
+ public SymmetrySettings {
+ if (terrainSymmetry.getNumSymPoints() % teamSymmetry.getNumSymPoints() != 0) {
+ throw new IllegalArgumentException("Team symmetry not a multiple of terrain symmetry");
+ }
+
+ if (terrainSymmetry.getNumSymPoints() % spawnSymmetry.getNumSymPoints() != 0) {
+ throw new IllegalArgumentException("Spawn symmetry not a multiple of terrain symmetry");
+ }
+
+ if (spawnSymmetry.getNumSymPoints() % teamSymmetry.getNumSymPoints() != 0) {
+ throw new IllegalArgumentException("Spawn symmetry not a multiple of team symmetry");
+ }
+ }
+
public SymmetrySettings(Symmetry symmetry) {
this(symmetry, symmetry, symmetry);
}
diff --git a/shared/src/main/java/com/faforever/neroxis/mask/BooleanMask.java b/shared/src/main/java/com/faforever/neroxis/mask/BooleanMask.java
index a19f62e7..7120eb52 100644
--- a/shared/src/main/java/com/faforever/neroxis/mask/BooleanMask.java
+++ b/shared/src/main/java/com/faforever/neroxis/mask/BooleanMask.java
@@ -6,6 +6,7 @@
import com.faforever.neroxis.util.BezierCurve;
import com.faforever.neroxis.util.SymmetryUtil;
import com.faforever.neroxis.util.functional.BiIntBooleanConsumer;
+import com.faforever.neroxis.util.functional.SymmetryRegionBoundsChecker;
import com.faforever.neroxis.util.functional.ToBooleanBiIntFunction;
import com.faforever.neroxis.util.vector.Vector2;
@@ -29,7 +30,7 @@
import static com.faforever.neroxis.brushes.Brushes.loadBrush;
@SuppressWarnings({"unchecked", "UnusedReturnValue", "unused"})
-public final class BooleanMask extends PrimitiveMask {
+public class BooleanMask extends PrimitiveMask {
private static final int BOOLEANS_PER_LONG = 64;
private static final long SINGLE_BIT_VALUE = 1;
private long[] mask;
@@ -56,12 +57,8 @@ public BooleanMask(int size, Long seed, SymmetrySettings symmetrySettings, Strin
this(size, seed, symmetrySettings, name, false);
}
- BooleanMask(BooleanMask other) {
- this(other, (String) null);
- }
-
- BooleanMask(BooleanMask other, String name) {
- super(other, name);
+ protected BooleanMask(BooleanMask other, String name, boolean immutable) {
+ super(other, name, immutable);
}
private , U extends Comparable> BooleanMask(T other, U minValue) {
@@ -126,6 +123,11 @@ private void setPrimitive(int x, int y, boolean value) {
setBit(x, y, value, getSize(), mask);
}
+ @Override
+ protected void copyValue(int sourceX, int sourceY, int destX, int destY) {
+ setPrimitive(destX, destY, getPrimitive(sourceX, sourceY));
+ }
+
@Override
public BooleanMask blur(int radius) {
return blur(radius, .5f);
@@ -234,7 +236,7 @@ protected BooleanMask setSizeInternal(int newSize) {
long[] oldMask = mask;
initializeMask(newSize);
Map coordinateMap = getSymmetricScalingCoordinateMap(oldSize, newSize);
- applyWithSymmetry(SymmetryType.SPAWN, (x, y) -> {
+ apply((x, y) -> {
boolean value = getBit(coordinateMap.get(x), coordinateMap.get(y), oldSize, oldMask);
setPrimitive(x, y, value);
});
@@ -606,13 +608,15 @@ public BooleanMask randomWalk(int numWalkers, int numSteps) {
int maxXBound = SymmetryUtil.getMaxXBound(symmetry, size);
IntUnaryOperator minYBoundFunction = SymmetryUtil.getMinYBoundFunction(symmetry, size);
IntUnaryOperator maxYBoundFunction = SymmetryUtil.getMaxYBoundFunction(symmetry, size);
+ SymmetryRegionBoundsChecker symmetryRegionBoundsChecker = SymmetryUtil.getSymmetryRegionBoundsChecker(
+ symmetry, size);
for (int i = 0; i < numWalkers; i++) {
int x = random.nextInt(maxXBound - minXBound) + minXBound;
int maxYBound = maxYBoundFunction.applyAsInt(x);
int minYBound = minYBoundFunction.applyAsInt(x);
int y = random.nextInt(maxYBound - minYBound + 1) + minYBound;
for (int j = 0; j < numSteps; j++) {
- if (inBounds(x, y, size)) {
+ if (inBounds(x, y, size) && symmetryRegionBoundsChecker.inBounds(x, y)) {
setPrimitive(x, y, true);
}
switch (random.nextInt(4)) {
@@ -714,6 +718,9 @@ public BooleanMask path(Vector2 start, Vector2 end, float maxStepSize, int numMi
SymmetryType symmetryType) {
return enqueue(() -> {
int size = getSize();
+ Symmetry symmetry = symmetrySettings.getSymmetry(symmetryType);
+ SymmetryRegionBoundsChecker symmetryRegionBoundsChecker = SymmetryUtil.getSymmetryRegionBoundsChecker(
+ symmetry, size);
List checkPoints = new ArrayList<>();
checkPoints.add(new Vector2(start));
for (int i = 0; i < numMiddlePoints; i++) {
@@ -737,9 +744,11 @@ public BooleanMask path(Vector2 start, Vector2 end, float maxStepSize, int numMi
Vector2 nextLoc = checkPoints.get(i + 1);
float oldAngle = location.angleTo(nextLoc) + (random.nextFloat() - .5f) * 2f * maxAngleError;
while (location.getDistance(nextLoc) > maxStepSize && numSteps < size * size) {
- List symmetryPoints = getSymmetryPoints(location, symmetryType);
- if (inBounds(location) && symmetryPoints.stream().allMatch(this::inBounds)) {
- setPrimitive((int) location.getX(), (int) location.getY(), true);
+ if (inBounds(location, size) && symmetryRegionBoundsChecker.inBounds(location)) {
+ List symmetryPoints = getSymmetryPoints(location, symmetryType);
+ if (symmetryPoints.stream().allMatch(this::inBounds)) {
+ setPrimitive(location, true);
+ }
}
float magnitude = StrictMath.max(1, random.nextFloat() * maxStepSize);
float angle = oldAngle * .5f + location.angleTo(nextLoc) * .5f
@@ -752,7 +761,7 @@ public BooleanMask path(Vector2 start, Vector2 end, float maxStepSize, int numMi
break;
}
}
- applySymmetry(SymmetryType.TERRAIN);
+ applySymmetry(symmetryType);
});
}
@@ -834,6 +843,8 @@ public BooleanMask progressiveWalk(int numWalkers, int numSteps) {
int maxXBound = SymmetryUtil.getMaxXBound(symmetry, size);
IntUnaryOperator minYBoundFunction = SymmetryUtil.getMinYBoundFunction(symmetry, size);
IntUnaryOperator maxYBoundFunction = SymmetryUtil.getMaxYBoundFunction(symmetry, size);
+ SymmetryRegionBoundsChecker symmetryRegionBoundsChecker = SymmetryUtil.getSymmetryRegionBoundsChecker(
+ symmetry, size);
for (int i = 0; i < numWalkers; i++) {
int x = random.nextInt(maxXBound - minXBound) + minXBound;
int maxYBound = maxYBoundFunction.applyAsInt(x);
@@ -843,7 +854,7 @@ public BooleanMask progressiveWalk(int numWalkers, int numSteps) {
int regressiveDir = random.nextInt(directions.size());
directions.remove(regressiveDir);
for (int j = 0; j < numSteps; j++) {
- if (inBounds(x, y, size)) {
+ if (inBounds(x, y, size) && symmetryRegionBoundsChecker.inBounds(x, y)) {
setPrimitive(x, y, true);
}
switch (directions.get(random.nextInt(directions.size()))) {
@@ -935,7 +946,7 @@ public BooleanMask erode(float strength) {
* @return the modified mask
*/
public BooleanMask acid(float strength, float size) {
- BooleanMask holes = new BooleanMask(this, getName() + "holes");
+ BooleanMask holes = new BooleanMask(this, getName() + "holes", false);
holes.randomize(strength, SymmetryType.SPAWN).inflate(size);
return enqueue(dependencies -> {
BooleanMask source = (BooleanMask) dependencies.getFirst();
@@ -950,7 +961,7 @@ public BooleanMask acid(float strength, float size) {
* @return the modified mask
*/
public BooleanMask splat(float strength, float size) {
- BooleanMask holes = new BooleanMask(this, getName() + "splat");
+ BooleanMask holes = new BooleanMask(this, getName() + "splat", false);
holes.randomize(strength, SymmetryType.SPAWN).inflate(size);
return enqueue(dependencies -> {
BooleanMask source = (BooleanMask) dependencies.getFirst();
@@ -1141,7 +1152,7 @@ public BooleanMask limitToSymmetryRegion(SymmetryType symmetryType) {
*/
public BooleanMask limitToCenteredCircle(float circleRadius) {
int size = getSize();
- BooleanMask symmetryLimit = new BooleanMask(size, null, symmetrySettings, getName() + "symmetryLimit",
+ BooleanMask symmetryLimit = new BooleanMask(size, null, symmetrySettings, getName() + "SymmetryLimit",
isParallel());
symmetryLimit.fillCircle(size / 2f, size / 2f, circleRadius, true);
return multiply(symmetryLimit);
diff --git a/shared/src/main/java/com/faforever/neroxis/mask/ComparableMask.java b/shared/src/main/java/com/faforever/neroxis/mask/ComparableMask.java
index f5641aa8..b6a9f252 100644
--- a/shared/src/main/java/com/faforever/neroxis/mask/ComparableMask.java
+++ b/shared/src/main/java/com/faforever/neroxis/mask/ComparableMask.java
@@ -3,13 +3,14 @@
import com.faforever.neroxis.map.SymmetrySettings;
@SuppressWarnings({"unchecked", "UnusedReturnValue", "unused"})
-public abstract sealed class ComparableMask, U extends ComparableMask> extends OperationsMask permits PrimitiveMask {
+public abstract class ComparableMask, U extends ComparableMask> extends
+ OperationsMask {
protected ComparableMask(int size, Long seed, SymmetrySettings symmetrySettings, String name, boolean parallel) {
super(size, seed, symmetrySettings, name, parallel);
}
- protected ComparableMask(U other, String name) {
- super(other, name);
+ protected ComparableMask(U other, String name, boolean immutable) {
+ super(other, name, immutable);
}
protected boolean valueAtEqualTo(int x, int y, T value) {
diff --git a/shared/src/main/java/com/faforever/neroxis/mask/FloatMask.java b/shared/src/main/java/com/faforever/neroxis/mask/FloatMask.java
index cca7cab0..81525b89 100644
--- a/shared/src/main/java/com/faforever/neroxis/mask/FloatMask.java
+++ b/shared/src/main/java/com/faforever/neroxis/mask/FloatMask.java
@@ -25,7 +25,7 @@
import static com.faforever.neroxis.brushes.Brushes.loadBrush;
@SuppressWarnings({"unchecked", "UnusedReturnValue", "unused"})
-public final class FloatMask extends PrimitiveMask {
+public class FloatMask extends PrimitiveMask {
private float[][] mask;
public FloatMask(int size, Long seed, SymmetrySettings symmetrySettings) {
@@ -70,19 +70,11 @@ public FloatMask(BufferedImage sourceImage, Long seed, SymmetrySettings symmetry
this(sourceImage, seed, symmetrySettings, scaleFactor, name, false);
}
- FloatMask(FloatMask other) {
- this(other, null);
- }
-
- FloatMask(FloatMask other, String name) {
- super(other, name);
- }
-
- FloatMask(BooleanMask other, float low, float high) {
+ protected FloatMask(BooleanMask other, float low, float high) {
this(other, low, high, null);
}
- FloatMask(BooleanMask other, float low, float high, String name) {
+ protected FloatMask(BooleanMask other, float low, float high, String name) {
this(other.getSize(), other.getNextSeed(), other.getSymmetrySettings(), name, other.isParallel());
enqueue(dependencies -> {
BooleanMask source = (BooleanMask) dependencies.getFirst();
@@ -90,6 +82,10 @@ public FloatMask(BufferedImage sourceImage, Long seed, SymmetrySettings symmetry
}, other);
}
+ protected FloatMask(FloatMask other, String name, boolean immutable) {
+ super(other, name, immutable);
+ }
+
private , U extends VectorMask> FloatMask(VectorMask other1,
VectorMask other2) {
this(other1, other2, null);
@@ -137,6 +133,11 @@ void setPrimitive(int x, int y, float value) {
mask[x][y] = value;
}
+ @Override
+ protected void copyValue(int sourceX, int sourceY, int destX, int destY) {
+ setPrimitive(destX, destY, getPrimitive(sourceX, sourceY));
+ }
+
/**
* Add perlin noise to the mask with the given resolution and noise scale
*
@@ -667,7 +668,7 @@ protected FloatMask setSizeInternal(int newSize) {
float[][] oldMask = mask;
initializeMask(newSize);
Map coordinateMap = getSymmetricScalingCoordinateMap(oldSize, newSize);
- applyWithSymmetry(SymmetryType.SPAWN, (x, y) -> {
+ apply((x, y) -> {
float value = oldMask[coordinateMap.get(x)][coordinateMap.get(y)];
setPrimitive(x, y, value);
});
diff --git a/shared/src/main/java/com/faforever/neroxis/mask/IntegerMask.java b/shared/src/main/java/com/faforever/neroxis/mask/IntegerMask.java
index 95169cbe..2de35ac9 100644
--- a/shared/src/main/java/com/faforever/neroxis/mask/IntegerMask.java
+++ b/shared/src/main/java/com/faforever/neroxis/mask/IntegerMask.java
@@ -15,7 +15,7 @@
import java.util.Map;
@SuppressWarnings({"UnusedReturnValue", "unused"})
-public final class IntegerMask extends PrimitiveMask {
+public class IntegerMask extends PrimitiveMask {
private int[][] mask;
public IntegerMask(int size, Long seed, SymmetrySettings symmetrySettings) {
@@ -39,14 +39,6 @@ public IntegerMask(int size, Long seed, SymmetrySettings symmetrySettings, Strin
this(size, seed, symmetrySettings, name, false);
}
- IntegerMask(IntegerMask other) {
- this(other, null);
- }
-
- IntegerMask(IntegerMask other, String name) {
- super(other, name);
- }
-
IntegerMask(BooleanMask other, int low, int high) {
this(other, low, high, null);
}
@@ -75,10 +67,19 @@ public IntegerMask(BufferedImage sourceImage, Long seed, SymmetrySettings symmet
this(sourceImage, seed, symmetrySettings, null, false);
}
+ protected IntegerMask(IntegerMask other, String name, boolean immutable) {
+ super(other, name, immutable);
+ }
+
private void setPrimitive(int x, int y, int value) {
mask[x][y] = value;
}
+ @Override
+ protected void copyValue(int sourceX, int sourceY, int destX, int destY) {
+ setPrimitive(destX, destY, getPrimitive(sourceX, sourceY));
+ }
+
public int getPrimitive(Vector2 location) {
return getPrimitive(StrictMath.round(location.getX()), StrictMath.round(location.getY()));
}
@@ -209,7 +210,7 @@ protected IntegerMask setSizeInternal(int newSize) {
int[][] oldMask = mask;
initializeMask(newSize);
Map coordinateMap = getSymmetricScalingCoordinateMap(oldSize, newSize);
- applyWithSymmetry(SymmetryType.SPAWN, (x, y) -> {
+ apply((x, y) -> {
int value = oldMask[coordinateMap.get(x)][coordinateMap.get(y)];
setPrimitive(x, y, value);
});
@@ -541,6 +542,7 @@ public IntegerMask applyWithOffset(IntegerMask other, TriIntConsumer action, int
}
});
}
+ applySymmetry(SymmetryType.SPAWN);
});
}
}
diff --git a/shared/src/main/java/com/faforever/neroxis/mask/MapMaskMethods.java b/shared/src/main/java/com/faforever/neroxis/mask/MapMaskMethods.java
index 1772a8af..8ed13ad5 100644
--- a/shared/src/main/java/com/faforever/neroxis/mask/MapMaskMethods.java
+++ b/shared/src/main/java/com/faforever/neroxis/mask/MapMaskMethods.java
@@ -1,63 +1,51 @@
package com.faforever.neroxis.mask;
-import com.faforever.neroxis.map.SCMap;
-import com.faforever.neroxis.map.Spawn;
import com.faforever.neroxis.map.SymmetryType;
import com.faforever.neroxis.util.vector.Vector2;
-import com.faforever.neroxis.util.vector.Vector3;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
-import java.util.stream.Collectors;
public class MapMaskMethods {
private MapMaskMethods() {
}
- public static BooleanMask connectTeams(SCMap map, long seed, BooleanMask exec, int minMiddlePoints,
+ public static BooleanMask connectTeams(List team0SpawnLocations, long seed, BooleanMask exec,
+ int minMiddlePoints,
int maxMiddlePoints, int numConnections, float maxStepSize) {
Random random = new Random(seed);
- List startTeamSpawns = map.getSpawns()
- .stream()
- .filter(spawn -> spawn.getTeamID() == 0)
- .collect(Collectors.toList());
for (int i = 0; i < numConnections; ++i) {
- Spawn startSpawn = startTeamSpawns.get(random.nextInt(startTeamSpawns.size()));
int numMiddlePoints;
if (maxMiddlePoints > minMiddlePoints) {
numMiddlePoints = random.nextInt(maxMiddlePoints - minMiddlePoints) + minMiddlePoints;
} else {
numMiddlePoints = maxMiddlePoints;
}
- Vector2 start = new Vector2(startSpawn.getPosition());
- Vector2 end = new Vector2(start);
+ Vector2 start = team0SpawnLocations.get(random.nextInt(team0SpawnLocations.size())).copy();
+ Vector2 end = start.copy();
float maxMiddleDistance = start.getDistance(end);
exec.connect(start, end, maxStepSize, numMiddlePoints, maxMiddleDistance, maxMiddleDistance / 2,
- (float) (StrictMath.PI / 2), SymmetryType.SPAWN);
+ (float) (StrictMath.PI / 2), SymmetryType.TERRAIN);
}
return exec;
}
- public static BooleanMask connectTeamsAroundCenter(SCMap map, long seed, BooleanMask exec, int minMiddlePoints,
+ public static BooleanMask connectTeamsAroundCenter(List team0SpawnLocations, long seed, BooleanMask exec,
+ int minMiddlePoints,
int maxMiddlePoints, int numConnections, float maxStepSize,
int bound) {
- List startTeamSpawns = map.getSpawns()
- .stream()
- .filter(spawn -> spawn.getTeamID() == 0)
- .collect(Collectors.toList());
return exec.enqueue(() -> {
Random random = new Random(seed);
for (int i = 0; i < numConnections; ++i) {
- Spawn startSpawn = startTeamSpawns.get(random.nextInt(startTeamSpawns.size()));
int numMiddlePoints;
if (maxMiddlePoints > minMiddlePoints) {
numMiddlePoints = random.nextInt(maxMiddlePoints - minMiddlePoints) + minMiddlePoints;
} else {
numMiddlePoints = maxMiddlePoints;
}
- Vector2 start = new Vector2(startSpawn.getPosition());
- Vector2 end = new Vector2(start);
+ Vector2 start = team0SpawnLocations.get(random.nextInt(team0SpawnLocations.size())).copy();
+ Vector2 end = start.copy();
float offCenterAngle = (float) (StrictMath.PI * (1f / 3f + random.nextFloat() / 3f));
offCenterAngle *= random.nextBoolean() ? 1 : -1;
offCenterAngle += start.angleTo(new Vector2(exec.getSize() / 2f, exec.getSize() / 2f));
@@ -65,28 +53,25 @@ public static BooleanMask connectTeamsAroundCenter(SCMap map, long seed, Boolean
end.clampMax(exec.getSize() - bound).clampMin(bound);
float maxMiddleDistance = start.getDistance(end);
exec.connect(start, end, maxStepSize, numMiddlePoints, maxMiddleDistance, maxMiddleDistance / 2,
- (float) (StrictMath.PI / 2), SymmetryType.SPAWN);
+ (float) (StrictMath.PI / 2), SymmetryType.TERRAIN);
}
});
}
- public static BooleanMask connectTeammates(SCMap map, long seed, BooleanMask exec, int maxMiddlePoints,
+ public static BooleanMask connectTeammates(List team0SpawnLocations, long seed, BooleanMask exec,
+ int maxMiddlePoints,
int numConnections, float maxStepSize) {
- List startTeamSpawns = map.getSpawns()
- .stream()
- .filter(spawn -> spawn.getTeamID() == 0)
- .collect(Collectors.toList());
return exec.enqueue(() -> {
Random random = new Random(seed);
- if (startTeamSpawns.size() > 1) {
- startTeamSpawns.forEach(startSpawn -> {
+ if (team0SpawnLocations.size() > 1) {
+ team0SpawnLocations.forEach(startSpawn -> {
for (int i = 0; i < numConnections; ++i) {
- ArrayList otherSpawns = new ArrayList<>(startTeamSpawns);
+ ArrayList otherSpawns = new ArrayList<>(team0SpawnLocations);
otherSpawns.remove(startSpawn);
- Spawn endSpawn = otherSpawns.get(random.nextInt(otherSpawns.size()));
+ Vector2 endSpawn = otherSpawns.get(random.nextInt(otherSpawns.size()));
int numMiddlePoints = random.nextInt(maxMiddlePoints);
- Vector2 start = new Vector2(startSpawn.getPosition());
- Vector2 end = new Vector2(endSpawn.getPosition());
+ Vector2 start = startSpawn.copy();
+ Vector2 end = endSpawn.copy();
float maxMiddleDistance = start.getDistance(end) / numMiddlePoints * 2;
exec.path(start, end, maxStepSize, numMiddlePoints, maxMiddleDistance, 0,
(float) (StrictMath.PI / 2), SymmetryType.TERRAIN);
@@ -132,12 +117,13 @@ public static BooleanMask pathInEdgeBounds(long seed, BooleanMask exec, float ma
});
}
- public static BooleanMask pathAroundSpawns(SCMap map, long seed, BooleanMask exec, float maxStepSize, int numPaths,
+ public static BooleanMask pathAroundSpawns(List team0SpawnLocations, long seed, BooleanMask exec,
+ float maxStepSize, int numPaths,
int maxMiddlePoints, int bound, float maxAngleError) {
return exec.enqueue(() -> {
Random random = new Random(seed);
- map.getSpawns().forEach(spawn -> {
- Vector2 start = new Vector2(spawn.getPosition());
+ team0SpawnLocations.forEach(spawn -> {
+ Vector2 start = spawn.copy();
for (int i = 0; i < numPaths; i++) {
int endX = (int) (random.nextFloat() * bound + start.getX());
int endY = (int) (random.nextFloat() * bound + start.getY());
@@ -145,31 +131,9 @@ public static BooleanMask pathAroundSpawns(SCMap map, long seed, BooleanMask exe
int numMiddlePoints = random.nextInt(maxMiddlePoints);
float maxMiddleDistance = start.getDistance(end) / numMiddlePoints * 2;
exec.path(start, end, maxStepSize, numMiddlePoints, maxMiddleDistance, 0, maxAngleError,
- SymmetryType.TERRAIN);
+ SymmetryType.SPAWN);
}
});
});
}
-
- public static BooleanMask fillSpawnCircle(SCMap map, BooleanMask exec, float radius) {
- return exec.enqueue(() -> {
- map.getSpawns().forEach(spawn -> {
- Vector3 location = spawn.getPosition();
- exec.fillCircle(location, radius, true);
- });
- });
- }
-
- public static BooleanMask fillSpawnCircleWithProbability(SCMap map, long seed, BooleanMask exec, float spawnSize,
- float probability) {
- return exec.enqueue(() -> {
- Random random = new Random(seed);
- if (random.nextFloat() < probability) {
- map.getSpawns().forEach(spawn -> {
- Vector3 location = spawn.getPosition();
- exec.fillCircle(location, spawnSize, true);
- });
- }
- });
- }
}
diff --git a/shared/src/main/java/com/faforever/neroxis/mask/Mask.java b/shared/src/main/java/com/faforever/neroxis/mask/Mask.java
index e05d6bbd..f2312f32 100644
--- a/shared/src/main/java/com/faforever/neroxis/mask/Mask.java
+++ b/shared/src/main/java/com/faforever/neroxis/mask/Mask.java
@@ -20,25 +20,27 @@
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
+import java.util.Set;
import java.util.function.Consumer;
import java.util.function.IntUnaryOperator;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
@SuppressWarnings({"unchecked", "UnusedReturnValue", "unused"})
-public abstract sealed class Mask> permits OperationsMask {
- private static final String MOCK_NAME = "Mock";
+public abstract class Mask> {
private static final String COPY_NAME = "Copy";
protected final Random random;
@Getter
private final String name;
@Getter
protected final SymmetrySettings symmetrySettings;
- private boolean immutable;
+ @Getter
+ private final boolean immutable;
private int plannedSize;
@Getter
@Setter
@@ -47,14 +49,22 @@ public abstract sealed class Mask> permits OperationsMas
@Setter
private boolean visualDebug;
private boolean visible;
- private boolean mock;
@Setter
private String visualName;
+ private int copyCount;
- protected Mask(U other, String name) {
- this(other.getSize(), other.isMock() ? null : other.getNextSeed(),
- other.getSymmetrySettings(), name, other.isParallel());
+ protected Mask(U other, String name, boolean immutable) {
+ int size = other.getSize();
+ this.symmetrySettings = other.getSymmetrySettings();
+ this.name = name == null ? String.valueOf(hashCode()) : name;
+ this.plannedSize = size;
+ this.parallel = other.isParallel();
+ Long seed = immutable ? null : other.getNextSeed();
+ random = seed != null ? new Random(seed) : null;
+ visible = !immutable;
+ initializeMask(size);
init(other);
+ this.immutable = immutable;
}
protected Mask(int size, Long seed, SymmetrySettings symmetrySettings, String name, boolean parallel) {
@@ -62,6 +72,7 @@ protected Mask(int size, Long seed, SymmetrySettings symmetrySettings, String na
this.name = name == null ? String.valueOf(hashCode()) : name;
this.plannedSize = size;
this.parallel = parallel;
+ this.immutable = false;
random = seed != null ? new Random(seed) : null;
visible = true;
initializeMask(size);
@@ -110,10 +121,6 @@ public U init(U other) {
protected abstract U copyFrom(U other);
- public boolean isMock() {
- return (name != null && name.endsWith(MOCK_NAME)) || mock;
- }
-
public int getSize() {
if (parallel && !Pipeline.isRunning()) {
return plannedSize;
@@ -188,13 +195,6 @@ public static boolean inBounds(Vector2 location, int size) {
return inBounds(x, y, size);
}
- @SneakyThrows
- public U immutableCopy() {
- Mask, U> copy = copy(getName() + MOCK_NAME);
- copy.setVisualName(getName());
- return copy.enqueue(copy::makeImmutable);
- }
-
protected abstract U fill(T value);
protected abstract T getZeroValue();
@@ -211,11 +211,6 @@ protected U enqueue(Runnable function) {
return enqueue(ignored -> function.run());
}
- private void makeImmutable() {
- immutable = true;
- mock = true;
- }
-
/**
* Set the mask to all zeros
*
@@ -248,14 +243,20 @@ protected U enqueue(Consumer>> function, Mask, ?>... usedMasks
return (U) this;
}
- protected void copyValue(int sourceX, int sourceY, int destX, int destY) {
- set(destX, destY, get(sourceX, sourceY));
+ private void copyValue(Vector2 source, Vector2 dest) {
+ copyValue((int) source.getX(), (int) source.getY(), (int) dest.getX(), (int) dest.getY());
}
- protected void assertMutable() {
- if (immutable) {
- throw new IllegalStateException("Mask is a mock and cannot be modified");
- }
+ private void copyValue(Vector2 source, int destX, int destY) {
+ copyValue((int) source.getX(), (int) source.getY(), destX, destY);
+ }
+
+ private void copyValue(int sourceX, int sourceY, Vector2 dest) {
+ copyValue(sourceX, sourceY, (int) dest.getX(), (int) dest.getY());
+ }
+
+ protected void copyValue(int sourceX, int sourceY, int destX, int destY) {
+ set(destX, destY, get(sourceX, sourceY));
}
protected abstract U setSizeInternal(int newSize);
@@ -291,7 +292,9 @@ protected static boolean inBounds(int x, int y, int size) {
}
protected U enqueue(Consumer>> function, Mask, ?>... usedMasks) {
- assertMutable();
+ if (immutable) {
+ throw new IllegalStateException("Mask is immutable and cannot be modified");
+ }
List> dependencies = Arrays.asList(usedMasks);
if (parallel && !Pipeline.isRunning()) {
if (dependencies.stream().anyMatch(dep -> !dep.parallel)) {
@@ -303,7 +306,7 @@ protected U enqueue(Consumer>> function, Mask, ?>... usedMasks
visible = false;
function.accept(dependencies);
visible = visibleState;
- if (((DebugUtil.DEBUG && isVisualDebug()) || (DebugUtil.VISUALIZE && !isMock() && !isParallel()))
+ if (((DebugUtil.DEBUG && isVisualDebug()) || (DebugUtil.VISUALIZE && !isImmutable() && !isParallel()))
&& visible) {
String callingMethod = DebugUtil.getLastStackTraceMethodInPackage("com.faforever.neroxis.mask");
String callingLine = DebugUtil.getLastStackTraceLineAfterPackage("com.faforever.neroxis.mask");
@@ -579,16 +582,41 @@ public boolean inHalf(int x, int y, float angle) {
}
protected U applySymmetry(SymmetryType symmetryType) {
- return enqueue(() -> {
- int size = getSize();
- Symmetry symmetry = symmetrySettings.getSymmetry(symmetryType);
- loopOutsideSymmetryRegion(symmetryType, (x, y) -> {
- Vector2 sourcePoint = SymmetryUtil.getSourcePoint(x, y, size, symmetry);
- if (inBounds(sourcePoint, size)) {
- copyValue((int) sourcePoint.getX(), (int) sourcePoint.getY(), x, y);
- }
+ Symmetry symmetry = symmetrySettings.getSymmetry(symmetryType);
+ if (symmetry == Symmetry.NONE) {
+ return (U) this;
+ }
+
+ if (symmetry.isPerfectSymmetry()) {
+ return enqueue(() -> {
+ int size = getSize();
+ loopOutsideSymmetryRegion(symmetryType, (x, y) -> {
+ Vector2 sourcePoint = SymmetryUtil.getSourcePoint(x, y, size, symmetry);
+ copyValue(sourcePoint, x, y);
+ });
});
- });
+ } else {
+ return enqueue(() -> {
+ Set sourcedPoints = new HashSet<>();
+ int size = getSize();
+ loopOutsideSymmetryRegion(symmetryType, (x, y) -> {
+ Vector2 sourcePoint = SymmetryUtil.getSourcePoint(x, y, size, symmetry);
+ sourcedPoints.add(sourcePoint);
+ if (inBounds(sourcePoint)) {
+ copyValue(sourcePoint, x, y);
+ }
+ });
+ loopInSymmetryRegion(symmetryType, (x, y) -> {
+ if (!sourcedPoints.contains(new Vector2(x, y))) {
+ applyAtSymmetryPoints(x, y, symmetryType, (sx, sy) -> {
+ if (inBounds(sx, sy, size)) {
+ copyValue(x, y, sx, sy);
+ }
+ });
+ }
+ });
+ });
+ }
}
public boolean inHalf(Vector2 pos, float angle) {
@@ -652,10 +680,10 @@ protected U applyWithOffset(U other, BiIntObjConsumer action, int xOffset, in
int smallerSize = StrictMath.min(size, otherSize);
int biggerSize = StrictMath.max(size, otherSize);
if (smallerSize == otherSize) {
- Map coordinateXMap = getShiftedCoordinateMap(xOffset, center, wrapEdges,
- otherSize, size);
- Map coordinateYMap = getShiftedCoordinateMap(yOffset, center, wrapEdges,
- otherSize, size);
+ Map coordinateXMap = getShiftedCoordinateMap(xOffset, center, wrapEdges, otherSize,
+ size);
+ Map coordinateYMap = getShiftedCoordinateMap(yOffset, center, wrapEdges, otherSize,
+ size);
other.apply((x, y) -> {
int shiftX = coordinateXMap.get(x);
int shiftY = coordinateYMap.get(y);
@@ -807,8 +835,12 @@ protected void assertSize(int size) {
*
* @return a copy of the mask
*/
+ @SneakyThrows
public U copy() {
- return copy(getName() + COPY_NAME);
+ Class> clazz = getClass();
+ String maskName = getName() + COPY_NAME + copyCount++;
+ return (U) clazz.getDeclaredConstructor(clazz, String.class, boolean.class).newInstance(this,
+ maskName, false);
}
public U getFinalMask() {
@@ -819,9 +851,15 @@ public U getFinalMask() {
}
@SneakyThrows
- public U copy(String maskName) {
+ private U copy(String maskName) {
+ Class> clazz = getClass();
+ return (U) clazz.getDeclaredConstructor(clazz, String.class, boolean.class).newInstance(this, maskName, false);
+ }
+
+ @SneakyThrows
+ public U immutableCopy() {
Class> clazz = getClass();
- return (U) clazz.getDeclaredConstructor(clazz, String.class).newInstance(this, maskName);
+ return (U) clazz.getDeclaredConstructor(clazz, String.class, boolean.class).newInstance(this, name, true);
}
public U startVisualDebugger() {
diff --git a/shared/src/main/java/com/faforever/neroxis/mask/NormalMask.java b/shared/src/main/java/com/faforever/neroxis/mask/NormalMask.java
index 8f1e9a66..5aef5494 100644
--- a/shared/src/main/java/com/faforever/neroxis/mask/NormalMask.java
+++ b/shared/src/main/java/com/faforever/neroxis/mask/NormalMask.java
@@ -9,7 +9,7 @@
import java.awt.image.WritableRaster;
@SuppressWarnings({"UnusedReturnValue", "unused"})
-public final class NormalMask extends VectorMask {
+public class NormalMask extends VectorMask {
public NormalMask(int size, Long seed, SymmetrySettings symmetrySettings) {
this(size, seed, null, false);
}
@@ -22,14 +22,6 @@ public NormalMask(int size, Long seed, SymmetrySettings symmetrySettings, String
this(size, seed, name, false);
}
- public NormalMask(NormalMask other) {
- this(other, null);
- }
-
- public NormalMask(NormalMask other, String name) {
- super(other, name);
- }
-
public NormalMask(FloatMask other) {
this(other, 1f, null);
}
@@ -61,6 +53,10 @@ public NormalMask(BufferedImage sourceImage, Long seed, SymmetrySettings symmetr
});
}
+ protected NormalMask(NormalMask other, String name, boolean immutable) {
+ super(other, name, immutable);
+ }
+
@Override
protected Vector3 createValue(float scaleFactor, float... components) {
assertMatchingDimension(components.length);
diff --git a/shared/src/main/java/com/faforever/neroxis/mask/OperationsMask.java b/shared/src/main/java/com/faforever/neroxis/mask/OperationsMask.java
index 3c4bd434..20fb84a4 100644
--- a/shared/src/main/java/com/faforever/neroxis/mask/OperationsMask.java
+++ b/shared/src/main/java/com/faforever/neroxis/mask/OperationsMask.java
@@ -6,15 +6,13 @@
import com.faforever.neroxis.util.vector.Vector2;
@SuppressWarnings({"unchecked", "UnusedReturnValue", "unused"})
-public abstract sealed class OperationsMask> extends Mask permits
- ComparableMask,
- VectorMask {
+public abstract class OperationsMask> extends Mask {
protected OperationsMask(int size, Long seed, SymmetrySettings symmetrySettings, String name, boolean parallel) {
super(size, seed, symmetrySettings, name, parallel);
}
- protected OperationsMask(U other, String name) {
- super(other, name);
+ protected OperationsMask(U other, String name, boolean immutable) {
+ super(other, name, immutable);
}
public abstract T getSum();
diff --git a/shared/src/main/java/com/faforever/neroxis/mask/PrimitiveMask.java b/shared/src/main/java/com/faforever/neroxis/mask/PrimitiveMask.java
index f247b8c7..322c40c2 100644
--- a/shared/src/main/java/com/faforever/neroxis/mask/PrimitiveMask.java
+++ b/shared/src/main/java/com/faforever/neroxis/mask/PrimitiveMask.java
@@ -3,13 +3,14 @@
import com.faforever.neroxis.map.SymmetrySettings;
@SuppressWarnings({"UnusedReturnValue", "unused"})
-public abstract sealed class PrimitiveMask, U extends ComparableMask> extends ComparableMask permits BooleanMask, FloatMask, IntegerMask {
+public abstract class PrimitiveMask, U extends ComparableMask> extends
+ ComparableMask {
public PrimitiveMask(int size, Long seed, SymmetrySettings symmetrySettings, String name, boolean parallel) {
super(size, seed, symmetrySettings, name, parallel);
}
- protected PrimitiveMask(U other, String name) {
- super(other, name);
+ protected PrimitiveMask(U other, String name, boolean immutable) {
+ super(other, name, immutable);
}
protected abstract int[][] getInnerCount();
diff --git a/shared/src/main/java/com/faforever/neroxis/mask/Vector2Mask.java b/shared/src/main/java/com/faforever/neroxis/mask/Vector2Mask.java
index 200a7e99..944f899a 100644
--- a/shared/src/main/java/com/faforever/neroxis/mask/Vector2Mask.java
+++ b/shared/src/main/java/com/faforever/neroxis/mask/Vector2Mask.java
@@ -8,7 +8,7 @@
import java.util.Arrays;
@SuppressWarnings({"UnusedReturnValue", "unused"})
-public final class Vector2Mask extends VectorMask {
+public class Vector2Mask extends VectorMask {
public Vector2Mask(int size, Long seed, SymmetrySettings symmetrySettings) {
this(size, seed, symmetrySettings, null, false);
}
@@ -30,14 +30,6 @@ public Vector2Mask(int size, Long seed, SymmetrySettings symmetrySettings, Strin
this(size, seed, symmetrySettings, name, false);
}
- public Vector2Mask(Vector2Mask other) {
- this(other, null);
- }
-
- public Vector2Mask(Vector2Mask other, String name) {
- super(other, name);
- }
-
public Vector2Mask(BufferedImage sourceImage, Long seed, SymmetrySettings symmetrySettings, float scaleFactor) {
this(sourceImage, seed, symmetrySettings, scaleFactor, null, false);
}
@@ -52,6 +44,10 @@ public Vector2Mask(BufferedImage sourceImage, Long seed, SymmetrySettings symmet
super(sourceImage, seed, symmetrySettings, scaleFactor, name, parallel);
}
+ protected Vector2Mask(Vector2Mask other, String name, boolean immutable) {
+ super(other, name, immutable);
+ }
+
@Override
protected Vector2 createValue(float scaleFactor, float... components) {
assertMatchingDimension(components.length);
diff --git a/shared/src/main/java/com/faforever/neroxis/mask/Vector3Mask.java b/shared/src/main/java/com/faforever/neroxis/mask/Vector3Mask.java
index 9f0a8cbe..304d005a 100644
--- a/shared/src/main/java/com/faforever/neroxis/mask/Vector3Mask.java
+++ b/shared/src/main/java/com/faforever/neroxis/mask/Vector3Mask.java
@@ -7,7 +7,7 @@
import java.awt.image.WritableRaster;
@SuppressWarnings({"UnusedReturnValue", "unused"})
-public final class Vector3Mask extends VectorMask {
+public class Vector3Mask extends VectorMask {
public Vector3Mask(int size, Long seed, SymmetrySettings symmetrySettings) {
this(size, seed, symmetrySettings, null, false);
}
@@ -29,14 +29,6 @@ public Vector3Mask(int size, Long seed, SymmetrySettings symmetrySettings, Strin
this(size, seed, symmetrySettings, name, false);
}
- public Vector3Mask(Vector3Mask other) {
- this(other, null);
- }
-
- public Vector3Mask(Vector3Mask other, String name) {
- super(other, name);
- }
-
public Vector3Mask(NormalMask other) {
this(other, null);
}
@@ -63,6 +55,10 @@ public Vector3Mask(BufferedImage sourceImage, Long seed, SymmetrySettings symmet
super(sourceImage, seed, symmetrySettings, scaleFactor, name, parallel);
}
+ protected Vector3Mask(Vector3Mask other, String name, boolean immutable) {
+ super(other, name, immutable);
+ }
+
@Override
protected Vector3 createValue(float scaleFactor, float... components) {
assertMatchingDimension(components.length);
diff --git a/shared/src/main/java/com/faforever/neroxis/mask/Vector4Mask.java b/shared/src/main/java/com/faforever/neroxis/mask/Vector4Mask.java
index 8438eb40..5109a0e8 100644
--- a/shared/src/main/java/com/faforever/neroxis/mask/Vector4Mask.java
+++ b/shared/src/main/java/com/faforever/neroxis/mask/Vector4Mask.java
@@ -7,7 +7,7 @@
import java.awt.image.WritableRaster;
@SuppressWarnings({"UnusedReturnValue", "unused"})
-public final class Vector4Mask extends VectorMask {
+public class Vector4Mask extends VectorMask {
public Vector4Mask(int size, Long seed, SymmetrySettings symmetrySettings) {
this(size, seed, symmetrySettings, null, false);
}
@@ -29,14 +29,6 @@ public Vector4Mask(int size, Long seed, SymmetrySettings symmetrySettings, Strin
this(size, seed, symmetrySettings, name, false);
}
- public Vector4Mask(Vector4Mask other) {
- this(other, null);
- }
-
- public Vector4Mask(Vector4Mask other, String name) {
- super(other, name);
- }
-
public Vector4Mask(BufferedImage sourceImage, Long seed, SymmetrySettings symmetrySettings, float scaleFactor) {
this(sourceImage, seed, symmetrySettings, scaleFactor, null, false);
}
@@ -51,6 +43,10 @@ public Vector4Mask(BufferedImage sourceImage, Long seed, SymmetrySettings symmet
super(sourceImage, seed, symmetrySettings, scaleFactor, name, parallel);
}
+ protected Vector4Mask(Vector4Mask other, String name, boolean immutable) {
+ super(other, name, immutable);
+ }
+
@Override
protected Vector4 createValue(float scaleFactor, float... components) {
assertMatchingDimension(components.length);
diff --git a/shared/src/main/java/com/faforever/neroxis/mask/VectorMask.java b/shared/src/main/java/com/faforever/neroxis/mask/VectorMask.java
index 3c249aa9..40424a70 100644
--- a/shared/src/main/java/com/faforever/neroxis/mask/VectorMask.java
+++ b/shared/src/main/java/com/faforever/neroxis/mask/VectorMask.java
@@ -19,12 +19,8 @@
import java.util.Map;
@SuppressWarnings({"unchecked", "UnusedReturnValue", "unused"})
-public abstract sealed class VectorMask, U extends VectorMask> extends
- OperationsMask permits
- NormalMask,
- Vector2Mask,
- Vector3Mask,
- Vector4Mask {
+public abstract class VectorMask, U extends VectorMask> extends
+ OperationsMask {
protected T[][] mask;
public VectorMask(BufferedImage sourceImage, Long seed, SymmetrySettings symmetrySettings, float scaleFactor,
@@ -59,8 +55,8 @@ public VectorMask(Long seed, String name, FloatMask... components) {
}, components);
}
- protected VectorMask(U other, String name) {
- super(other, name);
+ protected VectorMask(U other, String name, boolean immutable) {
+ super(other, name, immutable);
}
protected void assertMatchingDimension(int numImageComponents) {
@@ -168,8 +164,7 @@ protected U setSizeInternal(int newSize) {
T[][] oldMask = mask;
mask = getNullMask(newSize);
Map coordinateMap = getSymmetricScalingCoordinateMap(oldSize, newSize);
- setWithSymmetry(SymmetryType.SPAWN,
- (x, y) -> oldMask[coordinateMap.get(x)][coordinateMap.get(y)].copy());
+ set((x, y) -> oldMask[coordinateMap.get(x)][coordinateMap.get(y)].copy());
}
});
}
@@ -284,9 +279,9 @@ public U blurComponent(int radius, int component, BooleanMask other) {
return enqueue(dependencies -> {
BooleanMask limiter = (BooleanMask) dependencies.getFirst();
int[][] innerCount = getComponentInnerCount(component);
- setComponent(
- (x, y) -> limiter.get(x, y) ? calculateComponentAreaAverage(radius, x, y, innerCount) / 1000f : get(
- x, y).get(component), component);
+ setComponent((x, y) -> limiter.get(x, y) ?
+ calculateComponentAreaAverage(radius, x, y, innerCount) / 1000f : get(x, y).get(component),
+ component);
}, other);
}
@@ -635,8 +630,7 @@ public U setComponentWithOffset(FloatMask other, int component, int xOffset, int
boolean wrapEdges) {
return enqueue(dependencies -> {
FloatMask source = (FloatMask) dependencies.getFirst();
- applyComponentWithOffset(source, this::setComponentAt, component, xOffset, yOffset,
- center, wrapEdges);
+ applyComponentWithOffset(source, this::setComponentAt, component, xOffset, yOffset, center, wrapEdges);
}, other);
}
@@ -644,8 +638,7 @@ public U addComponentWithOffset(FloatMask other, int component, int xOffset, int
boolean wrapEdges) {
return enqueue(dependencies -> {
FloatMask source = (FloatMask) dependencies.getFirst();
- applyComponentWithOffset(source, this::addComponentAt, component, xOffset, yOffset,
- center, wrapEdges);
+ applyComponentWithOffset(source, this::addComponentAt, component, xOffset, yOffset, center, wrapEdges);
}, other);
}
@@ -653,8 +646,7 @@ public U subtractComponentWithOffset(FloatMask other, int component, int xOffset
boolean wrapEdges) {
return enqueue(dependencies -> {
FloatMask source = (FloatMask) dependencies.getFirst();
- applyComponentWithOffset(source, this::subtractComponentAt, component, xOffset,
- yOffset, center, wrapEdges);
+ applyComponentWithOffset(source, this::subtractComponentAt, component, xOffset, yOffset, center, wrapEdges);
}, other);
}
@@ -662,8 +654,7 @@ public U multiplyComponentWithOffset(FloatMask other, int component, int xOffset
boolean wrapEdges) {
return enqueue(dependencies -> {
FloatMask source = (FloatMask) dependencies.getFirst();
- applyComponentWithOffset(source, this::multiplyComponentAt, component, xOffset,
- yOffset, center, wrapEdges);
+ applyComponentWithOffset(source, this::multiplyComponentAt, component, xOffset, yOffset, center, wrapEdges);
}, other);
}
@@ -671,8 +662,7 @@ public U divideComponentWithOffset(FloatMask other, int component, int xOffset,
boolean wrapEdges) {
return enqueue(dependencies -> {
FloatMask source = (FloatMask) dependencies.getFirst();
- applyComponentWithOffset(source, this::divideComponentAt, component, xOffset,
- yOffset, center, wrapEdges);
+ applyComponentWithOffset(source, this::divideComponentAt, component, xOffset, yOffset, center, wrapEdges);
}, other);
}
@@ -684,10 +674,10 @@ private U applyComponentWithOffset(FloatMask other, BiIntFloatIntConsumer action
int smallerSize = StrictMath.min(size, otherSize);
int biggerSize = StrictMath.max(size, otherSize);
if (smallerSize == otherSize) {
- Map coordinateXMap = getShiftedCoordinateMap(xOffset, center, wrapEdges,
- otherSize, size);
- Map coordinateYMap = getShiftedCoordinateMap(yOffset, center, wrapEdges,
- otherSize, size);
+ Map coordinateXMap = getShiftedCoordinateMap(xOffset, center, wrapEdges, otherSize,
+ size);
+ Map coordinateYMap = getShiftedCoordinateMap(yOffset, center, wrapEdges, otherSize,
+ size);
other.apply((x, y) -> {
int shiftX = coordinateXMap.get(x);
int shiftY = coordinateYMap.get(y);
diff --git a/shared/src/main/java/com/faforever/neroxis/util/Pipeline.java b/shared/src/main/java/com/faforever/neroxis/util/Pipeline.java
index 5ee05061..c6460363 100644
--- a/shared/src/main/java/com/faforever/neroxis/util/Pipeline.java
+++ b/shared/src/main/java/com/faforever/neroxis/util/Pipeline.java
@@ -45,7 +45,7 @@ public static void add(Mask, ?> executingMask, List> maskDependenci
String callingMethod = null;
String callingLine = null;
- if (DebugUtil.DEBUG) {
+ if (DebugUtil.DEBUG || DebugUtil.VISUALIZE) {
callingMethod = DebugUtil.getLastStackTraceMethodInPackage("com.faforever.neroxis.mask");
callingLine = DebugUtil.getLastStackTraceLineAfterPackage("com.faforever.neroxis.mask");
}
@@ -82,7 +82,7 @@ public static void add(Mask, ?> executingMask, List> maskDependenci
executingMask.setVisualDebug(visualDebug);
if ((DebugUtil.DEBUG && visualDebug) || (DebugUtil.VISUALIZE
&&
- !executingMask.isMock())) {
+ !executingMask.isImmutable())) {
VisualDebugger.visualizeMask(executingMask,
finalCallingMethod,
finalCallingLine);
@@ -223,9 +223,9 @@ public Entry(int index, Mask, ?> executingMask, Collection dependencies
this.methodName = method;
this.line = line;
this.future = future.thenRunAsync(() -> {
- if (!executingMask.isMock() && dependants.stream()
- .anyMatch(entry -> !entry.getExecutingMask()
- .equals(executingMask))) {
+ if (!executingMask.isImmutable() && dependants.stream()
+ .anyMatch(entry -> !entry.getExecutingMask()
+ .equals(executingMask))) {
immutableResult = executingMask.immutableCopy();
} else {
immutableResult = executingMask;
diff --git a/shared/src/main/java/com/faforever/neroxis/util/SymmetryUtil.java b/shared/src/main/java/com/faforever/neroxis/util/SymmetryUtil.java
index 3034c7a7..2b6d2846 100644
--- a/shared/src/main/java/com/faforever/neroxis/util/SymmetryUtil.java
+++ b/shared/src/main/java/com/faforever/neroxis/util/SymmetryUtil.java
@@ -1,6 +1,7 @@
package com.faforever.neroxis.util;
import com.faforever.neroxis.map.Symmetry;
+import com.faforever.neroxis.util.functional.SymmetryRegionBoundsChecker;
import com.faforever.neroxis.util.vector.Vector2;
import java.util.ArrayList;
@@ -9,6 +10,14 @@
public class SymmetryUtil {
+ public static SymmetryRegionBoundsChecker getSymmetryRegionBoundsChecker(Symmetry symmetry, int size) {
+ int maxXBound = getMaxXBound(symmetry, size);
+ IntUnaryOperator minYBoundFunction = getMinYBoundFunction(symmetry, size);
+ IntUnaryOperator maxYBoundFunction = getMaxYBoundFunction(symmetry, size);
+ return (x, y) -> x >= 0 && x < maxXBound && y >= minYBoundFunction.applyAsInt(x)
+ && y < maxYBoundFunction.applyAsInt(x);
+ }
+
public static int getMaxXBound(Symmetry symmetry, int size) {
return switch (symmetry) {
case POINT4, POINT5, POINT6, POINT7, POINT8, POINT9, POINT10, POINT11, POINT12, POINT13, POINT14, POINT15,
diff --git a/shared/src/main/java/com/faforever/neroxis/util/functional/SymmetryRegionBoundsChecker.java b/shared/src/main/java/com/faforever/neroxis/util/functional/SymmetryRegionBoundsChecker.java
new file mode 100644
index 00000000..bd7151c0
--- /dev/null
+++ b/shared/src/main/java/com/faforever/neroxis/util/functional/SymmetryRegionBoundsChecker.java
@@ -0,0 +1,13 @@
+package com.faforever.neroxis.util.functional;
+
+import com.faforever.neroxis.util.vector.Vector2;
+
+public interface SymmetryRegionBoundsChecker {
+
+ boolean inBounds(int x, int y);
+
+ default boolean inBounds(Vector2 location) {
+ return inBounds((int) location.getX(), (int) location.getY());
+ }
+
+}
diff --git a/shared/src/main/java/com/faforever/neroxis/util/functional/ToBooleanFunction.java b/shared/src/main/java/com/faforever/neroxis/util/functional/ToBooleanFunction.java
deleted file mode 100644
index e4dbaca7..00000000
--- a/shared/src/main/java/com/faforever/neroxis/util/functional/ToBooleanFunction.java
+++ /dev/null
@@ -1,6 +0,0 @@
-package com.faforever.neroxis.util.functional;
-
-@FunctionalInterface
-public interface ToBooleanFunction {
- boolean apply(T value);
-}
diff --git a/shared/src/main/java/com/faforever/neroxis/util/vector/Vector.java b/shared/src/main/java/com/faforever/neroxis/util/vector/Vector.java
index 67113ac7..dfd7fb3c 100644
--- a/shared/src/main/java/com/faforever/neroxis/util/vector/Vector.java
+++ b/shared/src/main/java/com/faforever/neroxis/util/vector/Vector.java
@@ -1,11 +1,8 @@
package com.faforever.neroxis.util.vector;
-import lombok.EqualsAndHashCode;
-
import java.util.Arrays;
import java.util.Random;
-@EqualsAndHashCode
@SuppressWarnings("unchecked")
public abstract class Vector> {
public static final int X = 0;
@@ -340,4 +337,21 @@ public String toString() {
}
return Arrays.toString(strings).replace("[", "").replace("]", "");
}
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (!(o instanceof Vector> vector)) {
+ return false;
+ }
+
+ return Arrays.equals(components, vector.components);
+ }
+
+ @Override
+ public int hashCode() {
+ return Arrays.hashCode(components);
+ }
}
diff --git a/shared/src/main/java/com/faforever/neroxis/visualization/VisualDebugger.java b/shared/src/main/java/com/faforever/neroxis/visualization/VisualDebugger.java
index 52949420..074ee48c 100644
--- a/shared/src/main/java/com/faforever/neroxis/visualization/VisualDebugger.java
+++ b/shared/src/main/java/com/faforever/neroxis/visualization/VisualDebugger.java
@@ -31,7 +31,7 @@ public static void visualizeMask(Mask, ?> mask, String method, String line) {
SwingUtilities.invokeLater(() -> {
createGui();
String name = copyOfmask.getVisualName();
- updateList(name + " " + method + " " + line, copyOfmask.immutableCopy());
+ updateList(name, method, line, copyOfmask);
}
);
}
@@ -100,7 +100,8 @@ private static void updateVisibleCanvas(MaskListItem maskListItem) {
String maskName = maskListItem.maskName();
Mask, ?> mask = maskListItem.mask();
canvas.setMask(mask);
- frame.setTitle(String.format("Mask: %s MaskSize: %d", maskName, mask.getSize()));
+ frame.setTitle(String.format("Mask: %s Method: %s Line %s MaskSize: %d", maskName, maskListItem.method(),
+ maskListItem.line(), mask.getSize()));
}
private static void setupCanvas() {
@@ -116,9 +117,9 @@ private static void setupCanvas() {
frame.add(canvas, constraints);
}
- private static void updateList(String uniqueMaskName, Mask, ?> mask) {
- MASK_ITEMS_BY_NAME.computeIfAbsent(uniqueMaskName, ignored -> new ArrayList<>())
- .add(new MaskListItem(uniqueMaskName, mask));
+ private static void updateList(String maskIdentifier, String method, String line, Mask, ?> mask) {
+ MASK_ITEMS_BY_NAME.computeIfAbsent(maskIdentifier, ignored -> new ArrayList<>())
+ .add(new MaskListItem(maskIdentifier, method, line, mask));
refreshList();
}
@@ -142,10 +143,10 @@ private static void refreshList() {
}
}
- private record MaskListItem(String maskName, Mask, ?> mask) {
+ private record MaskListItem(String maskName, String method, String line, Mask, ?> mask) {
@Override
public String toString() {
- return maskName;
+ return String.join(" ", maskName, method, line);
}
}
}