001/* 002 * This file is part of Baritone. 003 * 004 * Baritone is free software: you can redistribute it and/or modify 005 * it under the terms of the GNU Lesser General Public License as published by 006 * the Free Software Foundation, either version 3 of the License, or 007 * (at your option) any later version. 008 * 009 * Baritone is distributed in the hope that it will be useful, 010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 012 * GNU Lesser General Public License for more details. 013 * 014 * You should have received a copy of the GNU Lesser General Public License 015 * along with Baritone. If not, see <https://www.gnu.org/licenses/>. 016 */ 017 018package baritone.api.utils; 019 020import javax.annotation.Nonnull; 021import net.minecraft.core.BlockPos; 022import net.minecraft.core.Direction; 023import net.minecraft.core.Vec3i; 024import net.minecraft.util.Mth; 025 026/** 027 * A better BlockPos that has fewer hash collisions (and slightly more performant offsets) 028 * <p> 029 * Is it really faster to subclass BlockPos and calculate a hash in the constructor like this, taking everything into account? 030 * Yes. 20% faster actually. It's called BETTER BlockPos for a reason. Source: 031 * <a href="https://docs.google.com/spreadsheets/d/1GWjOjOZINkg_0MkRgKRPH1kUzxjsnEROD9u3UFh_DJc">Benchmark Spreadsheet</a> 032 * 033 * @author leijurv 034 */ 035public final class BetterBlockPos extends BlockPos { 036 037 private static final int NUM_X_BITS = 26; 038 private static final int NUM_Z_BITS = NUM_X_BITS; 039 private static final int NUM_Y_BITS = 64 - NUM_X_BITS - NUM_Z_BITS; 040 private static final int Y_SHIFT = NUM_Z_BITS; 041 private static final int X_SHIFT = Y_SHIFT + NUM_Y_BITS; 042 private static final long X_MASK = (1L << NUM_X_BITS) - 1L; 043 private static final long Y_MASK = (1L << NUM_Y_BITS) - 1L; 044 private static final long Z_MASK = (1L << NUM_Z_BITS) - 1L; 045 046 public static final BetterBlockPos ORIGIN = new BetterBlockPos(0, 0, 0); 047 048 public final int x; 049 public final int y; 050 public final int z; 051 052 public BetterBlockPos(int x, int y, int z) { 053 super(x, y, z); 054 this.x = x; 055 this.y = y; 056 this.z = z; 057 } 058 059 public BetterBlockPos(double x, double y, double z) { 060 this(Mth.floor(x), Mth.floor(y), Mth.floor(z)); 061 } 062 063 public BetterBlockPos(BlockPos pos) { 064 this(pos.getX(), pos.getY(), pos.getZ()); 065 } 066 067 /** 068 * Like constructor but returns null if pos is null, good if you just need to possibly censor coordinates 069 * 070 * @param pos The BlockPos, possibly null, to convert 071 * @return A BetterBlockPos or null if pos was null 072 */ 073 public static BetterBlockPos from(BlockPos pos) { 074 if (pos == null) { 075 return null; 076 } 077 078 return new BetterBlockPos(pos); 079 } 080 081 @Override 082 public int hashCode() { 083 return (int) longHash(x, y, z); 084 } 085 086 public static long longHash(BetterBlockPos pos) { 087 return longHash(pos.x, pos.y, pos.z); 088 } 089 090 public static long longHash(int x, int y, int z) { 091 // TODO use the same thing as BlockPos.fromLong(); 092 // invertibility would be incredibly useful 093 /* 094 * This is the hashcode implementation of Vec3i (the superclass of the class which I shall not name) 095 * 096 * public int hashCode() { 097 * return (this.getY() + this.getZ() * 31) * 31 + this.getX(); 098 * } 099 * 100 * That is terrible and has tons of collisions and makes the HashMap terribly inefficient. 101 * 102 * That's why we grab out the X, Y, Z and calculate our own hashcode 103 */ 104 long hash = 3241; 105 hash = 3457689L * hash + x; 106 hash = 8734625L * hash + y; 107 hash = 2873465L * hash + z; 108 return hash; 109 } 110 111 @Override 112 public boolean equals(Object o) { 113 if (o == null) { 114 return false; 115 } 116 if (o instanceof BetterBlockPos) { 117 BetterBlockPos oth = (BetterBlockPos) o; 118 return oth.x == x && oth.y == y && oth.z == z; 119 } 120 // during path execution, like "if (whereShouldIBe.equals(whereAmI)) {" 121 // sometimes we compare a BlockPos to a BetterBlockPos 122 BlockPos oth = (BlockPos) o; 123 return oth.getX() == x && oth.getY() == y && oth.getZ() == z; 124 } 125 126 @Override 127 public BetterBlockPos above() { 128 // this is unimaginably faster than blockpos.up 129 // that literally calls 130 // this.up(1) 131 // which calls this.offset(Direction.UP, 1) 132 // which does return n == 0 ? this : new BlockPos(this.getX() + facing.getXOffset() * n, this.getY() + facing.getYOffset() * n, this.getZ() + facing.getZOffset() * n); 133 134 // how many function calls is that? up(), up(int), offset(Direction, int), new BlockPos, getX, getXOffset, getY, getYOffset, getZ, getZOffset 135 // that's ten. 136 // this is one function call. 137 return new BetterBlockPos(x, y + 1, z); 138 } 139 140 @Override 141 public BetterBlockPos above(int amt) { 142 // see comment in up() 143 return amt == 0 ? this : new BetterBlockPos(x, y + amt, z); 144 } 145 146 @Override 147 public BetterBlockPos below() { 148 // see comment in up() 149 return new BetterBlockPos(x, y - 1, z); 150 } 151 152 @Override 153 public BetterBlockPos below(int amt) { 154 // see comment in up() 155 return amt == 0 ? this : new BetterBlockPos(x, y - amt, z); 156 } 157 158 @Override 159 public BetterBlockPos relative(Direction dir) { 160 Vec3i vec = dir.getUnitVec3i(); 161 return new BetterBlockPos(x + vec.getX(), y + vec.getY(), z + vec.getZ()); 162 } 163 164 @Override 165 public BetterBlockPos relative(Direction dir, int dist) { 166 if (dist == 0) { 167 return this; 168 } 169 Vec3i vec = dir.getUnitVec3i(); 170 return new BetterBlockPos(x + vec.getX() * dist, y + vec.getY() * dist, z + vec.getZ() * dist); 171 } 172 173 @Override 174 public BetterBlockPos north() { 175 return new BetterBlockPos(x, y, z - 1); 176 } 177 178 @Override 179 public BetterBlockPos north(int amt) { 180 return amt == 0 ? this : new BetterBlockPos(x, y, z - amt); 181 } 182 183 @Override 184 public BetterBlockPos south() { 185 return new BetterBlockPos(x, y, z + 1); 186 } 187 188 @Override 189 public BetterBlockPos south(int amt) { 190 return amt == 0 ? this : new BetterBlockPos(x, y, z + amt); 191 } 192 193 @Override 194 public BetterBlockPos east() { 195 return new BetterBlockPos(x + 1, y, z); 196 } 197 198 @Override 199 public BetterBlockPos east(int amt) { 200 return amt == 0 ? this : new BetterBlockPos(x + amt, y, z); 201 } 202 203 @Override 204 public BetterBlockPos west() { 205 return new BetterBlockPos(x - 1, y, z); 206 } 207 208 @Override 209 public BetterBlockPos west(int amt) { 210 return amt == 0 ? this : new BetterBlockPos(x - amt, y, z); 211 } 212 213 public double distanceSq(final BetterBlockPos to) { 214 double dx = (double) this.x - to.x; 215 double dy = (double) this.y - to.y; 216 double dz = (double) this.z - to.z; 217 return dx * dx + dy * dy + dz * dz; 218 } 219 220 public double distanceTo(final BetterBlockPos to) { 221 double dx = (double) this.x - to.x; 222 double dy = (double) this.y - to.y; 223 double dz = (double) this.z - to.z; 224 return Math.sqrt(dx * dx + dy * dy + dz * dz); 225 } 226 227 @Override 228 @Nonnull 229 public String toString() { 230 return String.format( 231 "BetterBlockPos{x=%s,y=%s,z=%s}", 232 SettingsUtil.maybeCensor(x), 233 SettingsUtil.maybeCensor(y), 234 SettingsUtil.maybeCensor(z) 235 ); 236 } 237 238 public static long serializeToLong(final int x, final int y, final int z) { 239 return ((long) x & X_MASK) << X_SHIFT | ((long) y & Y_MASK) << Y_SHIFT | ((long) z & Z_MASK); 240 } 241 242 public static BetterBlockPos deserializeFromLong(final long serialized) { 243 final int x = (int) (serialized << 64 - X_SHIFT - NUM_X_BITS >> 64 - NUM_X_BITS); 244 final int y = (int) (serialized << 64 - Y_SHIFT - NUM_Y_BITS >> 64 - NUM_Y_BITS); 245 final int z = (int) (serialized << 64 - NUM_Z_BITS >> 64 - NUM_Z_BITS); 246 return new BetterBlockPos(x, y, z); 247 } 248}