From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Jake Potrebic Date: Thu, 13 Jan 2022 23:05:53 -0800 Subject: [PATCH] Add missing structure set seed configs The 4 missing structure set seed configs are strongholds, mineshafts, buried treasure, and ancient cities. Strongholds use a ring placement scheme which isn't random so they utilize the world seed by default, this adds a config to override it for just generating the ring positions. Mineshafts and Buried Treasure structure sets are special cases where the "salt" that can be defined for them via datapacks has 0 effect because the difference between the spacing and separation is 1 which is used as the upper bound in the random with salt. So the random always returns the same int (0) so the salt has no effect. This adds seeds/salts to the frequency reducer which has a similar effect. Co-authored-by: William Blake Galbreath diff --git a/src/main/java/net/minecraft/world/level/chunk/ChunkGenerator.java b/src/main/java/net/minecraft/world/level/chunk/ChunkGenerator.java index 4ce5d41b23d6204f280e6d4d21713ec5d9a724d1..9579889e4c7dedefc4f901ccac6157c425740481 100644 --- a/src/main/java/net/minecraft/world/level/chunk/ChunkGenerator.java +++ b/src/main/java/net/minecraft/world/level/chunk/ChunkGenerator.java @@ -133,7 +133,7 @@ public abstract class ChunkGenerator { // Spigot start private Stream possibleStructureSetsSpigot() { return this.possibleStructureSets().map(Holder::value).map((structureset) -> { - if (structureset.placement() instanceof RandomSpreadStructurePlacement randomConfig) { + if (structureset.placement() instanceof RandomSpreadStructurePlacement randomConfig && this.structureSets.getKey(structureset).getNamespace().equals(net.minecraft.resources.ResourceLocation.DEFAULT_NAMESPACE)) { // Paper - check namespace cause datapacks could add structure sets with the same path String name = this.structureSets.getKey(structureset).getPath(); int seed = randomConfig.salt; @@ -180,6 +180,11 @@ public abstract class ChunkGenerator { case "villages": seed = conf.villageSeed; break; + // Paper start + case "ancient_cities": + seed = conf.ancientCitySeed; + break; + // Paper end } structureset = new StructureSet(structureset.structures(), new RandomSpreadStructurePlacement(randomConfig.locateOffset, randomConfig.frequencyReductionMethod, randomConfig.frequency, seed, randomConfig.exclusionZone, randomConfig.spacing(), randomConfig.separation(), randomConfig.spreadType())); @@ -236,7 +241,13 @@ public abstract class ChunkGenerator { HolderSet holderset = concentricringsstructureplacement.preferredBiomes(); RandomSource randomsource = RandomSource.create(); + // Paper start + if (this.conf.strongholdSeed != null && this.structureSets.getResourceKey(holder).orElse(null) == net.minecraft.world.level.levelgen.structure.BuiltinStructureSets.STRONGHOLDS) { + randomsource.setSeed(this.conf.strongholdSeed); + } else { randomsource.setSeed(this instanceof FlatLevelSource ? 0L : randomstate.legacyLevelSeed()); + } + // Paper end double d0 = randomsource.nextDouble() * 3.141592653589793D * 2.0D; int l = 0; int i1 = 0; @@ -677,7 +688,7 @@ public abstract class ChunkGenerator { for (int i1 = chunkX - chunkRange; i1 <= chunkX + chunkRange; ++i1) { for (int j1 = chunkZ - chunkRange; j1 <= chunkZ + chunkRange; ++j1) { - if (structureplacement.isStructureChunk(this, noiseConfig, seed, i1, j1)) { + if (structureplacement.isStructureChunk(this, noiseConfig, seed, i1, j1, structureSet.unwrapKey().map(ResourceKey::location).orElse(null))) { // Paper return true; } } @@ -764,7 +775,7 @@ public abstract class ChunkGenerator { } } - if (structureplacement.isStructureChunk(this, noiseConfig, seed, chunkcoordintpair.x, chunkcoordintpair.z)) { + if (structureplacement.isStructureChunk(this, noiseConfig, seed, chunkcoordintpair.x, chunkcoordintpair.z, this.structureSets.getResourceKey(holder).map(ResourceKey::location).orElse(null))) { // Paper if (list.size() == 1) { this.tryGenerateStructure((StructureSet.StructureSelectionEntry) list.get(0), structureAccessor, registryManager, noiseConfig, structureTemplateManager, seed, chunk, chunkcoordintpair, sectionposition); } else { diff --git a/src/main/java/net/minecraft/world/level/levelgen/structure/placement/StructurePlacement.java b/src/main/java/net/minecraft/world/level/levelgen/structure/placement/StructurePlacement.java index 2fd1284c7f0d8e2cf35d03072089256d990b06eb..8ef0e9fa126cd96289bab48eaa06c2a1fbe4281e 100644 --- a/src/main/java/net/minecraft/world/level/levelgen/structure/placement/StructurePlacement.java +++ b/src/main/java/net/minecraft/world/level/levelgen/structure/placement/StructurePlacement.java @@ -59,10 +59,22 @@ public abstract class StructurePlacement { return this.exclusionZone; } + @Deprecated @io.papermc.paper.annotation.DoNotUse // Paper public boolean isStructureChunk(ChunkGenerator chunkGenerator, RandomState noiseConfig, long seed, int chunkX, int chunkZ) { + // Paper start - add missing structure set configs + return this.isStructureChunk(chunkGenerator, noiseConfig, seed, chunkX, chunkZ, null); + } + public boolean isStructureChunk(ChunkGenerator chunkGenerator, RandomState noiseConfig, long seed, int chunkX, int chunkZ, @org.jetbrains.annotations.Nullable net.minecraft.resources.ResourceLocation structureSetKey) { + Integer saltOverride = null; + if (net.minecraft.world.level.levelgen.structure.BuiltinStructureSets.MINESHAFTS.location().equals(structureSetKey)) { + saltOverride = chunkGenerator.conf.mineshaftSeed; + } else if (net.minecraft.world.level.levelgen.structure.BuiltinStructureSets.BURIED_TREASURES.location().equals(structureSetKey)) { + saltOverride = chunkGenerator.conf.buriedTreasureSeed; + } + // Paper end if (!this.isPlacementChunk(chunkGenerator, noiseConfig, seed, chunkX, chunkZ)) { return false; - } else if (this.frequency < 1.0F && !this.frequencyReductionMethod.shouldGenerate(seed, this.salt, chunkX, chunkZ, this.frequency)) { + } else if (this.frequency < 1.0F && !this.frequencyReductionMethod.shouldGenerate(seed, this.salt, chunkX, chunkZ, this.frequency, saltOverride)) { // Paper return false; } else { return !this.exclusionZone.isPresent() || !this.exclusionZone.get().isPlacementForbidden(chunkGenerator, noiseConfig, seed, chunkX, chunkZ); @@ -77,25 +89,31 @@ public abstract class StructurePlacement { public abstract StructurePlacementType type(); - private static boolean probabilityReducer(long seed, int salt, int chunkX, int chunkZ, float frequency) { + private static boolean probabilityReducer(long seed, int salt, int chunkX, int chunkZ, float frequency, @org.jetbrains.annotations.Nullable Integer saltOverride) { // Paper - ignore here WorldgenRandom worldgenRandom = new WorldgenRandom(new LegacyRandomSource(0L)); worldgenRandom.setLargeFeatureWithSalt(seed, salt, chunkX, chunkZ); return worldgenRandom.nextFloat() < frequency; } - private static boolean legacyProbabilityReducerWithDouble(long seed, int salt, int chunkX, int chunkZ, float frequency) { + private static boolean legacyProbabilityReducerWithDouble(long seed, int salt, int chunkX, int chunkZ, float frequency, @org.jetbrains.annotations.Nullable Integer saltOverride) { // Paper WorldgenRandom worldgenRandom = new WorldgenRandom(new LegacyRandomSource(0L)); + if (saltOverride == null) { // Paper worldgenRandom.setLargeFeatureSeed(seed, chunkX, chunkZ); + // Paper start + } else { + worldgenRandom.setLargeFeatureWithSalt(seed, chunkX, chunkZ, saltOverride); + } + // Paper end return worldgenRandom.nextDouble() < (double)frequency; } - private static boolean legacyArbitrarySaltProbabilityReducer(long seed, int salt, int chunkX, int chunkZ, float frequency) { + private static boolean legacyArbitrarySaltProbabilityReducer(long seed, int salt, int chunkX, int chunkZ, float frequency, @org.jetbrains.annotations.Nullable Integer saltOverride) { // Paper WorldgenRandom worldgenRandom = new WorldgenRandom(new LegacyRandomSource(0L)); - worldgenRandom.setLargeFeatureWithSalt(seed, chunkX, chunkZ, 10387320); + worldgenRandom.setLargeFeatureWithSalt(seed, chunkX, chunkZ, saltOverride != null ? saltOverride : 10387320); // Paper return worldgenRandom.nextFloat() < frequency; } - private static boolean legacyPillagerOutpostReducer(long seed, int salt, int chunkX, int chunkZ, float frequency) { + private static boolean legacyPillagerOutpostReducer(long seed, int salt, int chunkX, int chunkZ, float frequency, @org.jetbrains.annotations.Nullable Integer saltOverride) { // Paper - ignore here int i = chunkX >> 4; int j = chunkZ >> 4; WorldgenRandom worldgenRandom = new WorldgenRandom(new LegacyRandomSource(0L)); @@ -118,7 +136,7 @@ public abstract class StructurePlacement { @FunctionalInterface public interface FrequencyReducer { - boolean shouldGenerate(long seed, int salt, int chunkX, int chunkZ, float chance); + boolean shouldGenerate(long seed, int salt, int chunkX, int chunkZ, float chance, @org.jetbrains.annotations.Nullable Integer saltOverride); // Paper } public static enum FrequencyReductionMethod implements StringRepresentable { @@ -136,8 +154,8 @@ public abstract class StructurePlacement { this.reducer = generationPredicate; } - public boolean shouldGenerate(long seed, int salt, int chunkX, int chunkZ, float chance) { - return this.reducer.shouldGenerate(seed, salt, chunkX, chunkZ, chance); + public boolean shouldGenerate(long seed, int salt, int chunkX, int chunkZ, float chance, @org.jetbrains.annotations.Nullable Integer saltOverride) { // Paper + return this.reducer.shouldGenerate(seed, salt, chunkX, chunkZ, chance, saltOverride); // Paper } @Override diff --git a/src/main/java/org/spigotmc/SpigotWorldConfig.java b/src/main/java/org/spigotmc/SpigotWorldConfig.java index 6bcc46795d1f78746192cc107c4a1f61580ec3c5..5503ad6a93d331771a0e92c0da6adedf2ac81aff 100644 --- a/src/main/java/org/spigotmc/SpigotWorldConfig.java +++ b/src/main/java/org/spigotmc/SpigotWorldConfig.java @@ -362,6 +362,16 @@ public class SpigotWorldConfig public int mansionSeed; public int fossilSeed; public int portalSeed; + // Paper start - add missing structure set configs + public int ancientCitySeed; + public int buriedTreasureSeed; + public Integer mineshaftSeed; + public Long strongholdSeed; + private N getSeed(String path, java.util.function.Function toNumberFunc) { + final String value = this.getString(path, "default"); + return org.apache.commons.lang3.math.NumberUtils.isParsable(value) ? toNumberFunc.apply(value) : null; + } + // Paper end private void initWorldGenSeeds() { this.villageSeed = this.getInt( "seed-village", 10387312 ); @@ -379,6 +389,12 @@ public class SpigotWorldConfig this.mansionSeed = this.getInt( "seed-mansion", 10387319 ); this.fossilSeed = this.getInt( "seed-fossil", 14357921 ); this.portalSeed = this.getInt( "seed-portal", 34222645 ); + // Paper start - add missing structure set configs + this.ancientCitySeed = this.getInt("seed-ancientcity", 20083232); + this.buriedTreasureSeed = this.getInt("seed-buriedtreasure", 10387320); // StructurePlacement#HIGHLY_ARBITRARY_RANDOM_SALT + this.mineshaftSeed = this.getSeed("seed-mineshaft", Integer::parseInt); + this.strongholdSeed = this.getSeed("seed-stronghold", Long::parseLong); + // Paper end this.log( "Custom Map Seeds: Village: " + this.villageSeed + " Desert: " + this.desertSeed + " Igloo: " + this.iglooSeed + " Jungle: " + this.jungleSeed + " Swamp: " + this.swampSeed + " Monument: " + this.monumentSeed + " Ocean: " + this.oceanSeed + " Shipwreck: " + this.shipwreckSeed + " End City: " + this.endCitySeed + " Slime: " + this.slimeSeed + " Nether: " + this.netherSeed + " Mansion: " + this.mansionSeed + " Fossil: " + this.fossilSeed + " Portal: " + this.portalSeed ); }