diff --git a/src/api/java/baritone/api/Settings.java b/src/api/java/baritone/api/Settings.java
index 9130165f7..09fe85cf2 100644
--- a/src/api/java/baritone/api/Settings.java
+++ b/src/api/java/baritone/api/Settings.java
@@ -190,6 +190,15 @@ public final class Settings {
)));
+ /**
+ * A list of blocks to become air
+ *
+ * If a schematic asks for a block on this list, only air will be accepted at that location (and nothing on buildIgnoreBlocks)
+ */
+ public final Setting> okIfAir = new Setting<>(new ArrayList<>(Arrays.asList(
+
+ )));
+
/**
* If this is true, the builder will treat all non-air blocks as correct. It will only place new blocks.
*/
@@ -432,6 +441,11 @@ public final class Settings {
*/
public final Setting simplifyUnloadedYCoord = new Setting<>(true);
+ /**
+ * Whenever a block changes, repack the whole chunk that it's in
+ */
+ public final Setting repackOnAnyBlockChange = new Setting<>(true);
+
/**
* If a movement takes this many ticks more than its initial cost estimate, cancel it
*/
diff --git a/src/launch/java/baritone/launch/mixins/MixinClientPlayNetHandler.java b/src/launch/java/baritone/launch/mixins/MixinClientPlayNetHandler.java
index e31856c4d..15766b98e 100644
--- a/src/launch/java/baritone/launch/mixins/MixinClientPlayNetHandler.java
+++ b/src/launch/java/baritone/launch/mixins/MixinClientPlayNetHandler.java
@@ -17,15 +17,19 @@
package baritone.launch.mixins;
+import baritone.Baritone;
import baritone.api.BaritoneAPI;
import baritone.api.IBaritone;
import baritone.api.event.events.ChunkEvent;
import baritone.api.event.events.type.EventState;
+import baritone.cache.CachedChunk;
import net.minecraft.client.entity.player.ClientPlayerEntity;
import net.minecraft.client.network.play.ClientPlayNetHandler;
+import net.minecraft.network.play.server.SChangeBlockPacket;
import net.minecraft.network.play.server.SChunkDataPacket;
import net.minecraft.network.play.server.SCombatPacket;
-import net.minecraft.network.play.server.SUnloadChunkPacket;
+import net.minecraft.network.play.server.SMultiBlockChangePacket;
+import net.minecraft.util.math.ChunkPos;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
@@ -83,30 +87,62 @@ public class MixinClientPlayNetHandler {
}
@Inject(
- method = "processChunkUnload",
- at = @At("HEAD")
+ method = "handleBlockChange",
+ at = @At("RETURN")
)
- private void preChunkUnload(SUnloadChunkPacket packet, CallbackInfo ci) {
+ private void postHandleBlockChange(SChangeBlockPacket packetIn, CallbackInfo ci) {
+ if (!Baritone.settings().repackOnAnyBlockChange.value) {
+ return;
+ }
+ if (!CachedChunk.BLOCKS_TO_KEEP_TRACK_OF.contains(packetIn.getState().getBlock())) {
+ return;
+ }
for (IBaritone ibaritone : BaritoneAPI.getProvider().getAllBaritones()) {
ClientPlayerEntity player = ibaritone.getPlayerContext().player();
if (player != null && player.connection == (ClientPlayNetHandler) (Object) this) {
ibaritone.getGameEventHandler().onChunkEvent(
- new ChunkEvent(EventState.PRE, ChunkEvent.Type.UNLOAD, packet.getX(), packet.getZ())
+ new ChunkEvent(
+ EventState.POST,
+ ChunkEvent.Type.POPULATE_FULL,
+ packetIn.getPos().getX() >> 4,
+ packetIn.getPos().getZ() >> 4
+ )
);
}
}
}
@Inject(
- method = "processChunkUnload",
+ method = "handleMultiBlockChange",
at = @At("RETURN")
)
- private void postChunkUnload(SUnloadChunkPacket packet, CallbackInfo ci) {
+ private void postHandleMultiBlockChange(SMultiBlockChangePacket packetIn, CallbackInfo ci) {
+ if (!Baritone.settings().repackOnAnyBlockChange.value) {
+ return;
+ }
+ if (packetIn.getChangedBlocks().length == 0) {
+ return;
+ }
+ https://docs.oracle.com/javase/specs/jls/se7/html/jls-14.html#jls-14.15
+ {
+ for (SMultiBlockChangePacket.BlockUpdateData update : packetIn.getChangedBlocks()) {
+ if (CachedChunk.BLOCKS_TO_KEEP_TRACK_OF.contains(update.getBlockState().getBlock())) {
+ break https;
+ }
+ }
+ return;
+ }
+ ChunkPos pos = new ChunkPos(packetIn.getChangedBlocks()[0].getPos());
for (IBaritone ibaritone : BaritoneAPI.getProvider().getAllBaritones()) {
ClientPlayerEntity player = ibaritone.getPlayerContext().player();
if (player != null && player.connection == (ClientPlayNetHandler) (Object) this) {
ibaritone.getGameEventHandler().onChunkEvent(
- new ChunkEvent(EventState.POST, ChunkEvent.Type.UNLOAD, packet.getX(), packet.getZ())
+ new ChunkEvent(
+ EventState.POST,
+ ChunkEvent.Type.POPULATE_FULL,
+ pos.x,
+ pos.z
+ )
);
}
}
diff --git a/src/main/java/baritone/cache/CachedWorld.java b/src/main/java/baritone/cache/CachedWorld.java
index 3cfb8623f..634a79040 100644
--- a/src/main/java/baritone/cache/CachedWorld.java
+++ b/src/main/java/baritone/cache/CachedWorld.java
@@ -27,7 +27,7 @@ import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
import net.minecraft.util.RegistryKey;
import net.minecraft.util.math.BlockPos;
-import net.minecraft.world.World;
+import net.minecraft.util.math.ChunkPos;
import net.minecraft.world.chunk.Chunk;
import java.io.IOException;
@@ -35,6 +35,8 @@ import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.LinkedBlockingQueue;
/**
@@ -58,7 +60,17 @@ public final class CachedWorld implements ICachedWorld, Helper {
*/
private final String directory;
- private final LinkedBlockingQueue toPack = new LinkedBlockingQueue<>();
+ /**
+ * Queue of positions to pack. Refers to the toPackMap, in that every element of this queue will be a
+ * key in that map.
+ */
+ private final LinkedBlockingQueue toPackQueue = new LinkedBlockingQueue<>();
+
+ /**
+ * All chunk positions pending packing. This map will be updated in-place if a new update to the chunk occurs
+ * while waiting in the queue for the packer thread to get to it.
+ */
+ private final Map toPackMap = new ConcurrentHashMap<>();
private final RegistryKey dimension;
@@ -91,10 +103,8 @@ public final class CachedWorld implements ICachedWorld, Helper {
@Override
public final void queueForPacking(Chunk chunk) {
- try {
- toPack.put(chunk);
- } catch (InterruptedException e) {
- e.printStackTrace();
+ if (toPackMap.put(chunk.getPos(), chunk) == null) {
+ toPackQueue.add(chunk.getPos());
}
}
@@ -295,13 +305,9 @@ public final class CachedWorld implements ICachedWorld, Helper {
public void run() {
while (true) {
- // TODO: Add CachedWorld unloading to remove the redundancy of having this
- LinkedBlockingQueue queue = toPack;
- if (queue == null) {
- break;
- }
try {
- Chunk chunk = queue.take();
+ ChunkPos pos = toPackQueue.take();
+ Chunk chunk = toPackMap.remove(pos);
CachedChunk cached = ChunkPacker.pack(chunk);
CachedWorld.this.updateCachedChunk(cached);
//System.out.println("Processed chunk at " + chunk.x + "," + chunk.z);
diff --git a/src/main/java/baritone/process/BuilderProcess.java b/src/main/java/baritone/process/BuilderProcess.java
index 6f9b85bea..62cee7bf9 100644
--- a/src/main/java/baritone/process/BuilderProcess.java
+++ b/src/main/java/baritone/process/BuilderProcess.java
@@ -791,10 +791,13 @@ public final class BuilderProcess extends BaritoneProcessHelper implements IBuil
if (desired == null) {
return true;
}
- if (current.getBlock() instanceof AirBlock && desired.getBlock() instanceof AirBlock) {
+ if (current.getBlock() instanceof BlockLiquid && Baritone.settings().okIfWater.value) {
return true;
}
- if ((current.getBlock() == Blocks.WATER || current.getBlock() == Blocks.LAVA) && Baritone.settings().okIfWater.value) {
+ if (current.getBlock() instanceof BlockAir && Baritone.settings().okIfAir.value.contains(desired.getBlock())) {
+ return true;
+ }
+ if (desired.getBlock() instanceof BlockAir && Baritone.settings().buildIgnoreBlocks.value.contains(current.getBlock())) {
return true;
}
// TODO more complicated comparison logic I guess