Work on npc shop; now possible to buy and sell

This commit is contained in:
fullwall 2022-07-27 17:05:52 +08:00
parent 1f9931fdff
commit 70d7cfa6f2
7 changed files with 482 additions and 401 deletions

View File

@ -39,9 +39,16 @@ import net.citizensnpcs.api.trait.Trait;
import net.citizensnpcs.api.trait.TraitName;
import net.citizensnpcs.api.util.Colorizer;
import net.citizensnpcs.api.util.DataKey;
import net.citizensnpcs.trait.shop.ItemAction;
import net.citizensnpcs.trait.shop.ItemAction.ItemActionGUI;
import net.citizensnpcs.trait.shop.MoneyAction;
import net.citizensnpcs.trait.shop.MoneyAction.MoneyActionGUI;
import net.citizensnpcs.trait.shop.NPCShopAction;
import net.citizensnpcs.trait.shop.NPCShopAction.GUI;
import net.citizensnpcs.trait.shop.NPCShopAction.Transaction;
import net.citizensnpcs.trait.shop.PermissionAction;
import net.citizensnpcs.trait.shop.PermissionAction.PermissionActionGUI;
import net.citizensnpcs.util.Util;
/**
* Shop trait for NPC GUI shops.
@ -62,7 +69,7 @@ public class ShopTrait extends Trait {
public static class NPCShop {
@Persist(value = "")
private final String name;
private String name;
@Persist(reify = true)
private final List<NPCShopPage> pages = Lists.newArrayList();
@Persist
@ -72,6 +79,9 @@ public class ShopTrait extends Trait {
@Persist
private String viewPermission;
private NPCShop() {
}
private NPCShop(String name) {
this.name = name;
}
@ -276,13 +286,13 @@ public class ShopTrait extends Trait {
@MenuSlot(slot = { 3, 4 }, material = Material.DISPENSER, amount = 1, title = "<f>Place display item below")
public static class NPCShopItemEditor extends InventoryMenuPage {
@MenuPattern(
offset = { 0, 0 },
offset = { 0, 6 },
slots = { @MenuSlot(pat = 'x', material = Material.AIR) },
value = "x x\n x \nx x")
private InventoryMenuPattern actionItems;
private final Consumer<NPCShopItem> callback;
@MenuPattern(
offset = { 0, 6 },
offset = { 0, 0 },
slots = { @MenuSlot(pat = 'x', material = Material.AIR) },
value = "x x\n x \nx x")
private InventoryMenuPattern costItems;
@ -300,30 +310,29 @@ public class ShopTrait extends Trait {
public void initialise(MenuContext ctx) {
this.ctx = ctx;
if (modified.display != null) {
ctx.getSlot(9 + 4).setItemStack(modified.display);
ctx.getSlot(9 * 4 + 4).setItemStack(modified.display);
}
int pos = 0;
for (GUI template : NPCShopAction.getGUIs()) {
ItemStack item = template.createMenuItem();
if (item == null)
if (template.createMenuItem(null) == null)
continue;
costItems.getSlots().get(pos).setItemStack(item);
NPCShopAction oldCost = modified.cost.stream().filter(template::manages).findFirst().orElse(null);
costItems.getSlots().get(pos)
.setItemStack(Util.editTitle(template.createMenuItem(oldCost), title -> title + " Cost"));
costItems.getSlots().get(pos).setClickHandler(event -> {
event.setCancelled(true);
ctx.getMenu()
.transition(template.createEditor(
modified.cost.stream().filter(template::manages).findFirst().orElse(null),
cost -> modified.changeCost(template::manages, cost)));
ctx.getMenu().transition(
template.createEditor(oldCost, cost -> modified.changeCost(template::manages, cost)));
});
actionItems.getSlots().get(pos).setItemStack(item);
actionItems.getSlots().get(pos).addClickHandler(event -> {
NPCShopAction oldResult = modified.result.stream().filter(template::manages).findFirst().orElse(null);
actionItems.getSlots().get(pos)
.setItemStack(Util.editTitle(template.createMenuItem(oldResult), title -> title + " Result"));
actionItems.getSlots().get(pos).setClickHandler(event -> {
event.setCancelled(true);
ctx.getMenu()
.transition(template.createEditor(
modified.result.stream().filter(template::manages).findFirst().orElse(null),
result -> modified.changeResult(template::manages, result)));
ctx.getMenu().transition(template.createEditor(oldResult,
result -> modified.changeResult(template::manages, result)));
});
pos++;
@ -400,13 +409,16 @@ public class ShopTrait extends Trait {
}
public static class NPCShopPage {
@Persist("")
@Persist("$key")
private int index;
@Persist(keyType = Integer.class, reify = true)
private final Map<Integer, NPCShopItem> items = Maps.newHashMap();
@Persist
private String title;
private NPCShopPage() {
}
public NPCShopPage(int page) {
this.index = page;
}
@ -475,21 +487,23 @@ public class ShopTrait extends Trait {
ctx.getMenu().transition(new NPCShopViewer(shop));
});
}
ctx.getSlot(2).setDescription("<f>Edit shop view permission<br>" + shop.getRequiredPermission());
ctx.getSlot(6).setDescription("<f>Edit shop title<br>" + shop.title);
}
@MenuSlot(slot = { 0, 4 }, material = Material.FEATHER, amount = 1, title = "Edit shop items")
@MenuSlot(slot = { 0, 4 }, material = Material.FEATHER, amount = 1, title = "<f>Edit shop items")
public void onEditItems(InventoryMenuSlot slot, CitizensInventoryClickEvent event) {
event.setCancelled(true);
ctx.getMenu().transition(new NPCShopContentsEditor(shop));
}
@MenuSlot(slot = { 0, 2 }, material = Material.OAK_SIGN, amount = 1, title = "Edit shop permission")
@MenuSlot(slot = { 0, 2 }, material = Material.OAK_SIGN, amount = 1)
public void onPermissionChange(InventoryMenuSlot slot, CitizensInventoryClickEvent event) {
event.setCancelled(true);
ctx.getMenu().transition(InputMenus.stringSetter(shop::getRequiredPermission, shop::setPermission));
}
@MenuSlot(slot = { 0, 6 }, material = Material.NAME_TAG, amount = 1, title = "Edit shop title")
@MenuSlot(slot = { 0, 6 }, material = Material.NAME_TAG, amount = 1)
public void onSetTitle(InventoryMenuSlot slot, CitizensInventoryClickEvent event) {
event.setCancelled(true);
ctx.getMenu().transition(InputMenus.stringSetter(() -> shop.title, newTitle -> {
@ -497,7 +511,7 @@ public class ShopTrait extends Trait {
}));
}
@MenuSlot(slot = { 0, 0 }, material = Material.BOOK, amount = 1, title = "Edit shop type")
@MenuSlot(slot = { 0, 0 }, material = Material.BOOK, amount = 1, title = "<f>Edit shop type")
public void onShopTypeChange(InventoryMenuSlot slot, CitizensInventoryClickEvent event) {
event.setCancelled(true);
ctx.getMenu().transition(InputMenus.<ShopType> picker("Edit shop type", chosen -> {
@ -594,4 +608,9 @@ public class ShopTrait extends Trait {
}
private static StoredShops SAVED = new StoredShops();
static {
NPCShopAction.register(ItemAction.class, "items", new ItemActionGUI());
NPCShopAction.register(PermissionAction.class, "permissions", new PermissionActionGUI());
NPCShopAction.register(MoneyAction.class, "money", new MoneyActionGUI());
}
}

View File

@ -5,7 +5,6 @@ import com.google.common.base.Preconditions;
import com.google.common.io.BaseEncoding;
import net.citizensnpcs.Settings.Setting;
import net.citizensnpcs.api.npc.NPC;
import net.citizensnpcs.api.persistence.Persist;
import net.citizensnpcs.api.trait.Trait;
import net.citizensnpcs.api.trait.TraitName;
@ -88,33 +87,6 @@ public class SkinTrait extends Trait {
checkPlaceholder(false);
}
@SuppressWarnings("deprecation")
private void migrate() {
boolean update = false;
if (npc.data().has(NPC.PLAYER_SKIN_TEXTURE_PROPERTIES_METADATA)) {
textureRaw = npc.data().get(NPC.PLAYER_SKIN_TEXTURE_PROPERTIES_METADATA);
npc.data().remove(NPC.PLAYER_SKIN_TEXTURE_PROPERTIES_METADATA);
update = true;
}
if (npc.data().has(NPC.PLAYER_SKIN_TEXTURE_PROPERTIES_SIGN_METADATA)) {
signature = npc.data().get(NPC.PLAYER_SKIN_TEXTURE_PROPERTIES_SIGN_METADATA);
npc.data().remove(NPC.PLAYER_SKIN_TEXTURE_PROPERTIES_SIGN_METADATA);
update = true;
}
if (npc.data().has(NPC.PLAYER_SKIN_UUID_METADATA)) {
this.skinName = npc.data().get(NPC.PLAYER_SKIN_UUID_METADATA);
npc.data().remove(NPC.PLAYER_SKIN_UUID_METADATA);
update = true;
}
if (npc.data().has(NPC.PLAYER_SKIN_USE_LATEST)) {
this.updateSkins = npc.data().get(NPC.PLAYER_SKIN_USE_LATEST);
npc.data().remove(NPC.PLAYER_SKIN_USE_LATEST);
}
if (update) {
onSkinChange(false);
}
}
private void onSkinChange(boolean forceUpdate) {
if (npc.isSpawned() && npc.getEntity() instanceof SkinnableEntity) {
((SkinnableEntity) npc.getEntity()).getSkinTracker().notifySkinChange(forceUpdate);
@ -123,7 +95,6 @@ public class SkinTrait extends Trait {
@Override
public void run() {
migrate();
if (timer-- > 0)
return;
timer = Setting.PLACEHOLDER_SKIN_UPDATE_FREQUENCY.asInt();

View File

@ -0,0 +1,159 @@
package net.citizensnpcs.trait.shop;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import org.bukkit.Material;
import org.bukkit.entity.Entity;
import org.bukkit.entity.HumanEntity;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.InventoryHolder;
import org.bukkit.inventory.ItemStack;
import com.google.common.collect.Lists;
import net.citizensnpcs.api.gui.InventoryMenuPage;
import net.citizensnpcs.api.gui.InventoryMenuSlot;
import net.citizensnpcs.api.gui.Menu;
import net.citizensnpcs.api.gui.MenuContext;
import net.citizensnpcs.api.persistence.Persist;
import net.citizensnpcs.util.Util;
public class ItemAction extends NPCShopAction {
@Persist
public List<ItemStack> items = Lists.newArrayList();
public ItemAction() {
}
public ItemAction(ItemStack... items) {
this(Arrays.asList(items));
}
public ItemAction(List<ItemStack> items) {
this.items = items;
}
@Override
public Transaction grant(Entity entity) {
if (!(entity instanceof InventoryHolder))
return Transaction.fail();
Inventory source = ((InventoryHolder) entity).getInventory();
return Transaction.create(() -> {
int free = 0;
for (ItemStack stack : source.getContents()) {
if (stack == null || stack.getType() == Material.AIR) {
free++;
continue;
}
}
return free >= items.size();
}, () -> {
source.addItem(items.toArray(new ItemStack[items.size()]));
}, () -> {
source.removeItem(items.toArray(new ItemStack[items.size()]));
});
}
@Override
public Transaction take(Entity entity) {
if (!(entity instanceof InventoryHolder))
return Transaction.fail();
Inventory source = ((InventoryHolder) entity).getInventory();
return Transaction.create(() -> {
Map<Material, Integer> required = items.stream()
.collect(Collectors.toMap(k -> k.getType(), v -> v.getAmount()));
boolean contains = true;
for (Map.Entry<Material, Integer> entry : required.entrySet()) {
if (!source.contains(entry.getKey(), entry.getValue())) {
contains = false;
}
}
for (ItemStack item : items) {
if (item.hasItemMeta() && !source.contains(item)) {
contains = false;
}
}
return contains;
}, () -> {
source.removeItem(items.toArray(new ItemStack[items.size()]));
}, () -> {
source.addItem(items.toArray(new ItemStack[items.size()]));
});
}
@Menu(title = "Item editor", dimensions = { 3, 9 })
public static class ItemActionEditor extends InventoryMenuPage {
private ItemAction base;
private Consumer<NPCShopAction> callback;
private MenuContext ctx;
public ItemActionEditor() {
}
public ItemActionEditor(ItemAction base, Consumer<NPCShopAction> callback) {
this.base = base;
this.callback = callback;
}
@Override
public void initialise(MenuContext ctx) {
this.ctx = ctx;
for (int i = 0; i < 3 * 9; i++) {
InventoryMenuSlot slot = ctx.getSlot(i);
slot.clear();
if (i < base.items.size()) {
slot.setItemStack(base.items.get(i).clone());
}
slot.setClickHandler(event -> {
event.setCancelled(true);
event.setCurrentItem(event.getCursorNonNull());
});
}
}
@Override
public void onClose(HumanEntity player) {
List<ItemStack> items = Lists.newArrayList();
for (int i = 0; i < 3 * 9; i++) {
if (ctx.getSlot(i).getCurrentItem() != null) {
items.add(ctx.getSlot(i).getCurrentItem().clone());
}
}
callback.accept(items.isEmpty() ? null : new ItemAction(items));
}
}
public static class ItemActionGUI implements GUI {
@Override
public InventoryMenuPage createEditor(NPCShopAction previous, Consumer<NPCShopAction> callback) {
return new ItemActionEditor(previous == null ? new ItemAction() : null, callback);
}
@Override
public ItemStack createMenuItem(NPCShopAction previous) {
String description = null;
if (previous != null) {
ItemAction old = (ItemAction) previous;
description = old.items.size() + " items";
for (int i = 0; i < old.items.size(); i++) {
ItemStack item = old.items.get(i);
description += "\n" + item.getAmount() + " " + Util.prettyEnum(item.getType());
if (i == 3) {
description += "...";
break;
}
}
}
return Util.createItem(Material.CHEST, "Item", description);
}
@Override
public boolean manages(NPCShopAction action) {
return action instanceof ItemAction;
}
}
}

View File

@ -0,0 +1,100 @@
package net.citizensnpcs.trait.shop;
import java.util.function.Consumer;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.OfflinePlayer;
import org.bukkit.entity.Entity;
import org.bukkit.inventory.ItemStack;
import net.citizensnpcs.api.gui.InputMenus;
import net.citizensnpcs.api.gui.InventoryMenuPage;
import net.citizensnpcs.api.persistence.Persist;
import net.citizensnpcs.util.Util;
import net.milkbowl.vault.economy.Economy;
public class MoneyAction extends NPCShopAction {
@Persist
public double money;
public MoneyAction() {
}
@Override
public Transaction grant(Entity entity) {
if (!(entity instanceof OfflinePlayer))
return Transaction.fail();
Economy economy = Bukkit.getServicesManager().getRegistration(Economy.class).getProvider();
OfflinePlayer player = (OfflinePlayer) entity;
return Transaction.create(() -> {
return true;
}, () -> {
economy.depositPlayer(player, money);
}, () -> {
economy.withdrawPlayer(player, money);
});
}
@Override
public Transaction take(Entity entity) {
if (!(entity instanceof OfflinePlayer))
return Transaction.fail();
Economy economy = Bukkit.getServicesManager().getRegistration(Economy.class).getProvider();
OfflinePlayer player = (OfflinePlayer) entity;
return Transaction.create(() -> {
return economy.has(player, money);
}, () -> {
economy.withdrawPlayer(player, money);
}, () -> {
economy.depositPlayer(player, money);
});
}
public static class MoneyActionGUI implements GUI {
private Boolean supported;
@Override
public InventoryMenuPage createEditor(NPCShopAction previous, Consumer<NPCShopAction> callback) {
final MoneyAction action = previous == null ? new MoneyAction() : (MoneyAction) previous;
return InputMenus.filteredStringSetter(() -> Double.toString(action.money), (s) -> {
try {
double result = Double.parseDouble(s);
if (result < 0)
return false;
action.money = result;
} catch (NumberFormatException nfe) {
return false;
}
callback.accept(action);
return true;
});
}
@Override
public ItemStack createMenuItem(NPCShopAction previous) {
if (supported == null) {
try {
supported = Bukkit.getServicesManager().getRegistration(Economy.class).getProvider() != null;
} catch (Throwable t) {
supported = false;
}
}
if (!supported) {
return null;
}
String description = null;
if (previous != null) {
Economy economy = Bukkit.getServicesManager().getRegistration(Economy.class).getProvider();
MoneyAction old = (MoneyAction) previous;
description = old.money + " " + economy.currencyNamePlural();
}
return Util.createItem(Material.GOLD_INGOT, "Money", description);
}
@Override
public boolean manages(NPCShopAction action) {
return action instanceof MoneyAction;
}
}
}

View File

@ -1,39 +1,16 @@
package net.citizensnpcs.trait.shop;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.WeakHashMap;
import java.util.function.Consumer;
import java.util.function.Supplier;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.OfflinePlayer;
import org.bukkit.entity.Entity;
import org.bukkit.entity.HumanEntity;
import org.bukkit.entity.Player;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.InventoryHolder;
import org.bukkit.inventory.ItemStack;
import com.google.common.collect.Lists;
import net.citizensnpcs.api.gui.InputMenus;
import net.citizensnpcs.api.gui.InventoryMenuPage;
import net.citizensnpcs.api.gui.InventoryMenuSlot;
import net.citizensnpcs.api.gui.Menu;
import net.citizensnpcs.api.gui.MenuContext;
import net.citizensnpcs.api.persistence.Persist;
import net.citizensnpcs.api.persistence.PersistenceLoader;
import net.citizensnpcs.api.persistence.PersisterRegistry;
import net.citizensnpcs.api.util.Placeholders;
import net.citizensnpcs.trait.shop.NPCShopAction.ItemAction.ItemActionGUI;
import net.citizensnpcs.trait.shop.NPCShopAction.MoneyAction.MoneyActionGUI;
import net.citizensnpcs.trait.shop.NPCShopAction.PermissionAction.PermissionActionGUI;
import net.citizensnpcs.util.Util;
import net.milkbowl.vault.economy.Economy;
import net.milkbowl.vault.permission.Permission;
public abstract class NPCShopAction implements Cloneable {
@Override
@ -52,332 +29,11 @@ public abstract class NPCShopAction implements Cloneable {
public static interface GUI {
public InventoryMenuPage createEditor(NPCShopAction previous, Consumer<NPCShopAction> callback);
public ItemStack createMenuItem();
public ItemStack createMenuItem(NPCShopAction previous);
public boolean manages(NPCShopAction action);
}
public static class ItemAction extends NPCShopAction {
@Persist
public List<ItemStack> items = Lists.newArrayList();
public ItemAction() {
}
public ItemAction(ItemStack... items) {
this(Arrays.asList(items));
}
public ItemAction(List<ItemStack> items) {
this.items = items;
}
@Override
public Transaction grant(Entity entity) {
if (!(entity instanceof InventoryHolder))
return Transaction.fail();
Inventory source = ((InventoryHolder) entity).getInventory();
return Transaction.create(() -> {
return source.all(Material.AIR).size() > items.size();
}, () -> {
source.addItem(items.toArray(new ItemStack[items.size()]));
}, () -> {
source.removeItem(items.toArray(new ItemStack[items.size()]));
});
}
@Override
public Transaction take(Entity entity) {
if (!(entity instanceof InventoryHolder))
return Transaction.fail();
Inventory source = ((InventoryHolder) entity).getInventory();
return Transaction.create(() -> {
return source.all(Material.AIR).size() > items.size();
}, () -> {
source.removeItem(items.toArray(new ItemStack[items.size()]));
}, () -> {
source.addItem(items.toArray(new ItemStack[items.size()]));
});
}
@Menu(title = "Item editor", dimensions = { 3, 9 })
public static class ItemActionEditor extends InventoryMenuPage {
private ItemAction base;
private Consumer<NPCShopAction> callback;
private MenuContext ctx;
public ItemActionEditor() {
}
public ItemActionEditor(ItemAction base, Consumer<NPCShopAction> callback) {
this.base = base;
this.callback = callback;
}
@Override
public void initialise(MenuContext ctx) {
this.ctx = ctx;
for (int i = 0; i < 3 * 9; i++) {
InventoryMenuSlot slot = ctx.getSlot(i);
slot.clear();
if (i < base.items.size()) {
slot.setItemStack(base.items.get(i).clone());
}
slot.setClickHandler(event -> {
event.setCancelled(true);
event.setCurrentItem(event.getCursorNonNull());
});
}
}
@Override
public void onClose(HumanEntity player) {
List<ItemStack> items = Lists.newArrayList();
for (int i = 0; i < 3 * 9; i++) {
if (ctx.getSlot(i).getCurrentItem() != null) {
items.add(ctx.getSlot(i).getCurrentItem().clone());
}
}
callback.accept(items.isEmpty() ? null : new ItemAction(items));
}
}
public static class ItemActionGUI implements GUI {
@Override
public InventoryMenuPage createEditor(NPCShopAction previous, Consumer<NPCShopAction> callback) {
return new ItemActionEditor(previous == null ? new ItemAction() : null, callback);
}
@Override
public ItemStack createMenuItem() {
return Util.createItem(Material.CHEST, "Item");
}
@Override
public boolean manages(NPCShopAction action) {
return action instanceof ItemAction;
}
}
}
public static class MoneyAction extends NPCShopAction {
@Persist
public double money;
public MoneyAction() {
}
@Override
public Transaction grant(Entity entity) {
if (!(entity instanceof OfflinePlayer))
return Transaction.fail();
Economy economy = Bukkit.getServicesManager().getRegistration(Economy.class).getProvider();
OfflinePlayer player = (OfflinePlayer) entity;
return Transaction.create(() -> {
return true;
}, () -> {
economy.depositPlayer(player, money);
}, () -> {
economy.withdrawPlayer(player, money);
});
}
@Override
public Transaction take(Entity entity) {
if (!(entity instanceof OfflinePlayer))
return Transaction.fail();
Economy economy = Bukkit.getServicesManager().getRegistration(Economy.class).getProvider();
OfflinePlayer player = (OfflinePlayer) entity;
return Transaction.create(() -> {
return economy.has(player, money);
}, () -> {
economy.withdrawPlayer(player, money);
}, () -> {
economy.depositPlayer(player, money);
});
}
public static class MoneyActionGUI implements GUI {
private Boolean supported;
@Override
public InventoryMenuPage createEditor(NPCShopAction previous, Consumer<NPCShopAction> callback) {
final MoneyAction action = previous == null ? new MoneyAction() : (MoneyAction) previous;
return InputMenus.filteredStringSetter(() -> Double.toString(action.money), (s) -> {
try {
double result = Double.parseDouble(s);
if (result < 0)
return false;
action.money = result;
} catch (NumberFormatException nfe) {
return false;
}
callback.accept(action);
return true;
});
}
@Override
public ItemStack createMenuItem() {
if (supported == null) {
try {
supported = Bukkit.getServicesManager().getRegistration(Economy.class).getProvider() != null;
} catch (Throwable t) {
supported = false;
}
}
if (!supported) {
return null;
}
return Util.createItem(Material.GOLD_INGOT, "Money");
}
@Override
public boolean manages(NPCShopAction action) {
return action instanceof MoneyAction;
}
}
}
public static class PermissionAction extends NPCShopAction {
@Persist
public List<String> permissions = Lists.newArrayList();
public PermissionAction() {
}
public PermissionAction(List<String> permissions) {
this.permissions = permissions;
}
@Override
public Transaction grant(Entity entity) {
if (!(entity instanceof Player))
return Transaction.fail();
Player player = (Player) entity;
Permission perm = Bukkit.getServicesManager().getRegistration(Permission.class).getProvider();
return Transaction.create(() -> {
return true;
}, () -> {
for (String permission : permissions) {
perm.playerAdd(player, Placeholders.replace(permission, player));
}
}, () -> {
for (String permission : permissions) {
perm.playerRemove(player, Placeholders.replace(permission, player));
}
});
}
@Override
public Transaction take(Entity entity) {
if (!(entity instanceof Player))
return Transaction.fail();
Player player = (Player) entity;
Permission perm = Bukkit.getServicesManager().getRegistration(Permission.class).getProvider();
return Transaction.create(() -> {
for (String permission : permissions) {
if (!perm.playerHas(player, Placeholders.replace(permission, player))) {
return false;
}
}
return true;
}, () -> {
for (String permission : permissions) {
perm.playerRemove(player, Placeholders.replace(permission, player));
}
}, () -> {
for (String permission : permissions) {
perm.playerAdd(player, Placeholders.replace(permission, player));
}
});
}
@Menu(title = "Permissions editor", dimensions = { 3, 9 })
public static class PermissionActionEditor extends InventoryMenuPage {
private PermissionAction base;
private Consumer<NPCShopAction> callback;
public PermissionActionEditor() {
}
public PermissionActionEditor(PermissionAction base, Consumer<NPCShopAction> callback) {
this.base = base;
this.callback = callback;
}
@Override
public void initialise(MenuContext ctx) {
for (int i = 0; i < 3 * 9; i++) {
final int idx = i;
ctx.getSlot(i).clear();
if (i < base.permissions.size()) {
ctx.getSlot(i).setItemStack(new ItemStack(Material.FEATHER), "<f>Set permission",
"Right click to remove\nCurrently: " + base.permissions.get(i));
}
ctx.getSlot(i).setClickHandler(event -> {
if (event.isRightClick()) {
if (idx < base.permissions.size()) {
base.permissions.remove(idx);
ctx.getSlot(idx).setItemStack(null);
}
return;
}
ctx.getMenu().transition(InputMenus.stringSetter(
() -> idx < base.permissions.size() ? base.permissions.get(idx) : "", (res) -> {
if (res == null) {
if (idx < base.permissions.size()) {
base.permissions.remove(idx);
}
return;
}
if (idx < base.permissions.size()) {
base.permissions.set(idx, res);
} else {
base.permissions.add(res);
}
}));
});
}
}
@Override
public void onClose(HumanEntity player) {
callback.accept(base.permissions.isEmpty() ? null : base);
}
}
public static class PermissionActionGUI implements GUI {
private Boolean supported;
@Override
public InventoryMenuPage createEditor(NPCShopAction previous, Consumer<NPCShopAction> callback) {
return new PermissionActionEditor(
previous == null ? new PermissionAction() : (PermissionAction) previous, callback);
}
@Override
public ItemStack createMenuItem() {
if (supported == null) {
try {
supported = Bukkit.getServicesManager().getRegistration(Permission.class).getProvider() != null;
} catch (Throwable t) {
supported = false;
}
}
if (!supported) {
return null;
}
return Util.createItem(Util.getFallbackMaterial("OAK_SIGN", "SIGN"), "Permission");
}
@Override
public boolean manages(NPCShopAction action) {
return action instanceof PermissionAction;
}
}
}
public static class Transaction {
private final Runnable execute;
private final Supplier<Boolean> possible;
@ -424,9 +80,4 @@ public abstract class NPCShopAction implements Cloneable {
private static final Map<Class<? extends NPCShopAction>, GUI> GUI = new WeakHashMap<>();
private static final PersisterRegistry<NPCShopAction> REGISTRY = PersistenceLoader
.createRegistry(NPCShopAction.class);
static {
register(ItemAction.class, "items", new ItemActionGUI());
register(PermissionAction.class, "permissions", new PermissionActionGUI());
register(MoneyAction.class, "money", new MoneyActionGUI());
}
}

View File

@ -0,0 +1,173 @@
package net.citizensnpcs.trait.shop;
import java.util.List;
import java.util.function.Consumer;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.entity.Entity;
import org.bukkit.entity.HumanEntity;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import com.google.common.collect.Lists;
import net.citizensnpcs.api.gui.InputMenus;
import net.citizensnpcs.api.gui.InventoryMenuPage;
import net.citizensnpcs.api.gui.Menu;
import net.citizensnpcs.api.gui.MenuContext;
import net.citizensnpcs.api.persistence.Persist;
import net.citizensnpcs.api.util.Placeholders;
import net.citizensnpcs.util.Util;
import net.milkbowl.vault.permission.Permission;
public class PermissionAction extends NPCShopAction {
@Persist
public List<String> permissions = Lists.newArrayList();
public PermissionAction() {
}
public PermissionAction(List<String> permissions) {
this.permissions = permissions;
}
@Override
public Transaction grant(Entity entity) {
if (!(entity instanceof Player))
return Transaction.fail();
Player player = (Player) entity;
Permission perm = Bukkit.getServicesManager().getRegistration(Permission.class).getProvider();
return Transaction.create(() -> {
return true;
}, () -> {
for (String permission : permissions) {
perm.playerAdd(player, Placeholders.replace(permission, player));
}
}, () -> {
for (String permission : permissions) {
perm.playerRemove(player, Placeholders.replace(permission, player));
}
});
}
@Override
public Transaction take(Entity entity) {
if (!(entity instanceof Player))
return Transaction.fail();
Player player = (Player) entity;
Permission perm = Bukkit.getServicesManager().getRegistration(Permission.class).getProvider();
return Transaction.create(() -> {
for (String permission : permissions) {
if (!perm.playerHas(player, Placeholders.replace(permission, player))) {
return false;
}
}
return true;
}, () -> {
for (String permission : permissions) {
perm.playerRemove(player, Placeholders.replace(permission, player));
}
}, () -> {
for (String permission : permissions) {
perm.playerAdd(player, Placeholders.replace(permission, player));
}
});
}
@Menu(title = "Permissions editor", dimensions = { 3, 9 })
public static class PermissionActionEditor extends InventoryMenuPage {
private PermissionAction base;
private Consumer<NPCShopAction> callback;
public PermissionActionEditor() {
}
public PermissionActionEditor(PermissionAction base, Consumer<NPCShopAction> callback) {
this.base = base;
this.callback = callback;
}
@Override
public void initialise(MenuContext ctx) {
for (int i = 0; i < 3 * 9; i++) {
final int idx = i;
ctx.getSlot(i).clear();
if (i < base.permissions.size()) {
ctx.getSlot(i).setItemStack(new ItemStack(Material.FEATHER), "<f>Set permission",
"Right click to remove\nCurrently: " + base.permissions.get(i));
}
ctx.getSlot(i).setClickHandler(event -> {
if (event.isRightClick()) {
if (idx < base.permissions.size()) {
base.permissions.remove(idx);
ctx.getSlot(idx).setItemStack(null);
}
return;
}
ctx.getMenu().transition(InputMenus.stringSetter(
() -> idx < base.permissions.size() ? base.permissions.get(idx) : "", (res) -> {
if (res == null) {
if (idx < base.permissions.size()) {
base.permissions.remove(idx);
}
return;
}
if (idx < base.permissions.size()) {
base.permissions.set(idx, res);
} else {
base.permissions.add(res);
}
}));
});
}
}
@Override
public void onClose(HumanEntity player) {
callback.accept(base.permissions.isEmpty() ? null : base);
}
}
public static class PermissionActionGUI implements GUI {
private Boolean supported;
@Override
public InventoryMenuPage createEditor(NPCShopAction previous, Consumer<NPCShopAction> callback) {
return new PermissionActionEditor(previous == null ? new PermissionAction() : (PermissionAction) previous,
callback);
}
@Override
public ItemStack createMenuItem(NPCShopAction previous) {
if (supported == null) {
try {
supported = Bukkit.getServicesManager().getRegistration(Permission.class).getProvider() != null;
} catch (Throwable t) {
supported = false;
}
}
if (!supported) {
return null;
}
String description = null;
if (previous != null) {
PermissionAction old = (PermissionAction) previous;
description = old.permissions.size() + " permissions";
for (int i = 0; i < old.permissions.size(); i++) {
description += "\n" + old.permissions.get(i);
if (i == 3) {
description += "...";
break;
}
}
}
return Util.createItem(Util.getFallbackMaterial("OAK_SIGN", "SIGN"), "Permission", description);
}
@Override
public boolean manages(NPCShopAction action) {
return action instanceof PermissionAction;
}
}
}

View File

@ -5,6 +5,7 @@ import java.util.EnumSet;
import java.util.Random;
import java.util.Set;
import java.util.UUID;
import java.util.function.Function;
import org.bukkit.Bukkit;
import org.bukkit.Location;
@ -91,6 +92,13 @@ public class Util {
return stack;
}
public static ItemStack editTitle(ItemStack item, Function<String, String> transform) {
ItemMeta meta = item.getItemMeta();
meta.setDisplayName(transform.apply(meta.hasDisplayName() ? meta.getDisplayName() : ""));
item.setItemMeta(meta);
return item;
}
public static void face(Entity entity, float yaw, float pitch) {
double pitchCos = Math.cos(Math.toRadians(pitch));
Vector vector = new Vector(Math.sin(Math.toRadians(yaw)) * -pitchCos, -Math.sin(Math.toRadians(pitch)),