Skip to content

Commit

Permalink
feat: add hint text, dump+fill, refactors
Browse files Browse the repository at this point in the history
  • Loading branch information
rootEnginear committed Nov 8, 2023
1 parent e89cd73 commit 1b5cbc9
Show file tree
Hide file tree
Showing 5 changed files with 146 additions and 88 deletions.
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,9 @@ Organize your chests instantly with a single keystroke

1. Open a chest
2. Press a key:
- `S`: Sort (will also auto merge)
- `M`: Merge (try to merge stacks together)
- `S`: Sort
- `F`: Fill (inventory → chest)
- `D`: Dump (chest → inventory)

## FAQ

Expand Down
23 changes: 23 additions & 0 deletions src/main/java/rootenginear/sortchest/mixin/GuiChestMixin.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package rootenginear.sortchest.mixin;

import net.minecraft.client.gui.GuiChest;
import net.minecraft.client.gui.GuiContainer;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import rootenginear.sortchest.mixin.accessor.GuiScreenAccessor;

@Mixin(value = {GuiChest.class}, remap = false)
public class GuiChestMixin {
@Inject(method = "drawGuiContainerForegroundLayer", at = @At("TAIL"))
private void writeInstruction(CallbackInfo ci) {
GuiScreenAccessor screenThis = (GuiScreenAccessor) this;
GuiContainer containerThis = (GuiContainer) (Object) this;
screenThis.getFontRenderer().drawString("S: Sort ⇵, F: Fill ⊼", containerThis.xSize - 8 - 88 + 2, 6, 0x404040);
screenThis.getFontRenderer().drawString("D: Dump ⊻", containerThis.xSize - 8 - 48 + 2, containerThis.ySize - 96 + 2, 0x404040);
// screenThis.getFontRenderer().drawStringWithShadow("S: Sort ⇵", containerThis.xSize + 4, 6, 0xffffff);
// screenThis.getFontRenderer().drawStringWithShadow("F: Fill ⊼", containerThis.xSize + 4, 6 + 12, 0xffffff);
// screenThis.getFontRenderer().drawStringWithShadow("D: Dump ⊻", containerThis.xSize + 4, containerThis.ySize - 96 + 2, 0xffffff);
}
}
201 changes: 115 additions & 86 deletions src/main/java/rootenginear/sortchest/mixin/GuiContainerMixin.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,108 +8,90 @@
import net.minecraft.core.entity.player.EntityPlayer;
import net.minecraft.core.item.ItemStack;
import net.minecraft.core.player.inventory.Container;
import org.jetbrains.annotations.NotNull;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import rootenginear.sortchest.SortChest;
import rootenginear.sortchest.mixin.accessor.GuiChestAccessor;
import rootenginear.sortchest.mixin.accessor.GuiScreenAccessor;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Random;
import java.util.stream.Collectors;

