Initial Chunk Caching Commit
The actual code to run is commented out in GameEventHandler, uncomment for testing.
This commit is contained in:
		
							
								
								
									
										103
									
								
								src/main/java/baritone/bot/chunk/CachedChunk.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										103
									
								
								src/main/java/baritone/bot/chunk/CachedChunk.java
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,103 @@
 | 
			
		||||
package baritone.bot.chunk;
 | 
			
		||||
 | 
			
		||||
import baritone.bot.pathing.util.IBlockTypeAccess;
 | 
			
		||||
import baritone.bot.pathing.util.PathingBlockType;
 | 
			
		||||
 | 
			
		||||
import java.util.BitSet;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @author Brady
 | 
			
		||||
 * @since 8/3/2018 1:04 AM
 | 
			
		||||
 */
 | 
			
		||||
public final class CachedChunk implements IBlockTypeAccess {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * The size of the chunk data in bits. Equal to 16 KiB.
 | 
			
		||||
     * <br>
 | 
			
		||||
     * Chunks are 16x16x256, each block requires 2 bits.
 | 
			
		||||
     */
 | 
			
		||||
    public static final int SIZE = 2 * 16 * 16 * 256;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * The size of the chunk data in bytes. Equal to 16 KiB.
 | 
			
		||||
     */
 | 
			
