From 1dbfc9abe39a71063cbcbefa946f3b8cd149feee Mon Sep 17 00:00:00 2001 From: Brady Date: Sun, 18 Jun 2023 19:57:29 -0500 Subject: [PATCH 1/6] optimize block lookups and move goingTo to local --- .../baritone/behavior/ElytraBehavior.java | 59 ++++++------------- 1 file changed, 17 insertions(+), 42 deletions(-) diff --git a/src/main/java/baritone/behavior/ElytraBehavior.java b/src/main/java/baritone/behavior/ElytraBehavior.java index fa15e1678..c2ef38425 100644 --- a/src/main/java/baritone/behavior/ElytraBehavior.java +++ b/src/main/java/baritone/behavior/ElytraBehavior.java @@ -30,7 +30,6 @@ import net.minecraft.block.state.IBlockState; import net.minecraft.entity.item.EntityFireworkRocket; import net.minecraft.util.EnumHand; import net.minecraft.util.math.*; -import net.minecraft.world.World; import net.minecraft.world.chunk.Chunk; import java.util.*; @@ -69,7 +68,6 @@ public final class ElytraBehavior extends Behavior implements Helper { private boolean completePath; private int playerNear; - private int goingTo; private boolean recalculating; @@ -167,7 +165,6 @@ public final class ElytraBehavior extends Behavior implements Helper { public void clear() { this.path = Collections.emptyList(); this.playerNear = 0; - this.goingTo = 0; this.completePath = true; } @@ -175,7 +172,6 @@ public final class ElytraBehavior extends Behavior implements Helper { this.path = segment.collect(); this.removeBacktracks(); this.playerNear = 0; - this.goingTo = 0; this.completePath = segment.isFinished(); } @@ -187,14 +183,6 @@ public final class ElytraBehavior extends Behavior implements Helper { return this.playerNear; } - public void setGoingTo(int index) { - this.goingTo = index; - } - - public BetterBlockPos goingTo() { - return this.path.get(this.goingTo); - } - // mickey resigned private CompletableFuture path0(BlockPos src, BlockPos dst, UnaryOperator operator) { return ElytraBehavior.this.context.pathFindAsync(src, dst) @@ -319,6 +307,7 @@ public final class ElytraBehavior extends Behavior implements Helper { return; } + this.bsi = new BlockStateInterface(ctx); this.pathManager.tick(); final int playerNear = this.pathManager.getNear(); @@ -342,6 +331,7 @@ public final class ElytraBehavior extends Behavior implements Helper { final Vec3d start = ctx.playerFeetAsVec(); final boolean firework = isFireworkActive(); + BetterBlockPos goingTo = null; boolean forceUseFirework = false; this.sinceFirework++; @@ -354,7 +344,8 @@ public final class ElytraBehavior extends Behavior implements Helper { int minStep = playerNear; for (int i = Math.min(playerNear + 20, path.size() - 1); i >= minStep; i--) { for (int dy : heights) { - Vec3d dest = this.pathManager.pathAt(i).add(0, dy, 0); + final BetterBlockPos pos = path.get(i); + Vec3d dest = new Vec3d(pos).add(0, dy, 0); if (dy != 0) { if (i + lookahead >= path.size()) { continue; @@ -385,9 +376,8 @@ public final class ElytraBehavior extends Behavior implements Helper { continue; } forceUseFirework = pitch.second(); - - this.pathManager.setGoingTo(i); - this.aimPos = path.get(i).add(0, dy, 0); + goingTo = pos; + this.aimPos = goingTo.add(0, dy, 0); baritone.getLookBehavior().updateTarget(new Rotation(yaw, pitch.first()), false); break outermost; } @@ -399,7 +389,6 @@ public final class ElytraBehavior extends Behavior implements Helper { } } - final BetterBlockPos goingTo = this.pathManager.goingTo(); final boolean useOnDescend = !Baritone.settings().conserveFireworks.value || ctx.player().posY < goingTo.y + 5; final double currentSpeed = new Vec3d( ctx.player().motionX, @@ -456,7 +445,7 @@ public final class ElytraBehavior extends Behavior implements Helper { private boolean clearView(Vec3d start, Vec3d dest) { lines.add(new Pair<>(start, dest)); - return !rayTraceBlocks(ctx.world(), start.x, start.y, start.z, dest.x, dest.y, dest.z); + return !rayTraceBlocks(start.x, start.y, start.z, dest.x, dest.y, dest.z); } private Pair solvePitch(Vec3d goalDirection, int steps, int relaxation, boolean currentlyBoosted) { @@ -486,7 +475,6 @@ public final class ElytraBehavior extends Behavior implements Helper { Float bestPitch = null; double bestDot = Double.NEGATIVE_INFINITY; Vec3d motion = new Vec3d(ctx.player().motionX, ctx.player().motionY, ctx.player().motionZ); - BlockStateInterface bsi = new BlockStateInterface(ctx); float minPitch = desperate ? -90 : Math.max(good.getPitch() - Baritone.settings().elytraPitchRange.value, -89); float maxPitch = desperate ? 90 : Math.min(good.getPitch() + Baritone.settings().elytraPitchRange.value, 89); outer: @@ -501,7 +489,7 @@ public final class ElytraBehavior extends Behavior implements Helper { for (int x = MathHelper.floor(Math.min(actualPosition.x, actualPositionPrevTick.x) - 0.31); x <= Math.max(actualPosition.x, actualPositionPrevTick.x) + 0.31; x++) { for (int y = MathHelper.floor(Math.min(actualPosition.y, actualPositionPrevTick.y) - 0.2); y <= Math.max(actualPosition.y, actualPositionPrevTick.y) + 1; y++) { for (int z = MathHelper.floor(Math.min(actualPosition.z, actualPositionPrevTick.z) - 0.31); z <= Math.max(actualPosition.z, actualPositionPrevTick.z) + 0.31; z++) { - if (!passable(bsi.get0(x, y, z))) { + if (!this.passable(x, y, z)) { continue outer; } } @@ -519,6 +507,12 @@ public final class ElytraBehavior extends Behavior implements Helper { return bestPitch; } + private BlockStateInterface bsi; + + public boolean passable(int x, int y, int z) { + return passable(this.bsi.get0(x, y, z)); + } + public static boolean passable(IBlockState state) { return state.getMaterial() == Material.AIR; } @@ -574,20 +568,13 @@ public final class ElytraBehavior extends Behavior implements Helper { return new Vec3d(motionX, motionY, motionZ); } - private final BlockPos.MutableBlockPos mutableRaytraceBlockPos = new BlockPos.MutableBlockPos(); - - private boolean rayTraceBlocks(final World world, - final double startX, final double startY, final double startZ, + private boolean rayTraceBlocks(final double startX, final double startY, final double startZ, final double endX, final double endY, final double endZ) { int voxelCurrX = fastFloor(startX); int voxelCurrY = fastFloor(startY); int voxelCurrZ = fastFloor(startZ); - Chunk prevChunk; - IBlockState currentState = (prevChunk = cachedChunk(world, this.mutableRaytraceBlockPos.setPos(voxelCurrX, voxelCurrY, voxelCurrZ), null)).getBlockState(this.mutableRaytraceBlockPos); - - // This is true if player is standing inside of block. - if (!passable(currentState)) { + if (!this.passable(voxelCurrX, voxelCurrY, voxelCurrZ)) { return true; } @@ -663,8 +650,7 @@ public final class ElytraBehavior extends Behavior implements Helper { voxelCurrZ = (fastFloor(currPosZ) - zFloorOffset); } - currentState = (prevChunk = cachedChunk(world, this.mutableRaytraceBlockPos.setPos(voxelCurrX, voxelCurrY, voxelCurrZ), prevChunk)).getBlockState(this.mutableRaytraceBlockPos); - if (!passable(currentState)) { + if (!this.passable(voxelCurrX, voxelCurrY, voxelCurrZ)) { return true; } } @@ -677,15 +663,4 @@ public final class ElytraBehavior extends Behavior implements Helper { private static int fastFloor(final double v) { return ((int) (v + FLOOR_DOUBLE_D)) - FLOOR_DOUBLE_I; } - - private static Chunk cachedChunk(final World world, - final BlockPos pos, - final Chunk prevLookup) { - final int chunkX = pos.getX() >> 4; - final int chunkZ = pos.getZ() >> 4; - if (prevLookup != null && prevLookup.x == chunkX && prevLookup.z == chunkZ) { - return prevLookup; - } - return world.getChunk(chunkX, chunkZ); - } } \ No newline at end of file From 812be14375df960cc0495fcd62acc30698db0fa6 Mon Sep 17 00:00:00 2001 From: Leijurv Date: Sun, 18 Jun 2023 18:06:32 -0700 Subject: [PATCH 2/6] debug --- .../baritone/behavior/ElytraBehavior.java | 129 +++++++++++++++++- .../java/baritone/utils/PathRenderer.java | 14 +- 2 files changed, 134 insertions(+), 9 deletions(-) diff --git a/src/main/java/baritone/behavior/ElytraBehavior.java b/src/main/java/baritone/behavior/ElytraBehavior.java index c2ef38425..d0fd210eb 100644 --- a/src/main/java/baritone/behavior/ElytraBehavior.java +++ b/src/main/java/baritone/behavior/ElytraBehavior.java @@ -28,8 +28,12 @@ import baritone.utils.BlockStateInterface; import net.minecraft.block.material.Material; import net.minecraft.block.state.IBlockState; import net.minecraft.entity.item.EntityFireworkRocket; +import net.minecraft.util.EnumFacing; import net.minecraft.util.EnumHand; -import net.minecraft.util.math.*; +import net.minecraft.util.math.AxisAlignedBB; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.MathHelper; +import net.minecraft.util.math.Vec3d; import net.minecraft.world.chunk.Chunk; import java.util.*; @@ -44,7 +48,8 @@ public final class ElytraBehavior extends Behavior implements Helper { private static final long NETHER_SEED = 146008555100680L; // Used exclusively for PathRenderer - public List> lines; + public List> clearLines; + public List> blockedLines; public BlockPos aimPos; public List visiblePath; @@ -56,7 +61,8 @@ public final class ElytraBehavior extends Behavior implements Helper { public ElytraBehavior(Baritone baritone) { super(baritone); this.context = new NetherPathfinderContext(NETHER_SEED); - this.lines = new ArrayList<>(); + this.clearLines = new ArrayList<>(); + this.blockedLines = new ArrayList<>(); this.visiblePath = Collections.emptyList(); this.pathManager = new PathManager(); } @@ -300,7 +306,8 @@ public final class ElytraBehavior extends Behavior implements Helper { if (event.getType() == TickEvent.Type.OUT) { return; } - this.lines.clear(); + this.clearLines.clear(); + this.blockedLines.clear(); final List path = this.pathManager.getPath(); if (path.isEmpty()) { @@ -376,8 +383,12 @@ public final class ElytraBehavior extends Behavior implements Helper { continue; } forceUseFirework = pitch.second(); + logDirect("final dy " + dy); + logDirect("i " + i); + logDirect("playerNear " + playerNear); + logDirect("relaxation " + relaxation); goingTo = pos; - this.aimPos = goingTo.add(0, dy, 0); + this.aimPos = path.get(i).add(0, dy, 0); baritone.getLookBehavior().updateTarget(new Rotation(yaw, pitch.first()), false); break outermost; } @@ -444,8 +455,18 @@ public final class ElytraBehavior extends Behavior implements Helper { } private boolean clearView(Vec3d start, Vec3d dest) { - lines.add(new Pair<>(start, dest)); - return !rayTraceBlocks(start.x, start.y, start.z, dest.x, dest.y, dest.z); + boolean oxy = !rayTraceBlocks(start.x, start.y, start.z, dest.x, dest.y, dest.z); + boolean meow = !rayTraceBlocks(start, dest); + if (oxy != meow) { + logDirect(start + " " + dest + " " + oxy + " " + meow); + } + if (oxy) { + clearLines.add(new Pair<>(start, dest)); + return true; + } else { + blockedLines.add(new Pair<>(start, dest)); + return false; + } } private Pair solvePitch(Vec3d goalDirection, int steps, int relaxation, boolean currentlyBoosted) { @@ -663,4 +684,98 @@ public final class ElytraBehavior extends Behavior implements Helper { private static int fastFloor(final double v) { return ((int) (v + FLOOR_DOUBLE_D)) - FLOOR_DOUBLE_I; } + + private boolean rayTraceBlocks(Vec3d start, Vec3d end) { + int x1 = MathHelper.floor(end.x); + int y1 = MathHelper.floor(end.y); + int z1 = MathHelper.floor(end.z); + int x2 = MathHelper.floor(start.x); + int y2 = MathHelper.floor(start.y); + int z2 = MathHelper.floor(start.z); + BlockPos blockpos = new BlockPos(x2, y2, z2); + IBlockState iblockstate = ctx.world().getBlockState(blockpos); + if (!passable(iblockstate)) { + return true; + } + int steps = 200; + while (steps-- >= 0) { + if (Double.isNaN(start.x) || Double.isNaN(start.y) || Double.isNaN(start.z)) { + return false; + } + if (x2 == x1 && y2 == y1 && z2 == z1) { + return false; + } + boolean hitX = true; + boolean hitY = true; + boolean hitZ = true; + double nextX = 999.0D; + double nextY = 999.0D; + double nextZ = 999.0D; + if (x1 > x2) { + nextX = (double) x2 + 1.0D; + } else if (x1 < x2) { + nextX = (double) x2 + 0.0D; + } else { + hitX = false; + } + if (y1 > y2) { + nextY = (double) y2 + 1.0D; + } else if (y1 < y2) { + nextY = (double) y2 + 0.0D; + } else { + hitY = false; + } + if (z1 > z2) { + nextZ = (double) z2 + 1.0D; + } else if (z1 < z2) { + nextZ = (double) z2 + 0.0D; + } else { + hitZ = false; + } + double stepX = 999.0D; + double stepY = 999.0D; + double stepZ = 999.0D; + double dirX = end.x - start.x; + double dirY = end.y - start.y; + double dirZ = end.z - start.z; + if (hitX) { + stepX = (nextX - start.x) / dirX; + } + if (hitY) { + stepY = (nextY - start.y) / dirY; + } + if (hitZ) { + stepZ = (nextZ - start.z) / dirZ; + } + if (stepX == -0.0D) { + stepX = -1.0E-4D; + } + if (stepY == -0.0D) { + stepY = -1.0E-4D; + } + if (stepZ == -0.0D) { + stepZ = -1.0E-4D; + } + EnumFacing dir; + if (stepX < stepY && stepX < stepZ) { + dir = x1 > x2 ? EnumFacing.WEST : EnumFacing.EAST; + start = new Vec3d(nextX, start.y + dirY * stepX, start.z + dirZ * stepX); + } else if (stepY < stepZ) { + dir = y1 > y2 ? EnumFacing.DOWN : EnumFacing.UP; + start = new Vec3d(start.x + dirX * stepY, nextY, start.z + dirZ * stepY); + } else { + dir = z1 > z2 ? EnumFacing.NORTH : EnumFacing.SOUTH; + start = new Vec3d(start.x + dirX * stepZ, start.y + dirY * stepZ, nextZ); + } + x2 = MathHelper.floor(start.x) - (dir == EnumFacing.EAST ? 1 : 0); + y2 = MathHelper.floor(start.y) - (dir == EnumFacing.UP ? 1 : 0); + z2 = MathHelper.floor(start.z) - (dir == EnumFacing.SOUTH ? 1 : 0); + blockpos = new BlockPos(x2, y2, z2); + IBlockState iblockstate1 = ctx.world().getBlockState(blockpos); + if (!passable(iblockstate1)) { + return true; + } + } + return false; + } } \ No newline at end of file diff --git a/src/main/java/baritone/utils/PathRenderer.java b/src/main/java/baritone/utils/PathRenderer.java index 7274f5dbc..d608d4a2b 100644 --- a/src/main/java/baritone/utils/PathRenderer.java +++ b/src/main/java/baritone/utils/PathRenderer.java @@ -108,11 +108,21 @@ public final class PathRenderer implements IRenderer { if (elytra.aimPos != null) { drawGoal(ctx.player(), new GoalBlock(elytra.aimPos), partialTicks, Color.GREEN); } - if (!elytra.lines.isEmpty() && Baritone.settings().renderRaytraces.value) { + if (!elytra.clearLines.isEmpty() && Baritone.settings().renderRaytraces.value) { + IRenderer.startLines(Color.GREEN, settings.pathRenderLineWidthPixels.value, settings.renderPathIgnoreDepth.value); + boolean orig = settings.renderPathAsLine.value; + settings.renderPathAsLine.value = true; + for (Pair line : elytra.clearLines) { + emitLine(line.first().x, line.first().y, line.first().z, line.second().x, line.second().y, line.second().z); + } + settings.renderPathAsLine.value = orig; + IRenderer.endLines(settings.renderPathIgnoreDepth.value); + } + if (!elytra.blockedLines.isEmpty() && Baritone.settings().renderRaytraces.value) { IRenderer.startLines(Color.BLUE, settings.pathRenderLineWidthPixels.value, settings.renderPathIgnoreDepth.value); boolean orig = settings.renderPathAsLine.value; settings.renderPathAsLine.value = true; - for (Pair line : elytra.lines) { + for (Pair line : elytra.blockedLines) { emitLine(line.first().x, line.first().y, line.first().z, line.second().x, line.second().y, line.second().z); } settings.renderPathAsLine.value = orig; From a236031435d3c6d8c528c583da08df7372929cf7 Mon Sep 17 00:00:00 2001 From: Leijurv Date: Sun, 18 Jun 2023 18:09:45 -0700 Subject: [PATCH 3/6] fix raytracer --- src/main/java/baritone/behavior/ElytraBehavior.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/baritone/behavior/ElytraBehavior.java b/src/main/java/baritone/behavior/ElytraBehavior.java index d0fd210eb..3d3d4843c 100644 --- a/src/main/java/baritone/behavior/ElytraBehavior.java +++ b/src/main/java/baritone/behavior/ElytraBehavior.java @@ -455,7 +455,7 @@ public final class ElytraBehavior extends Behavior implements Helper { } private boolean clearView(Vec3d start, Vec3d dest) { - boolean oxy = !rayTraceBlocks(start.x, start.y, start.z, dest.x, dest.y, dest.z); + boolean oxy = !rayTraceBlocks(start.x + 0.0001 * Math.random(), start.y + 0.0001 * Math.random(), start.z + 0.0001 * Math.random(), dest.x + 0.0001 * Math.random(), dest.y + 0.0001 * Math.random(), dest.z + 0.0001 * Math.random()); boolean meow = !rayTraceBlocks(start, dest); if (oxy != meow) { logDirect(start + " " + dest + " " + oxy + " " + meow); From efae476bc028f04dbe01d9b99e4adfaeade003c1 Mon Sep 17 00:00:00 2001 From: Leijurv Date: Sun, 18 Jun 2023 18:16:13 -0700 Subject: [PATCH 4/6] solved --- src/main/java/baritone/behavior/ElytraBehavior.java | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/main/java/baritone/behavior/ElytraBehavior.java b/src/main/java/baritone/behavior/ElytraBehavior.java index 3d3d4843c..97dc24102 100644 --- a/src/main/java/baritone/behavior/ElytraBehavior.java +++ b/src/main/java/baritone/behavior/ElytraBehavior.java @@ -162,9 +162,9 @@ public final class ElytraBehavior extends Behavior implements Helper { private Vec3d pathAt(int i) { return new Vec3d( - this.path.get(i).x, - this.path.get(i).y, - this.path.get(i).z + this.path.get(i).x + 0.000123, + this.path.get(i).y + 0.000456, + this.path.get(i).z + 0.000789 ); } @@ -351,8 +351,7 @@ public final class ElytraBehavior extends Behavior implements Helper { int minStep = playerNear; for (int i = Math.min(playerNear + 20, path.size() - 1); i >= minStep; i--) { for (int dy : heights) { - final BetterBlockPos pos = path.get(i); - Vec3d dest = new Vec3d(pos).add(0, dy, 0); + Vec3d dest = this.pathManager.pathAt(i).add(0, dy, 0); if (dy != 0) { if (i + lookahead >= path.size()) { continue; @@ -387,7 +386,7 @@ public final class ElytraBehavior extends Behavior implements Helper { logDirect("i " + i); logDirect("playerNear " + playerNear); logDirect("relaxation " + relaxation); - goingTo = pos; + goingTo = path.get(i); this.aimPos = path.get(i).add(0, dy, 0); baritone.getLookBehavior().updateTarget(new Rotation(yaw, pitch.first()), false); break outermost; @@ -455,7 +454,7 @@ public final class ElytraBehavior extends Behavior implements Helper { } private boolean clearView(Vec3d start, Vec3d dest) { - boolean oxy = !rayTraceBlocks(start.x + 0.0001 * Math.random(), start.y + 0.0001 * Math.random(), start.z + 0.0001 * Math.random(), dest.x + 0.0001 * Math.random(), dest.y + 0.0001 * Math.random(), dest.z + 0.0001 * Math.random()); + boolean oxy = !rayTraceBlocks(start.x, start.y, start.z, dest.x, dest.y, dest.z); boolean meow = !rayTraceBlocks(start, dest); if (oxy != meow) { logDirect(start + " " + dest + " " + oxy + " " + meow); From 1837b66bb5153e14ad46cc7269fb3e6c70367bd0 Mon Sep 17 00:00:00 2001 From: Brady Date: Sun, 18 Jun 2023 21:24:13 -0500 Subject: [PATCH 5/6] 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)); From 9808f62fe4c004fd865970b4a1cfdf8f2cbadfe7 Mon Sep 17 00:00:00 2001 From: Brady Date: Sun, 18 Jun 2023 21:25:00 -0500 Subject: [PATCH 6/6] Send chunks to nether-pathfinder on `BlockUpdateEvent` --- .../java/baritone/behavior/ElytraBehavior.java | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/main/java/baritone/behavior/ElytraBehavior.java b/src/main/java/baritone/behavior/ElytraBehavior.java index 97dc24102..6260b42bf 100644 --- a/src/main/java/baritone/behavior/ElytraBehavior.java +++ b/src/main/java/baritone/behavior/ElytraBehavior.java @@ -18,9 +18,9 @@ package baritone.behavior; import baritone.Baritone; +import baritone.api.event.events.BlockChangeEvent; import baritone.api.event.events.ChunkEvent; import baritone.api.event.events.TickEvent; -import baritone.api.event.events.type.EventState; import baritone.api.utils.*; import baritone.behavior.elytra.NetherPathfinderContext; import baritone.behavior.elytra.UnpackedSegment; @@ -284,12 +284,19 @@ public final class ElytraBehavior extends Behavior implements Helper { @Override public void onChunkEvent(ChunkEvent event) { - if (event.getState() == EventState.POST && event.getType().isPopulate()) { + if (event.isPostPopulate()) { final Chunk chunk = ctx.world().getChunk(event.getX(), event.getZ()); this.context.queueForPacking(chunk); } } + @Override + public void onBlockChange(BlockChangeEvent event) { + event.getAffectedChunks().stream() + .map(pos -> ctx.world().getChunk(pos.x, pos.z)) + .forEach(this.context::queueForPacking); + } + public void path(BlockPos destination) { this.pathManager.pathToDestination(destination); } @@ -382,10 +389,6 @@ public final class ElytraBehavior extends Behavior implements Helper { continue; } forceUseFirework = pitch.second(); - logDirect("final dy " + dy); - logDirect("i " + i); - logDirect("playerNear " + playerNear); - logDirect("relaxation " + relaxation); goingTo = path.get(i); this.aimPos = path.get(i).add(0, dy, 0); baritone.getLookBehavior().updateTarget(new Rotation(yaw, pitch.first()), false);