@Mixin(value = {GuiContainer.class}, remap = false)
public class GuiContainerMixin {
@Inject(method = "keyTyped", at = @At("HEAD"), cancellable = true)
private void doSort(char c, int _i, int mouseX, int mouseY, CallbackInfo ci) {
GuiContainer containerThis = (GuiContainer) (Object) this;
if (!(containerThis instanceof GuiChest)) return;

// S - Sort
if (c == 's' && containerThis instanceof GuiChest) {
mergeItems(containerThis);
sortItems(containerThis);
char key = Character.toLowerCase(c);
if (key != 's' && key != 'd' && key != 'f') return;

ci.cancel();
}
GuiScreenAccessor screenThis = (GuiScreenAccessor) containerThis;
Minecraft mc = screenThis.getMc();
PlayerController playerController = mc.playerController;
EntityPlayer entityPlayer = mc.thePlayer;
Container inventorySlots = containerThis.inventorySlots;
int windowId = inventorySlots.windowId;

// D - Disorganize (Shuffle)
if (c == 'd' && containerThis instanceof GuiChest) {
GuiScreenAccessor screenThis = (GuiScreenAccessor) containerThis;
Minecraft mc = screenThis.getMc();
PlayerController playerController = mc.playerController;
EntityPlayer entityPlayer = mc.thePlayer;
Container inventorySlots = containerThis.inventorySlots;
int windowId = inventorySlots.windowId;
int countInvSlots = ((GuiChestAccessor) containerThis).getInventoryRows() * 9;

Random rand = new Random();

playerController.doInventoryAction(windowId, InventoryAction.CLICK_LEFT, new int[]{0, 0}, entityPlayer);
for (int i = 0; i < 100; i++) {
if (rand.nextInt(2) == 0) {
playerController.doInventoryAction(windowId, InventoryAction.CLICK_LEFT, new int[]{rand.nextInt(countInvSlots - 1) + 1, 0}, entityPlayer);
} else {
playerController.doInventoryAction(windowId, InventoryAction.CLICK_RIGHT, new int[]{rand.nextInt(countInvSlots - 1) + 1, 0}, entityPlayer);
}
}
playerController.doInventoryAction(windowId, InventoryAction.CLICK_LEFT, new int[]{0, 0}, entityPlayer);
// "D" - Dump chest to inv
if (key == 'd') {
dumpItemFromChest(playerController, entityPlayer, windowId);

ci.cancel();
return;
}

// M - Merge
if (c == 'm' && containerThis instanceof GuiChest) {
mergeItems(containerThis);
int countInvSlots = ((GuiChestAccessor) containerThis).getInventoryRows() * 9;

// "F" - Fill chest
if (key == 'f') {
dumpItemToChest(playerController, entityPlayer, windowId, countInvSlots);

ci.cancel();
return;
}

// "*S" - Shuffle
// boolean shiftOrCtrlPressed = Keyboard.isKeyDown(42) || Keyboard.isKeyDown(54) || Keyboard.isKeyDown(29) || Keyboard.isKeyDown(157);
// if (shiftOrCtrlPressed) {
// Random rand = new Random();
//
// playerController.doInventoryAction(windowId, InventoryAction.CLICK_LEFT, new int[]{0, 0}, entityPlayer);
// for (int i = 0; i < 100; i++) {
// if (rand.nextInt(2) == 0) {
// playerController.doInventoryAction(windowId, InventoryAction.CLICK_LEFT, new int[]{rand.nextInt(countInvSlots - 1) + 1, 0}, entityPlayer);
// } else {
// playerController.doInventoryAction(windowId, InventoryAction.CLICK_RIGHT, new int[]{rand.nextInt(countInvSlots - 1) + 1, 0}, entityPlayer);
// }
// }
// playerController.doInventoryAction(windowId, InventoryAction.CLICK_LEFT, new int[]{0, 0}, entityPlayer);
//
// ci.cancel();
// return;
// }

// "S" - Sort
mergeItemsInChest(playerController, entityPlayer, windowId, countInvSlots, inventorySlots);
sortItemsInChest(playerController, entityPlayer, windowId, countInvSlots, inventorySlots);

ci.cancel();
}

@Unique
private void sortItems(GuiContainer containerThis) {
GuiScreenAccessor screenThis = (GuiScreenAccessor) containerThis;
Minecraft mc = screenThis.getMc();
PlayerController playerController = mc.playerController;
EntityPlayer entityPlayer = mc.thePlayer;
Container inventorySlots = containerThis.inventorySlots;
int windowId = inventorySlots.windowId;
int countInvSlots = ((GuiChestAccessor) containerThis).getInventoryRows() * 9;

private void sortItemsInChest(PlayerController playerController, EntityPlayer entityPlayer, int windowId, int countInvSlots, Container inventorySlots) {
List<ItemStack> inv = new ArrayList<>(countInvSlots);
for (int i = 0; i < countInvSlots; i++) {
inv.add(inventorySlots.getSlot(i).getStack());
}

List<ItemStack> sorted = inv.stream().sorted((a, z) -> {
if (a == null && z == null) return 0;
if (a == null) return 1;
if (z == null) return -1;

int aId = a.itemID;
int zId = z.itemID;
if (aId != zId) return aId - zId;

int aMeta = a.getMetadata();
int zMeta = z.getMetadata();
SortChest.LOGGER.info("Comparing " + a + " to " + z);
SortChest.LOGGER.info("A meta: " + aMeta + ", Z meta: " + zMeta);
if (aMeta != zMeta) return aMeta - zMeta;

SortChest.LOGGER.info("Comparing " + a + " to " + z);
SortChest.LOGGER.info("A size: " + a.stackSize + ", Z size: " + z.stackSize);
return z.stackSize - a.stackSize;
}).collect(Collectors.toList());

for (int i = 0; i < countInvSlots; i++) {
ItemStack sortedItem = sorted.get(i);
if (sortedItem == null) break;
List<ItemStack> sorted = inv.stream().sorted(compareItemStacks()).collect(Collectors.toList());

SortChest.LOGGER.info(String.valueOf(sortedItem.stackSize));
}
for (int i = 0; i < countInvSlots; i++) {
ItemStack sortedItem = sorted.get(i);
if (sortedItem == null) break;
Expand All @@ -121,43 +103,90 @@ private void sortItems(GuiContainer containerThis) {
inv.set(i, inv.get(x));
inv.set(x, invItem);

playerController.doInventoryAction(windowId, InventoryAction.CLICK_LEFT, new int[]{x, 0}, entityPlayer);
playerController.doInventoryAction(windowId, InventoryAction.CLICK_LEFT, new int[]{i, 0}, entityPlayer);
playerController.doInventoryAction(windowId, InventoryAction.CLICK_LEFT, new int[]{x, 0}, entityPlayer);
swap(playerController, entityPlayer, windowId, x, i);
}
}

@Unique
private void mergeItems(GuiContainer containerThis) {
GuiScreenAccessor screenThis = (GuiScreenAccessor) containerThis;
Minecraft mc = screenThis.getMc();
PlayerController playerController = mc.playerController;
EntityPlayer entityPlayer = mc.thePlayer;
Container inventorySlots = containerThis.inventorySlots;
int windowId = inventorySlots.windowId;
int countInvSlots = ((GuiChestAccessor) containerThis).getInventoryRows() * 9;
@NotNull
private static Comparator<ItemStack> compareItemStacks() {
return (a, z) -> {
if (a == null && z == null) return 0;
if (a == null) return 1;
if (z == null) return -1;

int aId = a.itemID;
int zId = z.itemID;
if (aId != zId) return aId - zId;

int aMeta = a.getMetadata();
int zMeta = z.getMetadata();
if (aMeta != zMeta) return aMeta - zMeta;

List<Integer> inv = new ArrayList<>(countInvSlots);
return z.stackSize - a.stackSize;
};
}

@Unique
private static void swap(PlayerController playerController, EntityPlayer entityPlayer, int windowId, int x, int i) {
playerController.doInventoryAction(windowId, InventoryAction.CLICK_LEFT, new int[]{x, 0}, entityPlayer);
playerController.doInventoryAction(windowId, InventoryAction.CLICK_LEFT, new int[]{i, 0}, entityPlayer);
playerController.doInventoryAction(windowId, InventoryAction.CLICK_LEFT, new int[]{x, 0}, entityPlayer);
}

@Unique
private void mergeItemsInChest(PlayerController playerController, EntityPlayer entityPlayer, int windowId, int countInvSlots, Container inventorySlots) {
List<String> invData = new ArrayList<>(countInvSlots);
for (int i = 0; i < countInvSlots; i++) {
ItemStack item = inventorySlots.getSlot(i).getStack();
inv.add(item != null ? item.itemID : null);
invData.add(item != null ? item.itemID + ":" + item.getMetadata() : null);
}

for (int firstSlotIndex = 0; firstSlotIndex < countInvSlots; firstSlotIndex++) {
if (inv.get(firstSlotIndex) == null) continue;
if (invData.get(firstSlotIndex) == null) continue;

String itemData = invData.get(firstSlotIndex);
invData.set(firstSlotIndex, null);

int nextSlot = invData.indexOf(itemData);
if (nextSlot == -1) continue;

int itemId = inv.get(firstSlotIndex);
playerController.doInventoryAction(windowId, InventoryAction.CLICK_LEFT, new int[]{firstSlotIndex, 0}, entityPlayer);
inv.set(firstSlotIndex, null);

int nextSlot;
while ((nextSlot = inv.indexOf(itemId)) != -1) {
do {
playerController.doInventoryAction(windowId, InventoryAction.CLICK_LEFT, new int[]{nextSlot, 0}, entityPlayer);
playerController.doInventoryAction(windowId, InventoryAction.CLICK_LEFT, new int[]{nextSlot, 0}, entityPlayer);
inv.set(nextSlot, null);
}
invData.set(nextSlot, null);
} while ((nextSlot = invData.indexOf(itemData)) != -1);

playerController.doInventoryAction(windowId, InventoryAction.CLICK_LEFT, new int[]{firstSlotIndex, 0}, entityPlayer);
}
}

@Unique
private void dumpItemFromChest(PlayerController playerController, EntityPlayer entityPlayer, int windowId) {
playerController.doInventoryAction(windowId, InventoryAction.MOVE_ALL, new int[]{0, 0}, entityPlayer);
}

@Unique
private void dumpItemToChest(PlayerController playerController, EntityPlayer entityPlayer, int windowId, int countInvSlots) {
// Dump inventory (not hotbar) content
playerController.doInventoryAction(windowId, InventoryAction.MOVE_ALL, new int[]{countInvSlots, 0}, entityPlayer);

// Dump hotbar content
playerController.doInventoryAction(windowId, InventoryAction.MOVE_ALL, new int[]{countInvSlots + (9 * 3), 0}, entityPlayer);
}

// @Inject(method = "initGui", at = @At("TAIL"))
// private void addChestButtons(CallbackInfo ci) {
// GuiContainer containerThis = (GuiContainer) (Object) this;
// if (!(containerThis instanceof GuiChest)) return;
//
// GuiScreen screenThis = (GuiScreen) (Object) this;
// screenThis.controlList.clear();
// int centerX = (screenThis.width - containerThis.xSize) / 2;
// int centerY = (screenThis.height - containerThis.ySize) / 2;
// screenThis.controlList.add(new GuiButton(0, centerX + containerThis.xSize - 8 - 12 - 12 - 4, centerY + 4, 12, 12, "⇵"));
// screenThis.controlList.add(new GuiButton(1, centerX + containerThis.xSize - 8 - 12, centerY + 4, 12, 12, "⊼"));
// }
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,15 @@

import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiScreen;
import net.minecraft.client.render.FontRenderer;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;

@Mixin(value = {GuiScreen.class}, remap = false)
public interface GuiScreenAccessor {
@Accessor
Minecraft getMc();

@Accessor
FontRenderer getFontRenderer();
}
1 change: 1 addition & 0 deletions src/main/resources/sortchest.mixins.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"package": "rootenginear.sortchest.mixin",
"compatibilityLevel": "JAVA_8",
"client": [
"GuiChestMixin",
"GuiContainerMixin",
"accessor.GuiChestAccessor",
"accessor.GuiScreenAccessor"
Expand Down

0 comments on commit 1b5cbc9

Please sign in to comment.