From 9aa7b49d224bfde055e12bc84f6908ba0a50090d Mon Sep 17 00:00:00 2001 From: BuildTools Date: Thu, 6 May 2021 08:03:15 +0800 Subject: fine ironman --- .../miscfeatures/StorageManager.java | 595 +++++++++++++++++++++ 1 file changed, 595 insertions(+) create mode 100644 src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/StorageManager.java (limited to 'src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/StorageManager.java') diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/StorageManager.java b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/StorageManager.java new file mode 100644 index 00000000..54478fa4 --- /dev/null +++ b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/StorageManager.java @@ -0,0 +1,595 @@ +package io.github.moulberry.notenoughupdates.miscfeatures; + +import com.google.gson.*; +import io.github.moulberry.notenoughupdates.NotEnoughUpdates; +import io.github.moulberry.notenoughupdates.miscgui.StorageOverlay; +import io.github.moulberry.notenoughupdates.util.SBInfo; +import io.github.moulberry.notenoughupdates.util.Utils; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.inventory.GuiChest; +import net.minecraft.init.Blocks; +import net.minecraft.inventory.ContainerChest; +import net.minecraft.inventory.IInventory; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.*; +import net.minecraft.network.play.client.C0EPacketClickWindow; +import net.minecraft.network.play.server.S2DPacketOpenWindow; +import net.minecraft.network.play.server.S2EPacketCloseWindow; +import net.minecraft.network.play.server.S2FPacketSetSlot; +import net.minecraft.network.play.server.S30PacketWindowItems; +import org.lwjgl.input.Keyboard; + +import java.io.*; +import java.lang.reflect.Type; +import java.nio.charset.StandardCharsets; +import java.util.*; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.zip.GZIPInputStream; +import java.util.zip.GZIPOutputStream; + +public class StorageManager { + + private static final StorageManager INSTANCE = new StorageManager(); + private static final Gson GSON = new GsonBuilder() + .registerTypeAdapter(ItemStack.class, new ItemStackSerializer()) + .registerTypeAdapter(ItemStack.class, new ItemStackDeserilizer()).create(); + + public static class ItemStackSerializer implements JsonSerializer { + @Override + public JsonElement serialize(ItemStack src, Type typeOfSrc, + JsonSerializationContext context) { + NBTTagCompound tag = src.serializeNBT(); + return nbtToJson(tag); + } + } + + private static final Pattern JSON_FIX_REGEX = Pattern.compile("\"([^,:]+)\":"); + + public static class ItemStackDeserilizer implements JsonDeserializer { + @Override + public ItemStack deserialize(JsonElement json, Type typeOfT, + JsonDeserializationContext context) throws JsonParseException { + try { + JsonObject object = json.getAsJsonObject(); + + NBTTagCompound tag = JsonToNBT.getTagFromJson(JSON_FIX_REGEX.matcher(object.toString()).replaceAll("$1:")); + + Item item; + if(tag.hasKey("id", 8)) { + item = Item.getByNameOrId(tag.getString("id")); + } else { + item = Item.getItemById(tag.getShort("id")); + } + if(item == null) { + return null; + } + int stackSize = tag.getInteger("Count"); + int damage = tag.getInteger("Damage"); + + ItemStack stack = new ItemStack(item, stackSize, damage); + + if(tag.hasKey("tag")) { + NBTTagCompound itemTag = tag.getCompoundTag("tag"); + stack.setTagCompound(itemTag); + } + + return stack; + } catch(Exception e) { + e.printStackTrace(); + return null; + } + } + } + + private static JsonObject nbtToJson(NBTTagCompound NBTTagCompound) { + return (JsonObject) loadJson(NBTTagCompound); + } + + private static JsonElement loadJson(NBTBase tag) { + if (tag instanceof NBTTagCompound) { + NBTTagCompound compoundTag = (NBTTagCompound) tag; + JsonObject jsonObject = new JsonObject(); + for (String key : compoundTag.getKeySet()) { + jsonObject.add(key, loadJson(compoundTag.getTag(key))); + } + return jsonObject; + } else if (tag instanceof NBTTagList) { + NBTTagList listTag = (NBTTagList) tag; + JsonArray jsonArray = new JsonArray(); + for(int i=0; i pages = new HashMap<>(); + public final HashMap displayToStorageIdMap = new HashMap<>(); + } + + public StorageConfig storageConfig = new StorageConfig(); + + private int currentStoragePage = -1; + public boolean onStorageMenu = false; + + private String lastSearch = ""; + + private boolean[] storagePresent = new boolean[27]; + + //TODO: Replace with /storage {id} when hypixel becomes not lazy + public int desiredStoragePage = -1; + public long storageOpenSwitchMillis = 0; + + private ItemStack[] missingBackpackStacks = new ItemStack[18]; + + private boolean shouldRenderStorageOverlayCached = false; + + private static final Pattern WINDOW_REGEX = Pattern.compile(".+ Backpack \\((\\d+)/(\\d+)\\)"); + private static final Pattern ECHEST_WINDOW_REGEX = Pattern.compile("Ender Chest \\((\\d+)/(\\d+)\\)"); + + public void loadConfig(File file) { + try(BufferedReader reader = new BufferedReader(new InputStreamReader(new GZIPInputStream(new FileInputStream(file)), StandardCharsets.UTF_8))) { + storageConfig = GSON.fromJson(reader, StorageConfig.class); + } catch(Exception ignored) { } + if(storageConfig == null) { + storageConfig = new StorageConfig(); + } + } + + public void saveConfig(File file) { + try { + file.createNewFile(); + try(BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(new GZIPOutputStream(new FileOutputStream(file)), StandardCharsets.UTF_8))) { + writer.write(GSON.toJson(storageConfig)); + } + } catch(Exception ignored) { + ignored.printStackTrace(); + } + } + + public ItemStack getMissingBackpackStack(int storageId) { + if(missingBackpackStacks[storageId] != null) { + return missingBackpackStacks[storageId]; + } + + ItemStack stack = Utils.createItemStack(Item.getItemFromBlock(Blocks.stained_glass_pane), + "\u00a7cEmpty Backpack Slot "+(storageId+1), 12, + "", + "\u00a7eLeft-click a backpack", + "\u00a7eitem on this slot to place", + "\u00a7eit!"); + + missingBackpackStacks[storageId] = stack; + return stack; + } + + public boolean shouldRenderStorageOverlay(String containerName) { + if(!NotEnoughUpdates.INSTANCE.config.storageGUI.enableStorageGUI) { + shouldRenderStorageOverlayCached = false; + return false; + } + + if(!NotEnoughUpdates.INSTANCE.hasSkyblockScoreboard()) { + shouldRenderStorageOverlayCached = false; + return false; + } + + if(!(Minecraft.getMinecraft().currentScreen instanceof GuiChest)) { + shouldRenderStorageOverlayCached = false; + return false; + } + + if(getCurrentWindowId() != -1 && getCurrentPageId() != -1) { + shouldRenderStorageOverlayCached = true; + return true; + } + + shouldRenderStorageOverlayCached = containerName != null && containerName.trim().startsWith("Storage"); + return shouldRenderStorageOverlayCached; + } + + public boolean shouldRenderStorageOverlayFast() { + return shouldRenderStorageOverlayCached; + } + + private StoragePage[] getPagesForProfile() { + if(!NotEnoughUpdates.INSTANCE.hasSkyblockScoreboard()) return null; + if(SBInfo.getInstance().currentProfile == null) return null; + + return storageConfig.pages.computeIfAbsent(SBInfo.getInstance().currentProfile, k -> new StoragePage[27]); + } + + public StoragePage getPage(int pageIndex, boolean createPage) { + if(pageIndex == -1) return null; + + StoragePage[] pages = getPagesForProfile(); + if(pages == null) return null; + + if(createPage && pages[pageIndex] == null) pages[pageIndex] = new StoragePage(); + + return pages[pageIndex]; + } + + public void removePage(int pageIndex) { + if(pageIndex == -1) return; + + StoragePage[] pages = getPagesForProfile(); + if(pages == null) return; + + pages[pageIndex] = null; + } + + public StoragePage getCurrentPage() { + return getPage(getCurrentPageId(), true); + } + + private void setItemSlot(int index, ItemStack item) { + StoragePage page = getCurrentPage(); + if(page != null) { + page.items[index] = item; + } + } + + public int getCurrentPageId() { + if(!(Minecraft.getMinecraft().currentScreen instanceof GuiChest)) { + currentStoragePage = -1; + return -1; + } + + return currentStoragePage; + } + + public int getCurrentWindowId() { + if(!(Minecraft.getMinecraft().currentScreen instanceof GuiChest)) { + currentStoragePage = -1; + return -1; + } + + GuiChest chest = (GuiChest)Minecraft.getMinecraft().currentScreen; + + return chest.inventorySlots.windowId; + } + + public void sendToPage(int page) { + if(desiredStoragePage != getCurrentPageId() && + System.currentTimeMillis() - storageOpenSwitchMillis < 1000) return; + if(getCurrentPageId() == page) return; + + if(getCurrentWindowId() != -1 && onStorageMenu) { + if(page < 9) { + sendMouseClick(getCurrentWindowId(), 9+page); + } else { + sendMouseClick(getCurrentWindowId(), 27+page-MAX_ENDER_CHEST_PAGES); + } + } else { + storageOpenSwitchMillis = System.currentTimeMillis(); + desiredStoragePage = page; + + NotEnoughUpdates.INSTANCE.sendChatMessage("/storage"); + } + } + + private void sendMouseClick(int windowId, int slotIndex) { + Minecraft.getMinecraft().playerController.windowClick(windowId, slotIndex, 0, 0, + Minecraft.getMinecraft().thePlayer); + } + + public int getDisplayIdForStorageId(int storageId) { + if(storageId < 0) return -1; + for(Map.Entry entry : storageConfig.displayToStorageIdMap.entrySet()) { + if(entry.getValue() == storageId) { + return entry.getKey(); + } + } + return -1; + } + + public void openWindowPacket(S2DPacketOpenWindow packet) { + shouldRenderStorageOverlayCached = false; + if(!NotEnoughUpdates.INSTANCE.hasSkyblockScoreboard()) return; + + String windowTitle = Utils.cleanColour(packet.getWindowTitle().getUnformattedText()); + + Matcher matcher = WINDOW_REGEX.matcher(windowTitle); + Matcher matcherEchest = ECHEST_WINDOW_REGEX.matcher(windowTitle); + + currentStoragePage = -1; + onStorageMenu = false; + + if(windowTitle.trim().equals("Storage")) { + onStorageMenu = true; + + if(desiredStoragePage >= 0 && System.currentTimeMillis() - storageOpenSwitchMillis < 1000) { + if(desiredStoragePage < 9) { + sendMouseClick(getCurrentWindowId(), 9+desiredStoragePage); + } else { + sendMouseClick(getCurrentWindowId(), 27+desiredStoragePage-MAX_ENDER_CHEST_PAGES); + } + } + } else if(matcher.matches()) { + int page = Integer.parseInt(matcher.group(1)); + + if(page > 0 && page <= 18) { + currentStoragePage = page-1+MAX_ENDER_CHEST_PAGES; + + int displayId = getDisplayIdForStorageId(currentStoragePage); + if(displayId >= 0) StorageOverlay.getInstance().scrollToStorage(displayId, false); + + StoragePage spage = getCurrentPage(); + if(spage != null) { + spage.rows = packet.getSlotCount()/9 - 1; + } + } + } else if(matcherEchest.matches()) { + int page = Integer.parseInt(matcherEchest.group(1)); + + if(page > 0 && page <= 9) { + currentStoragePage = page-1; + + int displayId = getDisplayIdForStorageId(currentStoragePage); + if(displayId >= 0) StorageOverlay.getInstance().scrollToStorage(displayId, false); + + StoragePage spage = getCurrentPage(); + if(spage != null) { + spage.rows = packet.getSlotCount()/9 - 1; + } + } + } else { + StorageOverlay.getInstance().clearSearch(); + } + } + + public void closeWindowPacket(S2EPacketCloseWindow packet) { + shouldRenderStorageOverlayCached = false; + } + + public void setSlotPacket(S2FPacketSetSlot packet) { + if(!NotEnoughUpdates.INSTANCE.hasSkyblockScoreboard()) return; + if(getCurrentWindowId() == -1 || getCurrentWindowId() != packet.func_149175_c()) return; + + if(getCurrentPageId() != -1) { + StoragePage page = getCurrentPage(); + + int slot = packet.func_149173_d(); + if(page != null && slot >= 9 && slot < 9+page.rows*9) { + setItemSlot(packet.func_149173_d()-9, packet.func_149174_e()); + } + } else if(onStorageMenu) { + int slot = packet.func_149173_d(); + ItemStack stack = packet.func_149174_e(); + + if(slot >= 9 && slot < 18) { + int index = slot-9; + + boolean changed = false; + if(stack.getItem() == Item.getItemFromBlock(Blocks.stained_glass_pane) && + stack.getMetadata() == 14) { + if(storagePresent[index]) changed = true; + storagePresent[index] = false; + removePage(index); + } else { + if(!storagePresent[index]) changed = true; + storagePresent[index] = true; + getPage(index, true).backpackDisplayStack = stack; + } + + if(changed) { + synchronized(storageConfig.displayToStorageIdMap) { + storageConfig.displayToStorageIdMap.clear(); + int displayIndex = 0; + for(int i=0; i= 27 && slot < 45) { + int index = (slot-27)%9 + (slot-27)/9*9 + MAX_ENDER_CHEST_PAGES; + + boolean changed = false; + + if(stack.getItem() == Item.getItemFromBlock(Blocks.stained_glass_pane)) { + if(storagePresent[index]) changed = true; + storagePresent[index] = false; + removePage(index); + } else { + if(!storagePresent[index]) changed = true; + storagePresent[index] = true; + getPage(index, true).backpackDisplayStack = stack; + } + + if(changed) { + synchronized(storageConfig.displayToStorageIdMap) { + storageConfig.displayToStorageIdMap.clear(); + int displayIndex = 0; + for(int i=0; i searchId.get()) { + page.searchedId = -1; + return; + } + if(page.searchedId == searchId.get()) { + return; + } + + page.searchedId = searchId.get(); + + if(searchStr == null || searchStr.trim().isEmpty()) { + page.matchesSearch = true; + return; + } + + for(ItemStack stack : page.items) { + if(stack != null && NotEnoughUpdates.INSTANCE.manager.doesStackMatchSearch(stack, searchStr)) { + page.matchesSearch = true; + return; + } + } + page.matchesSearch = false; + } + + public void searchDisplay(String searchStr) { + synchronized(storageConfig.displayToStorageIdMap) { + storageConfig.displayToStorageIdMap.clear(); + + lastSearch = searchStr; + int sid = searchId.incrementAndGet(); + int displayIndex = 0; + for(int i=0; i 0) { + updateSearchForPage(searchStr, page); + if(page.matchesSearch) { + storageConfig.displayToStorageIdMap.put(displayIndex++, i); + } + } else { + storageConfig.displayToStorageIdMap.put(displayIndex++, i); + page.matchesSearch = true; + page.searchedId = sid; + } + } + } + } + } + } + + public void setItemsPacket(S30PacketWindowItems packet) { + if(!NotEnoughUpdates.INSTANCE.hasSkyblockScoreboard()) return; + if(getCurrentWindowId() == -1 || getCurrentWindowId() != packet.func_148911_c()) return; + + if(getCurrentPageId() != -1) { + StoragePage page = getPage(getCurrentPageId(), false); + + if(page != null) { + int max = Math.min(page.rows*9, packet.getItemStacks().length-9); + for(int i=0; i