Fix potential stronghold cache corruption if player exits world too quickly

This commit is contained in:
embeddedt 2026-05-23 16:32:56 -04:00
parent f8d2425242
commit 7c45564979
No known key found for this signature in database
GPG Key ID: A69433EC199B5613
3 changed files with 15 additions and 10 deletions

View File

@ -4,9 +4,9 @@ import com.llamalad7.mixinextras.injector.wrapmethod.WrapMethod;
import com.llamalad7.mixinextras.injector.wrapoperation.Operation; import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
import net.minecraft.Util; import net.minecraft.Util;
import net.minecraft.core.Holder; import net.minecraft.core.Holder;
import net.minecraft.core.RegistryAccess;
import net.minecraft.nbt.*; import net.minecraft.nbt.*;
import net.minecraft.resources.RegistryOps; import net.minecraft.resources.RegistryOps;
import net.minecraft.server.MinecraftServer;
import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.ChunkPos;
import net.minecraft.world.level.biome.BiomeSource; import net.minecraft.world.level.biome.BiomeSource;
import net.minecraft.world.level.chunk.ChunkGeneratorStructureState; import net.minecraft.world.level.chunk.ChunkGeneratorStructureState;
@ -41,22 +41,23 @@ public class ChunkGeneratorMixin implements IChunkGenerator {
private BiomeSource biomeSource; private BiomeSource biomeSource;
private Path mfix$dimensionPath; private Path mfix$dimensionPath;
private RegistryAccess.Frozen mfix$registryAccess; private MinecraftServer mfix$server;
private SoftReference<Map<String, List<ChunkPos>>> mfix$cachedPositions = new SoftReference<>(null); private SoftReference<Map<String, List<ChunkPos>>> mfix$cachedPositions = new SoftReference<>(null);
private static final String CACHE_FILENAME = "mfix_stronghold_cache_v2.nbt"; private static final String CACHE_FILENAME = "mfix_stronghold_cache_v2.nbt";
@Override @Override
public void mfix$setStrongholdCachePath(Path cachePath, RegistryAccess.Frozen registryAccess) { public void mfix$setStrongholdCachePath(Path cachePath, MinecraftServer server) {
this.mfix$dimensionPath = cachePath; this.mfix$dimensionPath = cachePath;
this.mfix$registryAccess = registryAccess; this.mfix$server = server;
} }
@WrapMethod(method = "generateRingPositions") @WrapMethod(method = "generateRingPositions")
private CompletableFuture<List<ChunkPos>> modernfix$cacheRingPositions(Holder<StructureSet> structureSet, private CompletableFuture<List<ChunkPos>> modernfix$cacheRingPositions(Holder<StructureSet> structureSet,
ConcentricRingsStructurePlacement placement, ConcentricRingsStructurePlacement placement,
Operation<CompletableFuture<List<ChunkPos>>> original) { Operation<CompletableFuture<List<ChunkPos>>> original) {
if (this.mfix$registryAccess == null || this.mfix$dimensionPath == null) { if (this.mfix$server == null || this.mfix$dimensionPath == null) {
return original.call(structureSet, placement); return original.call(structureSet, placement);
} }
@ -69,14 +70,18 @@ public class ChunkGeneratorMixin implements IChunkGenerator {
return CompletableFuture.completedFuture(List.copyOf(cached)); return CompletableFuture.completedFuture(List.copyOf(cached));
} }
var server = this.mfix$server;
return original.call(structureSet, placement).thenApplyAsync(positions -> { return original.call(structureSet, placement).thenApplyAsync(positions -> {
mfix$writeToCache(cacheKey, positions); // Skip write if server exited before we finished
if (server.isRunning()) {
mfix$writeToCache(cacheKey, positions);
}
return positions; return positions;
}, Util.ioPool()); }, Util.ioPool());
} }
private String mfix$makeCacheKey(ConcentricRingsStructurePlacement placement) { private String mfix$makeCacheKey(ConcentricRingsStructurePlacement placement) {
RegistryOps<Tag> ops = RegistryOps.create(NbtOps.INSTANCE, this.mfix$registryAccess); RegistryOps<Tag> ops = RegistryOps.create(NbtOps.INSTANCE, this.mfix$server.registryAccess());
String placementKey = ConcentricRingsStructurePlacement.CODEC.encodeStart(ops, placement) String placementKey = ConcentricRingsStructurePlacement.CODEC.encodeStart(ops, placement)
.result().map(Tag::toString).orElse(null); .result().map(Tag::toString).orElse(null);
String biomeSourceKey = BiomeSource.CODEC.encodeStart(ops, this.biomeSource) String biomeSourceKey = BiomeSource.CODEC.encodeStart(ops, this.biomeSource)

View File

@ -24,7 +24,7 @@ public class ServerLevelMixin {
@Local(ordinal = 0, argsOnly = true) LevelStorageSource.LevelStorageAccess levelStorageAccess, @Local(ordinal = 0, argsOnly = true) LevelStorageSource.LevelStorageAccess levelStorageAccess,
@Local(ordinal = 0, argsOnly = true) ResourceKey<Level> dimension, @Local(ordinal = 0, argsOnly = true) ResourceKey<Level> dimension,
@Local(ordinal = 0, argsOnly = true) MinecraftServer server) { @Local(ordinal = 0, argsOnly = true) MinecraftServer server) {
((IChunkGenerator)instance).mfix$setStrongholdCachePath(levelStorageAccess.getDimensionPath(dimension), server.registryAccess()); ((IChunkGenerator)instance).mfix$setStrongholdCachePath(levelStorageAccess.getDimensionPath(dimension), server);
original.call(instance); original.call(instance);
} }
} }

View File

@ -1,9 +1,9 @@
package org.embeddedt.modernfix.duck; package org.embeddedt.modernfix.duck;
import net.minecraft.core.RegistryAccess; import net.minecraft.server.MinecraftServer;
import java.nio.file.Path; import java.nio.file.Path;
public interface IChunkGenerator { public interface IChunkGenerator {
void mfix$setStrongholdCachePath(Path cachePath, RegistryAccess.Frozen registryAccess); void mfix$setStrongholdCachePath(Path cachePath, MinecraftServer server);
} }