-
-
Notifications
You must be signed in to change notification settings - Fork 509
/
QIOItemViewerContainer.java
606 lines (540 loc) · 25.4 KB
/
QIOItemViewerContainer.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
package mekanism.common.inventory.container;
import it.unimi.dsi.fastutil.objects.Object2LongMap;
import it.unimi.dsi.fastutil.objects.Object2LongOpenHashMap;
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.UUID;
import java.util.function.Consumer;
import java.util.function.Supplier;
import mekanism.api.Action;
import mekanism.api.math.MathUtils;
import mekanism.api.text.ILangEntry;
import mekanism.common.Mekanism;
import mekanism.common.MekanismLang;
import mekanism.common.config.MekanismConfig;
import mekanism.common.content.qio.IQIOCraftingWindowHolder;
import mekanism.common.content.qio.QIOCraftingTransferHelper;
import mekanism.common.content.qio.QIOCraftingWindow;
import mekanism.common.content.qio.QIOFrequency;
import mekanism.common.content.qio.SearchQueryParser;
import mekanism.common.content.qio.SearchQueryParser.ISearchQuery;
import mekanism.common.inventory.GuiComponents.IDropdownEnum;
import mekanism.common.inventory.GuiComponents.IToggleEnum;
import mekanism.common.inventory.ISlotClickHandler;
import mekanism.common.inventory.container.SelectedWindowData.WindowType;
import mekanism.common.inventory.container.slot.InsertableSlot;
import mekanism.common.inventory.container.slot.InventoryContainerSlot;
import mekanism.common.inventory.container.slot.VirtualCraftingOutputSlot;
import mekanism.common.inventory.container.slot.VirtualInventoryContainerSlot;
import mekanism.common.inventory.slot.CraftingWindowInventorySlot;
import mekanism.common.lib.inventory.HashedItem;
import mekanism.common.lib.inventory.HashedItem.UUIDAwareHashedItem;
import mekanism.common.network.PacketUtils;
import mekanism.common.network.to_server.qio.PacketQIOItemViewerSlotPlace;
import mekanism.common.network.to_server.qio.PacketQIOItemViewerSlotShiftTake;
import mekanism.common.network.to_server.qio.PacketQIOItemViewerSlotTake;
import mekanism.common.registration.impl.ContainerTypeRegistryObject;
import mekanism.common.util.InventoryUtils;
import mekanism.common.util.MekanismUtils;
import mekanism.common.util.MekanismUtils.ResourceType;
import net.minecraft.SharedConstants;
import net.minecraft.client.Minecraft;
import net.minecraft.network.chat.Component;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.util.Mth;
import net.minecraft.world.entity.player.Inventory;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.inventory.Slot;
import net.minecraft.world.item.ItemStack;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.lwjgl.glfw.GLFW;
public abstract class QIOItemViewerContainer extends MekanismContainer implements ISlotClickHandler {
public static final int SLOTS_X_MIN = 8, SLOTS_X_MAX = 16, SLOTS_Y_MIN = 2, SLOTS_Y_MAX = 48;
public static final int SLOTS_START_Y = 43;
private static final int DOUBLE_CLICK_TRANSFER_DURATION = SharedConstants.TICKS_PER_SECOND;
public static int getSlotsYMax() {
int maxY = Mth.ceil(Minecraft.getInstance().getWindow().getGuiScaledHeight() * 0.05 - 8) + 1;
return Mth.clamp(maxY, SLOTS_Y_MIN, SLOTS_Y_MAX);
}
private ListSortType sortType;
private SortDirection sortDirection;
private Object2LongMap<UUIDAwareHashedItem> cachedInventory = new Object2LongOpenHashMap<>();
private long cachedCountCapacity;
private int cachedTypeCapacity;
private long totalItems;
@Nullable
private List<IScrollableSlot> itemList;
@Nullable
private List<IScrollableSlot> searchList;
private Map<String, List<IScrollableSlot>> searchCache = new Object2ObjectOpenHashMap<>();
private String searchQuery = "";
private int doubleClickTransferTicks = 0;
private int lastSlot = -1;
private ItemStack lastStack = ItemStack.EMPTY;
private List<InventoryContainerSlot>[] craftingGridInputSlots;
protected final IQIOCraftingWindowHolder craftingWindowHolder;
private final VirtualInventoryContainerSlot[][] craftingSlots = new VirtualInventoryContainerSlot[IQIOCraftingWindowHolder.MAX_CRAFTING_WINDOWS][10];
protected QIOItemViewerContainer(ContainerTypeRegistryObject<?> type, int id, Inventory inv, boolean remote, IQIOCraftingWindowHolder craftingWindowHolder) {
super(type, id, inv);
this.craftingWindowHolder = craftingWindowHolder;
if (craftingWindowHolder == null) {
//Should never happen, but in case there was an error getting the tile it may have
Mekanism.logger.error("Error getting crafting window holder, closing.");
closeInventory(inv.player);
return;
}
if (remote) {
this.sortType = MekanismConfig.client.qioItemViewerSortType.get();
this.sortDirection = MekanismConfig.client.qioItemViewerSortDirection.get();
//Validate the max size when we are on the client, and fix it if it is incorrect
int maxY = getSlotsYMax();
if (MekanismConfig.client.qioItemViewerSlotsY.get() > maxY) {
MekanismConfig.client.qioItemViewerSlotsY.set(maxY);
// save the updated config info
MekanismConfig.client.save();
}
} else {
this.sortType = ListSortType.NAME;
this.sortDirection = SortDirection.ASCENDING;
craftingGridInputSlots = new List[IQIOCraftingWindowHolder.MAX_CRAFTING_WINDOWS];
}
}
@Nullable
public QIOFrequency getFrequency() {
return craftingWindowHolder.getFrequency();
}
public abstract boolean shiftClickIntoFrequency();
public abstract void toggleTargetDirection();
/**
* @apiNote Only used on the client
*/
public abstract QIOItemViewerContainer recreate();
protected void sync(QIOItemViewerContainer container) {
container.sortType = sortType;
container.cachedInventory = cachedInventory;
container.cachedCountCapacity = cachedCountCapacity;
container.cachedTypeCapacity = cachedTypeCapacity;
container.totalItems = totalItems;
container.itemList = itemList;
container.searchList = searchList;
container.searchCache = searchCache;
container.searchQuery = searchQuery;
container.selectedWindow = getSelectedWindow();
}
@Override
protected int getInventoryYOffset() {
//Use get or default as server side these configs don't exist but the config should be just fine
return SLOTS_START_Y + MekanismConfig.client.qioItemViewerSlotsY.getOrDefault() * 18 + 15;
}
@Override
protected int getInventoryXOffset() {
//Use get or default as server side these configs don't exist but the config should be just fine
return super.getInventoryXOffset() + (MekanismConfig.client.qioItemViewerSlotsX.getOrDefault() - 8) * 18 / 2;
}
@Override
protected void addSlots() {
super.addSlots();
for (QIOCraftingWindow craftingWindow : craftingWindowHolder.getCraftingWindows()) {
byte tableIndex = craftingWindow.getWindowIndex();
for (int slotIndex = 0; slotIndex < 9; slotIndex++) {
addCraftingSlot(craftingWindow.getInputSlot(slotIndex), tableIndex, slotIndex);
}
addCraftingSlot(craftingWindow.getOutputSlot(), tableIndex, 9);
}
}
private void addCraftingSlot(CraftingWindowInventorySlot slot, byte tableIndex, int slotIndex) {
VirtualInventoryContainerSlot containerSlot = slot.createContainerSlot();
craftingSlots[tableIndex][slotIndex] = containerSlot;
addSlot(containerSlot);
}
public VirtualInventoryContainerSlot getCraftingWindowSlot(byte tableIndex, int slotIndex) {
return craftingSlots[tableIndex][slotIndex];
}
@Override
protected void openInventory(@NotNull Inventory inv) {
super.openInventory(inv);
if (isRemote()) {
Mekanism.packetHandler().requestQIOData();
}
}
@Override
protected void closeInventory(@NotNull Player player) {
super.closeInventory(player);
if (!player.level().isClientSide()) {
QIOFrequency freq = getFrequency();
if (freq != null) {
freq.closeItemViewer((ServerPlayer) player);
}
}
}
@Override
public void broadcastChanges() {
super.broadcastChanges();
if (doubleClickTransferTicks > 0) {
doubleClickTransferTicks--;
} else {
resetTransferTracker();
}
}
private void resetTransferTracker() {
doubleClickTransferTicks = 0;
lastSlot = -1;
lastStack = ItemStack.EMPTY;
}
private void setTransferTracker(ItemStack stack, int slot) {
doubleClickTransferTicks = DOUBLE_CLICK_TRANSFER_DURATION;
lastSlot = slot;
lastStack = stack;
}
private void doDoubleClickTransfer(Player player) {
QIOFrequency freq = getFrequency();
if (freq != null) {
Consumer<InsertableSlot> slotConsumer = slot -> {
if (slot.hasItem() && slot.mayPickup(player)) {
//Note: We don't need to sanitize the slot's items as these are just InsertableSlots which have no restrictions on them on how much
// can be extracted at once so even if they somehow have an oversized stack it will be fine
ItemStack slotItem = slot.getItem();
if (InventoryUtils.areItemsStackable(lastStack, slotItem)) {
transferSuccess(slot, player, slotItem, freq.addItem(slotItem));
}
}
};
mainInventorySlots.forEach(slotConsumer);
hotBarSlots.forEach(slotConsumer);
}
}
/**
* Used to lazy initialize the various lists of slots for specific crafting grids
*
* @apiNote Only call on server
*/
private List<InventoryContainerSlot> getCraftingGridSlots(byte selectedCraftingGrid) {
List<InventoryContainerSlot> craftingGridSlots = craftingGridInputSlots[selectedCraftingGrid];
if (craftingGridSlots == null) {
//If we haven't precalculated which slots go with this crafting grid yet, do so
craftingGridSlots = new ArrayList<>();
for (int i = 0; i < 9; i++) {
craftingGridSlots.add(getCraftingWindowSlot(selectedCraftingGrid, i));
}
craftingGridInputSlots[selectedCraftingGrid] = craftingGridSlots;
}
return craftingGridSlots;
}
@NotNull
@Override
public ItemStack quickMoveStack(@NotNull Player player, int slotID) {
Slot currentSlot = slots.get(slotID);
if (currentSlot == null) {
return ItemStack.EMPTY;
}
if (currentSlot instanceof VirtualCraftingOutputSlot virtualSlot) {
//If we are clicking an output crafting slot, allow the slot itself to handle the transferring
return virtualSlot.shiftClickSlot(player, hotBarSlots, mainInventorySlots);
} else if (currentSlot instanceof InventoryContainerSlot) {
//Otherwise, if we are an inventory container slot (crafting input slots in this case)
// use our normal handling to attempt and transfer the contents to the player's inventory
return super.quickMoveStack(player, slotID);
}
// special handling for shift-clicking into GUI
if (!player.level().isClientSide()) {
//Note: We don't need to sanitize the slot's items as these are just InsertableSlots which have no restrictions on them on how much
// can be extracted at once so even if they somehow have an oversized stack it will be fine
ItemStack slotStack = currentSlot.getItem();
if (!shiftClickIntoFrequency()) {
Optional<ItemStack> windowHandling = tryTransferToWindow(player, currentSlot, slotStack);
if (windowHandling.isPresent()) {
return windowHandling.get();
}
}
QIOFrequency frequency = getFrequency();
if (frequency != null) {
if (!slotStack.isEmpty()) {
//There is an item in the slot
ItemStack ret = frequency.addItem(slotStack);
if (slotStack.getCount() != ret.getCount()) {
//We were able to insert some of it
//Make sure that we copy it so that we aren't just pointing to the reference of it
setTransferTracker(slotStack.copy(), slotID);
return transferSuccess(currentSlot, player, slotStack, ret);
}
} else {
if (slotID == lastSlot && !lastStack.isEmpty()) {
doDoubleClickTransfer(player);
}
resetTransferTracker();
return ItemStack.EMPTY;
}
}
if (shiftClickIntoFrequency()) {
//If we tried to shift click it into the frequency first, but weren't able to transfer it
// either because we don't have a frequency or the frequency is full:
// try to transfer it a potentially open window
return tryTransferToWindow(player, currentSlot, slotStack).orElse(ItemStack.EMPTY);
}
}
return ItemStack.EMPTY;
}
private Optional<ItemStack> tryTransferToWindow(Player player, Slot currentSlot, ItemStack slotStack) {
byte selectedCraftingGrid = getSelectedCraftingGrid(player.getUUID());
if (selectedCraftingGrid != -1) {
//If the player has a crafting window open
QIOCraftingWindow craftingWindow = getCraftingWindow(selectedCraftingGrid);
if (!craftingWindow.isOutput(slotStack)) {
// and the stack we are trying to transfer was not the output from the crafting window
// as then shift clicking should be sending it into the QIO, then try transferring it
// into the crafting window before transferring into the frequency
ItemStack stackToInsert = slotStack;
List<InventoryContainerSlot> craftingGridSlots = getCraftingGridSlots(selectedCraftingGrid);
SelectedWindowData windowData = craftingWindow.getWindowData();
//Start by trying to stack it with other things and if that fails try to insert it into empty slots
stackToInsert = insertItem(craftingGridSlots, stackToInsert, windowData);
if (stackToInsert.getCount() != slotStack.getCount()) {
//If something changed, decrease the stack by the amount we inserted,
// and return it as a new stack for what is now in the slot
return Optional.of(transferSuccess(currentSlot, player, slotStack, stackToInsert));
}
//Otherwise, if nothing changed, try to transfer into the QIO Frequency
}
}
return Optional.empty();
}
public void handleBatchUpdate(Object2LongMap<UUIDAwareHashedItem> itemMap, long countCapacity, int typeCapacity) {
cachedInventory = itemMap;
cachedCountCapacity = countCapacity;
cachedTypeCapacity = typeCapacity;
syncItemList();
}
public void handleUpdate(Object2LongMap<UUIDAwareHashedItem> itemMap, long countCapacity, int typeCapacity) {
cachedCountCapacity = countCapacity;
cachedTypeCapacity = typeCapacity;
if (itemMap.isEmpty()) {
//No items need updating, we just changed the counts/capacities, in general this should never be the case, but in case it is
// just short circuit a lot of logic
return;
}
itemMap.object2LongEntrySet().forEach(entry -> {
long value = entry.getLongValue();
if (value == 0) {
cachedInventory.removeLong(entry.getKey());
} else {
cachedInventory.put(entry.getKey(), value);
}
});
syncItemList();
}
public void handleKill() {
itemList = null;
searchList = null;
cachedInventory.clear();
}
public QIOCraftingTransferHelper getTransferHelper(Player player, QIOCraftingWindow craftingWindow) {
return new QIOCraftingTransferHelper(cachedInventory, hotBarSlots, mainInventorySlots, craftingWindow, player);
}
private void syncItemList() {
if (itemList == null) {
itemList = new ArrayList<>();
}
itemList.clear();
searchCache.clear();
totalItems = 0;
//Note: While when only updating some items it would be better in terms of memory churn to just update
// the entries in the itemList that changed instead of creating a new ItemSlotData for each one that is the same,
// this greatly increases the time complexity of doing so due to having to find the matching entry in the itemList
// so is not worth doing so
cachedInventory.forEach((key, value) -> {
itemList.add(new ItemSlotData(key, key.getUUID(), value));
totalItems += value;
});
sortItemList();
if (!searchQuery.isEmpty()) {
updateSearch(searchQuery);
}
}
private void sortItemList() {
if (itemList != null) {
sortType.sort(itemList, sortDirection);
}
}
/**
* @apiNote Only call this client side
*/
public void setSortDirection(SortDirection sortDirection) {
this.sortDirection = sortDirection;
MekanismConfig.client.qioItemViewerSortDirection.set(sortDirection);
MekanismConfig.client.save();
sortItemList();
}
public SortDirection getSortDirection() {
return sortDirection;
}
/**
* @apiNote Only call this client side
*/
public void setSortType(ListSortType sortType) {
this.sortType = sortType;
MekanismConfig.client.qioItemViewerSortType.set(sortType);
MekanismConfig.client.save();
sortItemList();
}
public ListSortType getSortType() {
return sortType;
}
@Nullable
public List<IScrollableSlot> getQIOItemList() {
return searchQuery.isEmpty() ? itemList : searchList;
}
public long getCountCapacity() {
return cachedCountCapacity;
}
public int getTypeCapacity() {
return cachedTypeCapacity;
}
public long getTotalItems() {
return totalItems;
}
public int getTotalTypes() {
return itemList == null ? 0 : itemList.size();
}
public byte getSelectedCraftingGrid() {
return getSelectedCraftingGrid(getSelectedWindow());
}
/**
* @apiNote Only call on server
*/
public byte getSelectedCraftingGrid(UUID player) {
return getSelectedCraftingGrid(getSelectedWindow(player));
}
private byte getSelectedCraftingGrid(@Nullable SelectedWindowData selectedWindow) {
if (selectedWindow != null && selectedWindow.type == WindowType.CRAFTING) {
return selectedWindow.extraData;
}
return (byte) -1;
}
public QIOCraftingWindow getCraftingWindow(int selectedCraftingGrid) {
if (selectedCraftingGrid < 0 || selectedCraftingGrid >= IQIOCraftingWindowHolder.MAX_CRAFTING_WINDOWS) {
throw new IllegalArgumentException("Selected crafting grid not in range.");
}
return craftingWindowHolder.getCraftingWindows()[selectedCraftingGrid];
}
/**
* @apiNote Only call on server
*/
public ItemStack insertIntoPlayerInventory(UUID player, ItemStack stack) {
SelectedWindowData selectedWindow = getSelectedWindow(player);
stack = insertItem(hotBarSlots, stack, true, selectedWindow);
stack = insertItem(mainInventorySlots, stack, true, selectedWindow);
stack = insertItem(hotBarSlots, stack, false, selectedWindow);
stack = insertItem(mainInventorySlots, stack, false, selectedWindow);
return stack;
}
/**
* @apiNote Only call on server
*/
public ItemStack simulateInsertIntoPlayerInventory(UUID player, ItemStack stack) {
SelectedWindowData selectedWindow = getSelectedWindow(player);
stack = insertItemCheckAll(hotBarSlots, stack, selectedWindow, Action.SIMULATE);
stack = insertItemCheckAll(mainInventorySlots, stack, selectedWindow, Action.SIMULATE);
return stack;
}
public void updateSearch(String queryText) {
// searches should only be updated on the client-side
if (!isRemote() || itemList == null) {
return;
}
searchQuery = queryText;
searchList = searchCache.computeIfAbsent(queryText, text -> {
List<IScrollableSlot> list = new ArrayList<>();
ISearchQuery query = SearchQueryParser.parse(text);
for (IScrollableSlot slot : itemList) {
if (query.test(slot.item().getInternalStack())) {
list.add(slot);
}
}
return list;
});
}
@Override
public void onClick(Supplier<@Nullable IScrollableSlot> slotProvider, int button, boolean hasShiftDown, ItemStack heldItem) {
if (hasShiftDown) {
IScrollableSlot slot = slotProvider.get();
if (slot != null) {
PacketUtils.sendToServer(new PacketQIOItemViewerSlotShiftTake(slot.itemUUID()));
}
} else if (button == GLFW.GLFW_MOUSE_BUTTON_LEFT || button == GLFW.GLFW_MOUSE_BUTTON_RIGHT) {
if (heldItem.isEmpty()) {
IScrollableSlot slot = slotProvider.get();
if (slot != null) {
int maxStackSize = Math.min(MathUtils.clampToInt(slot.count()), slot.item().getMaxStackSize());
//Left click -> as much as possible, right click -> half of a stack
//Cap it out at the max stack size of the item, but otherwise try to take the desired amount (taking at least one if it is a single item)
int toTake = button == GLFW.GLFW_MOUSE_BUTTON_LEFT ? maxStackSize : Math.max(1, maxStackSize / 2);
PacketUtils.sendToServer(new PacketQIOItemViewerSlotTake(slot.itemUUID(), toTake));
}
} else {
//Left click -> all held, right click -> single item
int toAdd = button == GLFW.GLFW_MOUSE_BUTTON_LEFT ? heldItem.getCount() : 1;
PacketUtils.sendToServer(new PacketQIOItemViewerSlotPlace(toAdd));
}
}
}
private record ItemSlotData(HashedItem item, UUID itemUUID, long count) implements IScrollableSlot {
}
public enum SortDirection implements IToggleEnum<SortDirection> {
ASCENDING(MekanismUtils.getResource(ResourceType.GUI, "arrow_up.png"), MekanismLang.LIST_SORT_ASCENDING_DESC),
DESCENDING(MekanismUtils.getResource(ResourceType.GUI, "arrow_down.png"), MekanismLang.LIST_SORT_DESCENDING_DESC);
private final ResourceLocation icon;
private final ILangEntry tooltip;
SortDirection(ResourceLocation icon, ILangEntry tooltip) {
this.icon = icon;
this.tooltip = tooltip;
}
@Override
public ResourceLocation getIcon() {
return icon;
}
@Override
public Component getTooltip() {
return tooltip.translate();
}
public boolean isAscending() {
return this == ASCENDING;
}
}
public enum ListSortType implements IDropdownEnum<ListSortType> {
NAME(MekanismLang.LIST_SORT_NAME, MekanismLang.LIST_SORT_NAME_DESC, Comparator.comparing(IScrollableSlot::getDisplayName)),
SIZE(MekanismLang.LIST_SORT_COUNT, MekanismLang.LIST_SORT_COUNT_DESC, Comparator.comparingLong(IScrollableSlot::count).thenComparing(IScrollableSlot::getDisplayName),
Comparator.comparingLong(IScrollableSlot::count).reversed().thenComparing(IScrollableSlot::getDisplayName)),
MOD(MekanismLang.LIST_SORT_MOD, MekanismLang.LIST_SORT_MOD_DESC, Comparator.comparing(IScrollableSlot::getModID).thenComparing(IScrollableSlot::getDisplayName),
Comparator.comparing(IScrollableSlot::getModID).reversed().thenComparing(IScrollableSlot::getDisplayName));
private final ILangEntry name;
private final ILangEntry tooltip;
private final Comparator<IScrollableSlot> ascendingComparator;
private final Comparator<IScrollableSlot> descendingComparator;
ListSortType(ILangEntry name, ILangEntry tooltip, Comparator<IScrollableSlot> ascendingComparator) {
this(name, tooltip, ascendingComparator, ascendingComparator.reversed());
}
ListSortType(ILangEntry name, ILangEntry tooltip, Comparator<IScrollableSlot> ascendingComparator, Comparator<IScrollableSlot> descendingComparator) {
this.name = name;
this.tooltip = tooltip;
this.ascendingComparator = ascendingComparator;
this.descendingComparator = descendingComparator;
}
public void sort(List<IScrollableSlot> list, SortDirection direction) {
list.sort(direction.isAscending() ? ascendingComparator : descendingComparator);
}
@Override
public Component getTooltip() {
return tooltip.translate();
}
@Override
public Component getShortName() {
return name.translate();
}
}
}