From 1837b66bb5153e14ad46cc7269fb3e6c70367bd0 Mon Sep 17 00:00:00 2001 From: Brady Date: Sun, 18 Jun 2023 21:24:13 -0500 Subject: [PATCH] Add `BlockChangeEvent` Moves the cache repack on block change functionality into `GameEventHandler` --- .../java/baritone/api/IBaritoneProvider.java | 17 +++ .../api/event/events/BlockChangeEvent.java | 49 +++++++ .../baritone/api/event/events/ChunkEvent.java | 15 +- .../listener/AbstractGameEventListener.java | 3 + .../event/listener/IGameEventListener.java | 7 + .../mixins/MixinNetHandlerPlayClient.java | 128 +++++++----------- .../java/baritone/event/GameEventHandler.java | 30 +++- 7 files changed, 164 insertions(+), 85 deletions(-) create mode 100644 src/api/java/baritone/api/event/events/BlockChangeEvent.java diff --git a/src/api/java/baritone/api/IBaritoneProvider.java b/src/api/java/baritone/api/IBaritoneProvider.java index 55d208e03..cf816b40f 100644 --- a/src/api/java/baritone/api/IBaritoneProvider.java +++ b/src/api/java/baritone/api/IBaritoneProvider.java @@ -23,6 +23,7 @@ import baritone.api.command.ICommandSystem; import baritone.api.schematic.ISchematicSystem; import net.minecraft.client.Minecraft; import net.minecraft.client.entity.EntityPlayerSP; +import net.minecraft.client.network.NetHandlerPlayClient; import java.util.List; import java.util.Objects; @@ -82,6 +83,22 @@ public interface IBaritoneProvider { return null; } + /** + * Provides the {@link IBaritone} instance for the player with the specified connection. + * + * @param connection The connection + * @return The {@link IBaritone} instance. + */ + default IBaritone getBaritoneForConnection(NetHandlerPlayClient connection) { + for (IBaritone baritone : this.getAllBaritones()) { + final EntityPlayerSP player = baritone.getPlayerContext().player(); + if (player != null && player.connection == connection) { + return baritone; + } + } + return null; + } + /** * Creates and registers a new {@link IBaritone} instance using the specified {@link Minecraft}. The existing * instance is returned if already registered. diff --git a/src/api/java/baritone/api/event/events/BlockChangeEvent.java b/src/api/java/baritone/api/event/events/BlockChangeEvent.java new file mode 100644 index 000000000..152c435ae --- /dev/null +++ b/src/api/java/baritone/api/event/events/BlockChangeEvent.java @@ -0,0 +1,49 @@ +/* + * This file is part of Baritone. + * + * Baritone is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Baritone is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Baritone. If not, see . + */ + +package baritone.api.event.events; + +import baritone.api.utils.Pair; +import net.minecraft.block.state.IBlockState; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.ChunkPos; + +import java.util.Collections; +import java.util.List; +import java.util.Set; + +/** + * @author Brady + */ +public final class BlockChangeEvent { + + private final Set affectedChunks; + private final List> blocks; + + public BlockChangeEvent(ChunkPos pos, List> blocks) { + this.affectedChunks = Collections.singleton(pos); + this.blocks = blocks; + } + + public Set getAffectedChunks() { + return this.affectedChunks; + } + + public List> getBlocks() { + return this.blocks; + } +} diff --git a/src/api/java/baritone/api/event/events/ChunkEvent.java b/src/api/java/baritone/api/event/events/ChunkEvent.java index a7b5d96f0..bb22a47b1 100644 --- a/src/api/java/baritone/api/event/events/ChunkEvent.java +++ b/src/api/java/baritone/api/event/events/ChunkEvent.java @@ -57,31 +57,38 @@ public final class ChunkEvent { /** * @return The state of the event */ - public final EventState getState() { + public EventState getState() { return this.state; } /** * @return The type of chunk event that occurred; */ - public final Type getType() { + public Type getType() { return this.type; } /** * @return The Chunk X position. */ - public final int getX() { + public int getX() { return this.x; } /** * @return The Chunk Z position. */ - public final int getZ() { + public int getZ() { return this.z; } + /** + * @return {@code true} if the event was fired after a chunk population + */ + public boolean isPostPopulate() { + return this.state == EventState.POST && this.type.isPopulate(); + } + public enum Type { /** diff --git a/src/api/java/baritone/api/event/listener/AbstractGameEventListener.java b/src/api/java/baritone/api/event/listener/AbstractGameEventListener.java index 9eac8de46..64ae0c16e 100644 --- a/src/api/java/baritone/api/event/listener/AbstractGameEventListener.java +++ b/src/api/java/baritone/api/event/listener/AbstractGameEventListener.java @@ -45,6 +45,9 @@ public interface AbstractGameEventListener extends IGameEventListener { @Override default void onChunkEvent(ChunkEvent event) {} + @Override + default void onBlockChange(BlockChangeEvent event) {} + @Override default void onRenderPass(RenderEvent event) {} diff --git a/src/api/java/baritone/api/event/listener/IGameEventListener.java b/src/api/java/baritone/api/event/listener/IGameEventListener.java index b074e978b..71e9521ad 100644 --- a/src/api/java/baritone/api/event/listener/IGameEventListener.java +++ b/src/api/java/baritone/api/event/listener/IGameEventListener.java @@ -72,6 +72,13 @@ public interface IGameEventListener { */ void onChunkEvent(ChunkEvent event); + /** + * Runs after a single or multi block change packet is received and processed. + * + * @param event The event + */ + void onBlockChange(BlockChangeEvent event); + /** * Runs once per world render pass. Two passes are made when {@link GameSettings#anaglyph} is on. *

diff --git a/src/launch/java/baritone/launch/mixins/MixinNetHandlerPlayClient.java b/src/launch/java/baritone/launch/mixins/MixinNetHandlerPlayClient.java index f1c1f7972..cdbeffc6c 100644 --- a/src/launch/java/baritone/launch/mixins/MixinNetHandlerPlayClient.java +++ b/src/launch/java/baritone/launch/mixins/MixinNetHandlerPlayClient.java @@ -17,24 +17,29 @@ package baritone.launch.mixins; -import baritone.Baritone; import baritone.api.BaritoneAPI; import baritone.api.IBaritone; +import baritone.api.event.events.BlockChangeEvent; import baritone.api.event.events.ChunkEvent; import baritone.api.event.events.type.EventState; -import baritone.cache.CachedChunk; -import net.minecraft.client.entity.EntityPlayerSP; +import baritone.api.utils.Pair; +import net.minecraft.block.state.IBlockState; import net.minecraft.client.network.NetHandlerPlayClient; import net.minecraft.network.play.server.SPacketBlockChange; import net.minecraft.network.play.server.SPacketChunkData; import net.minecraft.network.play.server.SPacketCombatEvent; import net.minecraft.network.play.server.SPacketMultiBlockChange; +import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.ChunkPos; 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 java.util.Arrays; +import java.util.Collections; +import java.util.stream.Collectors; + /** * @author Brady * @since 8/3/2018 @@ -50,19 +55,18 @@ public class MixinNetHandlerPlayClient { ) ) private void preRead(SPacketChunkData packetIn, CallbackInfo ci) { - for (IBaritone ibaritone : BaritoneAPI.getProvider().getAllBaritones()) { - EntityPlayerSP player = ibaritone.getPlayerContext().player(); - if (player != null && player.connection == (NetHandlerPlayClient) (Object) this) { - ibaritone.getGameEventHandler().onChunkEvent( - new ChunkEvent( - EventState.PRE, - packetIn.isFullChunk() ? ChunkEvent.Type.POPULATE_FULL : ChunkEvent.Type.POPULATE_PARTIAL, - packetIn.getChunkX(), - packetIn.getChunkZ() - ) - ); - } + IBaritone baritone = BaritoneAPI.getProvider().getBaritoneForConnection((NetHandlerPlayClient) (Object) this); + if (baritone == null) { + return; } + baritone.getGameEventHandler().onChunkEvent( + new ChunkEvent( + EventState.PRE, + packetIn.isFullChunk() ? ChunkEvent.Type.POPULATE_FULL : ChunkEvent.Type.POPULATE_PARTIAL, + packetIn.getChunkX(), + packetIn.getChunkZ() + ) + ); } @Inject( @@ -70,19 +74,18 @@ public class MixinNetHandlerPlayClient { at = @At("RETURN") ) private void postHandleChunkData(SPacketChunkData packetIn, CallbackInfo ci) { - for (IBaritone ibaritone : BaritoneAPI.getProvider().getAllBaritones()) { - EntityPlayerSP player = ibaritone.getPlayerContext().player(); - if (player != null && player.connection == (NetHandlerPlayClient) (Object) this) { - ibaritone.getGameEventHandler().onChunkEvent( - new ChunkEvent( - EventState.POST, - packetIn.isFullChunk() ? ChunkEvent.Type.POPULATE_FULL : ChunkEvent.Type.POPULATE_PARTIAL, - packetIn.getChunkX(), - packetIn.getChunkZ() - ) - ); - } + IBaritone baritone = BaritoneAPI.getProvider().getBaritoneForConnection((NetHandlerPlayClient) (Object) this); + if (baritone == null) { + return; } + baritone.getGameEventHandler().onChunkEvent( + new ChunkEvent( + EventState.POST, + packetIn.isFullChunk() ? ChunkEvent.Type.POPULATE_FULL : ChunkEvent.Type.POPULATE_PARTIAL, + packetIn.getChunkX(), + packetIn.getChunkZ() + ) + ); } @Inject( @@ -90,25 +93,14 @@ public class MixinNetHandlerPlayClient { at = @At("RETURN") ) private void postHandleBlockChange(SPacketBlockChange packetIn, CallbackInfo ci) { - if (!Baritone.settings().repackOnAnyBlockChange.value) { + IBaritone baritone = BaritoneAPI.getProvider().getBaritoneForConnection((NetHandlerPlayClient) (Object) this); + if (baritone == null) { return; } - if (!CachedChunk.BLOCKS_TO_KEEP_TRACK_OF.contains(packetIn.getBlockState().getBlock())) { - return; - } - for (IBaritone ibaritone : BaritoneAPI.getProvider().getAllBaritones()) { - EntityPlayerSP player = ibaritone.getPlayerContext().player(); - if (player != null && player.connection == (NetHandlerPlayClient) (Object) this) { - ibaritone.getGameEventHandler().onChunkEvent( - new ChunkEvent( - EventState.POST, - ChunkEvent.Type.POPULATE_FULL, - packetIn.getBlockPosition().getX() >> 4, - packetIn.getBlockPosition().getZ() >> 4 - ) - ); - } - } + + final ChunkPos pos = new ChunkPos(packetIn.getBlockPosition().getX() >> 4, packetIn.getBlockPosition().getZ() >> 4); + final Pair changed = new Pair<>(packetIn.getBlockPosition(), packetIn.getBlockState()); + baritone.getGameEventHandler().onBlockChange(new BlockChangeEvent(pos, Collections.singletonList(changed))); } @Inject( @@ -116,35 +108,20 @@ public class MixinNetHandlerPlayClient { at = @At("RETURN") ) private void postHandleMultiBlockChange(SPacketMultiBlockChange packetIn, CallbackInfo ci) { - if (!Baritone.settings().repackOnAnyBlockChange.value) { + IBaritone baritone = BaritoneAPI.getProvider().getBaritoneForConnection((NetHandlerPlayClient) (Object) this); + if (baritone == null) { return; } - if (packetIn.getChangedBlocks().length == 0) { - return; - } - https://docs.oracle.com/javase/specs/jls/se7/html/jls-14.html#jls-14.15 - { - for (SPacketMultiBlockChange.BlockUpdateData update : packetIn.getChangedBlocks()) { - if (CachedChunk.BLOCKS_TO_KEEP_TRACK_OF.contains(update.getBlockState().getBlock())) { - break https; - } - } - return; - } - ChunkPos pos = new ChunkPos(packetIn.getChangedBlocks()[0].getPos()); - for (IBaritone ibaritone : BaritoneAPI.getProvider().getAllBaritones()) { - EntityPlayerSP player = ibaritone.getPlayerContext().player(); - if (player != null && player.connection == (NetHandlerPlayClient) (Object) this) { - ibaritone.getGameEventHandler().onChunkEvent( - new ChunkEvent( - EventState.POST, - ChunkEvent.Type.POPULATE_FULL, - pos.x, - pos.z - ) - ); - } - } + + // All blocks have the same ChunkPos + final ChunkPos pos = new ChunkPos(packetIn.getChangedBlocks()[0].getPos()); + + baritone.getGameEventHandler().onBlockChange(new BlockChangeEvent( + pos, + Arrays.stream(packetIn.getChangedBlocks()) + .map(data -> new Pair<>(data.getPos(), data.getBlockState())) + .collect(Collectors.toList()) + )); } @Inject( @@ -155,11 +132,10 @@ public class MixinNetHandlerPlayClient { ) ) private void onPlayerDeath(SPacketCombatEvent packetIn, CallbackInfo ci) { - for (IBaritone ibaritone : BaritoneAPI.getProvider().getAllBaritones()) { - EntityPlayerSP player = ibaritone.getPlayerContext().player(); - if (player != null && player.connection == (NetHandlerPlayClient) (Object) this) { - ibaritone.getGameEventHandler().onPlayerDeath(); - } + IBaritone baritone = BaritoneAPI.getProvider().getBaritoneForConnection((NetHandlerPlayClient) (Object) this); + if (baritone == null) { + return; } + baritone.getGameEventHandler().onPlayerDeath(); } } diff --git a/src/main/java/baritone/event/GameEventHandler.java b/src/main/java/baritone/event/GameEventHandler.java index 0b46eb5e1..ceb05e739 100644 --- a/src/main/java/baritone/event/GameEventHandler.java +++ b/src/main/java/baritone/event/GameEventHandler.java @@ -23,8 +23,11 @@ import baritone.api.event.events.type.EventState; import baritone.api.event.listener.IEventBus; import baritone.api.event.listener.IGameEventListener; import baritone.api.utils.Helper; +import baritone.api.utils.Pair; +import baritone.cache.CachedChunk; import baritone.cache.WorldProvider; import baritone.utils.BlockStateInterface; +import net.minecraft.block.state.IBlockState; import net.minecraft.world.World; import net.minecraft.world.chunk.Chunk; @@ -75,13 +78,10 @@ public final class GameEventHandler implements IEventBus, Helper { } @Override - public final void onChunkEvent(ChunkEvent event) { + public void onChunkEvent(ChunkEvent event) { EventState state = event.getState(); ChunkEvent.Type type = event.getType(); - boolean isPostPopulate = state == EventState.POST - && (type == ChunkEvent.Type.POPULATE_FULL || type == ChunkEvent.Type.POPULATE_PARTIAL); - World world = baritone.getPlayerContext().world(); // Whenever the server sends us to another dimension, chunks are unloaded @@ -91,7 +91,7 @@ public final class GameEventHandler implements IEventBus, Helper { && type == ChunkEvent.Type.UNLOAD && world.getChunkProvider().isChunkGeneratedAt(event.getX(), event.getZ()); - if (isPostPopulate || isPreUnload) { + if (event.isPostPopulate() || isPreUnload) { baritone.getWorldProvider().ifWorldLoaded(worldData -> { Chunk chunk = world.getChunk(event.getX(), event.getZ()); worldData.getCachedWorld().queueForPacking(chunk); @@ -102,6 +102,26 @@ public final class GameEventHandler implements IEventBus, Helper { listeners.forEach(l -> l.onChunkEvent(event)); } + @Override + public void onBlockChange(BlockChangeEvent event) { + if (Baritone.settings().repackOnAnyBlockChange.value) { + final boolean keepingTrackOf = event.getBlocks().stream() + .map(Pair::second).map(IBlockState::getBlock) + .anyMatch(CachedChunk.BLOCKS_TO_KEEP_TRACK_OF::contains); + + if (keepingTrackOf) { + baritone.getWorldProvider().ifWorldLoaded(worldData -> { + final World world = baritone.getPlayerContext().world(); + event.getAffectedChunks().stream() + .map(pos -> world.getChunk(pos.x, pos.z)) + .forEach(worldData.getCachedWorld()::queueForPacking); + }); + } + } + + listeners.forEach(l -> l.onBlockChange(event)); + } + @Override public final void onRenderPass(RenderEvent event) { listeners.forEach(l -> l.onRenderPass(event));