From 3f7b5525779c17a79f19ad333c5f98fe2d3e1abf Mon Sep 17 00:00:00 2001 From: Brady Date: Tue, 7 Aug 2018 19:41:13 -0500 Subject: [PATCH] Cached Chunk Path Finding --- .../java/baritone/bot/GameEventHandler.java | 46 ++++++++++++++++--- .../java/baritone/bot/chunk/CachedRegion.java | 12 +++++ .../java/baritone/bot/chunk/CachedWorld.java | 10 +++- .../bot/chunk/CachedWorldProvider.java | 18 ++++++++ .../bot/pathing/calc/AStarPathFinder.java | 9 +++- .../bot/utils/BlockStateInterface.java | 37 +++++++++++++-- .../java/baritone/bot/utils/Rotation.java | 2 +- 7 files changed, 122 insertions(+), 12 deletions(-) diff --git a/src/main/java/baritone/bot/GameEventHandler.java b/src/main/java/baritone/bot/GameEventHandler.java index 504f570f3..f7f5dffc7 100755 --- a/src/main/java/baritone/bot/GameEventHandler.java +++ b/src/main/java/baritone/bot/GameEventHandler.java @@ -1,10 +1,20 @@ package baritone.bot; import baritone.bot.behavior.Behavior; +import baritone.bot.chunk.CachedWorld; +import baritone.bot.chunk.CachedWorldProvider; +import baritone.bot.chunk.ChunkPacker; import baritone.bot.event.IGameEventListener; import baritone.bot.event.events.*; +import baritone.bot.event.events.type.EventState; +import baritone.bot.utils.Helper; +import net.minecraft.client.renderer.BufferBuilder; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.client.renderer.vertex.DefaultVertexFormats; import net.minecraft.client.settings.KeyBinding; import org.lwjgl.input.Keyboard; +import org.lwjgl.opengl.GL11; import java.util.function.Consumer; @@ -12,7 +22,7 @@ import java.util.function.Consumer; * @author Brady * @since 7/31/2018 11:04 PM */ -public final class GameEventHandler implements IGameEventListener { +public final class GameEventHandler implements IGameEventListener, Helper { GameEventHandler() {} @@ -52,8 +62,6 @@ public final class GameEventHandler implements IGameEventListener { @Override public void onChunkEvent(ChunkEvent event) { - /* - EventState state = event.getState(); ChunkEvent.Type type = event.getType(); @@ -72,19 +80,23 @@ public final class GameEventHandler implements IGameEventListener { world.updateCachedChunk(event.getX(), event.getZ(), ChunkPacker.createPackedChunk(mc.world.getChunk(event.getX(), event.getZ())))); } - */ dispatch(behavior -> behavior.onChunkEvent(event)); } @Override public void onRenderPass(RenderEvent event) { + /* + CachedWorldProvider.INSTANCE.ifWorldLoaded(world -> world.forEachRegion(region -> region.forEachChunk(chunk -> { + drawChunkLine(region.getX() * 512 + chunk.getX() * 16, region.getZ() * 512 + chunk.getZ() * 16, event.getPartialTicks()); + }))); + */ + dispatch(behavior -> behavior.onRenderPass(event)); } @Override public void onWorldEvent(WorldEvent event) { - /* CachedWorldProvider cache = CachedWorldProvider.INSTANCE; switch (event.getState()) { @@ -97,7 +109,6 @@ public final class GameEventHandler implements IGameEventListener { cache.initWorld(event.getWorld()); break; } - */ dispatch(behavior -> behavior.onWorldEvent(event)); } @@ -115,4 +126,27 @@ public final class GameEventHandler implements IGameEventListener { private void dispatch(Consumer dispatchFunction) { Baritone.INSTANCE.getBehaviors().stream().filter(Behavior::isEnabled).forEach(dispatchFunction); } + + private void drawChunkLine(int posX, int posZ, float partialTicks) { + GlStateManager.enableBlend(); + GlStateManager.tryBlendFuncSeparate(770, 771, 1, 0); + GlStateManager.color(1.0F, 1.0F, 0.0F, 0.4F); + GL11.glLineWidth(2.0F); + GlStateManager.disableTexture2D(); + + Tessellator tessellator = Tessellator.getInstance(); + BufferBuilder buffer = tessellator.getBuffer(); + double d0 = mc.getRenderManager().viewerPosX; + double d1 = mc.getRenderManager().viewerPosY; + double d2 = mc.getRenderManager().viewerPosZ; + buffer.begin(3, DefaultVertexFormats.POSITION); + buffer.pos(posX - d0, 0 - d1, posZ - d2).endVertex(); + buffer.pos(posX - d0, 256 - d1, posZ - d2).endVertex(); + tessellator.draw(); + + GlStateManager.enableDepth(); + GlStateManager.depthMask(true); + GlStateManager.enableTexture2D(); + GlStateManager.disableBlend(); + } } diff --git a/src/main/java/baritone/bot/chunk/CachedRegion.java b/src/main/java/baritone/bot/chunk/CachedRegion.java index b0362ca2b..a44370971 100644 --- a/src/main/java/baritone/bot/chunk/CachedRegion.java +++ b/src/main/java/baritone/bot/chunk/CachedRegion.java @@ -11,6 +11,7 @@ import java.nio.file.Path; import java.nio.file.Paths; import java.util.Arrays; import java.util.BitSet; +import java.util.function.Consumer; import java.util.zip.GZIPOutputStream; /** @@ -62,6 +63,17 @@ public final class CachedRegion implements ICachedChunkAccess { return this.chunks[chunkX][chunkZ]; } + public void forEachChunk(Consumer consumer) { + for (int x = 0; x < 32; x++) { + for (int z = 0; z < 32; z++) { + CachedChunk chunk = getChunk(x, z); + if (chunk != null) { + consumer.accept(chunk); + } + } + } + } + public final void save(String directory) { try { Path path = Paths.get(directory); diff --git a/src/main/java/baritone/bot/chunk/CachedWorld.java b/src/main/java/baritone/bot/chunk/CachedWorld.java index 24bea82a6..32aa3b035 100644 --- a/src/main/java/baritone/bot/chunk/CachedWorld.java +++ b/src/main/java/baritone/bot/chunk/CachedWorld.java @@ -5,6 +5,7 @@ import it.unimi.dsi.fastutil.longs.Long2ObjectMap; import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; import java.util.BitSet; +import java.util.function.Consumer; /** * @author Brady @@ -83,7 +84,7 @@ public final class CachedWorld implements ICachedChunkAccess { * @param regionZ The region Z coordinate * @return The region located at the specified coordinates */ - private CachedRegion getOrCreateRegion(int regionX, int regionZ) { + CachedRegion getOrCreateRegion(int regionX, int regionZ) { return cachedRegions.computeIfAbsent(getRegionID(regionX, regionZ), id -> { CachedRegion newRegion = new CachedRegion(regionX, regionZ); newRegion.load(this.directory); @@ -91,6 +92,13 @@ public final class CachedWorld implements ICachedChunkAccess { }); } + public void forEachRegion(Consumer consumer) { + this.cachedRegions.forEach((id, r) -> { + if (r != null) + consumer.accept(r); + }); + } + /** * Returns the region ID based on the region coordinates. 0 will be * returned if the specified region coordinates are out of bounds. diff --git a/src/main/java/baritone/bot/chunk/CachedWorldProvider.java b/src/main/java/baritone/bot/chunk/CachedWorldProvider.java index fb2e69fde..560a6ca55 100644 --- a/src/main/java/baritone/bot/chunk/CachedWorldProvider.java +++ b/src/main/java/baritone/bot/chunk/CachedWorldProvider.java @@ -14,6 +14,8 @@ import java.nio.file.Path; import java.util.HashMap; import java.util.Map; import java.util.function.Consumer; +import java.util.regex.Matcher; +import java.util.regex.Pattern; /** * @author Brady @@ -23,6 +25,8 @@ public enum CachedWorldProvider implements Helper { INSTANCE; + private static final Pattern REGION_REGEX = Pattern.compile("r\\.(-?[0-9]+)\\.(-?[0-9]+)\\.bcr"); + private final Map singlePlayerWorldCache = new HashMap<>(); private CachedWorld currentWorld; @@ -47,6 +51,20 @@ public enum CachedWorldProvider implements Helper { } this.currentWorld = this.singlePlayerWorldCache.computeIfAbsent(dir.toString(), CachedWorld::new); + + try { + Files.list(dir).forEach(path -> { + String file = path.getFileName().toString(); + Matcher matcher = REGION_REGEX.matcher(file); + if (matcher.matches()) { + int rx = Integer.parseInt(matcher.group(1)); + int ry = Integer.parseInt(matcher.group(2)); + // Recognize the region for when we load from file + this.currentWorld.getOrCreateRegion(rx, ry); + } + }); + } catch (Exception ignored) {} + this.currentWorld.load(); } // TODO: Store server worlds diff --git a/src/main/java/baritone/bot/pathing/calc/AStarPathFinder.java b/src/main/java/baritone/bot/pathing/calc/AStarPathFinder.java index 0f0fd537e..da6a29a8d 100644 --- a/src/main/java/baritone/bot/pathing/calc/AStarPathFinder.java +++ b/src/main/java/baritone/bot/pathing/calc/AStarPathFinder.java @@ -1,5 +1,6 @@ package baritone.bot.pathing.calc; +import baritone.bot.chunk.CachedWorldProvider; import baritone.bot.pathing.calc.openset.BinaryHeapOpenSet; import baritone.bot.pathing.calc.openset.IOpenSet; import baritone.bot.pathing.goals.Goal; @@ -83,7 +84,13 @@ public class AStarPathFinder extends AbstractNodeCostSearch { if (movementToGetToNeighbor == null) { continue; } - if (Minecraft.getMinecraft().world.getChunk(movementToGetToNeighbor.getDest()) instanceof EmptyChunk) { + + boolean isPositionCached = false; + if (CachedWorldProvider.INSTANCE.getCurrentWorld() != null) + if (CachedWorldProvider.INSTANCE.getCurrentWorld().getBlockType(movementToGetToNeighbor.getDest()) != null) + isPositionCached = true; + + if (Minecraft.getMinecraft().world.getChunk(movementToGetToNeighbor.getDest()) instanceof EmptyChunk && !isPositionCached) { numEmptyChunk++; continue; } diff --git a/src/main/java/baritone/bot/utils/BlockStateInterface.java b/src/main/java/baritone/bot/utils/BlockStateInterface.java index 2b51ac566..2d01f2946 100644 --- a/src/main/java/baritone/bot/utils/BlockStateInterface.java +++ b/src/main/java/baritone/bot/utils/BlockStateInterface.java @@ -1,16 +1,47 @@ package baritone.bot.utils; +import baritone.bot.chunk.CachedWorld; +import baritone.bot.chunk.CachedWorldProvider; +import baritone.bot.pathing.util.PathingBlockType; import net.minecraft.block.Block; import net.minecraft.block.BlockFalling; import net.minecraft.block.BlockLiquid; import net.minecraft.block.state.IBlockState; -import net.minecraft.client.Minecraft; import net.minecraft.init.Blocks; import net.minecraft.util.math.BlockPos; +import net.minecraft.world.chunk.Chunk; + +public class BlockStateInterface implements Helper { -public class BlockStateInterface { public static IBlockState get(BlockPos pos) { // wrappers for future chunk caching capability - return Minecraft.getMinecraft().world.getBlockState(pos); + + // Invalid vertical position + if (pos.getY() < 0 || pos.getY() >= 256) + return Blocks.AIR.getDefaultState(); + + Chunk chunk = mc.world.getChunk(pos); + if (chunk.isLoaded()) { + return chunk.getBlockState(pos); + } else { + CachedWorld world = CachedWorldProvider.INSTANCE.getCurrentWorld(); + if (world != null) { + PathingBlockType type = world.getBlockType(pos); + if (type != null) { + switch (type) { + case AIR: + return Blocks.AIR.getDefaultState(); + case WATER: + return Blocks.WATER.getDefaultState(); + case AVOID: + return Blocks.LAVA.getDefaultState(); + case SOLID: + return Blocks.OBSIDIAN.getDefaultState(); + } + } + } + } + + return Blocks.AIR.getDefaultState(); } public static Block getBlock(BlockPos pos) { diff --git a/src/main/java/baritone/bot/utils/Rotation.java b/src/main/java/baritone/bot/utils/Rotation.java index 177c879a4..eda160020 100644 --- a/src/main/java/baritone/bot/utils/Rotation.java +++ b/src/main/java/baritone/bot/utils/Rotation.java @@ -4,7 +4,7 @@ import net.minecraft.util.Tuple; public class Rotation extends Tuple { - public Rotation(Float yaw, Float pitch) { + public Rotation(float yaw, float pitch) { super(yaw, pitch); } }