save containers and echests

This commit is contained in:
Leijurv 2018-12-03 17:20:56 -08:00
parent b22e93d6d0
commit 7ba987e7f7
No known key found for this signature in database
GPG Key ID: 44A3EA646EADAC6A
6 changed files with 212 additions and 17 deletions

View File

@ -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;

View File

@ -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<FutureInventory> 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<List<ItemStack>> 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<Path, EnderChestMemory> memory = new HashMap<>();
private final Path enderChest;
private List<ItemStack> 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);
}
}
}

View File

@ -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<BlockPos, RememberedInventory> 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<BlockPos, RememberedInventory> 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<ItemStack> readItemStacks(byte[] bytes) throws IOException {
PacketBuffer in = new PacketBuffer(Unpooled.wrappedBuffer(bytes));
return readItemStacks(in);
}
public static List<ItemStack> readItemStacks(PacketBuffer in) throws IOException {
int count = in.readInt();
System.out.println("Read count " + count);
List<ItemStack> result = new ArrayList<>();
for (int i = 0; i < count; i++) {
result.add(in.readItemStack());
}
return result;
}
public static byte[] writeItemStacks(List<ItemStack> write) {
ByteBuf buf = Unpooled.buffer();
PacketBuffer out = new PacketBuffer(buf);
writeItemStacks(write, out);
return buf.array();
}
public static void writeItemStacks(List<ItemStack> 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.
* <p>
@ -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);
}
}
}

View File

@ -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

View File

@ -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() {

View File

@ -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<List<ItemStack>> 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<BlockPos, IRememberedInventory> 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<ItemStack> stacks) {
for (ItemStack stack : stacks) {
if (!stack.isEmpty()) {
logDirect(stack.getCount() + "x " + stack.getDisplayName() + "@" + stack.getItemDamage());
}
}
}
}