WIP chunk saving optimization

This commit is contained in:
embeddedt 2026-03-04 18:41:28 -05:00
parent f23348c6cb
commit 17f930ea6f
No known key found for this signature in database
GPG Key ID: A69433EC199B5613
5 changed files with 102 additions and 0 deletions

View File

@ -0,0 +1,27 @@
package org.embeddedt.modernfix.common.mixin.bugfix.skip_redundant_saves;
import com.llamalad7.mixinextras.injector.v2.WrapWithCondition;
import net.minecraft.server.level.ChunkHolder;
import net.minecraft.world.level.chunk.ChunkAccess;
import net.minecraft.world.level.chunk.LevelChunk;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import javax.annotation.Nullable;
@Mixin(ChunkHolder.class)
public abstract class ChunkHolderMixin {
@Shadow
@Nullable
public abstract LevelChunk getTickingChunk();
/**
* @author embeddedt
* @reason prevent chunks from being flagged for saving when light engine is loading data from disk
*/
@WrapWithCondition(method = "sectionLightChanged", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/chunk/ChunkAccess;setUnsaved(Z)V"))
private boolean onlyMarkUnsavedIfAlreadyTicking(ChunkAccess instance, boolean unsaved) {
return this.getTickingChunk() != null;
}
}

View File

@ -0,0 +1,12 @@
package org.embeddedt.modernfix.common.mixin.bugfix.skip_redundant_saves;
import net.minecraft.server.level.ChunkMap;
import net.minecraft.world.level.ChunkPos;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Invoker;
@Mixin(ChunkMap.class)
public interface ChunkMapAccessor {
@Invoker("releaseLightTicket")
void mfix$invokeReleaseLightTicket(ChunkPos pos);
}

View File

@ -0,0 +1,26 @@
package org.embeddedt.modernfix.common.mixin.bugfix.skip_redundant_saves;
import com.llamalad7.mixinextras.sugar.Local;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.entity.ai.village.poi.PoiManager;
import net.minecraft.world.level.ChunkPos;
import net.minecraft.world.level.chunk.ChunkAccess;
import net.minecraft.world.level.chunk.ProtoChunk;
import net.minecraft.world.level.chunk.storage.ChunkSerializer;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@Mixin(ChunkSerializer.class)
public class ChunkSerializerMixin {
/**
* @author embeddedt
* @reason When reloading chunks from disk, they by definition normally don't need saving unless they've changed.
*/
@Inject(method = "read", at = @At(value = "CONSTANT", args = "stringValue=PostProcessing", ordinal = 0))
private static void updateUnsavedFlag(ServerLevel level, PoiManager poiManager, ChunkPos pos, CompoundTag tag, CallbackInfoReturnable<ProtoChunk> cir, @Local(ordinal = 0) ChunkAccess chunkaccess) {
chunkaccess.setUnsaved(tag.getBoolean("shouldSave"));
}
}

View File

@ -0,0 +1,36 @@
package org.embeddedt.modernfix.common.mixin.bugfix.skip_redundant_saves;
import net.minecraft.server.level.ChunkMap;
import net.minecraft.server.level.ThreadedLevelLightEngine;
import net.minecraft.world.level.chunk.ChunkAccess;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import java.util.concurrent.CompletableFuture;
@Mixin(ThreadedLevelLightEngine.class)
public class ThreadedLevelLightEngineMixin {
@Shadow
@Final
private ChunkMap chunkMap;
/**
* @author embeddedt
* @reason avoid toggling the lightCorrect flag when chunk is already lit, because it triggers saving
*/
@Inject(method = "lightChunk", at = @At("HEAD"), cancellable = true)
private void skipLightCorrectFlagChange(ChunkAccess chunk, boolean isAlreadyLit, CallbackInfoReturnable<CompletableFuture<ChunkAccess>> cir) {
if (isAlreadyLit) {
((ChunkMapAccessor)this.chunkMap).mfix$invokeReleaseLightTicket(chunk.getPos());
// Defensively ensure the lightCorrect flag is set properly on exit from this method
if (!chunk.isLightCorrect()) {
chunk.setLightCorrect(true);
}
cir.setReturnValue(CompletableFuture.completedFuture(chunk));
}
}
}

View File

@ -184,6 +184,7 @@ public class ModernFixEarlyConfig {
.put("mixin.feature.spam_thread_dump", false) .put("mixin.feature.spam_thread_dump", false)
.put("mixin.feature.disable_unihex_font", false) .put("mixin.feature.disable_unihex_font", false)
.put("mixin.feature.remove_chat_signing", false) .put("mixin.feature.remove_chat_signing", false)
.put("mixin.bugfix.skip_redundant_saves", false)
.put("mixin.feature.snapshot_easter_egg", true) .put("mixin.feature.snapshot_easter_egg", true)
.put("mixin.feature.warn_missing_perf_mods", true) .put("mixin.feature.warn_missing_perf_mods", true)
.put("mixin.feature.spark_profile_launch", false) .put("mixin.feature.spark_profile_launch", false)