diff --git a/src/api/java/baritone/api/utils/BetterBlockPos.java b/src/api/java/baritone/api/utils/BetterBlockPos.java index 01e53402e..3eb8068c1 100644 --- a/src/api/java/baritone/api/utils/BetterBlockPos.java +++ b/src/api/java/baritone/api/utils/BetterBlockPos.java @@ -35,6 +35,15 @@ import javax.annotation.Nonnull; */ public final class BetterBlockPos extends BlockPos { + private static final int NUM_X_BITS = 26; + private static final int NUM_Z_BITS = NUM_X_BITS; + private static final int NUM_Y_BITS = 64 - NUM_X_BITS - NUM_Z_BITS; + private static final int Y_SHIFT = NUM_Z_BITS; + private static final int X_SHIFT = Y_SHIFT + NUM_Y_BITS; + private static final long X_MASK = (1L << NUM_X_BITS) - 1L; + private static final long Y_MASK = (1L << NUM_Y_BITS) - 1L; + private static final long Z_MASK = (1L << NUM_Z_BITS) - 1L; + public static final BetterBlockPos ORIGIN = new BetterBlockPos(0, 0, 0); public final int x; @@ -226,4 +235,15 @@ public final class BetterBlockPos extends BlockPos { SettingsUtil.maybeCensor(z) ); } + + public static long serializeToLong(final int x, final int y, final int z) { + return ((long) x & X_MASK) << X_SHIFT | ((long) y & Y_MASK) << Y_SHIFT | ((long) z & Z_MASK); + } + + public static BetterBlockPos deserializeFromLong(final long serialized) { + final int x = (int) (serialized << 64 - X_SHIFT - NUM_X_BITS >> 64 - NUM_X_BITS); + final int y = (int) (serialized << 64 - Y_SHIFT - NUM_Y_BITS >> 64 - NUM_Y_BITS); + final int z = (int) (serialized << 64 - NUM_Z_BITS >> 64 - NUM_Z_BITS); + return new BetterBlockPos(x, y, z); + } } diff --git a/src/main/java/baritone/behavior/ElytraBehavior.java b/src/main/java/baritone/behavior/ElytraBehavior.java index d7f6ff8b9..73ccb69f1 100644 --- a/src/main/java/baritone/behavior/ElytraBehavior.java +++ b/src/main/java/baritone/behavior/ElytraBehavior.java @@ -43,6 +43,7 @@ import baritone.utils.PathingCommandContext; import baritone.utils.accessor.IEntityFireworkRocket; import it.unimi.dsi.fastutil.floats.FloatArrayList; import it.unimi.dsi.fastutil.floats.FloatIterator; +import it.unimi.dsi.fastutil.longs.Long2ReferenceOpenHashMap; import net.minecraft.block.material.Material; import net.minecraft.block.state.IBlockState; import net.minecraft.entity.item.EntityFireworkRocket; @@ -60,6 +61,8 @@ import java.util.function.Supplier; import java.util.function.UnaryOperator; import static baritone.api.pathing.movement.ActionCosts.COST_INF; +import static baritone.utils.BaritoneMath.fastCeil; +import static baritone.utils.BaritoneMath.fastFloor; public final class ElytraBehavior extends Behavior implements IElytraBehavior, Helper { @@ -447,6 +450,9 @@ public final class ElytraBehavior extends Behavior implements IElytraBehavior, H this.minimumBoostTicks = 0; } + // lol + MC_1_12_Collision_Fix.clear(); + // Reset rendered elements this.clearLines.clear(); this.blockedLines.clear(); @@ -567,7 +573,7 @@ public final class ElytraBehavior extends Behavior implements IElytraBehavior, H } else { // Create a point along the segment every block final Vec3d delta = path.getVec(i).subtract(path.getVec(i - 1)); - final int steps = MathHelper.floor(delta.length()); + final int steps = fastFloor(delta.length()); final Vec3d step = delta.normalize(); Vec3d stepped = path.getVec(i); for (int interp = 0; interp < steps; interp++) { @@ -893,7 +899,7 @@ public final class ElytraBehavior extends Behavior implements IElytraBehavior, H final float minPitch = desperate ? -90 : Math.max(goodPitch - Baritone.settings().elytraPitchRange.value, -89); final float maxPitch = desperate ? 90 : Math.min(goodPitch + Baritone.settings().elytraPitchRange.value, 89); - final FloatArrayList pitchValues = new FloatArrayList(MathHelper.ceil(maxPitch - minPitch) + 1); + final FloatArrayList pitchValues = new FloatArrayList(fastCeil(maxPitch - minPitch) + 1); for (float pitch = goodPitch; pitch <= maxPitch; pitch++) { pitchValues.add(pitch); } @@ -1039,11 +1045,13 @@ public final class ElytraBehavior extends Behavior implements IElytraBehavior, H Vec3d delta = goalDelta; Vec3d motion = ctx.playerMotion(); AxisAlignedBB hitbox = ctx.player().getEntityBoundingBox(); - List displacement = new ArrayList<>(); + List displacement = new ArrayList<>(ticks + 1); displacement.add(Vec3d.ZERO); for (int i = 0; i < ticks; i++) { - if (MC_1_12_Collision_Fix.bonk(this.bsi, hitbox)) { + final double cx = hitbox.minX + (hitbox.maxX - hitbox.minX) * 0.5D; + final double cz = hitbox.minZ + (hitbox.maxZ - hitbox.minZ) * 0.5D; + if (MC_1_12_Collision_Fix.bonk(this.bsi, cx, hitbox.minY, cz)) { return null; } if (delta.lengthSquared() < 1) { @@ -1060,9 +1068,9 @@ public final class ElytraBehavior extends Behavior implements IElytraBehavior, H // Collision box while the player is in motion, with additional padding for safety final AxisAlignedBB inMotion = hitbox.expand(motion.x, motion.y, motion.z).grow(0.01); - for (int x = MathHelper.floor(inMotion.minX); x < MathHelper.ceil(inMotion.maxX); x++) { - for (int y = MathHelper.floor(inMotion.minY); y < MathHelper.ceil(inMotion.maxY); y++) { - for (int z = MathHelper.floor(inMotion.minZ); z < MathHelper.ceil(inMotion.maxZ); z++) { + for (int x = fastFloor(inMotion.minX); x < fastCeil(inMotion.maxX); x++) { + for (int y = fastFloor(inMotion.minY); y < fastCeil(inMotion.maxY); y++) { + for (int z = fastFloor(inMotion.minZ); z < fastCeil(inMotion.maxZ); z++) { if (!this.passable(x, y, z, ignoreLava)) { return null; } @@ -1140,35 +1148,62 @@ public final class ElytraBehavior extends Behavior implements IElytraBehavior, H */ private static final class MC_1_12_Collision_Fix { - public static boolean bonk(final BlockStateInterface bsi, final AxisAlignedBB aabb) { - final Vec3d center = aabb.getCenter(); - final double width = (aabb.maxX - aabb.minX) * 0.35D; - final double x = center.x; - final double y = aabb.minY + 0.5D; - final double z = center.z; + private static final Long2ReferenceOpenHashMap PUSH_OUT_CACHE = new Long2ReferenceOpenHashMap<>(); + private static final Long2ReferenceOpenHashMap IS_OPEN_CACHE = new Long2ReferenceOpenHashMap<>(); + private static final double WIDTH = 0.35D * 0.6F; - return pushOutOfBlocks(bsi, x - width, y, z + width) - || pushOutOfBlocks(bsi, x - width, y, z - width) - || pushOutOfBlocks(bsi, x + width, y, z - width) - || pushOutOfBlocks(bsi, x + width, y, z + width); - } - - private static boolean pushOutOfBlocks(final BlockStateInterface bsi, - final double xIn, final double yIn, final double zIn) { - final int x = MathHelper.floor(xIn); - final int y = MathHelper.floor(yIn); - final int z = MathHelper.floor(zIn); - if (isOpenBlockSpace(bsi, x, y, z)) { - return false; + public static void clear() { + // TODO: I don't like this.... + if (MC_1_12_Collision_Fix.PUSH_OUT_CACHE.size() > 4096) { + MC_1_12_Collision_Fix.PUSH_OUT_CACHE.clear(); + } + if (MC_1_12_Collision_Fix.IS_OPEN_CACHE.size() > 4096) { + MC_1_12_Collision_Fix.IS_OPEN_CACHE.clear(); } - return isOpenBlockSpace(bsi, x - 1, y, z) - || isOpenBlockSpace(bsi, x + 1, y, z) - || isOpenBlockSpace(bsi, x, y, z - 1) - || isOpenBlockSpace(bsi, x, y, z + 1); } - private static boolean isOpenBlockSpace(BlockStateInterface bsi, final int x, final int y, final int z) { - return !bsi.get0(x, y, z).isNormalCube() && !bsi.get0(x, y + 1, z).isNormalCube(); + public static boolean bonk(final BlockStateInterface bsi, final double xIn, final double yIn, final double zIn) { + final int y = fastFloor(yIn + 0.5D); + final int minX = fastFloor(xIn - WIDTH); + final int minZ = fastFloor(zIn - WIDTH); + final int maxX = fastFloor(xIn + WIDTH); + final int maxZ = fastFloor(zIn + WIDTH); + + if (minX == maxX && minZ == maxZ) { + return pushOutOfBlocks(bsi, minX, y, minZ); + } else if (minX == maxX) { + return pushOutOfBlocks(bsi, minX, y, minZ) || pushOutOfBlocks(bsi, minX, y, maxZ); + } else if (minZ == maxZ) { + return pushOutOfBlocks(bsi, minX, y, minZ) || pushOutOfBlocks(bsi, maxX, y, minZ); + } + + return pushOutOfBlocks(bsi, minX, y, maxZ) + || pushOutOfBlocks(bsi, minX, y, minZ) + || pushOutOfBlocks(bsi, maxX, y, minZ) + || pushOutOfBlocks(bsi, maxX, y, maxZ); + } + + private static boolean pushOutOfBlocks(final BlockStateInterface bsi, final int x, final int y, final int z) { + final long hash = BetterBlockPos.serializeToLong(x, y, z); + Boolean result = PUSH_OUT_CACHE.get(hash); + if (result == null) { + PUSH_OUT_CACHE.put(hash, result = !isOpenBlockSpace(bsi, x, y, z) && ( + isOpenBlockSpace(bsi, x - 1, y, z) + || isOpenBlockSpace(bsi, x + 1, y, z) + || isOpenBlockSpace(bsi, x, y, z - 1) + || isOpenBlockSpace(bsi, x, y, z + 1)) + ); + } + return result; + } + + private static boolean isOpenBlockSpace(final BlockStateInterface bsi, final int x, final int y, final int z) { + final long hash = BetterBlockPos.serializeToLong(x, y, z); + Boolean result = IS_OPEN_CACHE.get(hash); + if (result == null) { + IS_OPEN_CACHE.put(hash, result = !bsi.get0(x, y, z).isNormalCube() && !bsi.get0(x, y + 1, z).isNormalCube()); + } + return result; } } diff --git a/src/main/java/baritone/behavior/elytra/UnpackedSegment.java b/src/main/java/baritone/behavior/elytra/UnpackedSegment.java index 22fa4f82d..0e0759625 100644 --- a/src/main/java/baritone/behavior/elytra/UnpackedSegment.java +++ b/src/main/java/baritone/behavior/elytra/UnpackedSegment.java @@ -19,7 +19,6 @@ package baritone.behavior.elytra; import baritone.api.utils.BetterBlockPos; import dev.babbaj.pathfinder.PathSegment; -import net.minecraft.util.math.BlockPos; import java.util.Arrays; import java.util.HashMap; @@ -77,7 +76,7 @@ public final class UnpackedSegment { public static UnpackedSegment from(final PathSegment segment) { return new UnpackedSegment( - Arrays.stream(segment.packed).mapToObj(BlockPos::fromLong).map(BetterBlockPos::new), + Arrays.stream(segment.packed).mapToObj(BetterBlockPos::deserializeFromLong), segment.finished ); } diff --git a/src/main/java/baritone/utils/BaritoneMath.java b/src/main/java/baritone/utils/BaritoneMath.java new file mode 100644 index 000000000..944fc899e --- /dev/null +++ b/src/main/java/baritone/utils/BaritoneMath.java @@ -0,0 +1,37 @@ +/* + * 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.utils; + +/** + * @author Brady + */ +public final class BaritoneMath { + + private BaritoneMath() {} + + private static final double FLOOR_DOUBLE_D = 1_073_741_824.0; + private static final int FLOOR_DOUBLE_I = 1_073_741_824; + + public static int fastFloor(final double v) { + return (int) (v + FLOOR_DOUBLE_D) - FLOOR_DOUBLE_I; + } + + public static int fastCeil(final double v) { + return FLOOR_DOUBLE_I - (int) (FLOOR_DOUBLE_D - v); + } +}