From 4bec49de5bd0c99d094b24dd9c7450c5b4332ddd Mon Sep 17 00:00:00 2001 From: Leijurv Date: Mon, 22 Apr 2019 14:34:31 -0700 Subject: [PATCH] filter explored chunks with json --- scripts/proguard.pro | 2 + .../baritone/api/process/IExploreProcess.java | 4 + .../api/utils/ExampleBaritoneControl.java | 18 ++ .../java/baritone/api/utils/MyChunkPos.java | 31 ++++ .../baritone/process/BackfillProcess.java | 2 +- .../java/baritone/process/ExploreProcess.java | 175 +++++++++++++++--- 6 files changed, 210 insertions(+), 22 deletions(-) create mode 100644 src/api/java/baritone/api/utils/MyChunkPos.java diff --git a/scripts/proguard.pro b/scripts/proguard.pro index 4bed6b5d..bb8df2ae 100644 --- a/scripts/proguard.pro +++ b/scripts/proguard.pro @@ -21,6 +21,8 @@ -keep class baritone.BaritoneProvider -keep class baritone.api.IBaritoneProvider +-keep class baritone.api.utils.MyChunkPos { *; } # even in standalone we need to keep this for gson reflect + # setting names are reflected from field names, so keep field names -keepclassmembers class baritone.api.Settings { public ; diff --git a/src/api/java/baritone/api/process/IExploreProcess.java b/src/api/java/baritone/api/process/IExploreProcess.java index bf30fa22..811a509f 100644 --- a/src/api/java/baritone/api/process/IExploreProcess.java +++ b/src/api/java/baritone/api/process/IExploreProcess.java @@ -17,6 +17,10 @@ package baritone.api.process; +import java.nio.file.Path; + public interface IExploreProcess extends IBaritoneProcess { void explore(int centerX, int centerZ); + + void applyJsonFilter(Path path, boolean invert) throws Exception; } diff --git a/src/api/java/baritone/api/utils/ExampleBaritoneControl.java b/src/api/java/baritone/api/utils/ExampleBaritoneControl.java index f758d15e..34761a0b 100644 --- a/src/api/java/baritone/api/utils/ExampleBaritoneControl.java +++ b/src/api/java/baritone/api/utils/ExampleBaritoneControl.java @@ -39,6 +39,7 @@ import net.minecraft.item.ItemStack; import net.minecraft.util.math.BlockPos; import net.minecraft.world.chunk.Chunk; +import java.nio.file.Path; import java.util.*; public class ExampleBaritoneControl implements Helper, AbstractGameEventListener { @@ -429,6 +430,23 @@ public class ExampleBaritoneControl implements Helper, AbstractGameEventListener logDirect("Following " + toFollow.get()); return true; } + if (msg.startsWith("explorefilter")) { + // explorefilter blah.json + // means that entries in blah.json are already explored + // explorefilter blah.json invert + // means that entries in blah.json are NOT already explored + String path = msg.substring("explorefilter".length()).trim(); + String[] parts = path.split(" "); + Path path1 = Minecraft.getMinecraft().gameDir.toPath().resolve(parts[0]); + try { + baritone.getExploreProcess().applyJsonFilter(path1, parts.length > 1); + logDirect("Loaded filter"); + } catch (Exception e) { + e.printStackTrace(); + logDirect("Unable to load " + path1); + } + return true; + } if (msg.equals("reloadall")) { baritone.getWorldProvider().getCurrentWorld().getCachedWorld().reloadAllFromDisk(); logDirect("ok"); diff --git a/src/api/java/baritone/api/utils/MyChunkPos.java b/src/api/java/baritone/api/utils/MyChunkPos.java new file mode 100644 index 00000000..5748a13d --- /dev/null +++ b/src/api/java/baritone/api/utils/MyChunkPos.java @@ -0,0 +1,31 @@ +/* + * 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.api.utils; + +/** + * Need a non obfed chunkpos that we can load using GSON + */ +public class MyChunkPos { + public int x; + public int z; + + @Override + public String toString() { + return x + ", " + z; + } +} \ No newline at end of file diff --git a/src/main/java/baritone/process/BackfillProcess.java b/src/main/java/baritone/process/BackfillProcess.java index be16f8b4..8567a049 100644 --- a/src/main/java/baritone/process/BackfillProcess.java +++ b/src/main/java/baritone/process/BackfillProcess.java @@ -123,7 +123,7 @@ public class BackfillProcess extends BaritoneProcessHelper { blocksToReplace.clear(); } } - + @Override public String displayName0() { return "Backfill"; diff --git a/src/main/java/baritone/process/ExploreProcess.java b/src/main/java/baritone/process/ExploreProcess.java index b848b679..6818e45b 100644 --- a/src/main/java/baritone/process/ExploreProcess.java +++ b/src/main/java/baritone/process/ExploreProcess.java @@ -25,10 +25,18 @@ import baritone.api.pathing.goals.GoalXZ; import baritone.api.process.IExploreProcess; import baritone.api.process.PathingCommand; import baritone.api.process.PathingCommandType; +import baritone.api.utils.MyChunkPos; import baritone.cache.CachedWorld; import baritone.utils.BaritoneProcessHelper; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import it.unimi.dsi.fastutil.longs.LongOpenHashSet; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.ChunkPos; +import java.io.InputStreamReader; +import java.nio.file.Files; +import java.nio.file.Path; import java.util.ArrayList; import java.util.List; @@ -36,6 +44,8 @@ public class ExploreProcess extends BaritoneProcessHelper implements IExplorePro private BlockPos explorationOrigin; + private IChunkFilter filter; + public ExploreProcess(Baritone baritone) { super(baritone); } @@ -50,6 +60,21 @@ public class ExploreProcess extends BaritoneProcessHelper implements IExplorePro explorationOrigin = new BlockPos(centerX, 0, centerZ); } + @Override + public void applyJsonFilter(Path path, boolean invert) throws Exception { + filter = new JsonChunkFilter(path, invert); + } + + public IChunkFilter calcFilter() { + IChunkFilter filter; + if (this.filter != null) { + filter = new EitherChunk(this.filter, new BaritoneChunkCache()); + } else { + filter = new BaritoneChunkCache(); + } + return filter; + } + @Override public PathingCommand onTick(boolean calcFailed, boolean isSafeToCancel) { if (calcFailed) { @@ -57,7 +82,13 @@ public class ExploreProcess extends BaritoneProcessHelper implements IExplorePro onLostControl(); return null; } - Goal[] closestUncached = closestUncachedChunks(explorationOrigin); + IChunkFilter filter = calcFilter(); + if (filter.finished()) { + logDirect("Explored all chunks"); + onLostControl(); + return null; + } + Goal[] closestUncached = closestUncachedChunks(explorationOrigin, filter); if (closestUncached == null) { logDebug("awaiting region load from disk"); return new PathingCommand(null, PathingCommandType.REQUEST_PAUSE); @@ -65,10 +96,9 @@ public class ExploreProcess extends BaritoneProcessHelper implements IExplorePro return new PathingCommand(new GoalComposite(closestUncached), PathingCommandType.FORCE_REVALIDATE_GOAL_AND_PATH); } - private Goal[] closestUncachedChunks(BlockPos center) { + private Goal[] closestUncachedChunks(BlockPos center, IChunkFilter filter) { int chunkX = center.getX() >> 4; int chunkZ = center.getZ() >> 4; - ICachedWorld cache = baritone.getWorldProvider().getCurrentWorld().getCachedWorld(); for (int dist = 0; ; dist++) { List centers = new ArrayList<>(); for (int dx = -dist; dx <= dist; dx++) { @@ -77,32 +107,28 @@ public class ExploreProcess extends BaritoneProcessHelper implements IExplorePro if (trueDist != dist) { continue; // not considering this one just yet in our expanding search } + switch (filter.isAlreadyExplored(chunkX + dx, chunkZ + dz)) { + case UNKNOWN: + return null; // awaiting load + case NOT_EXPLORED: + break; // note: this breaks the switch not the for + case EXPLORED: + continue; // note: this continues the for + } int centerX = (chunkX + dx) * 16 + 8; int centerZ = (chunkZ + dz) * 18 + 8; - - if (cache.isCached(centerX, centerZ)) { - continue; - } - if (!((CachedWorld) cache).regionLoaded(centerX, centerZ)) { - Baritone.getExecutor().execute(() -> { - ((CachedWorld) cache).tryLoadFromDisk(centerX >> 9, centerZ >> 9); - }); - return null; // we still need to load regions from disk in order to decide properly - } - int offsetCenterX = centerX; - int offsetCenterZ = centerZ; int offset = 16 * Baritone.settings().worldExploringChunkOffset.value; if (dx < 0) { - offsetCenterX -= offset; + centerX -= offset; } else { - offsetCenterX += offset; + centerX += offset; } if (dz < 0) { - offsetCenterZ -= offset; + centerZ -= offset; } else { - offsetCenterZ += offset; + centerZ += offset; } - centers.add(new BlockPos(offsetCenterX, 0, offsetCenterZ)); + centers.add(new BlockPos(centerX, 0, centerZ)); } } if (centers.size() > Baritone.settings().exploreChunkSetMinimumSize.value) { @@ -111,6 +137,113 @@ public class ExploreProcess extends BaritoneProcessHelper implements IExplorePro } } + private enum Status { + EXPLORED, NOT_EXPLORED, UNKNOWN; + } + + private interface IChunkFilter { + Status isAlreadyExplored(int chunkX, int chunkZ); + + boolean finished(); + } + + private class BaritoneChunkCache implements IChunkFilter { + + private final ICachedWorld cache = baritone.getWorldProvider().getCurrentWorld().getCachedWorld(); + + @Override + public Status isAlreadyExplored(int chunkX, int chunkZ) { + int centerX = chunkX << 4; + int centerZ = chunkZ << 4; + if (cache.isCached(centerX, centerZ)) { + return Status.EXPLORED; + } + if (!((CachedWorld) cache).regionLoaded(centerX, centerZ)) { + Baritone.getExecutor().execute(() -> { + ((CachedWorld) cache).tryLoadFromDisk(centerX >> 9, centerZ >> 9); + }); + return Status.UNKNOWN; // we still need to load regions from disk in order to decide properly + } + return Status.NOT_EXPLORED; + } + + @Override + public boolean finished() { + return false; + } + } + + private class JsonChunkFilter implements IChunkFilter { + private final boolean invert; // if true, the list is interpreted as a list of chunks that are NOT explored, if false, the list is interpreted as a list of chunks that ARE explored + private final LongOpenHashSet inFilter; + private final MyChunkPos[] positions; + + private JsonChunkFilter(Path path, boolean invert) throws Exception { // ioexception, json exception, etc + this.invert = invert; + Gson gson = new GsonBuilder().create(); + positions = gson.fromJson(new InputStreamReader(Files.newInputStream(path)), MyChunkPos[].class); + logDirect("Loaded " + positions.length + " positions"); + inFilter = new LongOpenHashSet(); + for (MyChunkPos mcp : positions) { + inFilter.add(ChunkPos.asLong(mcp.x, mcp.z)); + } + } + + @Override + public Status isAlreadyExplored(int chunkX, int chunkZ) { + if (inFilter.contains(ChunkPos.asLong(chunkX, chunkZ)) ^ invert) { + // either it's on the list of explored chunks, or it's not on the list of unexplored chunks + // either way, we have it + return Status.EXPLORED; + } else { + // either it's not on the list of explored chunks, or it's on the list of unexplored chunks + // either way, it depends on if baritone has cached it so defer to that + return Status.UNKNOWN; + } + } + + @Override + public boolean finished() { + if (!invert) { + // if invert is false, anything not on the list is uncached + return false; + } + // but if invert is true, anything not on the list IS assumed cached + // so we are done if everything on our list is cached! + BaritoneChunkCache bcc = new BaritoneChunkCache(); + for (MyChunkPos pos : positions) { + if (bcc.isAlreadyExplored(pos.x, pos.z) != Status.EXPLORED) { + // either waiting for it or dont have it at all + return false; + } + } + return true; // we have everything cached + } + } + + private class EitherChunk implements IChunkFilter { + private final IChunkFilter a; + private final IChunkFilter b; + + private EitherChunk(IChunkFilter a, IChunkFilter b) { + this.a = a; + this.b = b; + } + + @Override + public Status isAlreadyExplored(int chunkX, int chunkZ) { + if (a.isAlreadyExplored(chunkX, chunkZ) == Status.EXPLORED) { + return Status.EXPLORED; + } + return b.isAlreadyExplored(chunkX, chunkZ); + } + + @Override + public boolean finished() { + return a.finished() || b.finished(); + } + } + @Override public void onLostControl() { explorationOrigin = null; @@ -118,6 +251,6 @@ public class ExploreProcess extends BaritoneProcessHelper implements IExplorePro @Override public String displayName0() { - return "Exploring around " + explorationOrigin + ", currently going to " + new GoalComposite(closestUncachedChunks(explorationOrigin)); + return "Exploring around " + explorationOrigin + ", currently going to " + new GoalComposite(closestUncachedChunks(explorationOrigin, calcFilter())); } }