Remove fastutil pair

This commit is contained in:
themode 2024-04-15 00:03:37 +02:00 committed by mworzala
parent 643377ea22
commit 43e233e805
No known key found for this signature in database
GPG Key ID: B148F922E64797C7
4 changed files with 97 additions and 77 deletions

View File

@ -1,12 +1,11 @@
package net.minestom.server.inventory;
import it.unimi.dsi.fastutil.Pair;
import net.minestom.server.item.ItemStack;
import net.minestom.server.item.StackingRule;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.function.BiPredicate;
import java.util.function.UnaryOperator;
/**
* A transaction operator is a simpler operation that takes two items and returns two items.
@ -14,22 +13,26 @@ import java.util.function.BiPredicate;
* This allows a significant amount of logic reuse, since many operations are just the {@link #flip(TransactionOperator) flipped}
* version of others.
*/
public interface TransactionOperator {
public interface TransactionOperator extends UnaryOperator<TransactionOperator.Entry> {
/**
* Creates a new operator that filters the given one using the provided predicate
*/
static @NotNull TransactionOperator filter(@NotNull TransactionOperator operator, @NotNull BiPredicate<ItemStack, ItemStack> predicate) {
return (left, right) -> predicate.test(left, right) ? operator.apply(left, right) : null;
return (entry) -> {
final ItemStack left = entry.left();
final ItemStack right = entry.right();
return predicate.test(left, right) ? operator.apply(entry) : null;
};
}
/**
* Creates a new operator that flips the left and right before providing it to the given operator.
*/
static @NotNull TransactionOperator flip(@NotNull TransactionOperator operator) {
return (left, right) -> {
var pair = operator.apply(right, left);
return pair != null ? Pair.of(pair.right(), pair.left()) : null;
return (entry) -> {
final Entry pair = operator.apply(entry.reverse());
return pair != null ? new Entry(pair.right(), pair.left()) : null;
};
}
@ -37,7 +40,9 @@ public interface TransactionOperator {
* Provides operators that try to stack up to the provided number of items to the left.
*/
static @NotNull TransactionOperator stackLeftN(int count) {
return (left, right) -> {
return (entry) -> {
final ItemStack left = entry.left();
final ItemStack right = entry.right();
final StackingRule rule = StackingRule.get();
// Quick exit if the right is air (nothing can be transferred anyway)
@ -54,7 +59,7 @@ public interface TransactionOperator {
if (addedAmount == 0) return null;
return Pair.of(rule.apply(left.isAir() ? right : left, leftAmount + addedAmount), rule.apply(right, rightAmount - addedAmount));
return new Entry(rule.apply(left.isAir() ? right : left, leftAmount + addedAmount), rule.apply(right, rightAmount - addedAmount));
};
}
@ -62,7 +67,9 @@ public interface TransactionOperator {
* Stacks as many items to the left as possible, including if the left is an air item.<br>
* This will not swap the items if they are of different types.
*/
TransactionOperator STACK_LEFT = (left, right) -> {
TransactionOperator STACK_LEFT = (entry) -> {
final ItemStack left = entry.left();
final ItemStack right = entry.right();
final StackingRule rule = StackingRule.get();
// Quick exit if the right is air (nothing can be transferred anyway)
@ -77,7 +84,7 @@ public interface TransactionOperator {
int addedAmount = Math.min(rightAmount, rule.getMaxSize(left) - leftAmount);
return Pair.of(rule.apply(left.isAir() ? right : left, leftAmount + addedAmount), rule.apply(right, rightAmount - addedAmount));
return new Entry(rule.apply(left.isAir() ? right : left, leftAmount + addedAmount), rule.apply(right, rightAmount - addedAmount));
};
/**
@ -89,28 +96,26 @@ public interface TransactionOperator {
* Takes as many items as possible from both stacks, if the given items are stackable.
* This is a symmetric operation.
*/
TransactionOperator TAKE = (left, right) -> {
TransactionOperator TAKE = (entry) -> {
final ItemStack left = entry.left();
final ItemStack right = entry.right();
final StackingRule rule = StackingRule.get();
if (right.isAir() || !rule.canBeStacked(left, right)) {
return null;
}
int leftAmount = rule.getAmount(left);
int rightAmount = rule.getAmount(right);
int subtracted = Math.min(leftAmount, rightAmount);
return Pair.of(rule.apply(left, leftAmount - subtracted), rule.apply(right, rightAmount - subtracted));
final int leftAmount = rule.getAmount(left);
final int rightAmount = rule.getAmount(right);
final int subtracted = Math.min(leftAmount, rightAmount);
return new Entry(rule.apply(left, leftAmount - subtracted), rule.apply(right, rightAmount - subtracted));
};
/**
* Applies this operation to the two given items.
* They are unnamed as to abstract the operations performed from inventories.
* @param left the "left" item
* @param right the "right" item
* @return the resulting pair, or null to indicate no changes
*/
@Nullable Pair<ItemStack, ItemStack> apply(@NotNull ItemStack left, @NotNull ItemStack right);
default Entry apply(@NotNull ItemStack left, @NotNull ItemStack right) {
return apply(new Entry(left, right));
}
record Entry(@NotNull ItemStack left, @NotNull ItemStack right) {
public Entry reverse() {
return new Entry(right, left);
}
}
}

View File

@ -1,6 +1,5 @@
package net.minestom.server.inventory;
import it.unimi.dsi.fastutil.Pair;
import net.minestom.server.item.ItemStack;
import org.jetbrains.annotations.NotNull;
@ -38,10 +37,11 @@ public interface TransactionOption<T> {
*/
TransactionOption<Boolean> DRY_RUN = (inventory, result, itemChangesMap) -> result.isAir();
@NotNull T fill(@NotNull Inventory inventory, @NotNull ItemStack result, @NotNull Map<Integer, ItemStack> itemChangesMap);
@NotNull
T fill(@NotNull Inventory inventory, @NotNull ItemStack result, @NotNull Map<Integer, ItemStack> itemChangesMap);
default @NotNull T fill(@NotNull TransactionType type, @NotNull Inventory inventory, @NotNull ItemStack itemStack) {
Pair<ItemStack, Map<Integer, ItemStack>> result = type.process(itemStack, inventory::getItemStack);
return fill(inventory, result.left(), result.right());
final TransactionType.Entry result = type.apply(itemStack, inventory::getItemStack);
return fill(inventory, result.remaining(), result.changes());
}
}

View File

@ -1,6 +1,5 @@
package net.minestom.server.inventory;
import it.unimi.dsi.fastutil.Pair;
import it.unimi.dsi.fastutil.ints.Int2ObjectArrayMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import net.minestom.server.item.ItemStack;
@ -8,12 +7,13 @@ import org.jetbrains.annotations.NotNull;
import java.util.List;
import java.util.Map;
import java.util.function.BiFunction;
import java.util.function.IntFunction;
/**
* Represents a type of transaction that you can apply to an {@link Inventory}.
*/
public interface TransactionType {
public interface TransactionType extends BiFunction<@NotNull ItemStack, @NotNull IntFunction<ItemStack>, TransactionType.@NotNull Entry> {
/**
* Applies a transaction operator to a given list of slots, turning it into a TransactionType.
@ -22,16 +22,14 @@ public interface TransactionType {
return (item, getter) -> {
Int2ObjectMap<ItemStack> map = new Int2ObjectArrayMap<>();
for (int slot : slots) {
ItemStack slotItem = getter.apply(slot);
Pair<ItemStack, ItemStack> result = operator.apply(slotItem, item);
final ItemStack slotItem = getter.apply(slot);
final TransactionOperator.Entry result = operator.apply(slotItem, item);
if (result == null) continue;
map.put(slot, result.first());
item = result.second();
map.put(slot, result.left());
item = result.right();
}
return Pair.of(item, map);
return new Entry(item, map);
};
}
@ -43,14 +41,13 @@ public interface TransactionType {
static @NotNull TransactionType join(@NotNull TransactionType first, @NotNull TransactionType second) {
return (item, getter) -> {
// Calculate results
Pair<ItemStack, Map<Integer, ItemStack>> f = first.process(item, getter);
Pair<ItemStack, Map<Integer, ItemStack>> s = second.process(f.left(), getter);
final Entry f = first.apply(item, getter);
final Entry s = second.apply(f.remaining(), getter);
// Join results
Map<Integer, ItemStack> map = new Int2ObjectArrayMap<>();
map.putAll(f.right());
map.putAll(s.right());
return Pair.of(s.left(), map);
map.putAll(f.changes());
map.putAll(s.changes());
return new Entry(s.remaining(), map);
};
}
@ -59,17 +56,26 @@ public interface TransactionType {
* Can either take an air slot or be stacked.
*
* @param fill the list of slots that will be added to if they already have some of the item in it
* @param air the list of slots that will be added to if they have air (may be different from {@code fill}).
* @param air the list of slots that will be added to if they have air (may be different from {@code fill}).
*/
static @NotNull TransactionType add(@NotNull List<Integer> fill, @NotNull List<Integer> air) {
var first = general((slotItem, extra) -> !slotItem.isAir() ? TransactionOperator.STACK_LEFT.apply(slotItem, extra) : null, fill);
var second = general((slotItem, extra) -> slotItem.isAir() ? TransactionOperator.STACK_LEFT.apply(slotItem, extra) : null, air);
final TransactionType first = general(entry -> {
final ItemStack slotItem = entry.left();
final ItemStack extra = entry.right();
return !slotItem.isAir() ? TransactionOperator.STACK_LEFT.apply(slotItem, extra) : null;
}, fill);
final TransactionType second = general(entry -> {
final ItemStack slotItem = entry.left();
final ItemStack extra = entry.right();
return slotItem.isAir() ? TransactionOperator.STACK_LEFT.apply(slotItem, extra) : null;
}, air);
return TransactionType.join(first, second);
}
/**
* Takes an item from the inventory.
* Can either transform items to air or reduce their amount.
*
* @param takeSlots the ordered list of slots that will be taken from (if possible)
*/
static @NotNull TransactionType take(@NotNull List<Integer> takeSlots) {
@ -78,10 +84,18 @@ public interface TransactionType {
/**
* Processes the provided item into the given inventory.
*
* @param itemStack the item to process
* @param inventory the inventory function
* @return the remaining portion of the processed item, as well as the changes
*/
@NotNull Pair<ItemStack, Map<Integer, ItemStack>> process(@NotNull ItemStack itemStack, @NotNull IntFunction<ItemStack> inventory);
@Override
@NotNull
Entry apply(@NotNull ItemStack itemStack, @NotNull IntFunction<ItemStack> inventory);
record Entry(@NotNull ItemStack remaining, @NotNull Map<@NotNull Integer, @NotNull ItemStack> changes) {
public Entry {
changes = Map.copyOf(changes);
}
}
}

View File

@ -1,14 +1,16 @@
package net.minestom.server.inventory.click;
import it.unimi.dsi.fastutil.Pair;
import net.minestom.server.entity.EquipmentSlot;
import net.minestom.server.inventory.InventoryType;
import net.minestom.server.inventory.TransactionOperator;
import net.minestom.server.inventory.TransactionType;
import net.minestom.server.inventory.click.Click.Change.Cursor;
import net.minestom.server.inventory.click.Click.Change.DropFromPlayer;
import net.minestom.server.inventory.click.Click.Change.Main;
import net.minestom.server.inventory.click.Click.Change.Player;
import net.minestom.server.item.ItemStack;
import net.minestom.server.item.Material;
import net.minestom.server.item.StackingRule;
import net.minestom.server.inventory.click.Click.Change.*;
import net.minestom.server.utils.inventory.PlayerInventoryUtils;
import org.jetbrains.annotations.NotNull;
@ -33,7 +35,7 @@ public final class ClickProcessors {
final ItemStack cursor = getter.cursor();
final ItemStack clickedItem = getter.get(slot);
Pair<ItemStack, ItemStack> pair = TransactionOperator.STACK_LEFT.apply(clickedItem, cursor);
final TransactionOperator.Entry pair = TransactionOperator.STACK_LEFT.apply(clickedItem, cursor);
if (pair != null) { // Stackable items, combine their counts
return List.of(new Main(slot, pair.left()), new Cursor(pair.right()));
} else if (!RULE.canBeStacked(cursor, clickedItem)) { // If they're unstackable, switch them
@ -50,11 +52,11 @@ public final class ClickProcessors {
if (cursor.isAir()) { // Take half (rounded up) of the clicked item
int newAmount = (int) Math.ceil(RULE.getAmount(clickedItem) / 2d);
Pair<ItemStack, ItemStack> cursorSlot = TransactionOperator.stackLeftN(newAmount).apply(cursor, clickedItem);
final TransactionOperator.Entry cursorSlot = TransactionOperator.stackLeftN(newAmount).apply(cursor, clickedItem);
if (cursorSlot == null) return List.of();
return List.of(new Main(slot, cursorSlot.right()), new Cursor(cursorSlot.left()));
} else if (clickedItem.isAir() || RULE.canBeStacked(clickedItem, cursor)) { // Can add, transfer one over
Pair<ItemStack, ItemStack> slotCursor = TransactionOperator.stackLeftN(1).apply(clickedItem, cursor);
final TransactionOperator.Entry slotCursor = TransactionOperator.stackLeftN(1).apply(clickedItem, cursor);
if (slotCursor == null) return List.of();
return List.of(new Main(slot, slotCursor.left()), new Cursor(slotCursor.right()));
} else { // Two existing of items of different types, so switch
@ -63,9 +65,8 @@ public final class ClickProcessors {
}
public static @NotNull List<Click.Change> middleClick(int slot, @NotNull Click.Getter getter) {
var item = getter.get(slot);
final ItemStack item = getter.get(slot);
if (!getter.cursor().isAir() || item.isAir()) return List.of();
return List.of(new Cursor(RULE.apply(item, RULE.getMaxSize(item))));
}
@ -75,12 +76,12 @@ public final class ClickProcessors {
slots = new ArrayList<>(slots);
slots.removeIf(i -> i == slot);
Pair<ItemStack, Map<Integer, ItemStack>> result = TransactionType.add(slots, slots).process(clicked, getter::get);
final TransactionType.Entry result = TransactionType.add(slots, slots).apply(clicked, getter::get);
List<Click.Change> changes = new ArrayList<>();
result.right().forEach((slotId, item) -> changes.add(new Main(slotId, item)));
result.changes().forEach((slotId, item) -> changes.add(new Main(slotId, item)));
if (!result.left().equals(clicked)) {
changes.add(new Main(slot, result.left()));
if (!result.remaining().equals(clicked)) {
changes.add(new Main(slot, result.remaining()));
}
return changes;
@ -90,15 +91,17 @@ public final class ClickProcessors {
final ItemStack cursor = getter.cursor();
if (cursor.isAir()) return List.of();
var unstacked = TransactionType.general(TransactionOperator.filter(TransactionOperator.STACK_RIGHT, (left, right) -> RULE.getAmount(left) < RULE.getMaxSize(left)), slots);
var stacked = TransactionType.general(TransactionOperator.filter(TransactionOperator.STACK_RIGHT, (left, right) -> RULE.getAmount(left) == RULE.getMaxSize(left)), slots);
final TransactionType unstacked = TransactionType.general(TransactionOperator.filter(TransactionOperator.STACK_RIGHT,
(left, right) -> RULE.getAmount(left) < RULE.getMaxSize(left)), slots);
final TransactionType stacked = TransactionType.general(TransactionOperator.filter(TransactionOperator.STACK_RIGHT,
(left, right) -> RULE.getAmount(left) == RULE.getMaxSize(left)), slots);
Pair<ItemStack, Map<Integer, ItemStack>> result = TransactionType.join(unstacked, stacked).process(cursor, getter::get);
final TransactionType.Entry result = TransactionType.join(unstacked, stacked).apply(cursor, getter::get);
List<Click.Change> changes = new ArrayList<>();
result.right().forEach((slotId, item) -> changes.add(new Main(slotId, item)));
result.changes().forEach((slotId, item) -> changes.add(new Main(slotId, item)));
if (!result.left().equals(cursor)) {
changes.add(new Cursor(result.left()));
if (!result.remaining().equals(cursor)) {
changes.add(new Cursor(result.remaining()));
}
return changes;
@ -108,12 +111,12 @@ public final class ClickProcessors {
final ItemStack cursor = getter.cursor();
if (cursor.isAir()) return List.of();
Pair<ItemStack, Map<Integer, ItemStack>> result = TransactionType.general(TransactionOperator.stackLeftN(countPerSlot), slots).process(cursor, getter::get);
final TransactionType.Entry result = TransactionType.general(TransactionOperator.stackLeftN(countPerSlot), slots).apply(cursor, getter::get);
List<Click.Change> changes = new ArrayList<>();
result.right().forEach((slotId, item) -> changes.add(new Main(slotId, item)));
result.changes().forEach((slotId, item) -> changes.add(new Main(slotId, item)));
if (!result.left().equals(cursor)) {
changes.add(new Cursor(result.left()));
if (!result.remaining().equals(cursor)) {
changes.add(new Cursor(result.remaining()));
}
return changes;
@ -121,7 +124,6 @@ public final class ClickProcessors {
public static @NotNull List<Click.Change> middleDragClick(@NotNull List<Integer> slots, @NotNull Click.Getter getter) {
final ItemStack cursor = getter.cursor();
return slots.stream()
.filter(slot -> getter.get(slot).isAir())
.map(slot -> (Click.Change) new Main(slot, cursor))
@ -132,7 +134,7 @@ public final class ClickProcessors {
final ItemStack cursor = getter.cursor();
if (cursor.isAir()) return List.of(); // Do nothing
var pair = TransactionOperator.stackLeftN(amount).apply(ItemStack.AIR, cursor);
final TransactionOperator.Entry pair = TransactionOperator.stackLeftN(amount).apply(ItemStack.AIR, cursor);
if (pair == null) return List.of();
return List.of(new Cursor(pair.right()), new DropFromPlayer(pair.left()));
@ -142,7 +144,7 @@ public final class ClickProcessors {
final ItemStack item = getter.get(slot);
if (item.isAir()) return List.of(); // Do nothing
var pair = TransactionOperator.stackLeftN(amount).apply(ItemStack.AIR, item);
final TransactionOperator.Entry pair = TransactionOperator.stackLeftN(amount).apply(ItemStack.AIR, item);
if (pair == null) return List.of();
return List.of(new Main(slot, pair.right()), new DropFromPlayer(pair.left()));
@ -196,8 +198,7 @@ public final class ClickProcessors {
yield List.of(new Main(slot, offhandItem), new Player(OFF_HAND_SLOT, selectedItem));
}
case Click.Info.CreativeSetItem(int slot, ItemStack item) -> List.of(new Main(slot, item));
case Click.Info.CreativeDropItem(ItemStack item) ->
List.of(new DropFromPlayer(item));
case Click.Info.CreativeDropItem(ItemStack item) -> List.of(new DropFromPlayer(item));
};
}