From 9631cd67396ab51b9cead466511ee74a3e331d95 Mon Sep 17 00:00:00 2001 From: rfresh2 <89827146+rfresh2@users.noreply.github.com> Date: Tue, 18 Jun 2024 11:59:08 -0700 Subject: [PATCH] newchunks: skip loading block entities from packet fixes duplicate block entities being leaked to level tickers --- .../event/ChunkBlockUpdateEvent.java | 6 ++ .../event/ChunkBlocksUpdateEvent.java | 6 ++ .../xaeroplus/event/PacketReceivedEvent.java | 5 -- .../client/mc/MixinClientConnection.java | 20 ----- .../mc/MixinClientPlayNetworkHandler.java | 20 +++++ .../main/java/xaeroplus/module/Module.java | 19 +--- .../java/xaeroplus/module/ModuleManager.java | 4 +- .../module/impl/BaritoneGoalSync.java | 1 - .../xaeroplus/module/impl/FpsLimiter.java | 1 - .../java/xaeroplus/module/impl/NewChunks.java | 89 +++++++++---------- .../java/xaeroplus/module/impl/OldChunks.java | 1 - .../module/impl/PortalSkipDetection.java | 1 - .../java/xaeroplus/module/impl/Portals.java | 24 ++--- .../xaeroplus/module/impl/WaystoneSync.java | 1 - .../xaeroplus/module/impl/WorldTools.java | 1 - .../src/main/resources/xaeroplus.mixins.json | 1 - 16 files changed, 84 insertions(+), 116 deletions(-) create mode 100644 common/src/main/java/xaeroplus/event/ChunkBlockUpdateEvent.java create mode 100644 common/src/main/java/xaeroplus/event/ChunkBlocksUpdateEvent.java delete mode 100644 common/src/main/java/xaeroplus/event/PacketReceivedEvent.java delete mode 100644 common/src/main/java/xaeroplus/mixin/client/mc/MixinClientConnection.java diff --git a/common/src/main/java/xaeroplus/event/ChunkBlockUpdateEvent.java b/common/src/main/java/xaeroplus/event/ChunkBlockUpdateEvent.java new file mode 100644 index 00000000..ac78e001 --- /dev/null +++ b/common/src/main/java/xaeroplus/event/ChunkBlockUpdateEvent.java @@ -0,0 +1,6 @@ +package xaeroplus.event; + +import net.minecraft.network.protocol.game.ClientboundBlockUpdatePacket; + +// fired right before block update is applied to mc.level +public record ChunkBlockUpdateEvent(ClientboundBlockUpdatePacket packet) { } diff --git a/common/src/main/java/xaeroplus/event/ChunkBlocksUpdateEvent.java b/common/src/main/java/xaeroplus/event/ChunkBlocksUpdateEvent.java new file mode 100644 index 00000000..c4fe68c2 --- /dev/null +++ b/common/src/main/java/xaeroplus/event/ChunkBlocksUpdateEvent.java @@ -0,0 +1,6 @@ +package xaeroplus.event; + +import net.minecraft.network.protocol.game.ClientboundSectionBlocksUpdatePacket; + +// fired right before block updates are applied to mc.level +public record ChunkBlocksUpdateEvent(ClientboundSectionBlocksUpdatePacket packet) { } diff --git a/common/src/main/java/xaeroplus/event/PacketReceivedEvent.java b/common/src/main/java/xaeroplus/event/PacketReceivedEvent.java deleted file mode 100644 index e6bcc35c..00000000 --- a/common/src/main/java/xaeroplus/event/PacketReceivedEvent.java +++ /dev/null @@ -1,5 +0,0 @@ -package xaeroplus.event; - -import net.minecraft.network.protocol.Packet; - -public record PacketReceivedEvent(Packet packet) { } diff --git a/common/src/main/java/xaeroplus/mixin/client/mc/MixinClientConnection.java b/common/src/main/java/xaeroplus/mixin/client/mc/MixinClientConnection.java deleted file mode 100644 index eeda0baa..00000000 --- a/common/src/main/java/xaeroplus/mixin/client/mc/MixinClientConnection.java +++ /dev/null @@ -1,20 +0,0 @@ -package xaeroplus.mixin.client.mc; - -import net.minecraft.network.Connection; -import net.minecraft.network.PacketListener; -import net.minecraft.network.protocol.Packet; -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.CallbackInfo; -import xaeroplus.XaeroPlus; -import xaeroplus.event.PacketReceivedEvent; - -@Mixin(value = Connection.class) -public class MixinClientConnection { - - @Inject(method = "genericsFtw", at = @At("HEAD")) - private static void receivePacket(final Packet packet, final PacketListener listener, final CallbackInfo ci) { - XaeroPlus.EVENT_BUS.call(new PacketReceivedEvent(packet)); - } -} diff --git a/common/src/main/java/xaeroplus/mixin/client/mc/MixinClientPlayNetworkHandler.java b/common/src/main/java/xaeroplus/mixin/client/mc/MixinClientPlayNetworkHandler.java index 00a6ada9..b4bc8690 100644 --- a/common/src/main/java/xaeroplus/mixin/client/mc/MixinClientPlayNetworkHandler.java +++ b/common/src/main/java/xaeroplus/mixin/client/mc/MixinClientPlayNetworkHandler.java @@ -2,13 +2,17 @@ import net.minecraft.client.multiplayer.ClientLevel; import net.minecraft.client.multiplayer.ClientPacketListener; +import net.minecraft.network.protocol.game.ClientboundBlockUpdatePacket; import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket; +import net.minecraft.network.protocol.game.ClientboundSectionBlocksUpdatePacket; 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.CallbackInfo; import xaeroplus.XaeroPlus; +import xaeroplus.event.ChunkBlockUpdateEvent; +import xaeroplus.event.ChunkBlocksUpdateEvent; import xaeroplus.event.ChunkDataEvent; @Mixin(ClientPacketListener.class) @@ -19,4 +23,20 @@ public class MixinClientPlayNetworkHandler { public void onChunkData(final ClientboundLevelChunkWithLightPacket packet, final CallbackInfo ci) { XaeroPlus.EVENT_BUS.call(new ChunkDataEvent(level.getChunk(packet.getX(), packet.getZ()))); } + + @Inject(method = "handleChunkBlocksUpdate", at = @At( + value = "INVOKE", + target = "Lnet/minecraft/network/protocol/game/ClientboundSectionBlocksUpdatePacket;runUpdates(Ljava/util/function/BiConsumer;)V" + )) + public void onChunkBlocksUpdate(final ClientboundSectionBlocksUpdatePacket packet, final CallbackInfo ci) { + XaeroPlus.EVENT_BUS.call(new ChunkBlocksUpdateEvent(packet)); + } + + @Inject(method = "handleBlockUpdate", at = @At( + value = "INVOKE", + target = "Lnet/minecraft/client/multiplayer/ClientLevel;setServerVerifiedBlockState(Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/level/block/state/BlockState;I)V" + )) + public void onBlockUpdate(final ClientboundBlockUpdatePacket packet, final CallbackInfo ci) { + XaeroPlus.EVENT_BUS.call(new ChunkBlockUpdateEvent(packet)); + } } diff --git a/common/src/main/java/xaeroplus/module/Module.java b/common/src/main/java/xaeroplus/module/Module.java index 73024985..18af62b9 100644 --- a/common/src/main/java/xaeroplus/module/Module.java +++ b/common/src/main/java/xaeroplus/module/Module.java @@ -2,24 +2,9 @@ import xaeroplus.XaeroPlus; -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - public abstract class Module { - @Retention(RetentionPolicy.RUNTIME) - @Target(ElementType.TYPE) - public @interface ModuleInfo { - boolean enabled() default false; - } - - private boolean enabled = getDeclaration().enabled(); - - private ModuleInfo getDeclaration() { - return getClass().getAnnotation(ModuleInfo.class); - } + private boolean enabled = false; protected void onEnable() { @@ -66,7 +51,7 @@ public void disable() { public void toggle() { if (isEnabled()) { disable(); - } else if (!isEnabled()) { + } else { enable(); } } diff --git a/common/src/main/java/xaeroplus/module/ModuleManager.java b/common/src/main/java/xaeroplus/module/ModuleManager.java index 9e043986..f967c2a9 100644 --- a/common/src/main/java/xaeroplus/module/ModuleManager.java +++ b/common/src/main/java/xaeroplus/module/ModuleManager.java @@ -18,8 +18,8 @@ public static void init() { new Portals(), new PortalSkipDetection(), new WaystoneSync(), - new WorldTools()) - .forEach(ModuleManager::addModule); + new WorldTools() + ).forEach(ModuleManager::addModule); } private static void addModule(Module module) { diff --git a/common/src/main/java/xaeroplus/module/impl/BaritoneGoalSync.java b/common/src/main/java/xaeroplus/module/impl/BaritoneGoalSync.java index c1688396..b072af63 100644 --- a/common/src/main/java/xaeroplus/module/impl/BaritoneGoalSync.java +++ b/common/src/main/java/xaeroplus/module/impl/BaritoneGoalSync.java @@ -28,7 +28,6 @@ import static net.minecraft.world.level.Level.NETHER; import static net.minecraft.world.level.Level.OVERWORLD; -@Module.ModuleInfo() public class BaritoneGoalSync extends Module { @EventHandler diff --git a/common/src/main/java/xaeroplus/module/impl/FpsLimiter.java b/common/src/main/java/xaeroplus/module/impl/FpsLimiter.java index c811ab7c..8b7eeb5d 100644 --- a/common/src/main/java/xaeroplus/module/impl/FpsLimiter.java +++ b/common/src/main/java/xaeroplus/module/impl/FpsLimiter.java @@ -10,7 +10,6 @@ import java.util.function.Supplier; -@Module.ModuleInfo() public class FpsLimiter extends Module { // todo: Buffer and mutate the rotation framebuffer separately to not cause visual // impact while minimap north is not locked diff --git a/common/src/main/java/xaeroplus/module/impl/NewChunks.java b/common/src/main/java/xaeroplus/module/impl/NewChunks.java index 29344f50..403675eb 100644 --- a/common/src/main/java/xaeroplus/module/impl/NewChunks.java +++ b/common/src/main/java/xaeroplus/module/impl/NewChunks.java @@ -6,20 +6,13 @@ import net.lenni0451.lambdaevents.EventHandler; import net.minecraft.client.Minecraft; import net.minecraft.core.Direction; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.network.protocol.game.ClientboundBlockUpdatePacket; -import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket; -import net.minecraft.network.protocol.game.ClientboundSectionBlocksUpdatePacket; import net.minecraft.resources.ResourceKey; import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.Level; -import net.minecraft.world.level.chunk.LevelChunk; import net.minecraft.world.level.material.FluidState; import xaeroplus.Globals; import xaeroplus.XaeroPlus; -import xaeroplus.event.ClientTickEvent; -import xaeroplus.event.PacketReceivedEvent; -import xaeroplus.event.XaeroWorldChangeEvent; +import xaeroplus.event.*; import xaeroplus.feature.render.ChunkHighlightProvider; import xaeroplus.feature.render.ColorHelper; import xaeroplus.feature.render.highlights.ChunkHighlightCache; @@ -36,11 +29,10 @@ import static xaeroplus.feature.render.ColorHelper.getColor; import static xaeroplus.util.ChunkUtils.getActualDimension; -@Module.ModuleInfo() public class NewChunks extends Module { - // todo: add newchunk detection mode setting: fluid flows (current), timing, etc. - + // chunks where liquid has not flowed from source blocks private ChunkHighlightCache newChunksCache = new ChunkHighlightLocalCache(); + // chunks where liquid sources have already flowed private final Cache oldChunksCache = Caffeine.newBuilder() .maximumSize(50) .expireAfterWrite(10L, TimeUnit.SECONDS) @@ -69,54 +61,53 @@ public void setNewChunksCache(boolean disk) { } @EventHandler - public void onPacketReceivedEvent(final PacketReceivedEvent event) { + public void onMultiBlockUpdate(final ChunkBlocksUpdateEvent event) { if (mc.level == null || ((AccessorWorldRenderer) mc.levelRenderer).getChunks() == null) return; - // credits to BleachHack for this fluid flow based detection method - if (event.packet() instanceof ClientboundSectionBlocksUpdatePacket packet) { - packet.runUpdates((pos, state) -> { - if (!state.getFluidState().isEmpty() && !state.getFluidState().isSource()) { - ChunkPos chunkPos = new ChunkPos(pos); - for (Direction dir: searchDirs) { - if (mc.level.getBlockState(pos.relative(dir)).getFluidState().isSource() - && oldChunksCache.getIfPresent(ChunkUtils.chunkPosToLong(chunkPos)) == null) { - newChunksCache.addHighlight(chunkPos.x, chunkPos.z); - return; - } - } - } - }); - } else if (event.packet() instanceof ClientboundBlockUpdatePacket packet) { - if (!packet.getBlockState().getFluidState().isEmpty() && !packet.getBlockState().getFluidState().isSource()) { - ChunkPos chunkPos = new ChunkPos(packet.getPos()); - + event.packet().runUpdates((pos, state) -> { + if (!state.getFluidState().isEmpty() && !state.getFluidState().isSource()) { + ChunkPos chunkPos = new ChunkPos(pos); for (Direction dir: searchDirs) { - if (mc.level.getBlockState(packet.getPos().relative(dir)).getFluidState().isSource() - && oldChunksCache.getIfPresent(ChunkUtils.chunkPosToLong(chunkPos)) == null) { + if (mc.level.getBlockState(pos.relative(dir)).getFluidState().isSource() + && oldChunksCache.getIfPresent(ChunkUtils.chunkPosToLong(chunkPos)) == null) { newChunksCache.addHighlight(chunkPos.x, chunkPos.z); return; } } } - } else if (event.packet() instanceof ClientboundLevelChunkWithLightPacket packet) { - ChunkPos pos = new ChunkPos(packet.getX(), packet.getZ()); - if (!newChunksCache.isHighlighted(pos.x, pos.z, getActualDimension()) && mc.level.getChunkSource().getChunkForLighting(packet.getX(), packet.getZ()) == null) { - LevelChunk chunk = new LevelChunk(mc.level, pos); - try { - chunk.replaceWithPacketData(packet.getChunkData().getReadBuffer(), new CompoundTag(), packet.getChunkData().getBlockEntitiesTagsConsumer(packet.getX(), packet.getZ())); - } catch (Throwable e) { + }); + } + + @EventHandler + public void onBlockUpdate(final ChunkBlockUpdateEvent event) { + if (mc.level == null || ((AccessorWorldRenderer) mc.levelRenderer).getChunks() == null) return; + var packet = event.packet(); + if (!packet.getBlockState().getFluidState().isEmpty() && !packet.getBlockState().getFluidState().isSource()) { + final int chunkX = ChunkUtils.posToChunkPos(packet.getPos().getX()); + final int chunkZ = ChunkUtils.posToChunkPos(packet.getPos().getZ()); + final long chunkPosLong = ChunkUtils.chunkPosToLong(chunkX, chunkZ); + for (Direction dir: searchDirs) { + if (mc.level.getBlockState(packet.getPos().relative(dir)).getFluidState().isSource() + && oldChunksCache.getIfPresent(chunkPosLong) == null) { + newChunksCache.addHighlight(chunkX, chunkZ); return; } + } + } + } - for (int x = 0; x < 16; x++) { - for (int y = mc.level.getMinBuildHeight(); y < mc.level.getMaxBuildHeight(); y++) { - for (int z = 0; z < 16; z++) { - FluidState fluid = chunk.getFluidState(x, y, z); - - if (!fluid.isEmpty() && !fluid.isSource()) { - oldChunksCache.put(ChunkUtils.chunkPosToLong(pos), (byte) 0); - return; - } - } + @EventHandler + public void onChunkData(final ChunkDataEvent event) { + if (mc.level == null || ((AccessorWorldRenderer) mc.levelRenderer).getChunks() == null) return; + var chunk = event.chunk(); + var chunkPos = chunk.getPos(); + if (newChunksCache.isHighlighted(chunkPos.x, chunkPos.z, getActualDimension())) return; + for (int x = 0; x < 16; x++) { + for (int y = mc.level.getMinBuildHeight(); y < mc.level.getMaxBuildHeight(); y++) { + for (int z = 0; z < 16; z++) { + FluidState fluid = chunk.getFluidState(x, y, z); + if (!fluid.isEmpty() && !fluid.isSource()) { + oldChunksCache.put(ChunkUtils.chunkPosToLong(chunkPos), (byte) 0); + return; } } } diff --git a/common/src/main/java/xaeroplus/module/impl/OldChunks.java b/common/src/main/java/xaeroplus/module/impl/OldChunks.java index aa95106f..fa257cba 100644 --- a/common/src/main/java/xaeroplus/module/impl/OldChunks.java +++ b/common/src/main/java/xaeroplus/module/impl/OldChunks.java @@ -34,7 +34,6 @@ import static net.minecraft.world.level.Level.*; import static xaeroplus.feature.render.ColorHelper.getColor; -@Module.ModuleInfo() public class OldChunks extends Module { private ChunkHighlightCache oldChunksCache = new ChunkHighlightLocalCache(); private ChunkHighlightCache modernChunksCache = new ChunkHighlightLocalCache(); diff --git a/common/src/main/java/xaeroplus/module/impl/PortalSkipDetection.java b/common/src/main/java/xaeroplus/module/impl/PortalSkipDetection.java index 1ebfa694..12ce6a23 100644 --- a/common/src/main/java/xaeroplus/module/impl/PortalSkipDetection.java +++ b/common/src/main/java/xaeroplus/module/impl/PortalSkipDetection.java @@ -34,7 +34,6 @@ import static xaeroplus.util.ChunkUtils.*; import static xaeroplus.util.GuiMapHelper.*; -@Module.ModuleInfo() public class PortalSkipDetection extends Module { private final ExecutorService executorService = Executors.newSingleThreadExecutor(new ThreadFactoryBuilder() .setNameFormat("XaeroPlus-PortalSkipDetection-Search") diff --git a/common/src/main/java/xaeroplus/module/impl/Portals.java b/common/src/main/java/xaeroplus/module/impl/Portals.java index 23ce2ade..7cd75c4c 100644 --- a/common/src/main/java/xaeroplus/module/impl/Portals.java +++ b/common/src/main/java/xaeroplus/module/impl/Portals.java @@ -7,8 +7,6 @@ import net.lenni0451.lambdaevents.EventHandler; import net.minecraft.client.Minecraft; import net.minecraft.core.BlockPos; -import net.minecraft.network.protocol.game.ClientboundBlockUpdatePacket; -import net.minecraft.network.protocol.game.ClientboundSectionBlocksUpdatePacket; import net.minecraft.resources.ResourceKey; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.Block; @@ -21,10 +19,7 @@ import net.minecraft.world.level.chunk.LevelChunk; import xaeroplus.Globals; import xaeroplus.XaeroPlus; -import xaeroplus.event.ChunkDataEvent; -import xaeroplus.event.ClientTickEvent; -import xaeroplus.event.PacketReceivedEvent; -import xaeroplus.event.XaeroWorldChangeEvent; +import xaeroplus.event.*; import xaeroplus.feature.render.ChunkHighlightProvider; import xaeroplus.feature.render.ColorHelper; import xaeroplus.feature.render.highlights.ChunkHighlightCache; @@ -41,8 +36,6 @@ import static net.minecraft.world.level.Level.*; import static xaeroplus.feature.render.ColorHelper.getColor; - -@Module.ModuleInfo() public class Portals extends Module { private ChunkHighlightCache portalsCache = new ChunkHighlightLocalCache(); private final Minecraft mc = Minecraft.getInstance(); @@ -101,14 +94,13 @@ public void onChunkData(final ChunkDataEvent event) { } @EventHandler - public void onPacketReceived(final PacketReceivedEvent event) { - if (event.packet() instanceof ClientboundBlockUpdatePacket) { - final ClientboundBlockUpdatePacket packet = (ClientboundBlockUpdatePacket) event.packet(); - handleBlockChange(packet.getPos(), packet.getBlockState()); - } else if (event.packet() instanceof ClientboundSectionBlocksUpdatePacket) { - final ClientboundSectionBlocksUpdatePacket packet = (ClientboundSectionBlocksUpdatePacket) event.packet(); - packet.runUpdates(this::handleBlockChange); - } + public void onMultiBlockUpdate(final ChunkBlocksUpdateEvent event) { + event.packet().runUpdates(this::handleBlockChange); + } + + @EventHandler + public void onBlockUpdate(final ChunkBlockUpdateEvent event) { + handleBlockChange(event.packet().getPos(), event.packet().getBlockState()); } @EventHandler diff --git a/common/src/main/java/xaeroplus/module/impl/WaystoneSync.java b/common/src/main/java/xaeroplus/module/impl/WaystoneSync.java index 5f562414..d8e2de47 100644 --- a/common/src/main/java/xaeroplus/module/impl/WaystoneSync.java +++ b/common/src/main/java/xaeroplus/module/impl/WaystoneSync.java @@ -23,7 +23,6 @@ import static xaero.common.settings.ModSettings.COLORS; -@Module.ModuleInfo() public class WaystoneSync extends Module { private boolean subscribed = false; private BlayWaystonesHelper blayWaystonesHelper = new BlayWaystonesHelper(); diff --git a/common/src/main/java/xaeroplus/module/impl/WorldTools.java b/common/src/main/java/xaeroplus/module/impl/WorldTools.java index bb0a6b6b..79bbfbad 100644 --- a/common/src/main/java/xaeroplus/module/impl/WorldTools.java +++ b/common/src/main/java/xaeroplus/module/impl/WorldTools.java @@ -13,7 +13,6 @@ import static xaeroplus.feature.render.ColorHelper.getColor; -@Module.ModuleInfo() public class WorldTools extends Module { private int worldToolsColor = getColor(0, 255, 0, 100); diff --git a/common/src/main/resources/xaeroplus.mixins.json b/common/src/main/resources/xaeroplus.mixins.json index fa019faf..57b7cabb 100644 --- a/common/src/main/resources/xaeroplus.mixins.json +++ b/common/src/main/resources/xaeroplus.mixins.json @@ -71,7 +71,6 @@ "MixinWorldMapOption", "mc.AccessorGameOptions", "mc.AccessorWorldRenderer", - "mc.MixinClientConnection", "mc.MixinClientPlayNetworkHandler", "mc.MixinGlStateManager", "mc.MixinMinecraftClient",