diff --git a/src/main/java/com/jozufozu/flywheel/backend/Backend.java b/src/main/java/com/jozufozu/flywheel/backend/Backend.java index 770e0734c..51853e0ba 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/Backend.java +++ b/src/main/java/com/jozufozu/flywheel/backend/Backend.java @@ -43,6 +43,7 @@ public class Backend { private Matrix4f projectionMatrix = new Matrix4f(); private boolean instancedArrays; private boolean enabled; + public boolean chunkCachingEnabled; private final List> contexts = new ArrayList<>(); private final Map> materialRegistry = new HashMap<>(); @@ -153,6 +154,8 @@ public class Backend { enabled = FlwConfig.get() .enabled() && !OptifineHandler.usingShaders(); + chunkCachingEnabled = FlwConfig.get() + .chunkCaching(); } public boolean canUseInstancing(@Nullable World world) { diff --git a/src/main/java/com/jozufozu/flywheel/config/BooleanConfig.java b/src/main/java/com/jozufozu/flywheel/config/BooleanConfig.java index 8d143dea9..c34a80c32 100644 --- a/src/main/java/com/jozufozu/flywheel/config/BooleanConfig.java +++ b/src/main/java/com/jozufozu/flywheel/config/BooleanConfig.java @@ -18,6 +18,7 @@ import net.minecraftforge.api.distmarker.OnlyIn; public enum BooleanConfig { ENGINE(() -> BooleanConfig::enabled), NORMAL_OVERLAY(() -> BooleanConfig::normalOverlay), + CHUNK_CACHING(() -> BooleanConfig::chunkCaching), ; final Supplier> receiver; @@ -71,6 +72,25 @@ public enum BooleanConfig { player.displayClientMessage(text, false); } + @OnlyIn(Dist.CLIENT) + private static void chunkCaching(BooleanDirective state) { + ClientPlayerEntity player = Minecraft.getInstance().player; + if (player == null || state == null) return; + + if (state == BooleanDirective.DISPLAY) { + ITextComponent text = new StringTextComponent("Chunk caching is currently: ").append(boolToText(FlwConfig.get().client.debugNormals.get())); + player.displayClientMessage(text, false); + return; + } + + FlwConfig.get().client.chunkCaching.set(state.get()); + + ITextComponent text = boolToText(FlwConfig.get().client.chunkCaching.get()).append(new StringTextComponent(" chunk caching").withStyle(TextFormatting.WHITE)); + + player.displayClientMessage(text, false); + Backend.reloadWorldRenderers(); + } + private static IFormattableTextComponent boolToText(boolean b) { return b ? new StringTextComponent("enabled").withStyle(TextFormatting.DARK_GREEN) : new StringTextComponent("disabled").withStyle(TextFormatting.RED); } diff --git a/src/main/java/com/jozufozu/flywheel/config/FlwCommands.java b/src/main/java/com/jozufozu/flywheel/config/FlwCommands.java index fe58438d0..a601971cb 100644 --- a/src/main/java/com/jozufozu/flywheel/config/FlwCommands.java +++ b/src/main/java/com/jozufozu/flywheel/config/FlwCommands.java @@ -16,6 +16,8 @@ public class FlwCommands { dispatcher.register(Commands.literal("flywheel") .then(new BooleanConfigCommand("backend", BooleanConfig.ENGINE).register()) - .then(new BooleanConfigCommand("debugNormals", BooleanConfig.NORMAL_OVERLAY).register())); + .then(new BooleanConfigCommand("debugNormals", BooleanConfig.NORMAL_OVERLAY).register()) + .then(new BooleanConfigCommand("chunkCaching", BooleanConfig.CHUNK_CACHING).register()) + ); } } diff --git a/src/main/java/com/jozufozu/flywheel/config/FlwConfig.java b/src/main/java/com/jozufozu/flywheel/config/FlwConfig.java index 0fd5a2673..359d7111e 100644 --- a/src/main/java/com/jozufozu/flywheel/config/FlwConfig.java +++ b/src/main/java/com/jozufozu/flywheel/config/FlwConfig.java @@ -34,12 +34,17 @@ public class FlwConfig { return client.debugNormals.get(); } + public boolean chunkCaching() { + return client.chunkCaching.get(); + } + public static void init() { } public static class ClientConfig { public final BooleanValue enabled; public final BooleanValue debugNormals; + public final BooleanValue chunkCaching; public ClientConfig(ForgeConfigSpec.Builder builder) { @@ -48,6 +53,9 @@ public class FlwConfig { debugNormals = builder.comment("Enable or disable a debug overlay that colors pixels by their normal") .define("debugNormals", false); + + chunkCaching = builder.comment("Cache chunk lookups to improve performance.") + .define("chunkCaching", true); } } } diff --git a/src/main/java/com/jozufozu/flywheel/mixin/FastChunkProviderMixin.java b/src/main/java/com/jozufozu/flywheel/mixin/FastChunkProviderMixin.java index 9a1f3a0f9..28301ea18 100644 --- a/src/main/java/com/jozufozu/flywheel/mixin/FastChunkProviderMixin.java +++ b/src/main/java/com/jozufozu/flywheel/mixin/FastChunkProviderMixin.java @@ -1,6 +1,8 @@ package com.jozufozu.flywheel.mixin; +import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; @@ -8,7 +10,10 @@ import org.spongepowered.asm.mixin.injection.Redirect; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; +import com.jozufozu.flywheel.backend.Backend; + import net.minecraft.client.multiplayer.ClientChunkProvider; +import net.minecraft.client.world.ClientWorld; import net.minecraft.nbt.CompoundNBT; import net.minecraft.network.PacketBuffer; import net.minecraft.world.biome.BiomeContainer; @@ -20,6 +25,9 @@ import net.minecraft.world.chunk.IChunk; @Mixin(ClientChunkProvider.class) public abstract class FastChunkProviderMixin extends AbstractChunkProvider { + @Shadow + @Final + private ClientWorld level; @Unique private int lastX; @Unique @@ -32,36 +40,52 @@ public abstract class FastChunkProviderMixin extends AbstractChunkProvider { at = @At("HEAD"), cancellable = true) public void returnCachedChunk(int x, int z, ChunkStatus status, boolean create, CallbackInfoReturnable cir) { - if (status.isOrAfter(ChunkStatus.FULL) && lastChunk != null && x == lastX && z == lastZ) { - cir.setReturnValue(lastChunk); + if (Backend.getInstance().chunkCachingEnabled && status.isOrAfter(ChunkStatus.FULL)) { + synchronized (level) { + if (lastChunk != null && x == lastX && z == lastZ) { + cir.setReturnValue(lastChunk); + } + } } } @Inject(method = "getChunk", at = @At("RETURN")) public void cacheChunk(int x, int z, ChunkStatus status, boolean create, CallbackInfoReturnable cir) { - if (status.isOrAfter(ChunkStatus.FULL)) { - lastChunk = cir.getReturnValue(); - lastX = x; - lastZ = z; + if (Backend.getInstance().chunkCachingEnabled && status.isOrAfter(ChunkStatus.FULL)) { + synchronized (level) { + lastChunk = cir.getReturnValue(); + lastX = x; + lastZ = z; + } } } @Inject(method = "drop", at = @At("HEAD")) public void invalidateOnDrop(int x, int z, CallbackInfo ci) { - if (x == lastX && z == lastZ) - lastChunk = null; + if (Backend.getInstance().chunkCachingEnabled) { + synchronized (level) { + if (x == lastX && z == lastZ) lastChunk = null; + } + } } @Inject(method = "replaceWithPacketData", at = @At("HEAD")) public void invalidateOnPacket(int x, int z, BiomeContainer p_228313_3_, PacketBuffer p_228313_4_, CompoundNBT p_228313_5_, int p_228313_6_, boolean p_228313_7_, CallbackInfoReturnable cir) { - if (x == lastX && z == lastZ) - lastChunk = null; + if (Backend.getInstance().chunkCachingEnabled) { + synchronized (level) { + if (x == lastX && z == lastZ) lastChunk = null; + } + } } @Redirect(method = "isTickingChunk", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/multiplayer/ClientChunkProvider;hasChunk(II)Z")) public boolean redirectTicking(ClientChunkProvider clientChunkProvider, int x, int z) { - if (lastChunk != null && x == lastX && z == lastZ) return true; + if (Backend.getInstance().chunkCachingEnabled) { + synchronized (level) { + if (lastChunk != null && x == lastX && z == lastZ) return true; + } + } return clientChunkProvider.hasChunk(x, z); }