> 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));