Skip to content

Commit

Permalink
Sorting
Browse files Browse the repository at this point in the history
  • Loading branch information
anviaan committed Jul 21, 2024
1 parent e2bceef commit d5035c5
Show file tree
Hide file tree
Showing 6 changed files with 186 additions and 45 deletions.
39 changes: 39 additions & 0 deletions src/main/java/net/anvian/smartinventory/handler/Interaction.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package net.anvian.smartinventory.handler;

import net.minecraft.client.MinecraftClient;
import net.minecraft.client.network.ClientPlayerEntity;
import net.minecraft.client.network.ClientPlayerInteractionManager;
import net.minecraft.item.ItemStack;
import net.minecraft.screen.slot.SlotActionType;

public class Interaction {
private static final int LEFT_CLICK = 0;

public static ItemStack getCursorStack() {
return MinecraftClient.getInstance().player.currentScreenHandler.getCursorStack();
}

public static boolean hasEmptyCursor() {
return getCursorStack().isEmpty();
}

public static void clickStack(int slot) {
ClientPlayerInteractionManager manager = MinecraftClient.getInstance().interactionManager;
ClientPlayerEntity player = MinecraftClient.getInstance().player;
manager.clickSlot(getSyncId(), slot, LEFT_CLICK, SlotActionType.PICKUP, player);
}

public static void swapStacks(int slot, int target) {
ClientPlayerInteractionManager manager = MinecraftClient.getInstance().interactionManager;
ClientPlayerEntity player = MinecraftClient.getInstance().player;
manager.clickSlot(getSyncId(), slot, LEFT_CLICK, SlotActionType.PICKUP, player);
manager.clickSlot(getSyncId(), target, LEFT_CLICK, SlotActionType.PICKUP, player);
if (!Interaction.hasEmptyCursor()) {
manager.clickSlot(getSyncId(), slot, LEFT_CLICK, SlotActionType.PICKUP, player);
}
}

private static int getSyncId() {
return MinecraftClient.getInstance().player.currentScreenHandler.syncId;
}
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
package net.anvian.smartinventory.mixin;

import net.anvian.smartinventory.event.KeyInput;
import net.anvian.smartinventory.handler.ModKeyBinding;
import net.anvian.smartinventory.sort.SortInventory;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.screen.Screen;
import net.minecraft.client.gui.screen.ingame.CreativeInventoryScreen;
import net.minecraft.client.gui.screen.ingame.HandledScreen;
import net.minecraft.client.gui.screen.ingame.InventoryScreen;
import net.minecraft.screen.ScreenHandler;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
Expand All @@ -16,12 +17,14 @@
public class MixinKeyInputHandler {
@Inject(method = "keyPressed", at = @At("HEAD"))
private void onKeyPressed(int keyCode, int scanCode, int modifiers, CallbackInfoReturnable<Boolean> cir) {
if (keyCode == KeyInput.keyBinding.getDefaultKey().getCode()) {
MinecraftClient client = MinecraftClient.getInstance();
Screen screen = client.currentScreen;
if (keyCode == ModKeyBinding.keyBinding.getDefaultKey().getCode()) {
ScreenHandler screenHandler = MinecraftClient.getInstance().player.currentScreenHandler;
Screen screen = MinecraftClient.getInstance().currentScreen;

if (screen instanceof InventoryScreen || screen instanceof CreativeInventoryScreen) {
SortInventory.sortPlayerInventory(client);
SortInventory.sortPlayerInventory(screenHandler);
} else {
SortInventory.sortContainerInventory(screenHandler);
}
}
}
Expand Down
14 changes: 14 additions & 0 deletions src/main/java/net/anvian/smartinventory/slots/ContainerSlots.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package net.anvian.smartinventory.slots;

import net.minecraft.client.MinecraftClient;
import net.minecraft.entity.player.PlayerInventory;
import net.minecraft.screen.ScreenHandler;

public class ContainerSlots {
public static InventorySlots get() {
ScreenHandler screenHandler = MinecraftClient.getInstance().player.currentScreenHandler;
int from = 0;
int to = screenHandler.slots.size() - PlayerInventory.MAIN_SIZE;
return new InventorySlots(from, to);
}
}
39 changes: 39 additions & 0 deletions src/main/java/net/anvian/smartinventory/slots/InventorySlots.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package net.anvian.smartinventory.slots;

import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.screen.Screen;
import net.minecraft.client.gui.screen.ingame.CreativeInventoryScreen;
import net.minecraft.client.gui.screen.ingame.InventoryScreen;
import net.minecraft.screen.PlayerScreenHandler;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.IntStream;

public class InventorySlots extends ArrayList<Integer> {

public InventorySlots(int from, int to) {
super(IntStream.range(from, to).boxed().toList());
}

public InventorySlots(int from, int to, int offhand) {
super(IntStream.concat(IntStream.range(from, to), IntStream.of(offhand)).boxed().toList());
}

public InventorySlots(List<Integer> slots) {
super(slots);
}

public int getLastSlot() {
return this.get(this.size() - 1);
}

public InventorySlots excludeOffhand() {
Screen screen = MinecraftClient.getInstance().currentScreen;
if (screen instanceof InventoryScreen || screen instanceof CreativeInventoryScreen) {
this.remove(Integer.valueOf(PlayerScreenHandler.OFFHAND_ID));
return new InventorySlots(this);
}
return this;
}
}
23 changes: 23 additions & 0 deletions src/main/java/net/anvian/smartinventory/slots/PlayerSlots.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package net.anvian.smartinventory.slots;

import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.screen.ingame.InventoryScreen;
import net.minecraft.entity.player.PlayerInventory;
import net.minecraft.screen.PlayerScreenHandler;
import net.minecraft.screen.ScreenHandler;

public class PlayerSlots {
public static InventorySlots get() {
int from, to;
if (MinecraftClient.getInstance().currentScreen instanceof InventoryScreen) {
from = PlayerScreenHandler.INVENTORY_START;
to = PlayerScreenHandler.INVENTORY_END;
return new InventorySlots(from, to, PlayerScreenHandler.OFFHAND_ID);
} else {
ScreenHandler screenHandler = MinecraftClient.getInstance().player.currentScreenHandler;
from = screenHandler.slots.size() - PlayerInventory.MAIN_SIZE;
to = screenHandler.slots.size() - PlayerInventory.getHotbarSize();
return new InventorySlots(from, to);
}
}
}
103 changes: 63 additions & 40 deletions src/main/java/net/anvian/smartinventory/sort/SortInventory.java
Original file line number Diff line number Diff line change
@@ -1,64 +1,87 @@
package net.anvian.smartinventory.sort;

import net.minecraft.client.MinecraftClient;
import net.minecraft.entity.player.PlayerEntity;
import net.anvian.smartinventory.handler.Interaction;
import net.anvian.smartinventory.slots.ContainerSlots;
import net.anvian.smartinventory.slots.InventorySlots;
import net.anvian.smartinventory.slots.PlayerSlots;
import net.minecraft.item.ItemStack;
import net.minecraft.text.Text;
import net.minecraft.util.collection.DefaultedList;
import net.minecraft.screen.ScreenHandler;

import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class SortInventory {
private static final int HOTBAR_SIZE = 9;

public static void sortPlayerInventory(MinecraftClient client) {
PlayerEntity player = client.player;
if (player == null) return;

DefaultedList<ItemStack> inventory = player.getInventory().main;
Map<String, ItemStack> groupedItems = groupItems(inventory, HOTBAR_SIZE);
DefaultedList<ItemStack> sortedInventory = sortAndFilterInventory(groupedItems);
public static void sortPlayerInventory(ScreenHandler screenHandler) {
if (cursorCleared(PlayerSlots.get(), screenHandler)) {
mergeItemStacks(PlayerSlots.get().excludeOffhand(), screenHandler);
sortItemStacks(PlayerSlots.get().excludeOffhand(), screenHandler);
}
}

updateInventory(inventory, sortedInventory, HOTBAR_SIZE);
player.sendMessage(Text.of("Inventario ordenado!"), false);
public static void sortContainerInventory(ScreenHandler screenHandler) {
if (cursorCleared(ContainerSlots.get(), screenHandler)) {
mergeItemStacks(ContainerSlots.get(), screenHandler);
sortItemStacks(ContainerSlots.get(), screenHandler);
}
}

private static Map<String, ItemStack> groupItems(DefaultedList<ItemStack> inventory, int start) {
Map<String, ItemStack> groupedItems = new HashMap<>();
MinecraftClient client = MinecraftClient.getInstance();
if (client.player == null) return groupedItems;
private static boolean cursorCleared(InventorySlots inventorySlots, ScreenHandler screenHandler) {
if (!Interaction.hasEmptyCursor()) {
clearCursor(inventorySlots, screenHandler);
}
return Interaction.hasEmptyCursor();
}

for (int i = start; i < inventory.size(); i++) {
ItemStack stack = inventory.get(i);
if (!stack.isEmpty()) {
String key = stack.getItem().toString();
groupedItems.merge(key, stack, SortInventory::mergeStacks);
private static void mergeItemStacks(InventorySlots inventorySlots, ScreenHandler screenHandler) {
for (int slot : inventorySlots) {
ItemStack stack = screenHandler.getSlot(slot).getStack();
if (!stack.isEmpty() && stack.getCount() < stack.getMaxCount()) {
Interaction.clickStack(slot);
for (int tempSlot = slot + 1; Interaction.getCursorStack().getCount() < Interaction.getCursorStack().getMaxCount()
&& tempSlot <= inventorySlots.getLastSlot() && !Interaction.getCursorStack().isEmpty(); tempSlot++) {
if (ItemStack.areItemsEqual(Interaction.getCursorStack(), screenHandler.getSlot(tempSlot).getStack())) {
Interaction.clickStack(tempSlot);
}
}
if (!Interaction.hasEmptyCursor()) {
Interaction.clickStack(slot);
}
}
}
return groupedItems;
}

private static ItemStack mergeStacks(ItemStack existing, ItemStack incoming) {
int transferAmount = Math.min(incoming.getCount(), existing.getMaxCount() - existing.getCount());
existing.increment(transferAmount);
incoming.decrement(transferAmount);
return existing.getCount() == 0 ? incoming : existing;
private static void sortItemStacks(InventorySlots inventorySlots, ScreenHandler screenHandler) {
List<Integer> sortedSlots = getSortedSlots(inventorySlots, screenHandler);

for (int i = 0; i < sortedSlots.size(); i++) {
Interaction.swapStacks(sortedSlots.get(i), inventorySlots.get(i));
sortedSlots = getSortedSlots(inventorySlots, screenHandler);
}
}

private static DefaultedList<ItemStack> sortAndFilterInventory(Map<String, ItemStack> groupedItems) {
List<ItemStack> sortedList = groupedItems.values().stream()
.sorted(Comparator.comparing(stack -> stack.getItem().getName(stack).getString()))
private static List<Integer> getSortedSlots(InventorySlots inventorySlots, ScreenHandler screenHandler) {
return inventorySlots.stream()
.filter(slot -> !screenHandler.getSlot(slot).getStack().isEmpty())
.sorted(Comparator.comparing((Integer slot) -> screenHandler.getSlot(slot).getStack().getName().getString())
.thenComparing(slot -> screenHandler.getSlot(slot).getStack().getCount(), Comparator.reverseOrder()))
.toList();

return DefaultedList.copyOf(ItemStack.EMPTY, sortedList.toArray(new ItemStack[0]));
}

private static void updateInventory(DefaultedList<ItemStack> inventory, DefaultedList<ItemStack> sortedInventory, int start) {
for (int i = start; i < inventory.size(); i++) {
inventory.set(i, i - start < sortedInventory.size() ? sortedInventory.get(i - start) : ItemStack.EMPTY);
private static void clearCursor(InventorySlots inventorySlots, ScreenHandler screenHandler) {
for (int slot : inventorySlots) {
if (ItemStack.areItemsEqual(screenHandler.getSlot(slot).getStack(), Interaction.getCursorStack())) {
if (!Interaction.hasEmptyCursor()) {
Interaction.clickStack(slot);
}
}
}

for (int slot : inventorySlots) {
if (screenHandler.getSlot(slot).getStack().isEmpty()) {
if (!Interaction.hasEmptyCursor()) {
Interaction.clickStack(slot);
}
}
}
}
}

0 comments on commit d5035c5

Please sign in to comment.