From 7ba987e7f71e88b6f3c8e93ae4d45b2523982d61 Mon Sep 17 00:00:00 2001 From: Leijurv Date: Mon, 3 Dec 2018 17:20:56 -0800 Subject: [PATCH] save containers and echests --- src/main/java/baritone/Baritone.java | 4 + .../baritone/behavior/MemoryBehavior.java | 86 ++++++++++++++++-- .../java/baritone/cache/ContainerMemory.java | 88 +++++++++++++++++-- src/main/java/baritone/cache/WorldData.java | 10 +++ .../java/baritone/cache/WorldProvider.java | 4 +- .../utils/ExampleBaritoneControl.java | 37 ++++++++ 6 files changed, 212 insertions(+), 17 deletions(-) diff --git a/src/main/java/baritone/Baritone.java b/src/main/java/baritone/Baritone.java index 3f774842..1353dcc6 100755 --- a/src/main/java/baritone/Baritone.java +++ b/src/main/java/baritone/Baritone.java @@ -164,6 +164,10 @@ public class Baritone implements IBaritone { return this.playerContext; } + public MemoryBehavior getMemoryBehavior() { + return this.memoryBehavior; + } + @Override public FollowProcess getFollowProcess() { return this.followProcess; diff --git a/src/main/java/baritone/behavior/MemoryBehavior.java b/src/main/java/baritone/behavior/MemoryBehavior.java index d084eedc..06627d7e 100644 --- a/src/main/java/baritone/behavior/MemoryBehavior.java +++ b/src/main/java/baritone/behavior/MemoryBehavior.java @@ -29,6 +29,7 @@ import baritone.utils.BlockStateInterface; import net.minecraft.block.Block; import net.minecraft.block.BlockBed; import net.minecraft.init.Blocks; +import net.minecraft.item.ItemStack; import net.minecraft.network.Packet; import net.minecraft.network.play.client.CPacketCloseWindow; import net.minecraft.network.play.client.CPacketPlayerTryUseItemOnBlock; @@ -38,9 +39,12 @@ import net.minecraft.tileentity.TileEntity; import net.minecraft.tileentity.TileEntityLockable; import net.minecraft.util.EnumFacing; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.text.TextComponentTranslation; -import java.util.ArrayList; -import java.util.List; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.*; /** * @author Brady @@ -50,6 +54,8 @@ public final class MemoryBehavior extends Behavior { private final List futureInventories = new ArrayList<>(); // this is per-bot + private Integer enderChestWindowId; // nae nae + public MemoryBehavior(Baritone baritone) { super(baritone); } @@ -70,10 +76,7 @@ public final class MemoryBehavior extends Behavior { CPacketPlayerTryUseItemOnBlock packet = event.cast(); TileEntity tileEntity = ctx.world().getTileEntity(packet.getPos()); - if (tileEntity != null) { - System.out.println(tileEntity.getPos() + " " + packet.getPos()); - System.out.println(tileEntity); - } + // if tileEntity is an ender chest, we don't need to do anything. ender chests are treated the same regardless of what coordinate right clicked // Ensure the TileEntity is a container of some sort if (tileEntity instanceof TileEntityLockable) { @@ -96,6 +99,7 @@ public final class MemoryBehavior extends Behavior { if (p instanceof CPacketCloseWindow) { updateInventory(); + getCurrent().save(); } } } @@ -111,7 +115,14 @@ public final class MemoryBehavior extends Behavior { futureInventories.removeIf(i -> System.nanoTime() / 1000000L - i.time > 1000); System.out.println("Received packet " + packet.getGuiId() + " " + packet.getEntityId() + " " + packet.getSlotCount() + " " + packet.getWindowId()); - + System.out.println(packet.getWindowTitle()); + if (packet.getWindowTitle() instanceof TextComponentTranslation) { + // title is not customized (i.e. this isn't just a renamed shulker) + if (((TextComponentTranslation) packet.getWindowTitle()).getKey().equals("container.enderchest")) { + enderChestWindowId = packet.getWindowId(); + return; + } + } futureInventories.stream() .filter(i -> i.type.equals(packet.getGuiId()) && i.slots == packet.getSlotCount()) .findFirst().ifPresent(matched -> { @@ -125,6 +136,7 @@ public final class MemoryBehavior extends Behavior { if (p instanceof SPacketCloseWindow) { updateInventory(); + getCurrent().save(); } } } @@ -143,10 +155,24 @@ public final class MemoryBehavior extends Behavior { private void updateInventory() { - getCurrentContainer().getInventoryFromWindow(ctx.player().openContainer.windowId).ifPresent(inventory -> inventory.updateFromOpenWindow(ctx)); + int windowId = ctx.player().openContainer.windowId; + if (enderChestWindowId != null) { + if (windowId == enderChestWindowId) { + getCurrent().contents = ctx.player().openContainer.getInventory().subList(0, 27); + } else { + getCurrent().save(); + enderChestWindowId = null; + } + } + if (getCurrentContainer() != null) { + getCurrentContainer().getInventoryFromWindow(windowId).ifPresent(inventory -> inventory.updateFromOpenWindow(ctx)); + } } private ContainerMemory getCurrentContainer() { + if (baritone.getWorldProvider().getCurrentWorld() == null) { + return null; + } return (ContainerMemory) baritone.getWorldProvider().getCurrentWorld().getContainerMemory(); } @@ -198,4 +224,48 @@ public final class MemoryBehavior extends Behavior { System.out.println("Future inventory created " + time + " " + slots + " " + type + " " + pos); } } + + public Optional> echest() { + return Optional.ofNullable(getCurrent().contents).map(Collections::unmodifiableList); + } + + public EnderChestMemory getCurrent() { + Path path = baritone.getWorldProvider().getCurrentWorld().directory; + return EnderChestMemory.getByServerAndPlayer(path.getParent(), ctx.player().getUniqueID()); + } + + public static class EnderChestMemory { + private static final Map memory = new HashMap<>(); + private final Path enderChest; + private List contents; + + private EnderChestMemory(Path enderChest) { + this.enderChest = enderChest; + System.out.println("Echest storing in " + enderChest); + try { + this.contents = ContainerMemory.readItemStacks(Files.readAllBytes(enderChest)); + } catch (IOException e) { + e.printStackTrace(); + System.out.println("CANNOT read echest =( =("); + this.contents = null; + } + } + + public synchronized void save() { + System.out.println("Saving"); + if (contents != null) { + try { + enderChest.getParent().toFile().mkdir(); + Files.write(enderChest, ContainerMemory.writeItemStacks(contents)); + } catch (IOException e) { + e.printStackTrace(); + System.out.println("CANNOT save echest =( =("); + } + } + } + + private static synchronized EnderChestMemory getByServerAndPlayer(Path serverStorage, UUID player) { + return memory.computeIfAbsent(serverStorage.resolve("echests").resolve(player.toString()), EnderChestMemory::new); + } + } } diff --git a/src/main/java/baritone/cache/ContainerMemory.java b/src/main/java/baritone/cache/ContainerMemory.java index 52d1bf4f..8a638e4b 100644 --- a/src/main/java/baritone/cache/ContainerMemory.java +++ b/src/main/java/baritone/cache/ContainerMemory.java @@ -20,22 +20,69 @@ package baritone.cache; import baritone.api.cache.IContainerMemory; import baritone.api.cache.IRememberedInventory; import baritone.api.utils.IPlayerContext; +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; import net.minecraft.item.ItemStack; +import net.minecraft.network.PacketBuffer; import net.minecraft.util.math.BlockPos; +import java.io.IOException; +import java.nio.file.Files; import java.nio.file.Path; import java.util.*; public class ContainerMemory implements IContainerMemory { - public ContainerMemory(Path saveTo) { - // eventually - } + private final Path saveTo; /** * The current remembered inventories */ private final Map inventories = new HashMap<>(); + + public ContainerMemory(Path saveTo) { + this.saveTo = saveTo; + try { + read(Files.readAllBytes(saveTo)); + } catch (Exception ex) { + ex.printStackTrace(); + inventories.clear(); + } + } + + private void read(byte[] bytes) throws IOException { + System.out.println("READ BYTES " + bytes.length); + PacketBuffer in = new PacketBuffer(Unpooled.wrappedBuffer(bytes)); + int chests = in.readInt(); + for (int i = 0; i < chests; i++) { + int x = in.readInt(); + int y = in.readInt(); + int z = in.readInt(); + System.out.println("Read x y z " + x + " " + y + " " + z); + RememberedInventory rem = new RememberedInventory(); + rem.items.addAll(readItemStacks(in)); + rem.size = rem.items.size(); + if (rem.items.isEmpty()) { + continue; // this only happens if the list has no elements, not if the list has elements that are all empty item stacks + } + inventories.put(new BlockPos(x, y, z), rem); + } + } + + public synchronized void save() throws IOException { + ByteBuf buf = Unpooled.buffer(); + PacketBuffer out = new PacketBuffer(buf); + out.writeInt(inventories.size()); + for (Map.Entry entry : inventories.entrySet()) { + out.writeInt(entry.getKey().getX()); + out.writeInt(entry.getKey().getY()); + out.writeInt(entry.getKey().getZ()); + writeItemStacks(entry.getValue().getContents()); + } + System.out.println("CONTAINER BYTES " + buf.array().length); + Files.write(saveTo, buf.array()); + } + public synchronized void setup(BlockPos pos, int windowId, int slotCount) { RememberedInventory inventory = inventories.computeIfAbsent(pos, x -> new RememberedInventory()); inventory.windowId = windowId; @@ -57,6 +104,36 @@ public class ContainerMemory implements IContainerMemory { return new HashMap<>(inventories); } + public static List readItemStacks(byte[] bytes) throws IOException { + PacketBuffer in = new PacketBuffer(Unpooled.wrappedBuffer(bytes)); + return readItemStacks(in); + } + + public static List readItemStacks(PacketBuffer in) throws IOException { + int count = in.readInt(); + System.out.println("Read count " + count); + List result = new ArrayList<>(); + for (int i = 0; i < count; i++) { + result.add(in.readItemStack()); + } + return result; + } + + public static byte[] writeItemStacks(List write) { + ByteBuf buf = Unpooled.buffer(); + PacketBuffer out = new PacketBuffer(buf); + writeItemStacks(write, out); + return buf.array(); + } + + public static void writeItemStacks(List write, PacketBuffer out) { + System.out.println("WRITING ITEM STACKS " + write.size() + " " + write); + out.writeInt(write.size()); + for (ItemStack stack : write) { + out.writeItemStack(stack); + } + } + /** * An inventory that we are aware of. *

@@ -93,14 +170,9 @@ public class ContainerMemory implements IContainerMemory { return this.size; } - public int getWindowId() { - return this.windowId; - } - public void updateFromOpenWindow(IPlayerContext ctx) { items.clear(); items.addAll(ctx.player().openContainer.getInventory().subList(0, size)); - System.out.println("Saved " + items); } } } diff --git a/src/main/java/baritone/cache/WorldData.java b/src/main/java/baritone/cache/WorldData.java index 84fd6ff1..151edd4c 100644 --- a/src/main/java/baritone/cache/WorldData.java +++ b/src/main/java/baritone/cache/WorldData.java @@ -23,6 +23,7 @@ import baritone.api.cache.IContainerMemory; import baritone.api.cache.IWaypointCollection; import baritone.api.cache.IWorldData; +import java.io.IOException; import java.nio.file.Path; /** @@ -52,6 +53,15 @@ public class WorldData implements IWorldData { System.out.println("Started saving the world in a new thread"); cache.save(); }); + Baritone.getExecutor().execute(() -> { + System.out.println("Started saving saved containers in a new thread"); + try { + containerMemory.save(); + } catch (IOException e) { + e.printStackTrace(); + System.out.println("Failed to save saved containers"); + } + }); } @Override diff --git a/src/main/java/baritone/cache/WorldProvider.java b/src/main/java/baritone/cache/WorldProvider.java index fe33a4d1..83cf460d 100644 --- a/src/main/java/baritone/cache/WorldProvider.java +++ b/src/main/java/baritone/cache/WorldProvider.java @@ -95,7 +95,9 @@ public class WorldProvider implements IWorldProvider, Helper { } System.out.println("Baritone world data dir: " + dir); - this.currentWorld = worldCache.computeIfAbsent(dir, d -> new WorldData(d, dimension)); + synchronized (worldCache) { + this.currentWorld = worldCache.computeIfAbsent(dir, d -> new WorldData(d, dimension)); + } } public final void closeWorld() { diff --git a/src/main/java/baritone/utils/ExampleBaritoneControl.java b/src/main/java/baritone/utils/ExampleBaritoneControl.java index 958af776..508a5e1b 100644 --- a/src/main/java/baritone/utils/ExampleBaritoneControl.java +++ b/src/main/java/baritone/utils/ExampleBaritoneControl.java @@ -19,6 +19,7 @@ package baritone.utils; import baritone.Baritone; import baritone.api.Settings; +import baritone.api.cache.IRememberedInventory; import baritone.api.cache.IWaypoint; import baritone.api.event.events.ChatEvent; import baritone.api.pathing.goals.*; @@ -37,6 +38,7 @@ import net.minecraft.block.Block; import net.minecraft.client.multiplayer.ChunkProviderClient; import net.minecraft.entity.Entity; import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; import net.minecraft.util.math.BlockPos; import net.minecraft.world.chunk.Chunk; @@ -282,6 +284,33 @@ public class ExampleBaritoneControl extends Behavior implements Helper { logDirect("Baritone settings reset"); return true; } + if (msg.equals("echest")) { + Optional> contents = baritone.getMemoryBehavior().echest(); + if (contents.isPresent()) { + logDirect("echest contents:"); + log(contents.get()); + } else { + logDirect("echest contents unknown"); + } + return true; + } + if (msg.equals("chests")) { + System.out.println(baritone.getWorldProvider()); + System.out.println(baritone.getWorldProvider().getCurrentWorld()); + + System.out.println(baritone.getWorldProvider().getCurrentWorld().getContainerMemory()); + + System.out.println(baritone.getWorldProvider().getCurrentWorld().getContainerMemory().getRememberedInventories()); + + System.out.println(baritone.getWorldProvider().getCurrentWorld().getContainerMemory().getRememberedInventories().entrySet()); + + System.out.println(baritone.getWorldProvider().getCurrentWorld().getContainerMemory().getRememberedInventories().entrySet()); + for (Map.Entry entry : baritone.getWorldProvider().getCurrentWorld().getContainerMemory().getRememberedInventories().entrySet()) { + logDirect(entry.getKey() + ""); + log(entry.getValue().getContents()); + } + return true; + } if (msg.startsWith("followplayers")) { baritone.getFollowProcess().follow(EntityPlayer.class::isInstance); // O P P A logDirect("Following any players"); @@ -491,4 +520,12 @@ public class ExampleBaritoneControl extends Behavior implements Helper { } return false; } + + private void log(List stacks) { + for (ItemStack stack : stacks) { + if (!stack.isEmpty()) { + logDirect(stack.getCount() + "x " + stack.getDisplayName() + "@" + stack.getItemDamage()); + } + } + } }