		||||
    public static final int SIZE_IN_BYTES = SIZE / 8;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * An array of just 0s with the length of {@link CachedChunk#SIZE_IN_BYTES}
 | 
			
		||||
     */
 | 
			
		||||
    public static final byte[] EMPTY_CHUNK = new byte[SIZE_IN_BYTES];
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * The chunk x coordinate
 | 
			
		||||
     */
 | 
			
		||||
    private final int x;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * The chunk z coordinate
 | 
			
		||||
     */
 | 
			
		||||
    private final int z;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * The actual raw data of this packed chunk.
 | 
			
		||||
     * <br>
 | 
			
		||||
     * Each block is expressed as 2 bits giving a total of 16 KiB
 | 
			
		||||
     */
 | 
			
		||||
    private final BitSet data;
 | 
			
		||||
 | 
			
		||||
    CachedChunk(int x, int z, BitSet data) {
 | 
			
		||||
        if (data.size() != SIZE)
 | 
			
		||||
            throw new IllegalArgumentException("BitSet of invalid length provided");
 | 
			
		||||
 | 
			
		||||
        this.x = x;
 | 
			
		||||
        this.z = z;
 | 
			
		||||
        this.data = data;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public final PathingBlockType getBlockType(int x, int y, int z) {
 | 
			
		||||
        int index = getPositionIndex(x, y, z);
 | 
			
		||||
        return PathingBlockType.fromBits(data.get(index), data.get(index + 1));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void updateContents(BitSet data) {
 | 
			
		||||
        if (data.size() > SIZE)
 | 
			
		||||
            throw new IllegalArgumentException("BitSet of invalid length provided");
 | 
			
		||||
 | 
			
		||||
        for (int i = 0; i < data.length(); i++)
 | 
			
		||||
            this.data.set(i, data.get(i));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @return Thee chunk x coordinat
 | 
			
		||||
     */
 | 
			
		||||
    public final int getX() {
 | 
			
		||||
        return this.x;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @return The chunk z coordinate
 | 
			
		||||
     */
 | 
			
		||||
    public final int getZ() {
 | 
			
		||||
        return this.z;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @return Returns the raw packed chunk data as a byte array
 | 
			
		||||
     */
 | 
			
		||||
    public final byte[] toByteArray() {
 | 
			
		||||
        return this.data.toByteArray();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns the raw bit index of the specified position
 | 
			
		||||
     *
 | 
			
		||||
     * @param x The x position
 | 
			
		||||
     * @param y The y position
 | 
			
		||||
     * @param z The z position
 | 
			
		||||
     * @return The bit index
 | 
			
		||||
     */
 | 
			
		||||
    public static int getPositionIndex(int x, int y, int z) {
 | 
			
		||||
        return (x + (z << 4) + (y << 8)) * 2;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										141
									
								
								src/main/java/baritone/bot/chunk/CachedRegion.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										141
									
								
								src/main/java/baritone/bot/chunk/CachedRegion.java
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,141 @@
 | 
			
		||||
package baritone.bot.chunk;
 | 
			
		||||
 | 
			
		||||
import baritone.bot.pathing.util.PathingBlockType;
 | 
			
		||||
import baritone.bot.utils.GZIPUtils;
 | 
			
		||||
 | 
			
		||||
import java.io.ByteArrayOutputStream;
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
import java.nio.file.Files;
 | 
			
		||||
import java.nio.file.Path;
 | 
			
		||||
import java.nio.file.Paths;
 | 
			
		||||
import java.util.Arrays;
 | 
			
		||||
import java.util.BitSet;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @author Brady
 | 
			
		||||
 * @since 8/3/2018 9:35 PM
 | 
			
		||||
 */
 | 
			
		||||
public final class CachedRegion implements ICachedChunkAccess {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * All of the chunks in this region. A 16x16 array of them.
 | 
			
		||||
     *
 | 
			
		||||
     * I would make these 32x32 regions to be in line with the Anvil format, but 16 is a nice number.
 | 
			
		||||
     */
 | 
			
		||||
    private final CachedChunk[][] chunks = new CachedChunk[32][32];
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * The region x coordinate
 | 
			
		||||
     */
 | 
			
		||||
    private final int x;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * The region z coordinate
 | 
			
		||||
     */
 | 
			
		||||
    private final int z;
 | 
			
		||||
 | 
			
		||||
    CachedRegion(int x, int z) {
 | 
			
		||||
        this.x = x;
 | 
			
		||||
        this.z = z;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public final PathingBlockType getBlockType(int x, int y, int z) {
 | 
			
		||||
        CachedChunk chunk = this.getChunk(x >> 4, z >> 4);
 | 
			
		||||
        if (chunk != null) {
 | 
			
		||||
            return chunk.getBlockType(x, y, z);
 | 
			
		||||
        }
 | 
			
		||||
        return null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public final void updateCachedChunk(int chunkX, int chunkZ, BitSet data) {
 | 
			
		||||
        CachedChunk chunk = this.getChunk(chunkX, chunkZ);
 | 
			
		||||
        if (chunk == null)
 | 
			
		||||
            this.chunks[chunkX][chunkZ] = new CachedChunk(chunkX, chunkZ, data);
 | 
			
		||||
        else
 | 
			
		||||
            chunk.updateContents(data);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private CachedChunk getChunk(int chunkX, int chunkZ) {
 | 
			
		||||
        return this.chunks[chunkX][chunkZ];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public final void save(String directory) {
 | 
			
		||||
        try {
 | 
			
		||||
            Path path = Paths.get(directory);
 | 
			
		||||
            if (!Files.exists(path))
 | 
			
		||||
                Files.createDirectories(path);
 | 
			
		||||
 | 
			
		||||
            ByteArrayOutputStream bos = new ByteArrayOutputStream(32 * 32 * CachedChunk.SIZE_IN_BYTES);
 | 
			
		||||
            for (int z = 0; z < 32; z++) {
 | 
			
		||||
                for (int x = 0; x < 32; x++) {
 | 
			
		||||
                    CachedChunk chunk = this.chunks[x][z];
 | 
			
		||||
                    if (chunk == null) {
 | 
			
		||||
                        bos.write(CachedChunk.EMPTY_CHUNK);
 | 
			
		||||
                    } else {
 | 
			
		||||
                        byte[] chunkBytes = chunk.toByteArray();
 | 
			
		||||
                        bos.write(chunkBytes);
 | 
			
		||||
                        // Messy, but fills the empty 0s that should be trailing to fill up the space.
 | 
			
		||||
                        bos.write(new byte[CachedChunk.SIZE_IN_BYTES - chunkBytes.length]);
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            Path regionFile = getRegionFile(path, this.x, this.z);
 | 
			
		||||
            if (!Files.exists(regionFile))
 | 
			
		||||
                Files.createFile(regionFile);
 | 
			
		||||
 | 
			
		||||
            byte[] compressed = GZIPUtils.compress(bos.toByteArray());
 | 
			
		||||
            if (compressed != null)
 | 
			
		||||
                Files.write(regionFile, compressed);
 | 
			
		||||
        } catch (IOException ignored) {}
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void load(String directory) {
 | 
			
		||||
        try {
 | 
			
		||||
            Path path = Paths.get(directory);
 | 
			
		||||
            if (!Files.exists(path))
 | 
			
		||||
                Files.createDirectories(path);
 | 
			
		||||
 | 
			
		||||
            Path regionFile = getRegionFile(path, this.x, this.z);
 | 
			
		||||
            if (!Files.exists(regionFile))
 | 
			
		||||
                return;
 | 
			
		||||
 | 
			
		||||
            byte[] fileBytes = Files.readAllBytes(regionFile);
 | 
			
		||||
            byte[] decompressed = GZIPUtils.decompress(fileBytes);
 | 
			
		||||
            if (decompressed == null)
 | 
			
		||||
                return;
 | 
			
		||||
 | 
			
		||||
            for (int z = 0; z < 32; z++) {
 | 
			
		||||
                for (int x = 0; x < 32; x++) {
 | 
			
		||||
                    CachedChunk chunk = this.chunks[x][z];
 | 
			
		||||
                    if (chunk != null) {
 | 
			
		||||
                        int index = (x + (z << 5)) * CachedChunk.SIZE_IN_BYTES;
 | 
			
		||||
                        byte[] bytes = Arrays.copyOfRange(decompressed, index, index + CachedChunk.SIZE_IN_BYTES);
 | 
			
		||||
                        BitSet bits = BitSet.valueOf(bytes);
 | 
			
		||||
                        chunk.updateContents(bits);
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        } catch (IOException ignored) {}
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @return The region x coordinate
 | 
			
		||||
     */
 | 
			
		||||
    public final int getX() {
 | 
			
		||||
        return this.x;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @return The region z coordinate
 | 
			
		||||
     */
 | 
			
		||||
    public final int getZ() {
 | 
			
		||||
        return this.z;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static Path getRegionFile(Path cacheDir, int regionX, int regionZ) {
 | 
			
		||||
        return Paths.get(cacheDir.toString() + "\\r." + regionX + "." + regionZ + ".bcr");
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										119
									
								
								src/main/java/baritone/bot/chunk/CachedWorld.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										119
									
								
								src/main/java/baritone/bot/chunk/CachedWorld.java
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,119 @@
 | 
			
		||||
package baritone.bot.chunk;
 | 
			
		||||
 | 
			
		||||
import baritone.bot.pathing.util.PathingBlockType;
 | 
			
		||||
import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
 | 
			
		||||
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
 | 
			
		||||
 | 
			
		||||
import java.util.BitSet;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @author Brady
 | 
			
		||||
 * @since 8/4/2018 12:02 AM
 | 
			
		||||
 */
 | 
			
		||||
public final class CachedWorld implements ICachedChunkAccess {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * The maximum number of regions in any direction from (0,0)
 | 
			
		||||
     */
 | 
			
		||||
    private static final int REGION_MAX = 117188;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * A map of all of the cached regions.
 | 
			
		||||
     */
 | 
			
		||||
    private Long2ObjectMap<CachedRegion> cachedRegions = new Long2ObjectOpenHashMap<>();
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * The directory that the cached region files are saved to
 | 
			
		||||
     */
 | 
			
		||||
    private final String directory;
 | 
			
		||||
 | 
			
		||||
    public CachedWorld(String directory) {
 | 
			
		||||
        this.directory = directory;
 | 
			
		||||
        // Insert an invalid region element
 | 
			
		||||
        cachedRegions.put(0, null);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public final PathingBlockType getBlockType(int x, int y, int z) {
 | 
			
		||||
        CachedRegion region = getRegion(x >> 9, z >> 9);
 | 
			
		||||
        if (region != null) {
 | 
			
		||||
            return region.getBlockType(x, y, z);
 | 
			
		||||
        }
 | 
			
		||||
        return null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public final void updateCachedChunk(int chunkX, int chunkZ, BitSet data) {
 | 
			
		||||
        CachedRegion region = getOrCreateRegion(chunkX >> 5, chunkZ >> 5);
 | 
			
		||||
        if (region != null) {
 | 
			
		||||
            region.updateCachedChunk(chunkX & 31, chunkZ & 31, data);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public final void save() {
 | 
			
		||||
        this.cachedRegions.values().forEach(region -> {
 | 
			
		||||
            if (region != null)
 | 
			
		||||
                region.save(this.directory);
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public final void load() {
 | 
			
		||||
        this.cachedRegions.values().forEach(region -> {
 | 
			
		||||
            if (region != null)
 | 
			
		||||
                region.load(this.directory);
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns the region at the specified region coordinates
 | 
			
		||||
     *
 | 
			
		||||
     * @param regionX The region X coordinate
 | 
			
		||||
     * @param regionZ The region Z coordinate
 | 
			
		||||
     * @return The region located at the specified coordinates
 | 
			
		||||
     */
 | 
			
		||||
    public final CachedRegion getRegion(int regionX, int regionZ) {
 | 
			
		||||
        return cachedRegions.get(getRegionID(regionX, regionZ));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns the region at the specified region coordinates. If a
 | 
			
		||||
     * region is not found, then a new one is created.
 | 
			
		||||
     *
 | 
			
		||||
     * @param regionX The region X coordinate
 | 
			
		||||
     * @param regionZ The region Z coordinate
 | 
			
		||||
     * @return The region located at the specified coordinates
 | 
			
		||||
     */
 | 
			
		||||
    private CachedRegion getOrCreateRegion(int regionX, int regionZ) {
 | 
			
		||||
        return cachedRegions.computeIfAbsent(getRegionID(regionX, regionZ), id -> {
 | 
			
		||||
            CachedRegion newRegion = new CachedRegion(regionX, regionZ);
 | 
			
		||||
            newRegion.load(this.directory);
 | 
			
		||||
            return newRegion;
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns the region ID based on the region coordinates. 0 will be
 | 
			
		||||
     * returned if the specified region coordinates are out of bounds.
 | 
			
		||||
     *
 | 
			
		||||
     * @param regionX The region X coordinate
 | 
			
		||||
     * @param regionZ The region Z coordinate
 | 
			
		||||
     * @return The region ID
 | 
			
		||||
     */
 | 
			
		||||
    private long getRegionID(int regionX, int regionZ) {
 | 
			
		||||
        if (!isRegionInWorld(regionX, regionZ))
 | 
			
		||||
            return 0;
 | 
			
		||||
 | 
			
		||||
        return (long) regionX & 0xFFFFFFFFL | ((long) regionZ & 0xFFFFFFFFL) << 32;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns whether or not the specified region coordinates is within the world bounds.
 | 
			
		||||
     *
 | 
			
		||||
     * @param regionX The region X coordinate
 | 
			
		||||
     * @param regionZ The region Z coordinate
 | 
			
		||||
     * @return Whether or not the region is in world bounds
 | 
			
		||||
     */
 | 
			
		||||
    private boolean isRegionInWorld(int regionX, int regionZ) {
 | 
			
		||||
        return regionX <= REGION_MAX && regionX >= -REGION_MAX && regionZ <= REGION_MAX && regionZ >= -REGION_MAX;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										63
									
								
								src/main/java/baritone/bot/chunk/CachedWorldProvider.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								src/main/java/baritone/bot/chunk/CachedWorldProvider.java
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,63 @@
 | 
			
		||||
package baritone.bot.chunk;
 | 
			
		||||
 | 
			
		||||
import baritone.bot.utils.Helper;
 | 
			
		||||
import baritone.launch.mixins.accessor.IAnvilChunkLoader;
 | 
			
		||||
import baritone.launch.mixins.accessor.IChunkProviderServer;
 | 
			
		||||
import net.minecraft.client.multiplayer.WorldClient;
 | 
			
		||||
import net.minecraft.server.integrated.IntegratedServer;
 | 
			
		||||
import net.minecraft.world.WorldServer;
 | 
			
		||||
 | 
			
		||||
import java.io.File;
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
import java.nio.file.Files;
 | 
			
		||||
import java.nio.file.Path;
 | 
			
		||||
import java.util.HashMap;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
import java.util.function.Consumer;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @author Brady
 | 
			
		||||
 * @since 8/4/2018 11:06 AM
 | 
			
		||||
 */
 | 
			
		||||
public enum CachedWorldProvider implements Helper {
 | 
			
		||||
 | 
			
		||||
    INSTANCE;
 | 
			
		||||
 | 
			
		||||
    private final Map<String, CachedWorld> singlePlayerWorldCache = new HashMap<>();
 | 
			
		||||
 | 
			
		||||
    private CachedWorld currentWorld;
 | 
			
		||||
 | 
			
		||||
    public final CachedWorld getCurrentWorld() {
 | 
			
		||||
        return this.currentWorld;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public final void initWorld(WorldClient world) {
 | 
			
		||||
        IntegratedServer integratedServer;
 | 
			
		||||
        if ((integratedServer = mc.getIntegratedServer()) != null) {
 | 
			
		||||
 | 
			
		||||
            WorldServer localServerWorld = integratedServer.getWorld(world.provider.getDimensionType().getId());
 | 
			
		||||
            IChunkProviderServer provider = (IChunkProviderServer) localServerWorld.getChunkProvider();
 | 
			
		||||
            IAnvilChunkLoader loader = (IAnvilChunkLoader) provider.getChunkLoader();
 | 
			
		||||
 | 
			
		||||
            Path dir = new File(new File(loader.getChunkSaveLocation(), "region"), "cache").toPath();
 | 
			
		||||
            if (!Files.exists(dir)) {
 | 
			
		||||
                try {
 | 
			
		||||
                    Files.createDirectories(dir);
 | 
			
		||||
                } catch (IOException ignored) {}
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            this.currentWorld = this.singlePlayerWorldCache.computeIfAbsent(dir.toString(), CachedWorld::new);
 | 
			
		||||
            this.currentWorld.load();
 | 
			
		||||
        }
 | 
			
		||||
        // TODO: Store server worlds
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public final void closeWorld() {
 | 
			
		||||
        this.currentWorld = null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public final void ifWorldLoaded(Consumer<CachedWorld> currentWorldConsumer) {
 | 
			
		||||
        if (this.currentWorld != null)
 | 
			
		||||
            currentWorldConsumer.accept(this.currentWorld);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										60
									
								
								src/main/java/baritone/bot/chunk/ChunkPacker.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										60
									
								
								src/main/java/baritone/bot/chunk/ChunkPacker.java
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,60 @@
 | 
			
		||||
package baritone.bot.chunk;
 | 
			
		||||
 | 
			
		||||
import baritone.bot.pathing.movement.MovementHelper;
 | 
			
		||||
import baritone.bot.pathing.util.PathingBlockType;
 | 
			
		||||
import baritone.bot.utils.Helper;
 | 
			
		||||
import net.minecraft.block.Block;
 | 
			
		||||
import net.minecraft.block.BlockAir;
 | 
			
		||||
import net.minecraft.block.state.IBlockState;
 | 
			
		||||
import net.minecraft.util.math.BlockPos;
 | 
			
		||||
import net.minecraft.world.chunk.Chunk;
 | 
			
		||||
 | 
			
		||||
import java.util.BitSet;
 | 
			
		||||
 | 
			
		||||
import static net.minecraft.block.Block.NULL_AABB;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @author Brady
 | 
			
		||||
 * @since 8/3/2018 1:09 AM
 | 
			
		||||
 */
 | 
			
		||||
public final class ChunkPacker implements Helper {
 | 
			
		||||
 | 
			
		||||
    private ChunkPacker() {}
 | 
			
		||||
 | 
			
		||||
    public static BitSet createPackedChunk(Chunk chunk) {
 | 
			
		||||
        BitSet bitSet = new BitSet(CachedChunk.SIZE);
 | 
			
		||||
        try {
 | 
			
		||||
            for (int y = 0; y < 256; y++) {
 | 
			
		||||
                for (int z = 0; z < 16; z++) {
 | 
			
		||||
                    for (int x = 0; x < 16; x++) {
 | 
			
		||||
                        int index = CachedChunk.getPositionIndex(x, y, z);
 | 
			
		||||
                        boolean[] bits = getPathingBlockType(new BlockPos(x, y, z), chunk.getBlockState(x, y, z)).getBits();
 | 
			
		||||
                        bitSet.set(index, bits[0]);
 | 
			
		||||
                        bitSet.set(index + 1, bits[1]);
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        } catch (Exception e) {
 | 
			
		||||
            e.printStackTrace();
 | 
			
		||||
        }
 | 
			
		||||
        return bitSet;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static PathingBlockType getPathingBlockType(BlockPos pos, IBlockState state) {
 | 
			
		||||
        Block block = state.getBlock();
 | 
			
		||||
 | 
			
		||||
        if (MovementHelper.isWater(block)) {
 | 
			
		||||
            return PathingBlockType.WATER;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (MovementHelper.avoidWalkingInto(block)) {
 | 
			
		||||
            return PathingBlockType.AVOID;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (block instanceof BlockAir || state.getCollisionBoundingBox(mc.world, pos) == NULL_AABB) {
 | 
			
		||||
            return PathingBlockType.AIR;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return PathingBlockType.SOLID;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										14
									
								
								src/main/java/baritone/bot/chunk/ICachedChunkAccess.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								src/main/java/baritone/bot/chunk/ICachedChunkAccess.java
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,14 @@
 | 
			
		||||
package baritone.bot.chunk;
 | 
			
		||||
 | 
			
		||||
import baritone.bot.pathing.util.IBlockTypeAccess;
 | 
			
		||||
 | 
			
		||||
import java.util.BitSet;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @author Brady
 | 
			
		||||
 * @since 8/4/2018 1:10 AM
 | 
			
		||||
 */
 | 
			
		||||
public interface ICachedChunkAccess extends IBlockTypeAccess {
 | 
			
		||||
 | 
			
		||||
    void updateCachedChunk(int chunkX, int chunkZ, BitSet data);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										40
									
								
								src/main/java/baritone/bot/event/events/WorldEvent.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								src/main/java/baritone/bot/event/events/WorldEvent.java
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,40 @@
 | 
			
		||||
package baritone.bot.event.events;
 | 
			
		||||
 | 
			
		||||
import baritone.bot.event.events.type.EventState;
 | 
			
		||||
import net.minecraft.client.multiplayer.WorldClient;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @author Brady
 | 
			
		||||
 * @since 8/4/2018 3:13 AM
 | 
			
		||||
 */
 | 
			
		||||
public final class WorldEvent {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * The new world that is being loaded. {@code null} if being unloaded.
 | 
			
		||||
     */
 | 
			
		||||
    private final WorldClient world;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * The state of the event
 | 
			
		||||
     */
 | 
			
		||||
    private final EventState state;
 | 
			
		||||
 | 
			
		||||
    public WorldEvent(WorldClient world, EventState state) {
 | 
			
		||||
        this.world = world;
 | 
			
		||||
        this.state = state;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @return The new world that is being loaded. {@code null} if being unloaded.
 | 
			
		||||
     */
 | 
			
		||||
    public final WorldClient getWorld() {
 | 
			
		||||
        return this.world;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @return The state of the event
 | 
			
		||||
     */
 | 
			
		||||
    public final EventState getState() {
 | 
			
		||||
        return this.state;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,17 @@
 | 
			
		||||
package baritone.bot.pathing.util;
 | 
			
		||||
 | 
			
		||||
import baritone.bot.utils.Helper;
 | 
			
		||||
import net.minecraft.util.math.BlockPos;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @author Brady
 | 
			
		||||
 * @since 8/4/2018 2:01 AM
 | 
			
		||||
 */
 | 
			
		||||
public interface IBlockTypeAccess extends Helper {
 | 
			
		||||
 | 
			
		||||
    PathingBlockType getBlockType(int x, int y, int z);
 | 
			
		||||
 | 
			
		||||
    default PathingBlockType getBlockType(BlockPos pos) {
 | 
			
		||||
        return getBlockType(pos.getX(), pos.getY(), pos.getZ());
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,35 @@
 | 
			
		||||
package baritone.bot.pathing.util;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @author Brady
 | 
			
		||||
 * @since 8/4/2018 1:11 AM
 | 
			
		||||
 */
 | 
			
		||||
public enum PathingBlockType {
 | 
			
		||||
 | 
			
		||||
    AIR  (0b00),
 | 
			
		||||
    WATER(0b01),
 | 
			
		||||
    AVOID(0b10),
 | 
			
		||||
    SOLID(0b11);
 | 
			
		||||
 | 
			
		||||
    private final boolean[] bits;
 | 
			
		||||
 | 
			
		||||
    PathingBlockType(int bits) {
 | 
			
		||||
        this.bits = new boolean[] {
 | 
			
		||||
                (bits & 0b10) != 0,
 | 
			
		||||
                (bits & 0b01) != 0
 | 
			
		||||
        };
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public final boolean[] getBits() {
 | 
			
		||||
        return this.bits;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static PathingBlockType fromBits(boolean b1, boolean b2) {
 | 
			
		||||
        for (PathingBlockType type : values())
 | 
			
		||||
            if (type.bits[0] == b1 && type.bits[1] == b2)
 | 
			
		||||
                return type;
 | 
			
		||||
 | 
			
		||||
        // This will never happen, but if it does, assume it's just AIR
 | 
			
		||||
        return PathingBlockType.AIR;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,16 @@
 | 
			
		||||
package baritone.launch.mixins;
 | 
			
		||||
 | 
			
		||||
import net.minecraft.world.chunk.storage.IChunkLoader;
 | 
			
		||||
import net.minecraft.world.gen.ChunkProviderServer;
 | 
			
		||||
import org.spongepowered.asm.mixin.Mixin;
 | 
			
		||||
import org.spongepowered.asm.mixin.gen.Accessor;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @author Brady
 | 
			
		||||
 * @since 8/4/2018 11:33 AM
 | 
			
		||||
 */
 | 
			
		||||
@Mixin(ChunkProviderServer.class)
 | 
			
		||||
public interface MixinChunkProviderServer {
 | 
			
		||||
 | 
			
		||||
    @Accessor IChunkLoader getChunkLoader();
 | 
			
		||||
}
 | 
			
		||||
@@ -1,7 +1,10 @@
 | 
			
		||||
package baritone.launch.mixins;
 | 
			
		||||
 | 
			
		||||
import baritone.bot.Baritone;
 | 
			
		||||
import baritone.bot.event.events.WorldEvent;
 | 
			
		||||
import baritone.bot.event.events.type.EventState;
 | 
			
		||||
import net.minecraft.client.Minecraft;
 | 
			
		||||
import net.minecraft.client.multiplayer.WorldClient;
 | 
			
		||||
import net.minecraft.item.ItemStack;
 | 
			
		||||
import net.minecraft.util.EnumActionResult;
 | 
			
		||||
import net.minecraft.util.math.BlockPos;
 | 
			
		||||
@@ -21,8 +24,8 @@ import org.spongepowered.asm.mixin.injection.callback.LocalCapture;
 | 
			
		||||
@Mixin(Minecraft.class)
 | 
			
		||||
public class MixinMinecraft {
 | 
			
		||||
 | 
			
		||||
    @Shadow
 | 
			
		||||
    private int leftClickCounter;
 | 
			
		||||
    @Shadow private int leftClickCounter;
 | 
			
		||||
    @Shadow public WorldClient world;
 | 
			
		||||
 | 
			
		||||
    @Inject(
 | 
			
		||||
            method = "init",
 | 
			
		||||
@@ -99,4 +102,38 @@ public class MixinMinecraft {
 | 
			
		||||
        bot.getMemory().scanBlock(pos.offset(mc.objectMouseOver.sideHit));
 | 
			
		||||
        bot.getActionHandler().onPlacedBlock(stack, pos);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Inject(
 | 
			
		||||
            method = "loadWorld(Lnet/minecraft/client/multiplayer/WorldClient;Ljava/lang/String;)V",
 | 
			
		||||
            at = @At("HEAD")
 | 
			
		||||
    )
 | 
			
		||||
    private void preLoadWorld(WorldClient world, String loadingMessage, CallbackInfo ci) {
 | 
			
		||||
        // If we're unloading the world but one doesn't exist, ignore it
 | 
			
		||||
        if (this.world == null && world == null)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        Baritone.INSTANCE.getGameEventHandler().onWorldEvent(
 | 
			
		||||
                new WorldEvent(
 | 
			
		||||
                        world,
 | 
			
		||||
                        EventState.PRE
 | 
			
		||||
                )
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Inject(
 | 
			
		||||
            method = "loadWorld(Lnet/minecraft/client/multiplayer/WorldClient;Ljava/lang/String;)V",
 | 
			
		||||
            at = @At("RETURN")
 | 
			
		||||
    )
 | 
			
		||||
    private void postLoadWorld(WorldClient world, String loadingMessage, CallbackInfo ci) {
 | 
			
		||||
        // If we're unloading the world but one doesn't exist, ignore it
 | 
			
		||||
        if (this.world == null && world == null)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        Baritone.INSTANCE.getGameEventHandler().onWorldEvent(
 | 
			
		||||
                new WorldEvent(
 | 
			
		||||
                        world,
 | 
			
		||||
                        EventState.POST
 | 
			
		||||
                )
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,17 @@
 | 
			
		||||
package baritone.launch.mixins.accessor;
 | 
			
		||||
 | 
			
		||||
import net.minecraft.world.chunk.storage.AnvilChunkLoader;
 | 
			
		||||
import org.spongepowered.asm.mixin.Mixin;
 | 
			
		||||
import org.spongepowered.asm.mixin.gen.Accessor;
 | 
			
		||||
 | 
			
		||||
import java.io.File;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @author Brady
 | 
			
		||||
 * @since 8/4/2018 11:36 AM
 | 
			
		||||
 */
 | 
			
		||||
@Mixin(AnvilChunkLoader.class)
 | 
			
		||||
public interface IAnvilChunkLoader {
 | 
			
		||||
 | 
			
		||||
    @Accessor File getChunkSaveLocation();
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,16 @@
 | 
			
		||||
package baritone.launch.mixins.accessor;
 | 
			
		||||
 | 
			
		||||
import net.minecraft.world.chunk.storage.IChunkLoader;
 | 
			
		||||
import net.minecraft.world.gen.ChunkProviderServer;
 | 
			
		||||
import org.spongepowered.asm.mixin.Mixin;
 | 
			
		||||
import org.spongepowered.asm.mixin.gen.Accessor;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @author Brady
 | 
			
		||||
 * @since 8/4/2018 11:33 AM
 | 
			
		||||
 */
 | 
			
		||||
@Mixin(ChunkProviderServer.class)
 | 
			
		||||
public interface IChunkProviderServer {
 | 
			
		||||
 | 
			
		||||
    @Accessor IChunkLoader getChunkLoader();
 | 
			
		||||
}
 | 
			
		||||
@@ -14,6 +14,9 @@
 | 
			
		||||
    "MixinMain",
 | 
			
		||||
    "MixinMinecraft",
 | 
			
		||||
    "MixinNetHandlerPlayClient",
 | 
			
		||||
    "MixinWorldClient"
 | 
			
		||||
    "MixinWorldClient",
 | 
			
		||||
 | 
			
		||||
    "accessor.IAnvilChunkLoader",
 | 
			
		||||
    "accessor.IChunkProviderServer"
 | 
			
		||||
  ]
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user