From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Phoenix616 Date: Mon, 13 Jan 2020 15:40:32 +0100 Subject: [PATCH] Seed based feature search This tries to work around the issue where the server will load surrounding chunks up to a radius of 100 chunks in order to search for features e.g. when running the /locate command or for treasure maps (issue #2312). This is done by backporting Mojang's change in 1.17 which makes it so that the biome (generated by the seed) is checked first if the feature can be generated before actually to load the chunk. Additionally to that the center location of the target chunk is simply returned if the chunk is not loaded to avoid the sync chunk load. As this can lead to less precise locations a toggle is provided to enable the sync loading of the target chunk again. The main downside of this is that it breaks once the seed or generator changes but this should usually not happen. A config option to disable this completely is added though in case that should ever be necessary. diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java index 81afddeadbece05f3d9ef604a3d2b3cc0a731cde..e3ca2c9d72e16dabd888234d069fbfa21c1d6fa1 100644 --- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java +++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java @@ -376,6 +376,14 @@ public class PaperWorldConfig { } } + public boolean seedBasedFeatureSearch = true; + public boolean seedBasedFeatureSearchLoadsChunks = false; + private void seedBasedFeatureSearch() { + seedBasedFeatureSearch = getBoolean("seed-based-feature-search", seedBasedFeatureSearch); + seedBasedFeatureSearchLoadsChunks = getBoolean("seed-based-feature-search-loads-chunks", seedBasedFeatureSearchLoadsChunks); + log("Feature search is based on seed: " + seedBasedFeatureSearch + ", loads chunks:" + seedBasedFeatureSearchLoadsChunks); + } + public int maxCollisionsPerEntity; private void maxEntityCollision() { maxCollisionsPerEntity = getInt( "max-entity-collisions", this.spigotConfig.getInt("max-entity-collisions", 8) ); diff --git a/src/main/java/net/minecraft/world/level/levelgen/feature/StructureFeature.java b/src/main/java/net/minecraft/world/level/levelgen/feature/StructureFeature.java index 3878a7f6402a1dff1e019e16dd8772ec7303ebe7..ef77b7e54c9ce3379b3bd6991aebcb4889029907 100644 --- a/src/main/java/net/minecraft/world/level/levelgen/feature/StructureFeature.java +++ b/src/main/java/net/minecraft/world/level/levelgen/feature/StructureFeature.java @@ -171,7 +171,24 @@ public abstract class StructureFeature { if (!world.getWorldBorder().isChunkInBounds(chunkPos.x, chunkPos.z)) { continue; } // Paper boolean bl3 = world.getBiomeManager().getPrimaryBiomeAtChunk(chunkPos).getGenerationSettings().isValidStart(this); if (bl3) { - ChunkAccess chunkAccess = world.getChunk(chunkPos.x, chunkPos.z, ChunkStatus.STRUCTURE_STARTS); + // Paper start - seed based feature search + ChunkAccess chunkAccess = null; + if (structureAccessor.getWorld().paperConfig.seedBasedFeatureSearch) { + Biome biomeBase = structureAccessor.getWorld().getBiomeManager().getBiome(new BlockPos(chunkPos.getMinBlockX() + 9, 0, chunkPos.getMinBlockZ() + 9)); + if (!biomeBase.getGenerationSettings().isValidStart(this)) { + continue; + } + if (!structureAccessor.getWorld().paperConfig.seedBasedFeatureSearchLoadsChunks) { + chunkAccess = structureAccessor.getWorld().getChunkIfLoaded(chunkPos.x, chunkPos.z); + if (chunkAccess == null) { + return chunkPos.getWorldPosition().offset(8, searchStartPos.getY(), 8); + } + } + } + if (chunkAccess == null) { + chunkAccess = world.getChunk(chunkPos.x, chunkPos.z, ChunkStatus.STRUCTURE_STARTS); + } + // Paper end StructureStart structureStart = structureAccessor.getStartForFeature(SectionPos.bottomOf(chunkAccess), this, chunkAccess); if (structureStart != null && structureStart.isValid()) { if (skipExistingChunks && structureStart.canBeReferenced()) {