Modify items in ItemAction

This commit is contained in:
fullwall 2024-03-24 00:53:47 +08:00
parent 8696a5709e
commit 8f538721cc
2 changed files with 72 additions and 83 deletions

View File

@ -51,43 +51,6 @@ public class ItemAction extends NPCShopAction {
this.items = items;
}
private boolean containsItems(ItemStack[] contents, int repeats, boolean modify) {
List<Integer> req = items.stream().map(i -> i.getAmount() * repeats).collect(Collectors.toList());
for (int i = 0; i < contents.length; i++) {
ItemStack toMatch = contents[i];
if (toMatch == null || toMatch.getType() == Material.AIR || tooDamaged(toMatch))
continue;
toMatch = toMatch.clone();
for (int j = 0; j < items.size(); j++) {
if (toMatch == null)
break;
ItemStack item = items.get(j);
if (req.get(j) <= 0 || !matches(item, toMatch))
continue;
int remaining = req.get(j);
int taken = toMatch.getAmount() > remaining ? remaining : toMatch.getAmount();
if (toMatch.getAmount() == taken) {
toMatch = null;
} else {
toMatch.setAmount(toMatch.getAmount() - taken);
}
if (modify) {
if (toMatch == null) {
contents[i] = null;
} else {
contents[i] = toMatch.clone();
}
}
req.set(j, remaining - taken);
}
}
return req.stream().collect(Collectors.summingInt(n -> n)) <= 0;
}
@Override
public String describe() {
if (items.size() == 1)
@ -135,6 +98,36 @@ public class ItemAction extends NPCShopAction {
.orElse(0);
}
private void giveItems(ItemStack[] inventory, int repeats) {
for (int i = 0; i < repeats; i++) {
List<ItemStack> toAdd = items.stream().map(ItemStack::clone).collect(Collectors.toList());
for (int j = 0; j < inventory.length; j++) {
if (toAdd.isEmpty())
return;
if (inventory[j] == null)
continue;
ItemStack last = toAdd.get(toAdd.size() - 1);
if (!inventory[j].isSimilar(last) || inventory[j].getAmount() >= inventory[j].getMaxStackSize())
continue;
int diff = inventory[j].getMaxStackSize() - inventory[j].getAmount();
if (diff >= last.getAmount()) {
inventory[j].setAmount(inventory[j].getAmount() + last.getAmount());
toAdd.remove(toAdd.size() - 1);
} else {
inventory[j].setAmount(inventory[j].getAmount() + diff);
last.setAmount(last.getAmount() - diff);
}
}
for (int j = 0; j < inventory.length; j++) {
if (toAdd.isEmpty())
break;
if (inventory[j] == null || inventory[j].getType() == Material.AIR) {
inventory[j] = toAdd.remove(toAdd.size() - 1);
}
}
}
}
@Override
public Transaction grant(Entity entity, InventoryMultiplexer im, int repeats) {
if (!(entity instanceof InventoryHolder))
@ -149,30 +142,8 @@ public class ItemAction extends NPCShopAction {
}
}
return free >= items.size() * repeats;
}, () -> im.transact(inventory -> {
for (int i = 0; i < repeats; i++) {
List<ItemStack> toAdd = items.stream().map(ItemStack::clone).collect(Collectors.toList());
for (int j = 0; j < inventory.length; j++) {
if (toAdd.isEmpty())
break;
if (inventory[j] == null || inventory[j].getType() == Material.AIR) {
inventory[j] = toAdd.remove(toAdd.size() - 1);
}
}
}
}), () -> im.transact(inventory -> {
for (int i = 0; i < repeats; i++) {
List<ItemStack> toRemove = items.stream().map(ItemStack::clone).collect(Collectors.toList());
for (int j = 0; j < inventory.length; j++) {
if (toRemove.isEmpty())
break;
if (toRemove.get(toRemove.size() - 1).equals(inventory[j])) {
inventory[j] = null;
toRemove.remove(toRemove.size() - 1);
}
}
}
}));
}, () -> im.transact(inventory -> giveItems(inventory, repeats)),
() -> im.transact(inventory -> takeItems(inventory, repeats, true)));
}
private boolean matches(ItemStack a, ItemStack b) {
@ -219,29 +190,46 @@ public class ItemAction extends NPCShopAction {
if (!(entity instanceof InventoryHolder))
return Transaction.fail();
return Transaction.create(() -> containsItems(im.getInventory(), repeats, false),
() -> im.transact(inventory -> containsItems(inventory, repeats, true)),
() -> im.transact(inventory -> {
for (ItemStack item : items.stream().map(ItemStack::clone).toArray(ItemStack[]::new)) {
for (int i = 0; i < inventory.length; i++) {
ItemStack stack = inventory[i];
if (stack == null || stack.getType() == Material.AIR) {
inventory[i] = item;
break;
}
if (stack.getMaxStackSize() > stack.getAmount() && matches(stack, item)) {
int free = stack.getMaxStackSize() - stack.getAmount();
if (item.getAmount() > free) {
item.setAmount(item.getAmount() - free);
stack.setAmount(stack.getMaxStackSize());
} else {
stack.setAmount(stack.getAmount() + item.getAmount());
break;
}
}
}
return Transaction.create(() -> takeItems(im.getInventory(), repeats, false),
() -> im.transact(inventory -> takeItems(inventory, repeats, true)),
() -> im.transact(inventory -> giveItems(inventory, repeats)));
}
private boolean takeItems(ItemStack[] contents, int repeats, boolean modify) {
List<Integer> req = items.stream().map(i -> i.getAmount() * repeats).collect(Collectors.toList());
for (int i = 0; i < contents.length; i++) {
ItemStack toMatch = contents[i];
if (toMatch == null || toMatch.getType() == Material.AIR || tooDamaged(toMatch))
continue;
toMatch = toMatch.clone();
for (int j = 0; j < items.size(); j++) {
if (toMatch == null)
break;
ItemStack item = items.get(j);
if (req.get(j) <= 0 || !matches(item, toMatch))
continue;
int remaining = req.get(j);
int taken = toMatch.getAmount() > remaining ? remaining : toMatch.getAmount();
if (toMatch.getAmount() == taken) {
toMatch = null;
} else {
toMatch.setAmount(toMatch.getAmount() - taken);
}
if (modify) {
if (toMatch == null) {
contents[i] = null;
} else {
contents[i] = toMatch.clone();
}
}));
}
req.set(j, remaining - taken);
}
}
return req.stream().collect(Collectors.summingInt(n -> n)) <= 0;
}
private boolean tooDamaged(ItemStack toMatch) {

View File

@ -375,6 +375,7 @@
"citizens.commands.npc.sheep.color-set" : "양의 색상이 [{0}]로 설정되었습니다.",
"citizens.commands.npc.sheep.description" : "양 타입 부여",
"citizens.commands.npc.sheep.invalid-color" : "유효하지 않은 양 색상이 지정되었습니다. 유효한 색상은 다음과 같습니다: [[{0}]].",
"citizens.commands.npc.shop.deleted" : "상점 [[{0}]]이(가) 삭제되었습니다.",
"citizens.commands.npc.shop.description" : "NPC 상점 편집/표시",
"citizens.commands.npc.shulker.color-set" : "[[{0}]]의 색상이 [{1}]로 설정되었습니다.",
"citizens.commands.npc.shulker.description" : "셜커 타입 부여",