Skip to content

Commit dd27853

Browse files
committed
new sort stuff
1 parent fd5d7c0 commit dd27853

18 files changed

Lines changed: 633 additions & 61 deletions

‎gradle.properties‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ minecraft_version=1.21.1
1818
# as they do not follow standard versioning conventions.
1919
minecraft_version_range=[1.21.1, 1.22)
2020
# The Neo version must agree with the Minecraft version to get a valid artifact
21-
neo_version=21.1.173
21+
neo_version=21.1.265
2222
# The Neo version range can use any version of Neo as bounds
2323
neo_version_range=[21.1.0,)
2424
# The loader version range can only use the major version of FML as bounds

‎src/main/java/invtweaks/config/InvTweaksConfig.java‎

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ public class InvTweaksConfig {
6565
.put("com.github.glodblock.epp.client.gui.*", new ContOverride(NO_POS_OVERRIDE, NO_POS_OVERRIDE, ""))
6666
.put("org.cyclops.integrateddynamics.inventory.container.*", new ContOverride(NO_POS_OVERRIDE, NO_POS_OVERRIDE, ""))
6767
.put("org.cyclops.integratedterminals.inventory.container.ContainerTerminalStoragePart", new ContOverride(NO_POS_OVERRIDE, NO_POS_OVERRIDE, ""))
68-
.put("com.refinedmods.refinedstorage.screen.*", new ContOverride(NO_POS_OVERRIDE, NO_POS_OVERRIDE, ""))
68+
.put("com.refinedmods.refinedstorage.*", new ContOverride(NO_POS_OVERRIDE, NO_POS_OVERRIDE, ""))
6969
.put("net.p3pp3rf1y.sophisticatedbackpacks.common.gui.BackpackContainer", new ContOverride(NO_POS_OVERRIDE, NO_POS_OVERRIDE, ""))
7070
.put("net.p3pp3rf1y.sophisticatedstorage.common.gui.StorageContainerMenu", new ContOverride(NO_POS_OVERRIDE, NO_POS_OVERRIDE, ""))
7171
.put("tfar.craftingstation.CraftingStationMenu", new ContOverride(NO_POS_OVERRIDE, NO_POS_OVERRIDE, ""))
@@ -97,6 +97,9 @@ public class InvTweaksConfig {
9797
private static final ModConfigSpec.BooleanValue ENABLE_QUICKVIEW;
9898
private static final ModConfigSpec.IntValue ENABLE_SORT;
9999
private static final ModConfigSpec.IntValue ENABLE_BUTTONS;
100+
private static final ModConfigSpec.BooleanValue ENABLE_QUICK_STACK;
101+
private static final ModConfigSpec.BooleanValue ENABLE_THROW_ALL;
102+
private static final ModConfigSpec.EnumValue<SortOrder> SORT_ORDER;
100103
private static final ModConfigSpec.ConfigValue<List<? extends UnmodifiableConfig>> CONT_OVERRIDES;
101104
private static final Map<UUID, Map<String, Category>> playerToCats = new HashMap<>();
102105
private static final Map<UUID, Ruleset> playerToRules = new HashMap<>();
@@ -159,6 +162,15 @@ public class InvTweaksConfig {
159162
"CATEGORY = /OTHER covers all remaining items after other rules are exhausted")
160163
.defineList("rules", DEFAULT_RAW_RULES, obj -> obj instanceof String);
161164

165+
SORT_ORDER =
166+
builder
167+
.comment(
168+
"Order of items within a category, in /OTHER slots and in containers",
169+
"CREATIVE = creative inventory tab order, then item name",
170+
"NAME = item name",
171+
"MOD = mod, then item name")
172+
.defineEnum("sortOrder", SortOrder.CREATIVE);
173+
162174
CONT_OVERRIDES =
163175
builder
164176
.comment(
@@ -208,6 +220,21 @@ public class InvTweaksConfig {
208220
"2 = buttons for external sorting only",
209221
"3 = all buttons enabled (default)")
210222
.defineInRange("enableButtons", 3, 0, 3);
223+
ENABLE_QUICK_STACK =
224+
builder
225+
.comment(
226+
"Show quick stack buttons next to the player and container inventories",
227+
"Clicking moves items into the other inventory, if that inventory already holds the same item",
228+
"Shift-clicking moves everything that fits",
229+
"/LOCKED and /FROZEN slots are left alone")
230+
.define("quickStack", true);
231+
ENABLE_THROW_ALL =
232+
builder
233+
.comment(
234+
"Ctrl+Shift+drop key over an item throws every stack of that item from the same inventory",
235+
"/LOCKED and /FROZEN slots are left alone, except the stack under the cursor",
236+
"Inactive when Inventory Essentials is installed, which has its own bulk drop on the same keys")
237+
.define("throwAll", true);
211238

212239
builder.pop();
213240
}
@@ -374,6 +401,21 @@ public static boolean isQuickViewEnabled() {
374401
return ENABLE_QUICKVIEW.get();
375402
}
376403

404+
public static boolean isQuickStackEnabled() {
405+
return ENABLE_QUICK_STACK.get();
406+
}
407+
408+
public static boolean isThrowAllEnabled() {
409+
return ENABLE_THROW_ALL.get();
410+
}
411+
412+
public static SortOrder getSortOrder() {
413+
return SORT_ORDER.get();
414+
}
415+
416+
public static void setSortOrder(SortOrder order) {
417+
SORT_ORDER.set(order);
418+
}
377419
public static boolean isDebugEnabled() {
378420
return CLIENT_CONFIG.isLoaded() && ENABLE_DEBUG.get();
379421
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package invtweaks.config;
2+
3+
public enum SortOrder {
4+
CREATIVE,
5+
NAME,
6+
MOD
7+
}

‎src/main/java/invtweaks/events/ClientEvents.java‎

Lines changed: 63 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,16 @@
77
import invtweaks.config.ContOverride;
88
import invtweaks.config.InvTweaksConfig;
99
import invtweaks.config.Ruleset;
10+
import invtweaks.gui.InvTweaksButtonQuickStack;
1011
import invtweaks.gui.InvTweaksButtonSort;
12+
import invtweaks.network.PacketQuickStack;
1113
import invtweaks.network.PacketSortInv;
14+
import invtweaks.network.PacketSortOrdered;
15+
import invtweaks.util.ClientSortOrder;
1216
import invtweaks.util.ClientUtils;
17+
import invtweaks.util.QuickStack;
1318
import invtweaks.util.Sorting;
19+
import invtweaks.util.ThrowAll;
1420
import invtweaks.util.Utils;
1521
import it.unimi.dsi.fastutil.ints.IntArrayList;
1622
import it.unimi.dsi.fastutil.ints.IntList;
@@ -51,10 +57,25 @@ private ClientEvents() {
5157
public static final int MIN_SLOTS = 9;
5258

5359
private static void requestSort(boolean isPlayer, String screenClass) {
54-
if (ClientUtils.serverConnectionExists()) {
60+
Player player = ClientUtils.safeGetPlayer();
61+
if (player == null) {
62+
return;
63+
}
64+
if (ClientUtils.serverHasChannel(PacketSortOrdered.TYPE)) {
65+
PacketDistributor.sendToServer(new PacketSortOrdered(isPlayer, screenClass, ClientSortOrder.ranks(player, isPlayer)));
66+
} else if (ClientUtils.serverConnectionExists()) {
5567
PacketDistributor.sendToServer(new PacketSortInv(isPlayer, screenClass));
5668
} else {
57-
Sorting.executeSort(ClientUtils.safeGetPlayer(), isPlayer, screenClass);
69+
Sorting.executeSort(player, isPlayer, screenClass, ClientSortOrder.comparator());
70+
}
71+
}
72+
73+
private static void requestQuickStack(boolean fromPlayer, String screenClass) {
74+
boolean moveAll = ClientUtils.isQuickStackAllDown();
75+
if (ClientUtils.serverHasChannel(PacketQuickStack.TYPE)) {
76+
PacketDistributor.sendToServer(new PacketQuickStack(fromPlayer, moveAll, screenClass));
77+
} else {
78+
QuickStack.execute(ClientUtils.safeGetPlayer(), fromPlayer, moveAll, screenClass);
5879
}
5980
}
6081

@@ -85,17 +106,21 @@ public static void onScreenEventInit(ScreenEvent.Init.Post event) {
85106
InvTweaksMod.LOGGER.info("Opened screen {} with menu {}", screen.getClass().getName(), screen.getMenu().getClass().getName());
86107
}
87108

109+
String screenClass = screen.getClass().getName();
110+
88111
// first, work with player inventory
89-
Slot placement = getDefaultButtonPlacement(screen.getMenu().slots, Utils::isPlayerSlot);
90-
if (placement != null
112+
Slot playerPlacement = getDefaultButtonPlacement(screen.getMenu().slots, Utils::isPlayerSlot);
113+
boolean hasPlayerSortButton = false;
114+
if (playerPlacement != null
91115
&& InvTweaksConfig.isSortEnabled(true)
92116
&& InvTweaksConfig.isButtonEnabled(true)) {
93117
try {
94118
event.addListener(
95119
new InvTweaksButtonSort(
96-
screen.getGuiLeft() + placement.x + 17,
97-
screen.getGuiTop() + placement.y,
98-
btn -> requestSort(true, screen.getClass().getName())));
120+
screen.getGuiLeft() + playerPlacement.x + 17,
121+
screen.getGuiTop() + playerPlacement.y,
122+
btn -> requestSort(true, screenClass)));
123+
hasPlayerSortButton = true;
99124
} catch (Exception e) {
100125
Throwables.throwIfUnchecked(e);
101126
throw new RuntimeException(e);
@@ -112,7 +137,7 @@ public static void onScreenEventInit(ScreenEvent.Init.Post event) {
112137
x = override.getX();
113138
y = override.getY();
114139
}
115-
placement = getDefaultButtonPlacement(screen.getMenu().slots, slot -> slot.isActive() && !(Utils.isPlayerSlot(slot) || slot.container instanceof CraftingContainer));
140+
Slot placement = getDefaultButtonPlacement(screen.getMenu().slots, slot -> slot.isActive() && !(Utils.isPlayerSlot(slot) || slot.container instanceof CraftingContainer));
116141
if (placement != null) {
117142
if (x == InvTweaksConfig.NO_POS_OVERRIDE) {
118143
x = placement.x + 17;
@@ -122,18 +147,35 @@ public static void onScreenEventInit(ScreenEvent.Init.Post event) {
122147
}
123148
}
124149

150+
boolean hasButtonPosition = x != InvTweaksConfig.NO_POS_OVERRIDE && y != InvTweaksConfig.NO_POS_OVERRIDE;
151+
boolean hasExtSortButton = false;
125152
if (InvTweaksConfig.isSortEnabled(false)) {
126153
try {
127-
boolean hasButtonPosition = x != InvTweaksConfig.NO_POS_OVERRIDE && y != InvTweaksConfig.NO_POS_OVERRIDE;
128154
if (hasButtonPosition && InvTweaksConfig.isButtonEnabled(false)) {
129-
event.addListener(new InvTweaksButtonSort(screen.getGuiLeft() + x, screen.getGuiTop() + y, btn -> requestSort(false, screen.getClass().getName())));
155+
event.addListener(new InvTweaksButtonSort(screen.getGuiLeft() + x, screen.getGuiTop() + y, btn -> requestSort(false, screenClass)));
156+
hasExtSortButton = true;
130157
}
131158
screensWithExtSort.add(screen);
132159
} catch (Exception e) {
133160
Throwables.throwIfUnchecked(e);
134161
throw new RuntimeException(e);
135162
}
136163
}
164+
165+
if (hasButtonPosition && InvTweaksConfig.isQuickStackEnabled()) {
166+
event.addListener(new InvTweaksButtonQuickStack(
167+
screen.getGuiLeft() + x,
168+
screen.getGuiTop() + y + (hasExtSortButton ? 18 : 0),
169+
false,
170+
btn -> requestQuickStack(false, screenClass)));
171+
if (playerPlacement != null) {
172+
event.addListener(new InvTweaksButtonQuickStack(
173+
screen.getGuiLeft() + playerPlacement.x + 17,
174+
screen.getGuiTop() + playerPlacement.y + (hasPlayerSortButton ? 18 : 0),
175+
true,
176+
btn -> requestQuickStack(true, screenClass)));
177+
}
178+
}
137179
}
138180
}
139181
}
@@ -154,6 +196,17 @@ public static boolean isJEIKeyboardActive() {
154196
@SubscribeEvent
155197
public static void onKeyPressed(ScreenEvent.KeyPressed.Pre event) {
156198
if (event.getScreen() instanceof AbstractContainerScreen<?> screen && !(screen instanceof CreativeModeInventoryScreen) && !(screen.getFocused() instanceof EditBox) && !isJEIKeyboardActive()) {
199+
if (InvTweaksConfig.isThrowAllEnabled()
200+
&& !ThrowAll.isHandledElsewhere()
201+
&& Screen.hasControlDown() && Screen.hasShiftDown()
202+
&& Minecraft.getInstance().options.keyDrop.matches(event.getKeyCode(), event.getScanCode())) {
203+
Slot hovered = screen.getSlotUnderMouse();
204+
Player player = Minecraft.getInstance().player;
205+
if (hovered != null && player != null && ThrowAll.execute(player, hovered, screen.getClass().getName())) {
206+
event.setCanceled(true);
207+
return;
208+
}
209+
}
157210
if (
158211
InvTweaksConfig.isSortEnabled(true) &&
159212
KeyMappings.SORT_PLAYER.isActiveAndMatches(InputConstants.getKey(event.getKeyCode(), event.getScanCode()))

‎src/main/java/invtweaks/gui/InvTweaksButton.java‎

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,10 @@ public void renderWidget(GuiGraphics graphics, int mouseX, int mouseY, float par
2727
&& mouseY >= this.getY()
2828
&& mouseX < this.getX() + this.width
2929
&& mouseY < this.getY() + this.height;
30-
graphics.blit(button, getX(), getY(), tx, ty + (isHovered ? 16 : 0), 14, 16);
30+
graphics.blit(button, getX(), getY(), textureX(), ty + (isHovered ? 16 : 0), 14, 16);
31+
}
32+
33+
protected int textureX() {
34+
return tx;
3135
}
3236
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package invtweaks.gui;
2+
3+
import invtweaks.util.ClientUtils;
4+
import net.minecraft.client.gui.components.Tooltip;
5+
import net.minecraft.network.chat.Component;
6+
7+
public class InvTweaksButtonQuickStack extends InvTweaksButton {
8+
private final boolean towardsContainer;
9+
10+
public InvTweaksButtonQuickStack(int x, int y, boolean towardsContainer, OnPress handler) {
11+
super(x, y, towardsContainer ? 14 : 28, 0, handler);
12+
this.towardsContainer = towardsContainer;
13+
setTooltip(Tooltip.create(Component.translatable(towardsContainer ? "invtweaks.button.quick_stack.to_container" : "invtweaks.button.quick_stack.to_player")));
14+
}
15+
16+
public boolean isTowardsContainer() {
17+
return towardsContainer;
18+
}
19+
20+
@Override
21+
protected int textureX() {
22+
return (towardsContainer ? 14 : 28) + (ClientUtils.isQuickStackAllDown() ? 28 : 0);
23+
}
24+
}

‎src/main/java/invtweaks/network/NetworkDispatcher.java‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ public static void register(final RegisterPayloadHandlersEvent event) {
1818

1919
registrar.optional()
2020
.playToServer(PacketSortInv.TYPE, PacketSortInv.CODEC, (payload, context) -> payload.handle(payload, context))
21+
.playToServer(PacketSortOrdered.TYPE, PacketSortOrdered.CODEC, PacketSortOrdered::handle)
22+
.playToServer(PacketQuickStack.TYPE, PacketQuickStack.CODEC, PacketQuickStack::handle)
2123
.playToServer(PacketUpdateConfig.TYPE, PacketUpdateConfig.CODEC, (payload, context) -> payload.handle(payload, context));
2224
}
2325
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package invtweaks.network;
2+
3+
import invtweaks.InvTweaksMod;
4+
import invtweaks.util.QuickStack;
5+
import io.netty.buffer.ByteBuf;
6+
import net.minecraft.network.codec.ByteBufCodecs;
7+
import net.minecraft.network.codec.StreamCodec;
8+
import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
9+
import net.minecraft.resources.ResourceLocation;
10+
import net.neoforged.neoforge.network.handling.IPayloadContext;
11+
12+
public record PacketQuickStack(boolean fromPlayer, boolean moveAll, String screenClass) implements CustomPacketPayload {
13+
public static final Type<PacketQuickStack> TYPE = new Type<>(ResourceLocation.fromNamespaceAndPath(InvTweaksMod.MODID, "packet_quick_stack"));
14+
public static final StreamCodec<ByteBuf, PacketQuickStack> CODEC = StreamCodec.composite(
15+
ByteBufCodecs.BOOL, PacketQuickStack::fromPlayer,
16+
ByteBufCodecs.BOOL, PacketQuickStack::moveAll,
17+
ByteBufCodecs.STRING_UTF8, PacketQuickStack::screenClass,
18+
PacketQuickStack::new);
19+
20+
@Override
21+
public Type<? extends CustomPacketPayload> type() {
22+
return TYPE;
23+
}
24+
25+
public static void handle(PacketQuickStack payload, IPayloadContext context) {
26+
context.enqueueWork(() -> QuickStack.execute(context.player(), payload.fromPlayer(), payload.moveAll(), payload.screenClass()))
27+
.exceptionally(e -> {
28+
InvTweaksMod.LOGGER.error("Failed to quick stack", e);
29+
return null;
30+
});
31+
}
32+
}

‎src/main/java/invtweaks/network/PacketSortInv.java‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import invtweaks.InvTweaksMod;
44
import invtweaks.util.Sorting;
5+
import invtweaks.util.Utils;
56
import net.minecraft.network.RegistryFriendlyByteBuf;
67
import net.minecraft.network.codec.StreamCodec;
78
import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
@@ -41,7 +42,7 @@ public Type<? extends CustomPacketPayload> type() {
4142

4243
@Override
4344
public void handle(PacketSortInv payload, IPayloadContext context) {
44-
context.enqueueWork(() -> Sorting.executeSort(context.player(), payload.isPlayer, payload.screenName))
45+
context.enqueueWork(() -> Sorting.executeSort(context.player(), payload.isPlayer, payload.screenName, Utils.FALLBACK_COMPARATOR))
4546
.exceptionally(e -> {
4647
InvTweaksMod.LOGGER.error("Failed to sort inventory", e);
4748
return null;
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
package invtweaks.network;
2+
3+
import invtweaks.InvTweaksMod;
4+
import invtweaks.util.Sorting;
5+
import io.netty.buffer.ByteBuf;
6+
import net.minecraft.network.codec.ByteBufCodecs;
7+
import net.minecraft.network.codec.StreamCodec;
8+
import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
9+
import net.minecraft.resources.ResourceLocation;
10+
import net.neoforged.neoforge.network.handling.IPayloadContext;
11+
12+
import java.util.List;
13+
14+
public record PacketSortOrdered(boolean isPlayer, String screenClass, List<Integer> ranks) implements CustomPacketPayload {
15+
private static final int MAX_RANKS = 4096;
16+
17+
public static final Type<PacketSortOrdered> TYPE = new Type<>(ResourceLocation.fromNamespaceAndPath(InvTweaksMod.MODID, "packet_sort_ordered"));
18+
public static final StreamCodec<ByteBuf, PacketSortOrdered> CODEC = StreamCodec.composite(
19+
ByteBufCodecs.BOOL, PacketSortOrdered::isPlayer,
20+
ByteBufCodecs.STRING_UTF8, PacketSortOrdered::screenClass,
21+
ByteBufCodecs.VAR_INT.apply(ByteBufCodecs.list(MAX_RANKS)), PacketSortOrdered::ranks,
22+
PacketSortOrdered::new);
23+
24+
@Override
25+
public Type<? extends CustomPacketPayload> type() {
26+
return TYPE;
27+
}
28+
29+
public static void handle(PacketSortOrdered payload, IPayloadContext context) {
30+
context.enqueueWork(() -> Sorting.executeSort(
31+
context.player(),
32+
payload.isPlayer(),
33+
payload.screenClass(),
34+
Sorting.orderFromRanks(context.player(), payload.isPlayer(), payload.ranks())))
35+
.exceptionally(e -> {
36+
InvTweaksMod.LOGGER.error("Failed to sort inventory", e);
37+
return null;
38+
});
39+
}
40+
}

0 commit comments

Comments
 (0)