From 8b5d1d0298902469ae32d56678e40623f8854c9e Mon Sep 17 00:00:00 2001 From: CrazyDev22 Date: Fri, 10 May 2024 15:58:26 +0200 Subject: [PATCH] rewrite jigsaw placement logic to prevent placements from being too close --- .../components/MantleJigsawComponent.java | 81 ++++++++----------- .../object/IrisJigsawStructurePlacement.java | 61 +++++++++++++- 2 files changed, 93 insertions(+), 49 deletions(-) diff --git a/core/src/main/java/com/volmit/iris/engine/mantle/components/MantleJigsawComponent.java b/core/src/main/java/com/volmit/iris/engine/mantle/components/MantleJigsawComponent.java index f10ff67c7..b7d8223b7 100644 --- a/core/src/main/java/com/volmit/iris/engine/mantle/components/MantleJigsawComponent.java +++ b/core/src/main/java/com/volmit/iris/engine/mantle/components/MantleJigsawComponent.java @@ -18,7 +18,6 @@ package com.volmit.iris.engine.mantle.components; -import com.volmit.iris.engine.data.cache.Cache; import com.volmit.iris.engine.jigsaw.PlannedStructure; import com.volmit.iris.engine.mantle.EngineMantle; import com.volmit.iris.engine.mantle.IrisMantleComponent; @@ -35,34 +34,31 @@ import com.volmit.iris.util.math.Position2; import com.volmit.iris.util.math.RNG; import com.volmit.iris.util.matter.slices.container.JigsawStructuresContainer; import com.volmit.iris.util.noise.CNG; -import com.volmit.iris.util.noise.NoiseType; +import org.jetbrains.annotations.Nullable; import java.util.List; public class MantleJigsawComponent extends IrisMantleComponent { + private final CNG cng; public MantleJigsawComponent(EngineMantle engineMantle) { super(engineMantle, MantleFlag.JIGSAW); - } - - private RNG applyNoise(int x, int z) { - long seed = Cache.key(x, z) + getEngineMantle().getEngine().getSeedManager().getJigsaw(); - CNG cng = CNG.signatureFast(new RNG(seed), NoiseType.WHITE, NoiseType.GLOB); - return new RNG((long) (seed * cng.noise(x, z))); + cng = NoiseStyle.STATIC.create(new RNG(jigsaw())); } @Override public void generateLayer(MantleWriter writer, int x, int z, ChunkContext context) { - RNG rng = applyNoise(x, z); int xxx = 8 + (x << 4); int zzz = 8 + (z << 4); IrisRegion region = getComplex().getRegionStream().get(xxx, zzz); IrisBiome biome = getComplex().getTrueBiomeStream().get(xxx, zzz); - generateJigsaw(writer, rng, x, z, biome, region); + generateJigsaw(writer, x, z, biome, region); } @ChunkCoordinates - private void generateJigsaw(MantleWriter writer, RNG rng, int x, int z, IrisBiome biome, IrisRegion region) { + private void generateJigsaw(MantleWriter writer, int x, int z, IrisBiome biome, IrisRegion region) { + long seed = cng.fit(Integer.MIN_VALUE, Integer.MIN_VALUE, x, z); + if (getDimension().getStronghold() != null) { List poss = getDimension().getStrongholds(seed()); @@ -70,7 +66,7 @@ public class MantleJigsawComponent extends IrisMantleComponent { for (Position2 pos : poss) { if (x == pos.getX() >> 4 && z == pos.getZ() >> 4) { IrisJigsawStructure structure = getData().getJigsawStructureLoader().load(getDimension().getStronghold()); - place(writer, pos.toIris(), structure, rng); + place(writer, pos.toIris(), structure, new RNG(seed)); return; } } @@ -80,27 +76,23 @@ public class MantleJigsawComponent extends IrisMantleComponent { KSet cachedRegions = new KSet<>(); KMap> cache = new KMap<>(); KMap distanceCache = new KMap<>(); - boolean placed = placeStructures(writer, rng, x, z, biome.getJigsawStructures(), cachedRegions, cache, distanceCache); + boolean placed = placeStructures(writer, seed, x, z, biome.getJigsawStructures(), cachedRegions, cache, distanceCache); if (!placed) - placed = placeStructures(writer, rng, x, z, region.getJigsawStructures(), cachedRegions, cache, distanceCache); + placed = placeStructures(writer, seed, x, z, region.getJigsawStructures(), cachedRegions, cache, distanceCache); if (!placed) - placeStructures(writer, rng, x, z, getDimension().getJigsawStructures(), cachedRegions, cache, distanceCache); + placeStructures(writer, seed, x, z, getDimension().getJigsawStructures(), cachedRegions, cache, distanceCache); } @ChunkCoordinates - private boolean placeStructures(MantleWriter writer, RNG rng, int x, int z, KList structures, + private boolean placeStructures(MantleWriter writer, long seed, int x, int z, KList structures, KSet cachedRegions, KMap> cache, KMap distanceCache) { - for (IrisJigsawStructurePlacement i : structures) { - if (rng.nextInt(i.getRarity()) == 0) { - if (checkMinDistances(i.collectMinDistances(), x, z, cachedRegions, cache, distanceCache)) - continue; - IrisPosition position = new IrisPosition((x << 4) + rng.nextInt(15), 0, (z << 4) + rng.nextInt(15)); - IrisJigsawStructure structure = getData().getJigsawStructureLoader().load(i.getStructure()); - if (place(writer, position, structure, rng)) - return true; - } - } - return false; + IrisJigsawStructurePlacement i = pick(structures, seed, x, z); + if (i == null || checkMinDistances(i.collectMinDistances(), x, z, cachedRegions, cache, distanceCache)) + return false; + RNG rng = new RNG(seed); + IrisPosition position = new IrisPosition((x << 4) + rng.nextInt(15), 0, (z << 4) + rng.nextInt(15)); + IrisJigsawStructure structure = getData().getJigsawStructureLoader().load(i.getStructure()); + return place(writer, position, structure, rng); } @ChunkCoordinates @@ -138,7 +130,7 @@ public class MantleJigsawComponent extends IrisMantleComponent { public IrisJigsawStructure guess(int x, int z) { // todo The guess doesnt bring into account that the placer may return -1 // todo doesnt bring skipped placements into account - RNG rng = applyNoise(x, z); + long seed = cng.fit(Integer.MIN_VALUE, Integer.MIN_VALUE, x, z); IrisBiome biome = getEngineMantle().getEngine().getSurfaceBiome((x << 4) + 8, (z << 4) + 8); IrisRegion region = getEngineMantle().getEngine().getRegion((x << 4) + 8, (z << 4) + 8); @@ -154,29 +146,26 @@ public class MantleJigsawComponent extends IrisMantleComponent { } } - for (IrisJigsawStructurePlacement i : biome.getJigsawStructures()) { - if (rng.nextInt(i.getRarity()) == 0) { - return getData().getJigsawStructureLoader().load(i.getStructure()); - } - } + IrisJigsawStructurePlacement i = pick(biome.getJigsawStructures(), seed, x, z); + if (i == null) i = pick(region.getJigsawStructures(), seed, x, z); + if (i == null) i = pick(getDimension().getJigsawStructures(), seed, x, z); + return i != null ? getData().getJigsawStructureLoader().load(i.getStructure()) : null; + } - for (IrisJigsawStructurePlacement i : region.getJigsawStructures()) { - if (rng.nextInt(i.getRarity()) == 0) { - return getData().getJigsawStructureLoader().load(i.getStructure()); - } - } - - for (IrisJigsawStructurePlacement i : getDimension().getJigsawStructures()) { - if (rng.nextInt(i.getRarity()) == 0) { - return getData().getJigsawStructureLoader().load(i.getStructure()); - } - } - - return null; + @Nullable + @ChunkCoordinates + private IrisJigsawStructurePlacement pick(List structures, long seed, int x, int z) { + return IRare.pick(structures.stream() + .filter(p -> p.shouldPlace(jigsaw(), x, z)) + .toList(), new RNG(seed).nextDouble()); } @BlockCoordinates private boolean place(MantleWriter writer, IrisPosition position, IrisJigsawStructure structure, RNG rng) { return new PlannedStructure(structure, position, rng).place(writer, getMantle(), writer.getEngine()); } + + private long jigsaw() { + return getEngineMantle().getEngine().getSeedManager().getJigsaw(); + } } diff --git a/core/src/main/java/com/volmit/iris/engine/object/IrisJigsawStructurePlacement.java b/core/src/main/java/com/volmit/iris/engine/object/IrisJigsawStructurePlacement.java index 16eea76e8..f5a10361a 100644 --- a/core/src/main/java/com/volmit/iris/engine/object/IrisJigsawStructurePlacement.java +++ b/core/src/main/java/com/volmit/iris/engine/object/IrisJigsawStructurePlacement.java @@ -18,20 +18,23 @@ package com.volmit.iris.engine.object; +import com.volmit.iris.Iris; import com.volmit.iris.engine.object.annotations.ArrayType; import com.volmit.iris.engine.object.annotations.Desc; +import com.volmit.iris.engine.object.annotations.MinNumber; import com.volmit.iris.engine.object.annotations.RegistryListResource; import com.volmit.iris.engine.object.annotations.Required; import com.volmit.iris.engine.object.annotations.Snippet; import com.volmit.iris.util.collection.KList; import com.volmit.iris.util.collection.KMap; +import com.volmit.iris.util.documentation.ChunkCoordinates; +import com.volmit.iris.util.math.RNG; import lombok.AllArgsConstructor; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.NoArgsConstructor; import lombok.experimental.Accessors; - @Snippet("jigsaw-structure-placement") @Accessors(chain = true) @NoArgsConstructor @@ -39,16 +42,33 @@ import lombok.experimental.Accessors; @Desc("Represents a jigsaw structure placer") @Data @EqualsAndHashCode(callSuper = false) -public class IrisJigsawStructurePlacement { +public class IrisJigsawStructurePlacement implements IRare { @RegistryListResource(IrisJigsawStructure.class) @Required @Desc("The structure to place") private String structure; @Required - @Desc("The 1 in X chance rarity") + @Desc("The 1 in X chance rarity applies when generating multiple structures at once") private int rarity = 100; + @Required + @Desc("The salt to use when generating the structure (to differentiate structures)") + private int salt = 76134; + + @Required + @MinNumber(0) + @Desc("Average distance in chunks between two neighboring generation attempts") + private int spacing = 32; + + @Required + @MinNumber(0) + @Desc("Minimum distance in chunks between two neighboring generation attempts\nThe maximum distance of two neighboring generation attempts is 2*spacing - separation") + private int separation = 16; + + @Desc("The method used to spread the structure") + private SpreadType spreadType = SpreadType.TRIANGULAR; + @ArrayType(type = IrisJigsawMinDistance.class) @Desc("List of minimum distances to check for") private KList minDistances = new KList<>(); @@ -64,4 +84,39 @@ public class IrisJigsawStructurePlacement { private int toChunks(int blocks) { return (int) Math.ceil(blocks / 16d); } + + @ChunkCoordinates + public boolean shouldPlace(long seed, int x, int z) { + if (separation > spacing) { + separation = spacing; + Iris.warn("JigsawStructurePlacement: separation must be less than or equal to spacing"); + } + + int i = Math.floorDiv(x, spacing); + int j = Math.floorDiv(z, spacing); + RNG rng = new RNG(i * 341873128712L + j * 132897987541L + seed + salt); + + int k = spacing - separation; + int l = spreadType.apply(rng, k); + int m = spreadType.apply(rng, k); + return i * spacing + l == x && j * spacing + m == z; + } + + public enum SpreadType { + LINEAR(RNG::i), + TRIANGULAR((rng, bound) -> (rng.i(bound) + rng.i(bound)) / 2); + private final SpreadMethod method; + + SpreadType(SpreadMethod method) { + this.method = method; + } + + public int apply(RNG rng, int bound) { + return method.apply(rng, bound); + } + } + + private interface SpreadMethod { + int apply(RNG rng, int bound); + } }