Add basic cost/result placeholders.

This commit is contained in:
fullwall 2023-01-01 23:28:21 +08:00
parent fa5cdb9211
commit 83040ed525
4 changed files with 74 additions and 20 deletions

View File

@ -4,6 +4,8 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.function.Function; import java.util.function.Function;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.ChatColor; import org.bukkit.ChatColor;
@ -17,6 +19,7 @@ import org.bukkit.inventory.meta.ItemMeta;
import com.google.common.base.Joiner; import com.google.common.base.Joiner;
import com.google.common.base.Splitter; import com.google.common.base.Splitter;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import com.google.common.collect.Maps; import com.google.common.collect.Maps;
@ -36,9 +39,11 @@ import net.citizensnpcs.api.gui.MenuPattern;
import net.citizensnpcs.api.gui.MenuSlot; import net.citizensnpcs.api.gui.MenuSlot;
import net.citizensnpcs.api.npc.NPC; import net.citizensnpcs.api.npc.NPC;
import net.citizensnpcs.api.persistence.Persist; import net.citizensnpcs.api.persistence.Persist;
import net.citizensnpcs.api.persistence.Persistable;
import net.citizensnpcs.api.trait.Trait; import net.citizensnpcs.api.trait.Trait;
import net.citizensnpcs.api.trait.TraitName; import net.citizensnpcs.api.trait.TraitName;
import net.citizensnpcs.api.trait.trait.Owner; import net.citizensnpcs.api.trait.trait.Owner;
import net.citizensnpcs.api.util.DataKey;
import net.citizensnpcs.api.util.Messaging; import net.citizensnpcs.api.util.Messaging;
import net.citizensnpcs.api.util.Placeholders; import net.citizensnpcs.api.util.Placeholders;
import net.citizensnpcs.trait.shop.CommandAction; import net.citizensnpcs.trait.shop.CommandAction;
@ -243,14 +248,16 @@ public class ShopTrait extends Trait {
} }
} }
public static class NPCShopItem implements Cloneable { public static class NPCShopItem implements Cloneable, Persistable {
@Persist
private String clickMessage;
@Persist
private String clickToConfirmMessage;
@Persist @Persist
private final List<NPCShopAction> cost = Lists.newArrayList(); private final List<NPCShopAction> cost = Lists.newArrayList();
@Persist @Persist
private ItemStack display; private ItemStack display;
@Persist @Persist
private String message;
@Persist
private final List<NPCShopAction> result = Lists.newArrayList(); private final List<NPCShopAction> result = Lists.newArrayList();
private void changeAction(List<NPCShopAction> source, Function<NPCShopAction, Boolean> filter, private void changeAction(List<NPCShopAction> source, Function<NPCShopAction, Boolean> filter,
@ -308,35 +315,67 @@ public class ShopTrait extends Trait {
ItemStack stack = display.clone(); ItemStack stack = display.clone();
ItemMeta meta = stack.getItemMeta(); ItemMeta meta = stack.getItemMeta();
if (meta.hasDisplayName()) { if (meta.hasDisplayName()) {
meta.setDisplayName(Placeholders.replace(meta.getDisplayName(), player)); meta.setDisplayName(placeholders(meta.getDisplayName(), player));
} }
if (!meta.hasLore()) { if (!meta.hasLore()) {
List<String> lore = Lists.newArrayList(); List<String> lore = Lists.newArrayList();
if (cost.size() > 0) { if (cost.size() > 0) {
result.forEach((a) -> lore.add(a.describe())); result.forEach(a -> lore.add(a.describe()));
} }
if (result.size() > 0) { if (result.size() > 0) {
result.forEach((a) -> lore.add(a.describe())); result.forEach(a -> lore.add(a.describe()));
} }
} }
if (meta.hasLore()) { if (meta.hasLore()) {
meta.setLore(Lists.transform(meta.getLore(), line -> Placeholders.replace(line, player))); meta.setLore(Lists.transform(meta.getLore(), line -> placeholders(line, player)));
} }
stack.setItemMeta(meta); stack.setItemMeta(meta);
return stack; return stack;
} }
public void onClick(NPCShop shop, CitizensInventoryClickEvent event) { @Override
public void load(DataKey key) {
if (key.keyExists("message")) {
clickMessage = key.getString("message");
key.removeKey("message");
}
}
public void onClick(NPCShop shop, CitizensInventoryClickEvent event, boolean secondClick) {
if (clickToConfirmMessage != null && !secondClick) {
Messaging.sendColorless(event.getWhoClicked(),
placeholders(clickToConfirmMessage, (Player) event.getWhoClicked()));
return;
}
List<Transaction> take = execute(cost, action -> action.take(event.getWhoClicked())); List<Transaction> take = execute(cost, action -> action.take(event.getWhoClicked()));
if (take == null) if (take == null)
return; return;
if (execute(result, action -> action.grant(event.getWhoClicked())) == null) { if (execute(result, action -> action.grant(event.getWhoClicked())) == null) {
take.forEach(a -> a.rollback()); take.forEach(a -> a.rollback());
} }
if (message != null) { if (clickMessage != null) {
Messaging.sendColorless(event.getWhoClicked(), message); Messaging.sendColorless(event.getWhoClicked(),
Placeholders.replace(clickMessage, (Player) event.getWhoClicked()));
} }
} }
private String placeholders(String string, Player player) {
string = Placeholders.replace(string, player);
StringBuffer sb = new StringBuffer();
Matcher matcher = PLACEHOLDER_REGEX.matcher(string);
while (matcher.find()) {
matcher.appendReplacement(sb, Joiner.on(", ").join(
Iterables.transform(matcher.group(1).equals("cost") ? cost : result, NPCShopAction::describe)));
}
matcher.appendTail(sb);
return sb.toString();
}
@Override
public void save(DataKey key) {
}
private static final Pattern PLACEHOLDER_REGEX = Pattern.compile("<(cost|result)>", Pattern.CASE_INSENSITIVE);
} }
@Menu(title = "NPC Shop Item Editor", type = InventoryType.CHEST, dimensions = { 6, 9 }) @Menu(title = "NPC Shop Item Editor", type = InventoryType.CHEST, dimensions = { 6, 9 })
@ -368,12 +407,22 @@ public class ShopTrait extends Trait {
if (modified.display != null) { if (modified.display != null) {
ctx.getSlot(9 * 4 + 4).setItemStack(modified.display); ctx.getSlot(9 * 4 + 4).setItemStack(modified.display);
} }
ctx.getSlot(9 * 3 + 4).setItemStack(new ItemStack(Util.getFallbackMaterial("OAK_SIGN", "SIGN")), ctx.getSlot(9 * 3 + 3).setItemStack(new ItemStack(Util.getFallbackMaterial("OAK_SIGN", "SIGN")),
"Set message to send on click, currently:", modified.message); "Set message to send on click, currently:",
ctx.getSlot(9 * 3 + 4).setClickHandler( modified.clickMessage == null ? "Unset" : modified.clickMessage);
e -> ctx.getMenu().transition(InputMenus.stringSetter(() -> modified.message, s -> { ctx.getSlot(9 * 3 + 3).setClickHandler(
modified.message = s; e -> ctx.getMenu().transition(InputMenus.stringSetter(() -> modified.clickMessage, s -> {
ctx.getSlot(9 * 3 + 4).setDescription(modified.message); modified.clickMessage = s;
ctx.getSlot(9 * 3 + 3).setDescription(modified.clickMessage);
})));
ctx.getSlot(9 * 3 + 5).setItemStack(new ItemStack(Util.getFallbackMaterial("FEATHER", "SIGN")),
"Set click to confirm message.", "You can use <cost> or <result> placeholders.\nCurrently:\n"
+ (modified.clickToConfirmMessage == null ? "Unset" : modified.clickToConfirmMessage));
ctx.getSlot(9 * 3 + 5).setClickHandler(
e -> ctx.getMenu().transition(InputMenus.stringSetter(() -> modified.clickToConfirmMessage, s -> {
modified.clickToConfirmMessage = s;
ctx.getSlot(9 * 3 + 5).setDescription(modified.clickToConfirmMessage);
}))); })));
int pos = 0; int pos = 0;
for (GUI template : NPCShopAction.getGUIs()) { for (GUI template : NPCShopAction.getGUIs()) {
@ -425,7 +474,7 @@ public class ShopTrait extends Trait {
})); }));
} }
@MenuSlot(slot = { 4, 3 }, material = Material.FEATHER, amount = 1, title = "<f>Set name") @MenuSlot(slot = { 4, 3 }, material = Material.NAME_TAG, amount = 1, title = "<f>Set name")
public void onEditName(InventoryMenuSlot slot, CitizensInventoryClickEvent event) { public void onEditName(InventoryMenuSlot slot, CitizensInventoryClickEvent event) {
event.setCancelled(true); event.setCancelled(true);
if (modified.display == null) if (modified.display == null)
@ -587,6 +636,7 @@ public class ShopTrait extends Trait {
public static class NPCShopViewer extends InventoryMenuPage { public static class NPCShopViewer extends InventoryMenuPage {
private MenuContext ctx; private MenuContext ctx;
private int currentPage = 0; private int currentPage = 0;
private NPCShopItem lastClickedItem;
private final Player player; private final Player player;
private final NPCShop shop; private final NPCShop shop;
@ -612,7 +662,8 @@ public class ShopTrait extends Trait {
ctx.getSlot(i).setItemStack(item.getDisplayItem(player)); ctx.getSlot(i).setItemStack(item.getDisplayItem(player));
ctx.getSlot(i).setClickHandler(evt -> { ctx.getSlot(i).setClickHandler(evt -> {
evt.setCancelled(true); evt.setCancelled(true);
item.onClick(shop, evt); item.onClick(shop, evt, lastClickedItem == item);
lastClickedItem = item;
}); });
} }

View File

@ -136,7 +136,7 @@ public class CommandAction extends NPCShopAction {
CommandAction old = (CommandAction) previous; CommandAction old = (CommandAction) previous;
description = old.describe(); description = old.describe();
} }
return Util.createItem(Material.BOOK, "Command", description); return Util.createItem(Material.COMMAND_BLOCK, "Command", description);
} }
@Override @Override

View File

@ -88,6 +88,9 @@ public class ItemAction extends NPCShopAction {
@Override @Override
public String describe() { public String describe() {
if (items.size() == 1) {
return items.get(0).getAmount() + " " + Util.prettyEnum(items.get(0).getType());
}
String description = items.size() + " items"; String description = items.size() + " items";
for (int i = 0; i < items.size(); i++) { for (int i = 0; i < items.size(); i++) {
ItemStack item = items.get(i); ItemStack item = items.get(i);

View File

@ -169,7 +169,7 @@ public class PermissionAction extends NPCShopAction {
PermissionAction old = (PermissionAction) previous; PermissionAction old = (PermissionAction) previous;
description = old.describe(); description = old.describe();
} }
return Util.createItem(Util.getFallbackMaterial("OAK_SIGN", "SIGN"), "Permission", description); return Util.createItem(Material.PAPER, "Permission", description);
} }
@Override @Override