Initial Chunk Caching Commit
The actual code to run is commented out in GameEventHandler, uncomment for testing.
This commit is contained in:
parent
4fc74a85c1
commit
10c847074a
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"
|
||||
]
|
||||
}
|
Loading…
Reference in New Issue
Block a user