diff --git a/patches/server/Configurable-feature-seeds.patch b/patches/server/Configurable-feature-seeds.patch new file mode 100644 index 000000000..4d619dbe0 --- /dev/null +++ b/patches/server/Configurable-feature-seeds.patch @@ -0,0 +1,98 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Nassim Jahnke +Date: Tue, 31 Aug 2021 17:05:27 +0200 +Subject: [PATCH] Configurable feature seeds + +Co-authored-by: Thonk <30448663+ExcessiveAmountsOfZombies@users.noreply.github.com> + +diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java ++++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java +@@ -0,0 +0,0 @@ public class PaperWorldConfig { + return table; + } + ++ public it.unimi.dsi.fastutil.objects.Object2LongOpenHashMap featureSeeds = new it.unimi.dsi.fastutil.objects.Object2LongOpenHashMap<>(); ++ private void featureSeeds() { ++ featureSeeds.defaultReturnValue(-1); ++ final boolean randomise = getBoolean("feature-seeds.generate-random-seeds-for-all", false); ++ final ConfigurationSection defaultSection = config.getConfigurationSection("world-settings.default.feature-seeds"); ++ final ConfigurationSection section = config.getConfigurationSection("world-settings." + worldName + ".feature-seeds"); ++ final net.minecraft.core.Registry> registry ++ = net.minecraft.server.MinecraftServer.getServer().registryAccess().registryOrThrow(net.minecraft.core.Registry.CONFIGURED_FEATURE_REGISTRY); ++ if (section != null) { ++ loadFeatureSeeds(section, registry); ++ } ++ ++ // Also use default set seeds if not already set per world ++ loadFeatureSeeds(defaultSection, registry); ++ ++ if (randomise) { ++ final Map randomisedSeeds = new HashMap<>(); ++ final java.util.Random random = new java.util.Random(); ++ for (final net.minecraft.resources.ResourceLocation resourceLocation : registry.keySet()) { ++ if (featureSeeds.containsKey(resourceLocation)) { ++ continue; ++ } ++ ++ final long seed = random.nextLong(); ++ randomisedSeeds.put("world-settings." + worldName + ".feature-seeds." + resourceLocation.getPath(), seed); ++ featureSeeds.put(resourceLocation, seed); ++ } ++ if (!randomisedSeeds.isEmpty()) { ++ config.addDefaults(randomisedSeeds); ++ } ++ } ++ } ++ ++ private void loadFeatureSeeds(final ConfigurationSection section, final net.minecraft.core.Registry> registry) { ++ for (final String key : section.getKeys(false)) { ++ if (!(section.get(key) instanceof Number)) { ++ continue; ++ } ++ ++ final net.minecraft.resources.ResourceLocation location = new net.minecraft.resources.ResourceLocation(key); ++ if (!registry.containsKey(location)) { ++ logError("Invalid feature resource location: " + location); ++ continue; ++ } ++ ++ featureSeeds.putIfAbsent(location, section.getLong(key)); ++ } ++ } ++ + public int getBehaviorTickRate(String typeName, String entityType, int def) { + return getIntOrDefault(behaviorTickRates, typeName, entityType, def); + } +diff --git a/src/main/java/net/minecraft/world/level/biome/Biome.java b/src/main/java/net/minecraft/world/level/biome/Biome.java +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/main/java/net/minecraft/world/level/biome/Biome.java ++++ b/src/main/java/net/minecraft/world/level/biome/Biome.java +@@ -0,0 +0,0 @@ public final class Biome { + + public void generate(StructureFeatureManager structureAccessor, ChunkGenerator chunkGenerator, WorldGenRegion region, long populationSeed, WorldgenRandom random, BlockPos origin) { + List>>> list = this.generationSettings.features(); +- Registry> registry = region.registryAccess().registryOrThrow(Registry.CONFIGURED_FEATURE_REGISTRY); ++ Registry> registry = region.registryAccess().registryOrThrow(Registry.CONFIGURED_FEATURE_REGISTRY); // Paper - diff on change + Registry> registry2 = region.registryAccess().registryOrThrow(Registry.STRUCTURE_FEATURE_REGISTRY); + int i = GenerationStep.Decoration.values().length; + +@@ -0,0 +0,0 @@ public final class Biome { + Supplier supplier3 = () -> { + return registry.getResourceKey(configuredFeature).map(Object::toString).orElseGet(configuredFeature::toString); + }; +- random.setFeatureSeed(populationSeed, k, j); ++ // Paper start - change populationSeed used in random ++ long featurePopulationSeed = populationSeed; ++ final ResourceLocation location = registry.getKey(configuredFeature); ++ final long configFeatureSeed = region.getMinecraftWorld().paperConfig.featureSeeds.getLong(location); ++ if (configFeatureSeed != -1) { ++ final ChunkPos center = region.getCenter(); ++ featurePopulationSeed = random.setDecorationSeed(configFeatureSeed, center.getMinBlockX(), center.getMinBlockZ()); // See ChunkGenerator#addVanillaDecorations ++ } ++ random.setFeatureSeed(featurePopulationSeed, k, j); ++ // Paper end + + try { + region.setCurrentlyGenerating(supplier3); diff --git a/patches/server/Paper-config-files.patch b/patches/server/Paper-config-files.patch index 2b46cbe0f..f5cc5f115 100644 --- a/patches/server/Paper-config-files.patch +++ b/patches/server/Paper-config-files.patch @@ -546,6 +546,11 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + return config.getInt("world-settings." + worldName + "." + path, config.getInt("world-settings.default." + path)); + } + ++ private long getLong(String path, long def) { ++ config.addDefault("world-settings.default." + path, def); ++ return config.getLong("world-settings." + worldName + "." + path, config.getLong("world-settings.default." + path)); ++ } ++ + private float getFloat(String path, float def) { + // TODO: Figure out why getFloat() always returns the default value. + return (float) getDouble(path, (double) def);