From 470222069968c20a8a9661510e338b4a3153056f Mon Sep 17 00:00:00 2001 From: JohnBraham Date: Wed, 2 Sep 2026 22:34:48 +0100 Subject: [PATCH 1/5] Prioritize saved vault starts on chunk load --- .../world/AncientCakeVaultPalette.java | 24 +++++++++++++++---- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/src/main/java/zone/moddev/mc/cakeworld/world/AncientCakeVaultPalette.java b/src/main/java/zone/moddev/mc/cakeworld/world/AncientCakeVaultPalette.java index 33738c5..5b55c52 100644 --- a/src/main/java/zone/moddev/mc/cakeworld/world/AncientCakeVaultPalette.java +++ b/src/main/java/zone/moddev/mc/cakeworld/world/AncientCakeVaultPalette.java @@ -126,20 +126,34 @@ public static void onChunkLoad(ChunkEvent.Load event) { .equals(Level.OVERWORLD)) { return; } - // Keep the callback non-reentrant, but isolate the 128 authoritative - // Stronghold start candidates from ordinary chunk-load traffic. A large - // world-generation scan can otherwise keep moving a candidate behind - // newer loads before the deferred server-tick pass observes its start. + // Keep the callback non-reentrant, but isolate actual saved Stronghold + // starts and the 128 early-load candidates from ordinary chunk traffic. + // A large world-generation scan can otherwise keep moving a start behind + // newer loads before the deferred server-tick pass observes it. PendingSlice pending = new PendingSlice( level.dimension(), chunk.getPos(), 0); - if (isStrongholdStartCandidate(level, chunk.getPos())) { + if (hasSavedStrongholdStart(level, chunk) + || isStrongholdStartCandidate( + level, chunk.getPos())) { START_CANDIDATES.addLast(pending); } else { PENDING.addFirst(pending); } } + private static boolean hasSavedStrongholdStart( + ServerLevel level, LevelChunk chunk) { + ConfiguredStructureFeature stronghold = + configuredStronghold(level); + if (stronghold == null) { + return false; + } + StructureStart start = chunk.getStartForFeature( + stronghold); + return start != null && start.isValid(); + } + @SubscribeEvent public static void onServerTick( TickEvent.ServerTickEvent event) { From 0fab4b360b72055bb0a499c4e4a0181c251e5d57 Mon Sep 17 00:00:00 2001 From: JohnBraham Date: Wed, 2 Sep 2026 23:16:53 +0100 Subject: [PATCH 2/5] Stabilize vault palette activation --- .../world/AncientCakeVaultPalette.java | 101 ++++++++++++++---- 1 file changed, 78 insertions(+), 23 deletions(-) diff --git a/src/main/java/zone/moddev/mc/cakeworld/world/AncientCakeVaultPalette.java b/src/main/java/zone/moddev/mc/cakeworld/world/AncientCakeVaultPalette.java index 5b55c52..2b46fe3 100644 --- a/src/main/java/zone/moddev/mc/cakeworld/world/AncientCakeVaultPalette.java +++ b/src/main/java/zone/moddev/mc/cakeworld/world/AncientCakeVaultPalette.java @@ -66,7 +66,18 @@ public final class AncientCakeVaultPalette { new ConcurrentLinkedDeque<>(); private static final ConcurrentMap> CONVERTED_STARTS = new ConcurrentHashMap<>(); - private static final int MAX_REFERENCE_ATTEMPTS = 4; + // A marker read from or written to chunk data is durable. Keep that + // distinction so a later load never rewrites a player's authored blocks, + // while a second event in the same generation session can repair an early, + // superseded palette pass. + private static final ConcurrentMap> + PERSISTED_CONVERTED_STARTS = + new ConcurrentHashMap<>(); + // Structure starts can become visible before their final blocks do. Require + // one second of consecutive server-tick visibility before first conversion. + private static final int REQUIRED_VISIBLE_ATTEMPTS = 20; + private static final int MAX_REFERENCE_ATTEMPTS = + REQUIRED_VISIBLE_ATTEMPTS + 4; private static final int MAX_START_ACTIVATION_ATTEMPTS = 1200; private static volatile Set strongholdStartCandidates; @@ -85,11 +96,14 @@ public static void onChunkDataLoad( } CompoundTag persistent = event.getData() .getCompound(PERSISTENT_KEY); - Set starts = convertedStarts( - event.getChunk().getPos().toLong()); + long chunkKey = event.getChunk().getPos().toLong(); + Set starts = convertedStarts(chunkKey); + Set persisted = persistedConvertedStarts( + chunkKey); for (long start : persistent.getLongArray( CONVERTED_STARTS_KEY)) { starts.add(start); + persisted.add(start); } } @@ -115,6 +129,9 @@ public static void onChunkDataSave( .sorted().toArray()); event.getData().put(PERSISTENT_KEY, persistent); + persistedConvertedStarts( + event.getChunk().getPos().toLong()) + .addAll(starts); } @SubscribeEvent @@ -130,11 +147,14 @@ public static void onChunkLoad(ChunkEvent.Load event) { // starts and the 128 early-load candidates from ordinary chunk traffic. // A large world-generation scan can otherwise keep moving a start behind // newer loads before the deferred server-tick pass observes it. + boolean savedStart = hasSavedStrongholdStart( + level, chunk); PendingSlice pending = new PendingSlice( level.dimension(), - chunk.getPos(), 0); - if (hasSavedStrongholdStart(level, chunk) - || isStrongholdStartCandidate( + chunk.getPos(), 0, 0, savedStart); + if (savedStart) { + START_CANDIDATES.addFirst(pending); + } else if (isStrongholdStartCandidate( level, chunk.getPos())) { START_CANDIDATES.addLast(pending); } else { @@ -198,15 +218,12 @@ public static void onServerTick( if (stronghold == null) { continue; } - boolean themed = false; StructureStart direct = chunk.getStartForFeature( stronghold); - if (isCakeWorldVault( - level, direct)) { - themeLoadedChunks(level, direct); - themed = isConverted(chunk, direct); - } + StructureStart visibleVault = + isCakeWorldVault(level, direct) + ? direct : null; for (long reference : chunk.getReferencesForFeature( stronghold)) { @@ -219,12 +236,24 @@ public static void onServerTick( StructureStart start = owner.getStartForFeature( stronghold); - if (isCakeWorldVault( - level, start)) { - themeLoadedChunks(level, start); - themed |= isConverted(chunk, start); + if (visibleVault == null + && isCakeWorldVault( + level, start)) { + visibleVault = start; } } + int visibleAttempts = visibleVault == null + ? 0 : pending.visibleAttempts() + 1; + boolean themed = false; + // Do not let host/JVM scheduling decide whether the palette runs before + // or after the native structure writes its final blocks. + if (visibleVault != null + && visibleAttempts + >= REQUIRED_VISIBLE_ATTEMPTS) { + themeLoadedChunks(level, visibleVault, + pending.refreshSessionConversion()); + themed = isConverted(chunk, visibleVault); + } boolean hasReferences = !chunk .getReferencesForFeature(stronghold) .isEmpty(); @@ -240,11 +269,19 @@ public static void onServerTick( && (startCandidate || direct != null || hasReferences)) { Deque retries = startCandidate + || pending.refreshSessionConversion() ? START_CANDIDATES : PENDING; - retries.addLast(new PendingSlice( + PendingSlice retry = new PendingSlice( pending.dimension(), pending.chunk(), - pending.attempts() + 1)); + pending.attempts() + 1, + visibleAttempts, + pending.refreshSessionConversion()); + if (pending.refreshSessionConversion()) { + retries.addFirst(retry); + } else { + retries.addLast(retry); + } } } } @@ -271,6 +308,7 @@ public static void onServerStopped( START_CANDIDATES.clear(); PENDING.clear(); CONVERTED_STARTS.clear(); + PERSISTED_CONVERTED_STARTS.clear(); strongholdStartCandidates = null; } @@ -334,7 +372,8 @@ private static boolean isCakeWorldVault( private static void themeLoadedChunks( ServerLevel level, - StructureStart start) { + StructureStart start, + boolean refreshSessionConversion) { BoundingBox bounds = start.getBoundingBox(); int minimumChunkX = Math.floorDiv(bounds.minX(), 16); @@ -352,7 +391,8 @@ private static void themeLoadedChunks( themeChunk(level, level.getChunk( chunkX, chunkZ), - start); + start, + refreshSessionConversion); } } } @@ -361,11 +401,16 @@ private static void themeLoadedChunks( private static void themeChunk( ServerLevel level, LevelChunk chunk, - StructureStart start) { + StructureStart start, + boolean refreshSessionConversion) { Set converted = convertedStarts( chunk.getPos().toLong()); long startKey = start.getChunkPos().toLong(); - if (converted.contains(startKey)) { + if (converted.contains(startKey) + && (!refreshSessionConversion + || persistedConvertedStarts( + chunk.getPos().toLong()) + .contains(startKey))) { return; } ChunkPos chunkPos = chunk.getPos(); @@ -400,6 +445,14 @@ private static Set convertedStarts( .newKeySet()); } + private static Set persistedConvertedStarts( + long chunkKey) { + return PERSISTED_CONVERTED_STARTS + .computeIfAbsent(chunkKey, + ignored -> ConcurrentHashMap + .newKeySet()); + } + /** * Exposes vanilla's deterministic graph seam for regression evidence. */ @@ -565,6 +618,8 @@ private record PendingSlice( net.minecraft.resources.ResourceKey dimension, ChunkPos chunk, - int attempts) { + int attempts, + int visibleAttempts, + boolean refreshSessionConversion) { } } From deac9e3d89a3bed2ee67aa5eba0f19df41c2bced Mon Sep 17 00:00:00 2001 From: JohnBraham Date: Wed, 2 Sep 2026 23:42:47 +0100 Subject: [PATCH 3/5] Trace fixed-world vault activation --- .../world/AncientCakeVaultPalette.java | 55 ++++++++++++++++++- 1 file changed, 53 insertions(+), 2 deletions(-) diff --git a/src/main/java/zone/moddev/mc/cakeworld/world/AncientCakeVaultPalette.java b/src/main/java/zone/moddev/mc/cakeworld/world/AncientCakeVaultPalette.java index 2b46fe3..5fce362 100644 --- a/src/main/java/zone/moddev/mc/cakeworld/world/AncientCakeVaultPalette.java +++ b/src/main/java/zone/moddev/mc/cakeworld/world/AncientCakeVaultPalette.java @@ -8,6 +8,9 @@ import java.util.concurrent.ConcurrentLinkedDeque; import java.util.concurrent.ConcurrentMap; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + import zone.moddev.mc.cakeworld.CakeWorld; import zone.moddev.mc.cakeworld.init.CakeWorldBlocks; import zone.moddev.mc.cakeworld.init.CakeWorldFluids; @@ -56,6 +59,7 @@ */ @Mod.EventBusSubscriber(modid = CakeWorld.MODID) public final class AncientCakeVaultPalette { + private static final Logger LOGGER = LogManager.getLogger(); private static final String PERSISTENT_KEY = "cakeworld_ancient_cake_vault_palette"; private static final String CONVERTED_STARTS_KEY = @@ -105,6 +109,10 @@ public static void onChunkDataLoad( starts.add(start); persisted.add(start); } + if (fixedWorldgenEvidence()) { + LOGGER.info("Ancient Cake Vault marker load: chunk={}, starts={}", + event.getChunk().getPos(), persisted); + } } @SubscribeEvent @@ -132,6 +140,10 @@ public static void onChunkDataSave( persistedConvertedStarts( event.getChunk().getPos().toLong()) .addAll(starts); + if (fixedWorldgenEvidence()) { + LOGGER.info("Ancient Cake Vault marker save: chunk={}, starts={}", + event.getChunk().getPos(), starts); + } } @SubscribeEvent @@ -152,10 +164,21 @@ public static void onChunkLoad(ChunkEvent.Load event) { PendingSlice pending = new PendingSlice( level.dimension(), chunk.getPos(), 0, 0, savedStart); + boolean startCandidate = isStrongholdStartCandidate( + level, chunk.getPos()); + if (fixedWorldgenEvidence() + && (savedStart || startCandidate)) { + LOGGER.info("Ancient Cake Vault load event: chunk={}, savedStart={}, candidate={}, converted={}, persisted={}", + chunk.getPos(), savedStart, + startCandidate, + CONVERTED_STARTS.getOrDefault( + chunk.getPos().toLong(), Set.of()), + PERSISTED_CONVERTED_STARTS.getOrDefault( + chunk.getPos().toLong(), Set.of())); + } if (savedStart) { START_CANDIDATES.addFirst(pending); - } else if (isStrongholdStartCandidate( - level, chunk.getPos())) { + } else if (startCandidate) { START_CANDIDATES.addLast(pending); } else { PENDING.addFirst(pending); @@ -260,6 +283,29 @@ && isCakeWorldVault( boolean startCandidate = isStrongholdStartCandidate( level, pending.chunk()); + if (fixedWorldgenEvidence() + && (pending.refreshSessionConversion() + || direct != null || hasReferences) + && (pending.attempts() == 0 + || visibleAttempts == 1 + || visibleAttempts + == REQUIRED_VISIBLE_ATTEMPTS + || pending.attempts() + == MAX_REFERENCE_ATTEMPTS + || pending.attempts() + == MAX_START_ACTIVATION_ATTEMPTS)) { + LOGGER.info("Ancient Cake Vault tick probe: chunk={}, attempt={}, visibleAttempts={}, refresh={}, candidate={}, direct={}, references={}, visibleVault={}, themed={}, converted={}, persisted={}", + pending.chunk(), pending.attempts(), + visibleAttempts, + pending.refreshSessionConversion(), + startCandidate, direct != null, + hasReferences, visibleVault != null, + themed, + CONVERTED_STARTS.getOrDefault( + pending.chunk().toLong(), Set.of()), + PERSISTED_CONVERTED_STARTS.getOrDefault( + pending.chunk().toLong(), Set.of())); + } int maximumAttempts = startCandidate ? MAX_START_ACTIVATION_ATTEMPTS : MAX_REFERENCE_ATTEMPTS; @@ -453,6 +499,11 @@ private static Set persistedConvertedStarts( .newKeySet()); } + private static boolean fixedWorldgenEvidence() { + return Boolean.getBoolean( + "cakeworld.fixedWorldgenEvidence"); + } + /** * Exposes vanilla's deterministic graph seam for regression evidence. */ From 14afe250d2b8322131085127218e3fb6350d5811 Mon Sep 17 00:00:00 2001 From: JohnBraham Date: Wed, 2 Sep 2026 23:45:55 +0100 Subject: [PATCH 4/5] Retry saved vault starts through biome activation --- .../mc/cakeworld/world/AncientCakeVaultPalette.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/main/java/zone/moddev/mc/cakeworld/world/AncientCakeVaultPalette.java b/src/main/java/zone/moddev/mc/cakeworld/world/AncientCakeVaultPalette.java index 5fce362..392cbc7 100644 --- a/src/main/java/zone/moddev/mc/cakeworld/world/AncientCakeVaultPalette.java +++ b/src/main/java/zone/moddev/mc/cakeworld/world/AncientCakeVaultPalette.java @@ -283,6 +283,8 @@ && isCakeWorldVault( boolean startCandidate = isStrongholdStartCandidate( level, pending.chunk()); + boolean authoritativeStart = startCandidate + || pending.refreshSessionConversion(); if (fixedWorldgenEvidence() && (pending.refreshSessionConversion() || direct != null || hasReferences) @@ -306,16 +308,15 @@ && isCakeWorldVault( PERSISTED_CONVERTED_STARTS.getOrDefault( pending.chunk().toLong(), Set.of())); } - int maximumAttempts = startCandidate + int maximumAttempts = authoritativeStart ? MAX_START_ACTIVATION_ATTEMPTS : MAX_REFERENCE_ATTEMPTS; if (!themed && pending.attempts() < maximumAttempts - && (startCandidate || direct != null + && (authoritativeStart || direct != null || hasReferences)) { - Deque retries = startCandidate - || pending.refreshSessionConversion() + Deque retries = authoritativeStart ? START_CANDIDATES : PENDING; PendingSlice retry = new PendingSlice( pending.dimension(), From db06b24820ee2f1973f7cc888e854ba91552fb86 Mon Sep 17 00:00:00 2001 From: JohnBraham Date: Thu, 3 Sep 2026 00:26:48 +0100 Subject: [PATCH 5/5] Make vault audit select an eligible stronghold --- .../gametest/DeepPantryGameTests.java | 89 ++++++++- .../world/AncientCakeVaultPalette.java | 179 +++--------------- 2 files changed, 115 insertions(+), 153 deletions(-) diff --git a/src/main/java/zone/moddev/mc/cakeworld/gametest/DeepPantryGameTests.java b/src/main/java/zone/moddev/mc/cakeworld/gametest/DeepPantryGameTests.java index cfacbc9..e89897b 100644 --- a/src/main/java/zone/moddev/mc/cakeworld/gametest/DeepPantryGameTests.java +++ b/src/main/java/zone/moddev/mc/cakeworld/gametest/DeepPantryGameTests.java @@ -159,8 +159,10 @@ import net.minecraft.world.level.levelgen.structure.PoolElementStructurePiece; import net.minecraft.world.level.levelgen.structure.StrongholdPieces; import net.minecraft.world.level.levelgen.structure.StructurePiece; +import net.minecraft.world.level.levelgen.structure.StructureSet; import net.minecraft.world.level.levelgen.structure.StructureStart; import net.minecraft.world.level.levelgen.structure.TemplateStructurePiece; +import net.minecraft.world.level.levelgen.structure.placement.ConcentricRingsStructurePlacement; import net.minecraft.world.level.chunk.LevelChunk; import net.minecraft.world.level.portal.PortalShape; import net.minecraft.world.level.storage.loot.BuiltInLootTables; @@ -10447,19 +10449,29 @@ private static LocatedVault locateAncientCakeVault( GameTestHelper helper, ServerLevel level, ConfiguredStructureFeature configured, BlockPos origin) { + ChunkPos startChunk = nearestEligibleVaultStart( + helper, level, configured, origin); + BlockPos vaultOrigin = startChunk + .getMiddleBlockPosition(level.getSeaLevel()); BlockPos located = level.findNearestMapFeature( AncientCakeVaultFeature.STRUCTURE_TAG, - origin, 512, false); + vaultOrigin, 512, false); require(helper, located != null, "The fixed-seed CakeWorld contained no locatable Ancient Cake Vault within 512 chunks"); BlockPos eyeLocated = level.findNearestMapFeature( ConfiguredStructureTags .EYE_OF_ENDER_LOCATED, - origin, 512, false); + vaultOrigin, 512, false); require(helper, eyeLocated != null, "The fixed-seed Ancient Cake Vault was not locatable with a vanilla Eye of Ender"); - ChunkPos startChunk = new ChunkPos(located); + require(helper, + new ChunkPos(located).equals(startChunk) + && new ChunkPos(eyeLocated) + .equals(startChunk), + "CakeWorld and Eye-of-Ender locate routes did not resolve the selected eligible Stronghold start: selected=" + + startChunk + ", own=" + located + + ", eye=" + eyeLocated); net.minecraft.world.level.chunk.LevelChunk startLevelChunk = level.getChunk(startChunk.x, @@ -10560,6 +10572,77 @@ private static LocatedVault locateAncientCakeVault( portal, library, corridor); } + private static ChunkPos nearestEligibleVaultStart( + GameTestHelper helper, ServerLevel level, + ConfiguredStructureFeature configured, + BlockPos origin) { + StructureSet structureSet = level.registryAccess() + .registryOrThrow( + Registry.STRUCTURE_SET_REGISTRY) + .get(AncientCakeVaultFeature + .STRUCTURE_SET_ID); + require(helper, + structureSet != null + && structureSet.placement() + instanceof ConcentricRingsStructurePlacement, + "The native Stronghold ring placement required by Ancient Cake Vaults was absent"); + ConcentricRingsStructurePlacement placement = + (ConcentricRingsStructurePlacement) + structureSet.placement(); + List ringPositions = level + .getChunkSource().getGenerator() + .getRingPositionsFor(placement); + require(helper, + ringPositions != null + && !ringPositions.isEmpty(), + "The native Stronghold placement exposed no generated ring positions"); + List nearestFirst = ringPositions.stream() + .sorted(Comparator.comparingLong( + chunk -> horizontalDistanceSquared( + chunk, origin))) + .toList(); + List rejected = new java.util.ArrayList<>(); + for (ChunkPos candidate : nearestFirst) { + LevelChunk chunk = level.getChunk( + candidate.x, candidate.z); + StructureStart start = chunk + .getStartForFeature(configured); + BlockPos biomePosition = candidate + .getMiddleBlockPosition( + level.getSeaLevel()); + ResourceLocation biome = level.registryAccess() + .registryOrThrow(Registry.BIOME_REGISTRY) + .getKey(level.getBiome( + biomePosition).value()); + boolean valid = start != null + && start.isValid() + && start.getFeature() == configured; + if (valid && level.getBiome(biomePosition) + .is(AncientCakeVaultFeature + .GENERATES_IN)) { + return candidate; + } + if (rejected.size() < 8) { + rejected.add(candidate + "=" + biome + + "(valid=" + valid + ")"); + } + } + require(helper, false, + "The fixed-seed CakeWorld contained no saved Stronghold start in an Ancient Cake Vault biome; nearest candidates=" + + rejected); + throw new IllegalStateException( + "Unreachable after GameTest failure"); + } + + private static long horizontalDistanceSquared( + ChunkPos chunk, BlockPos origin) { + long deltaX = (long) chunk.getMiddleBlockX() + - origin.getX(); + long deltaZ = (long) chunk.getMiddleBlockZ() + - origin.getZ(); + return deltaX * deltaX + deltaZ * deltaZ; + } + private static String structuresLabel( ServerLevel level, ConfiguredStructureFeature configured) { diff --git a/src/main/java/zone/moddev/mc/cakeworld/world/AncientCakeVaultPalette.java b/src/main/java/zone/moddev/mc/cakeworld/world/AncientCakeVaultPalette.java index 392cbc7..33738c5 100644 --- a/src/main/java/zone/moddev/mc/cakeworld/world/AncientCakeVaultPalette.java +++ b/src/main/java/zone/moddev/mc/cakeworld/world/AncientCakeVaultPalette.java @@ -8,9 +8,6 @@ import java.util.concurrent.ConcurrentLinkedDeque; import java.util.concurrent.ConcurrentMap; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; - import zone.moddev.mc.cakeworld.CakeWorld; import zone.moddev.mc.cakeworld.init.CakeWorldBlocks; import zone.moddev.mc.cakeworld.init.CakeWorldFluids; @@ -59,7 +56,6 @@ */ @Mod.EventBusSubscriber(modid = CakeWorld.MODID) public final class AncientCakeVaultPalette { - private static final Logger LOGGER = LogManager.getLogger(); private static final String PERSISTENT_KEY = "cakeworld_ancient_cake_vault_palette"; private static final String CONVERTED_STARTS_KEY = @@ -70,18 +66,7 @@ public final class AncientCakeVaultPalette { new ConcurrentLinkedDeque<>(); private static final ConcurrentMap> CONVERTED_STARTS = new ConcurrentHashMap<>(); - // A marker read from or written to chunk data is durable. Keep that - // distinction so a later load never rewrites a player's authored blocks, - // while a second event in the same generation session can repair an early, - // superseded palette pass. - private static final ConcurrentMap> - PERSISTED_CONVERTED_STARTS = - new ConcurrentHashMap<>(); - // Structure starts can become visible before their final blocks do. Require - // one second of consecutive server-tick visibility before first conversion. - private static final int REQUIRED_VISIBLE_ATTEMPTS = 20; - private static final int MAX_REFERENCE_ATTEMPTS = - REQUIRED_VISIBLE_ATTEMPTS + 4; + private static final int MAX_REFERENCE_ATTEMPTS = 4; private static final int MAX_START_ACTIVATION_ATTEMPTS = 1200; private static volatile Set strongholdStartCandidates; @@ -100,18 +85,11 @@ public static void onChunkDataLoad( } CompoundTag persistent = event.getData() .getCompound(PERSISTENT_KEY); - long chunkKey = event.getChunk().getPos().toLong(); - Set starts = convertedStarts(chunkKey); - Set persisted = persistedConvertedStarts( - chunkKey); + Set starts = convertedStarts( + event.getChunk().getPos().toLong()); for (long start : persistent.getLongArray( CONVERTED_STARTS_KEY)) { starts.add(start); - persisted.add(start); - } - if (fixedWorldgenEvidence()) { - LOGGER.info("Ancient Cake Vault marker load: chunk={}, starts={}", - event.getChunk().getPos(), persisted); } } @@ -137,13 +115,6 @@ public static void onChunkDataSave( .sorted().toArray()); event.getData().put(PERSISTENT_KEY, persistent); - persistedConvertedStarts( - event.getChunk().getPos().toLong()) - .addAll(starts); - if (fixedWorldgenEvidence()) { - LOGGER.info("Ancient Cake Vault marker save: chunk={}, starts={}", - event.getChunk().getPos(), starts); - } } @SubscribeEvent @@ -155,48 +126,20 @@ public static void onChunkLoad(ChunkEvent.Load event) { .equals(Level.OVERWORLD)) { return; } - // Keep the callback non-reentrant, but isolate actual saved Stronghold - // starts and the 128 early-load candidates from ordinary chunk traffic. - // A large world-generation scan can otherwise keep moving a start behind - // newer loads before the deferred server-tick pass observes it. - boolean savedStart = hasSavedStrongholdStart( - level, chunk); + // Keep the callback non-reentrant, but isolate the 128 authoritative + // Stronghold start candidates from ordinary chunk-load traffic. A large + // world-generation scan can otherwise keep moving a candidate behind + // newer loads before the deferred server-tick pass observes its start. PendingSlice pending = new PendingSlice( level.dimension(), - chunk.getPos(), 0, 0, savedStart); - boolean startCandidate = isStrongholdStartCandidate( - level, chunk.getPos()); - if (fixedWorldgenEvidence() - && (savedStart || startCandidate)) { - LOGGER.info("Ancient Cake Vault load event: chunk={}, savedStart={}, candidate={}, converted={}, persisted={}", - chunk.getPos(), savedStart, - startCandidate, - CONVERTED_STARTS.getOrDefault( - chunk.getPos().toLong(), Set.of()), - PERSISTED_CONVERTED_STARTS.getOrDefault( - chunk.getPos().toLong(), Set.of())); - } - if (savedStart) { - START_CANDIDATES.addFirst(pending); - } else if (startCandidate) { + chunk.getPos(), 0); + if (isStrongholdStartCandidate(level, chunk.getPos())) { START_CANDIDATES.addLast(pending); } else { PENDING.addFirst(pending); } } - private static boolean hasSavedStrongholdStart( - ServerLevel level, LevelChunk chunk) { - ConfiguredStructureFeature stronghold = - configuredStronghold(level); - if (stronghold == null) { - return false; - } - StructureStart start = chunk.getStartForFeature( - stronghold); - return start != null && start.isValid(); - } - @SubscribeEvent public static void onServerTick( TickEvent.ServerTickEvent event) { @@ -241,12 +184,15 @@ public static void onServerTick( if (stronghold == null) { continue; } + boolean themed = false; StructureStart direct = chunk.getStartForFeature( stronghold); - StructureStart visibleVault = - isCakeWorldVault(level, direct) - ? direct : null; + if (isCakeWorldVault( + level, direct)) { + themeLoadedChunks(level, direct); + themed = isConverted(chunk, direct); + } for (long reference : chunk.getReferencesForFeature( stronghold)) { @@ -259,76 +205,32 @@ public static void onServerTick( StructureStart start = owner.getStartForFeature( stronghold); - if (visibleVault == null - && isCakeWorldVault( - level, start)) { - visibleVault = start; + if (isCakeWorldVault( + level, start)) { + themeLoadedChunks(level, start); + themed |= isConverted(chunk, start); } } - int visibleAttempts = visibleVault == null - ? 0 : pending.visibleAttempts() + 1; - boolean themed = false; - // Do not let host/JVM scheduling decide whether the palette runs before - // or after the native structure writes its final blocks. - if (visibleVault != null - && visibleAttempts - >= REQUIRED_VISIBLE_ATTEMPTS) { - themeLoadedChunks(level, visibleVault, - pending.refreshSessionConversion()); - themed = isConverted(chunk, visibleVault); - } boolean hasReferences = !chunk .getReferencesForFeature(stronghold) .isEmpty(); boolean startCandidate = isStrongholdStartCandidate( level, pending.chunk()); - boolean authoritativeStart = startCandidate - || pending.refreshSessionConversion(); - if (fixedWorldgenEvidence() - && (pending.refreshSessionConversion() - || direct != null || hasReferences) - && (pending.attempts() == 0 - || visibleAttempts == 1 - || visibleAttempts - == REQUIRED_VISIBLE_ATTEMPTS - || pending.attempts() - == MAX_REFERENCE_ATTEMPTS - || pending.attempts() - == MAX_START_ACTIVATION_ATTEMPTS)) { - LOGGER.info("Ancient Cake Vault tick probe: chunk={}, attempt={}, visibleAttempts={}, refresh={}, candidate={}, direct={}, references={}, visibleVault={}, themed={}, converted={}, persisted={}", - pending.chunk(), pending.attempts(), - visibleAttempts, - pending.refreshSessionConversion(), - startCandidate, direct != null, - hasReferences, visibleVault != null, - themed, - CONVERTED_STARTS.getOrDefault( - pending.chunk().toLong(), Set.of()), - PERSISTED_CONVERTED_STARTS.getOrDefault( - pending.chunk().toLong(), Set.of())); - } - int maximumAttempts = authoritativeStart + int maximumAttempts = startCandidate ? MAX_START_ACTIVATION_ATTEMPTS : MAX_REFERENCE_ATTEMPTS; if (!themed && pending.attempts() < maximumAttempts - && (authoritativeStart || direct != null + && (startCandidate || direct != null || hasReferences)) { - Deque retries = authoritativeStart + Deque retries = startCandidate ? START_CANDIDATES : PENDING; - PendingSlice retry = new PendingSlice( + retries.addLast(new PendingSlice( pending.dimension(), pending.chunk(), - pending.attempts() + 1, - visibleAttempts, - pending.refreshSessionConversion()); - if (pending.refreshSessionConversion()) { - retries.addFirst(retry); - } else { - retries.addLast(retry); - } + pending.attempts() + 1)); } } } @@ -355,7 +257,6 @@ public static void onServerStopped( START_CANDIDATES.clear(); PENDING.clear(); CONVERTED_STARTS.clear(); - PERSISTED_CONVERTED_STARTS.clear(); strongholdStartCandidates = null; } @@ -419,8 +320,7 @@ private static boolean isCakeWorldVault( private static void themeLoadedChunks( ServerLevel level, - StructureStart start, - boolean refreshSessionConversion) { + StructureStart start) { BoundingBox bounds = start.getBoundingBox(); int minimumChunkX = Math.floorDiv(bounds.minX(), 16); @@ -438,8 +338,7 @@ private static void themeLoadedChunks( themeChunk(level, level.getChunk( chunkX, chunkZ), - start, - refreshSessionConversion); + start); } } } @@ -448,16 +347,11 @@ private static void themeLoadedChunks( private static void themeChunk( ServerLevel level, LevelChunk chunk, - StructureStart start, - boolean refreshSessionConversion) { + StructureStart start) { Set converted = convertedStarts( chunk.getPos().toLong()); long startKey = start.getChunkPos().toLong(); - if (converted.contains(startKey) - && (!refreshSessionConversion - || persistedConvertedStarts( - chunk.getPos().toLong()) - .contains(startKey))) { + if (converted.contains(startKey)) { return; } ChunkPos chunkPos = chunk.getPos(); @@ -492,19 +386,6 @@ private static Set convertedStarts( .newKeySet()); } - private static Set persistedConvertedStarts( - long chunkKey) { - return PERSISTED_CONVERTED_STARTS - .computeIfAbsent(chunkKey, - ignored -> ConcurrentHashMap - .newKeySet()); - } - - private static boolean fixedWorldgenEvidence() { - return Boolean.getBoolean( - "cakeworld.fixedWorldgenEvidence"); - } - /** * Exposes vanilla's deterministic graph seam for regression evidence. */ @@ -670,8 +551,6 @@ private record PendingSlice( net.minecraft.resources.ResourceKey dimension, ChunkPos chunk, - int attempts, - int visibleAttempts, - boolean refreshSessionConversion) { + int attempts) { } }