mirror of
https://github.com/CitizensDev/Citizens2.git
synced 2025-04-08 21:25:42 +02:00
Work on /npc shop, QoL tweaks, fix scoreboard team removal
This commit is contained in:
parent
ddf5660c66
commit
9cf7779ff4
@ -34,7 +34,6 @@ import net.citizensnpcs.api.CitizensPlugin;
|
|||||||
import net.citizensnpcs.api.InventoryHelper;
|
import net.citizensnpcs.api.InventoryHelper;
|
||||||
import net.citizensnpcs.api.SkullMetaProvider;
|
import net.citizensnpcs.api.SkullMetaProvider;
|
||||||
import net.citizensnpcs.api.ai.speech.SpeechFactory;
|
import net.citizensnpcs.api.ai.speech.SpeechFactory;
|
||||||
import net.citizensnpcs.api.command.CommandContext;
|
|
||||||
import net.citizensnpcs.api.command.CommandManager;
|
import net.citizensnpcs.api.command.CommandManager;
|
||||||
import net.citizensnpcs.api.command.CommandManager.CommandInfo;
|
import net.citizensnpcs.api.command.CommandManager.CommandInfo;
|
||||||
import net.citizensnpcs.api.command.Injector;
|
import net.citizensnpcs.api.command.Injector;
|
||||||
@ -71,6 +70,7 @@ import net.citizensnpcs.npc.ai.speech.Chat;
|
|||||||
import net.citizensnpcs.npc.ai.speech.CitizensSpeechFactory;
|
import net.citizensnpcs.npc.ai.speech.CitizensSpeechFactory;
|
||||||
import net.citizensnpcs.npc.profile.ProfileFetcher;
|
import net.citizensnpcs.npc.profile.ProfileFetcher;
|
||||||
import net.citizensnpcs.npc.skin.Skin;
|
import net.citizensnpcs.npc.skin.Skin;
|
||||||
|
import net.citizensnpcs.trait.ShopTrait;
|
||||||
import net.citizensnpcs.util.Messages;
|
import net.citizensnpcs.util.Messages;
|
||||||
import net.citizensnpcs.util.NMS;
|
import net.citizensnpcs.util.NMS;
|
||||||
import net.citizensnpcs.util.PlayerUpdateTask;
|
import net.citizensnpcs.util.PlayerUpdateTask;
|
||||||
@ -103,6 +103,7 @@ public class Citizens extends JavaPlugin implements CitizensPlugin {
|
|||||||
private boolean saveOnDisable = true;
|
private boolean saveOnDisable = true;
|
||||||
private NPCDataStore saves;
|
private NPCDataStore saves;
|
||||||
private NPCSelector selector;
|
private NPCSelector selector;
|
||||||
|
private Storage shops;
|
||||||
private final SkullMetaProvider skullMetaProvider = new SkullMetaProvider() {
|
private final SkullMetaProvider skullMetaProvider = new SkullMetaProvider() {
|
||||||
@Override
|
@Override
|
||||||
public String getTexture(SkullMeta meta) {
|
public String getTexture(SkullMeta meta) {
|
||||||
@ -305,8 +306,7 @@ public class Citizens extends JavaPlugin implements CitizensPlugin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void onDependentPluginDisable() {
|
public void onDependentPluginDisable() {
|
||||||
storeNPCs();
|
storeNPCs(false);
|
||||||
saves.saveToDiskImmediate();
|
|
||||||
saveOnDisable = false;
|
saveOnDisable = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -347,7 +347,8 @@ public class Citizens extends JavaPlugin implements CitizensPlugin {
|
|||||||
registerScriptHelpers();
|
registerScriptHelpers();
|
||||||
|
|
||||||
saves = createStorage(getDataFolder());
|
saves = createStorage(getDataFolder());
|
||||||
if (saves == null) {
|
shops = new YamlStorage(new File(getDataFolder(), "shops.yml"));
|
||||||
|
if (saves == null || !shops.load()) {
|
||||||
Messaging.severeTr(Messages.FAILED_LOAD_SAVES);
|
Messaging.severeTr(Messages.FAILED_LOAD_SAVES);
|
||||||
Bukkit.getPluginManager().disablePlugin(this);
|
Bukkit.getPluginManager().disablePlugin(this);
|
||||||
return;
|
return;
|
||||||
@ -420,6 +421,9 @@ public class Citizens extends JavaPlugin implements CitizensPlugin {
|
|||||||
saves.reloadFromSource();
|
saves.reloadFromSource();
|
||||||
saves.loadInto(npcRegistry);
|
saves.loadInto(npcRegistry);
|
||||||
|
|
||||||
|
shops.load();
|
||||||
|
ShopTrait.loadShops(shops.getKey(""));
|
||||||
|
|
||||||
getServer().getPluginManager().callEvent(new CitizensReloadEvent());
|
getServer().getPluginManager().callEvent(new CitizensReloadEvent());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -504,17 +508,21 @@ public class Citizens extends JavaPlugin implements CitizensPlugin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void storeNPCs() {
|
public void storeNPCs() {
|
||||||
|
storeNPCs(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void storeNPCs(boolean async) {
|
||||||
if (saves == null)
|
if (saves == null)
|
||||||
return;
|
return;
|
||||||
saves.storeAll(npcRegistry);
|
saves.storeAll(npcRegistry);
|
||||||
}
|
ShopTrait.saveShops(shops.getKey(""));
|
||||||
|
|
||||||
public void storeNPCs(CommandContext args) {
|
|
||||||
storeNPCs();
|
|
||||||
boolean async = args.hasFlag('a');
|
|
||||||
if (async) {
|
if (async) {
|
||||||
saves.saveToDisk();
|
saves.saveToDisk();
|
||||||
|
new Thread(() -> {
|
||||||
|
shops.save();
|
||||||
|
}).start();
|
||||||
} else {
|
} else {
|
||||||
|
shops.save();
|
||||||
saves.saveToDiskImmediate();
|
saves.saveToDiskImmediate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -536,6 +544,8 @@ public class Citizens extends JavaPlugin implements CitizensPlugin {
|
|||||||
Messaging.logTr(Messages.NUM_LOADED_NOTIFICATION, Iterables.size(npcRegistry), "?");
|
Messaging.logTr(Messages.NUM_LOADED_NOTIFICATION, Iterables.size(npcRegistry), "?");
|
||||||
startMetrics();
|
startMetrics();
|
||||||
scheduleSaveTask(Setting.SAVE_TASK_DELAY.asInt());
|
scheduleSaveTask(Setting.SAVE_TASK_DELAY.asInt());
|
||||||
|
shops.load();
|
||||||
|
ShopTrait.loadShops(shops.getKey(""));
|
||||||
Bukkit.getPluginManager().callEvent(new CitizensEnableEvent());
|
Bukkit.getPluginManager().callEvent(new CitizensEnableEvent());
|
||||||
new PlayerUpdateTask().runTaskTimer(Citizens.this, 0, 1);
|
new PlayerUpdateTask().runTaskTimer(Citizens.this, 0, 1);
|
||||||
enabled = true;
|
enabled = true;
|
||||||
@ -545,8 +555,7 @@ public class Citizens extends JavaPlugin implements CitizensPlugin {
|
|||||||
private class CitizensSaveTask implements Runnable {
|
private class CitizensSaveTask implements Runnable {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
storeNPCs();
|
storeNPCs(false);
|
||||||
saves.saveToDisk();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -73,7 +73,7 @@ public class AdminCommands {
|
|||||||
permission = "citizens.admin")
|
permission = "citizens.admin")
|
||||||
public void save(CommandContext args, CommandSender sender, NPC npc) {
|
public void save(CommandContext args, CommandSender sender, NPC npc) {
|
||||||
Messaging.sendTr(sender, Messages.CITIZENS_SAVING);
|
Messaging.sendTr(sender, Messages.CITIZENS_SAVING);
|
||||||
plugin.storeNPCs(args);
|
plugin.storeNPCs(args.hasFlag('a'));
|
||||||
Messaging.sendTr(sender, Messages.CITIZENS_SAVED);
|
Messaging.sendTr(sender, Messages.CITIZENS_SAVED);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1191,7 +1191,7 @@ public class NPCCommands {
|
|||||||
int id = npcs.get(i).getId();
|
int id = npcs.get(i).getId();
|
||||||
String line = StringHelper.wrap(id) + " " + npcs.get(i).getName() + " (<<[[tp:command(/npc tp --id " + id
|
String line = StringHelper.wrap(id) + " " + npcs.get(i).getName() + " (<<[[tp:command(/npc tp --id " + id
|
||||||
+ "):Teleport to this NPC>>) (<<[[summon:command(/npc tph --id " + id
|
+ "):Teleport to this NPC>>) (<<[[summon:command(/npc tph --id " + id
|
||||||
+ "):Teleport NPC to me>> (<<<c>-:command(/npc remove " + id + "):Remove this NPC>>)";
|
+ "):Teleport NPC to me>>) (<<<c>-:command(/npc remove " + id + "):Remove this NPC>>)";
|
||||||
paginator.addLine(line);
|
paginator.addLine(line);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2567,11 +2567,12 @@ public class NPCCommands {
|
|||||||
|
|
||||||
@Command(
|
@Command(
|
||||||
aliases = { "npc" },
|
aliases = { "npc" },
|
||||||
usage = "tp",
|
usage = "tp (-e(xact))",
|
||||||
desc = "Teleport to a NPC",
|
desc = "Teleport in front of an NPC",
|
||||||
modifiers = { "tp", "teleport" },
|
modifiers = { "tp", "teleport" },
|
||||||
min = 1,
|
min = 1,
|
||||||
max = 1,
|
max = 1,
|
||||||
|
flags = "e",
|
||||||
permission = "citizens.npc.tp")
|
permission = "citizens.npc.tp")
|
||||||
public void tp(CommandContext args, Player player, NPC npc) {
|
public void tp(CommandContext args, Player player, NPC npc) {
|
||||||
Location to = npc.getOrAddTrait(CurrentLocation.class).getLocation();
|
Location to = npc.getOrAddTrait(CurrentLocation.class).getLocation();
|
||||||
@ -2579,6 +2580,10 @@ public class NPCCommands {
|
|||||||
Messaging.sendError(player, Messages.TELEPORT_NPC_LOCATION_NOT_FOUND);
|
Messaging.sendError(player, Messages.TELEPORT_NPC_LOCATION_NOT_FOUND);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (!args.hasFlag('e')) {
|
||||||
|
to = to.clone().add(to.getDirection().setY(0));
|
||||||
|
to.setDirection(to.getDirection().multiply(-1)).setPitch(0);
|
||||||
|
}
|
||||||
player.teleport(to, TeleportCause.COMMAND);
|
player.teleport(to, TeleportCause.COMMAND);
|
||||||
Messaging.sendTr(player, Messages.TELEPORTED_TO_NPC, npc.getName());
|
Messaging.sendTr(player, Messages.TELEPORTED_TO_NPC, npc.getName());
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package net.citizensnpcs.trait;
|
package net.citizensnpcs.trait;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.EnumSet;
|
import java.util.EnumSet;
|
||||||
@ -28,6 +29,7 @@ import com.google.common.base.Splitter;
|
|||||||
import com.google.common.collect.Iterables;
|
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;
|
||||||
|
import com.google.common.collect.Sets;
|
||||||
import com.google.common.io.BaseEncoding;
|
import com.google.common.io.BaseEncoding;
|
||||||
import com.google.common.io.ByteArrayDataOutput;
|
import com.google.common.io.ByteArrayDataOutput;
|
||||||
import com.google.common.io.ByteStreams;
|
import com.google.common.io.ByteStreams;
|
||||||
@ -324,6 +326,14 @@ public class CommandTrait extends Trait {
|
|||||||
commands.remove(id);
|
commands.remove(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void save(DataKey key) {
|
||||||
|
Collection<NPCCommand> commands = this.commands.values();
|
||||||
|
for (PlayerNPCCommand playerCommand : cooldowns.values()) {
|
||||||
|
playerCommand.prune(globalCooldowns, commands);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void sendErrorMessage(Player player, CommandTraitMessages msg, Function<String, String> transform,
|
private void sendErrorMessage(Player player, CommandTraitMessages msg, Function<String, String> transform,
|
||||||
Object... objects) {
|
Object... objects) {
|
||||||
if (hideErrorMessages) {
|
if (hideErrorMessages) {
|
||||||
@ -445,6 +455,7 @@ public class CommandTrait extends Trait {
|
|||||||
int globalCooldown;
|
int globalCooldown;
|
||||||
Hand hand;
|
Hand hand;
|
||||||
int id;
|
int id;
|
||||||
|
String key;
|
||||||
int n;
|
int n;
|
||||||
boolean op;
|
boolean op;
|
||||||
List<String> perms;
|
List<String> perms;
|
||||||
@ -466,6 +477,12 @@ public class CommandTrait extends Trait {
|
|||||||
this.bungeeServer = split.size() == 2 && split.get(0).equalsIgnoreCase("server") ? split.get(1) : null;
|
this.bungeeServer = split.size() == 2 && split.get(0).equalsIgnoreCase("server") ? split.get(1) : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getEncodedKey() {
|
||||||
|
if (key != null)
|
||||||
|
return key;
|
||||||
|
return key = BaseEncoding.base64().encode(command.getBytes());
|
||||||
|
}
|
||||||
|
|
||||||
public void run(NPC npc, Player clicker) {
|
public void run(NPC npc, Player clicker) {
|
||||||
String cmd = command;
|
String cmd = command;
|
||||||
if (command.startsWith("say")) {
|
if (command.startsWith("say")) {
|
||||||
@ -628,7 +645,7 @@ public class CommandTrait extends Trait {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
long currentTimeSec = System.currentTimeMillis() / 1000;
|
long currentTimeSec = System.currentTimeMillis() / 1000;
|
||||||
String commandKey = BaseEncoding.base64().encode(command.command.getBytes());
|
String commandKey = command.getEncodedKey();
|
||||||
if (lastUsed.containsKey(commandKey)) {
|
if (lastUsed.containsKey(commandKey)) {
|
||||||
long deadline = ((Number) lastUsed.get(commandKey)).longValue() + command.cooldown;
|
long deadline = ((Number) lastUsed.get(commandKey)).longValue() + command.cooldown;
|
||||||
if (currentTimeSec < deadline) {
|
if (currentTimeSec < deadline) {
|
||||||
@ -667,6 +684,34 @@ public class CommandTrait extends Trait {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void prune(Map<String, Long> globalCooldowns, Collection<NPCCommand> commands) {
|
||||||
|
long currentTimeSec = System.currentTimeMillis() / 1000;
|
||||||
|
Set<String> commandKeys = Sets.newHashSet();
|
||||||
|
for (NPCCommand command : commands) {
|
||||||
|
String commandKey = command.getEncodedKey();
|
||||||
|
commandKeys.add(commandKey);
|
||||||
|
Number number = lastUsed.get(commandKey);
|
||||||
|
if (number != null && number.longValue() + command.cooldown <= currentTimeSec) {
|
||||||
|
lastUsed.remove(commandKey);
|
||||||
|
}
|
||||||
|
if (globalCooldowns != null) {
|
||||||
|
number = globalCooldowns.get(commandKey);
|
||||||
|
if (number != null && number.longValue() + command.globalCooldown <= currentTimeSec) {
|
||||||
|
globalCooldowns.remove(commandKey);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (String key : Sets.difference(Sets.newHashSet(lastUsed.keySet()), commandKeys)) {
|
||||||
|
lastUsed.remove(key);
|
||||||
|
nUsed.remove(key);
|
||||||
|
}
|
||||||
|
if (globalCooldowns != null) {
|
||||||
|
for (String key : Sets.difference(Sets.newHashSet(globalCooldowns.keySet()), commandKeys)) {
|
||||||
|
globalCooldowns.remove(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static boolean requiresTracking(NPCCommand command) {
|
public static boolean requiresTracking(NPCCommand command) {
|
||||||
return command.globalCooldown > 0 || command.cooldown > 0 || command.n > 0
|
return command.globalCooldown > 0 || command.cooldown > 0 || command.n > 0
|
||||||
|| (command.perms != null && command.perms.size() > 0);
|
|| (command.perms != null && command.perms.size() > 0);
|
||||||
|
@ -87,6 +87,7 @@ public class ScoreboardTrait extends Trait {
|
|||||||
if (team.hasEntry(name)) {
|
if (team.hasEntry(name)) {
|
||||||
if (team.getSize() == 1) {
|
if (team.getSize() == 1) {
|
||||||
for (Player player : Bukkit.getOnlinePlayers()) {
|
for (Player player : Bukkit.getOnlinePlayers()) {
|
||||||
|
SENT_TEAMS.remove(player.getUniqueId(), team.getName());
|
||||||
NMS.sendTeamPacket(player, team, 1);
|
NMS.sendTeamPacket(player, team, 1);
|
||||||
}
|
}
|
||||||
team.unregister();
|
team.unregister();
|
||||||
|
@ -3,6 +3,7 @@ package net.citizensnpcs.trait;
|
|||||||
import java.util.List;
|
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 org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.ChatColor;
|
import org.bukkit.ChatColor;
|
||||||
@ -26,15 +27,20 @@ import net.citizensnpcs.api.gui.InputMenus;
|
|||||||
import net.citizensnpcs.api.gui.InputMenus.Choice;
|
import net.citizensnpcs.api.gui.InputMenus.Choice;
|
||||||
import net.citizensnpcs.api.gui.InventoryMenu;
|
import net.citizensnpcs.api.gui.InventoryMenu;
|
||||||
import net.citizensnpcs.api.gui.InventoryMenuPage;
|
import net.citizensnpcs.api.gui.InventoryMenuPage;
|
||||||
|
import net.citizensnpcs.api.gui.InventoryMenuPattern;
|
||||||
import net.citizensnpcs.api.gui.InventoryMenuSlot;
|
import net.citizensnpcs.api.gui.InventoryMenuSlot;
|
||||||
import net.citizensnpcs.api.gui.Menu;
|
import net.citizensnpcs.api.gui.Menu;
|
||||||
import net.citizensnpcs.api.gui.MenuContext;
|
import net.citizensnpcs.api.gui.MenuContext;
|
||||||
|
import net.citizensnpcs.api.gui.MenuPattern;
|
||||||
import net.citizensnpcs.api.gui.MenuSlot;
|
import net.citizensnpcs.api.gui.MenuSlot;
|
||||||
import net.citizensnpcs.api.persistence.Persist;
|
import net.citizensnpcs.api.persistence.Persist;
|
||||||
|
import net.citizensnpcs.api.persistence.PersistenceLoader;
|
||||||
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.util.Colorizer;
|
import net.citizensnpcs.api.util.Colorizer;
|
||||||
|
import net.citizensnpcs.api.util.DataKey;
|
||||||
import net.citizensnpcs.trait.shop.NPCShopAction;
|
import net.citizensnpcs.trait.shop.NPCShopAction;
|
||||||
|
import net.citizensnpcs.trait.shop.NPCShopAction.GUI;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Shop trait for NPC GUI shops.
|
* Shop trait for NPC GUI shops.
|
||||||
@ -46,11 +52,11 @@ public class ShopTrait extends Trait {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public NPCShop getDefaultShop() {
|
public NPCShop getDefaultShop() {
|
||||||
return NPC_SHOPS.computeIfAbsent(npc.getUniqueId().toString(), NPCShop::new);
|
return StoredShops.NPC_SHOPS.computeIfAbsent(npc.getUniqueId().toString(), NPCShop::new);
|
||||||
}
|
}
|
||||||
|
|
||||||
public NPCShop getShop(String name) {
|
public NPCShop getShop(String name) {
|
||||||
return SHOPS.computeIfAbsent(name, NPCShop::new);
|
return StoredShops.GLOBAL_SHOPS.computeIfAbsent(name, NPCShop::new);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class NPCShop {
|
public static class NPCShop {
|
||||||
@ -200,11 +206,36 @@ public class ShopTrait extends Trait {
|
|||||||
|
|
||||||
public static class NPCShopItem implements Cloneable {
|
public static class NPCShopItem implements Cloneable {
|
||||||
@Persist
|
@Persist
|
||||||
private List<NPCShopAction> cost;
|
private final List<NPCShopAction> cost = Lists.newArrayList();
|
||||||
@Persist
|
@Persist
|
||||||
private ItemStack display;
|
private ItemStack display;
|
||||||
@Persist
|
@Persist
|
||||||
private List<NPCShopAction> result;
|
private final List<NPCShopAction> result = Lists.newArrayList();
|
||||||
|
|
||||||
|
private void changeAction(List<NPCShopAction> source, Function<NPCShopAction, Boolean> filter,
|
||||||
|
NPCShopAction delta) {
|
||||||
|
for (int i = 0; i < source.size(); i++) {
|
||||||
|
if (filter.apply(source.get(i))) {
|
||||||
|
if (delta == null) {
|
||||||
|
source.remove(i);
|
||||||
|
} else {
|
||||||
|
source.set(i, delta);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (delta != null) {
|
||||||
|
source.add(delta);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void changeCost(Function<NPCShopAction, Boolean> filter, NPCShopAction cost) {
|
||||||
|
changeAction(this.cost, filter, cost);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void changeResult(Function<NPCShopAction, Boolean> filter, NPCShopAction result) {
|
||||||
|
changeAction(this.result, filter, result);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public NPCShopItem clone() {
|
public NPCShopItem clone() {
|
||||||
@ -220,9 +251,19 @@ public class ShopTrait extends Trait {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Menu(title = "NPC Shop Item Editor", type = InventoryType.CHEST, dimensions = { 6, 9 })
|
@Menu(title = "NPC Shop Item Editor", type = InventoryType.CHEST, dimensions = { 6, 9 })
|
||||||
@MenuSlot(slot = { 0, 4 }, material = Material.DISPENSER, amount = 1, title = "Place display item below")
|
@MenuSlot(slot = { 3, 4 }, material = Material.DISPENSER, amount = 1, title = "<f>Place display item below")
|
||||||
public static class NPCShopItemEditor extends InventoryMenuPage {
|
public static class NPCShopItemEditor extends InventoryMenuPage {
|
||||||
|
@MenuPattern(
|
||||||
|
offset = { 0, 0 },
|
||||||
|
slots = { @MenuSlot(pat = 'x', material = Material.AIR) },
|
||||||
|
value = "x x\n x \nx x")
|
||||||
|
private InventoryMenuPattern actionItems;
|
||||||
private final Consumer<NPCShopItem> callback;
|
private final Consumer<NPCShopItem> callback;
|
||||||
|
@MenuPattern(
|
||||||
|
offset = { 0, 6 },
|
||||||
|
slots = { @MenuSlot(pat = 'x', material = Material.AIR) },
|
||||||
|
value = "x x\n x \nx x")
|
||||||
|
private InventoryMenuPattern costItems;
|
||||||
private MenuContext ctx;
|
private MenuContext ctx;
|
||||||
private final NPCShopItem modified;
|
private final NPCShopItem modified;
|
||||||
private NPCShopItem original;
|
private NPCShopItem original;
|
||||||
@ -239,9 +280,34 @@ public class ShopTrait extends Trait {
|
|||||||
if (modified.display != null) {
|
if (modified.display != null) {
|
||||||
ctx.getSlot(9 + 4).setItemStack(modified.display);
|
ctx.getSlot(9 + 4).setItemStack(modified.display);
|
||||||
}
|
}
|
||||||
|
int pos = 0;
|
||||||
|
for (GUI template : NPCShopAction.getGUIs()) {
|
||||||
|
ItemStack item = template.createMenuItem();
|
||||||
|
if (item == null)
|
||||||
|
continue;
|
||||||
|
costItems.getSlots().get(pos).setItemStack(item);
|
||||||
|
costItems.getSlots().get(pos).addClickHandler(event -> {
|
||||||
|
event.setCancelled(true);
|
||||||
|
ctx.getMenu()
|
||||||
|
.transition(template.createEditor(
|
||||||
|
modified.cost.stream().filter(template::manages).findFirst().orElse(null),
|
||||||
|
cost -> modified.changeCost(template::manages, cost)));
|
||||||
|
});
|
||||||
|
|
||||||
|
actionItems.getSlots().get(pos).setItemStack(item);
|
||||||
|
actionItems.getSlots().get(pos).addClickHandler(event -> {
|
||||||
|
event.setCancelled(true);
|
||||||
|
ctx.getMenu()
|
||||||
|
.transition(template.createEditor(
|
||||||
|
modified.result.stream().filter(template::manages).findFirst().orElse(null),
|
||||||
|
result -> modified.changeResult(template::manages, result)));
|
||||||
|
});
|
||||||
|
|
||||||
|
pos++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@MenuSlot(slot = { 4, 3 }, material = Material.REDSTONE_BLOCK, amount = 1, title = "Cancel")
|
@MenuSlot(slot = { 5, 3 }, material = Material.REDSTONE_BLOCK, amount = 1, title = "<7>Cancel")
|
||||||
public void onCancel(InventoryMenuSlot slot, CitizensInventoryClickEvent event) {
|
public void onCancel(InventoryMenuSlot slot, CitizensInventoryClickEvent event) {
|
||||||
event.setCancelled(true);
|
event.setCancelled(true);
|
||||||
ctx.getMenu().transitionBack();
|
ctx.getMenu().transitionBack();
|
||||||
@ -255,20 +321,23 @@ public class ShopTrait extends Trait {
|
|||||||
callback.accept(original);
|
callback.accept(original);
|
||||||
}
|
}
|
||||||
|
|
||||||
@MenuSlot(slot = { 1, 5 }, material = Material.BOOK, amount = 1, title = "Set description")
|
@MenuSlot(slot = { 4, 5 }, material = Material.BOOK, amount = 1, title = "<f>Set description")
|
||||||
public void onEditDescription(InventoryMenuSlot slot, CitizensInventoryClickEvent event) {
|
public void onEditDescription(InventoryMenuSlot slot, CitizensInventoryClickEvent event) {
|
||||||
event.setCancelled(true);
|
event.setCancelled(true);
|
||||||
if (modified.display == null)
|
if (modified.display == null)
|
||||||
return;
|
return;
|
||||||
ctx.getMenu().transition(InputMenus.stringSetter(
|
ctx.getMenu()
|
||||||
() -> Joiner.on("<br>").skipNulls().join(modified.display.getItemMeta().getLore()), description -> {
|
.transition(InputMenus.stringSetter(() -> modified.display.getItemMeta().hasLore()
|
||||||
ItemMeta meta = modified.display.getItemMeta();
|
? Joiner.on("<br>").skipNulls().join(modified.display.getItemMeta().getLore())
|
||||||
meta.setLore(Lists.newArrayList(Splitter.on("<br>").split(Colorizer.parseColors(description))));
|
: "", description -> {
|
||||||
modified.display.setItemMeta(meta);
|
ItemMeta meta = modified.display.getItemMeta();
|
||||||
}));
|
meta.setLore(Lists
|
||||||
|
.newArrayList(Splitter.on("<br>").split(Colorizer.parseColors(description))));
|
||||||
|
modified.display.setItemMeta(meta);
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
@MenuSlot(slot = { 1, 3 }, material = Material.FEATHER, amount = 1, title = "Set name")
|
@MenuSlot(slot = { 4, 3 }, material = Material.FEATHER, 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)
|
||||||
@ -280,7 +349,7 @@ public class ShopTrait extends Trait {
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ClickHandler(slot = { 1, 4 })
|
@ClickHandler(slot = { 4, 4 })
|
||||||
public void onModifyDisplayItem(InventoryMenuSlot slot, CitizensInventoryClickEvent event) {
|
public void onModifyDisplayItem(InventoryMenuSlot slot, CitizensInventoryClickEvent event) {
|
||||||
event.setCancelled(true);
|
event.setCancelled(true);
|
||||||
if (event.getCursor() != null) {
|
if (event.getCursor() != null) {
|
||||||
@ -292,14 +361,14 @@ public class ShopTrait extends Trait {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@MenuSlot(slot = { 4, 4 }, material = Material.TNT, amount = 1, title = "<c>Remove")
|
@MenuSlot(slot = { 5, 4 }, material = Material.TNT, amount = 1, title = "<c>Remove")
|
||||||
public void onRemove(InventoryMenuSlot slot, CitizensInventoryClickEvent event) {
|
public void onRemove(InventoryMenuSlot slot, CitizensInventoryClickEvent event) {
|
||||||
original = null;
|
original = null;
|
||||||
event.setCancelled(true);
|
event.setCancelled(true);
|
||||||
ctx.getMenu().transitionBack();
|
ctx.getMenu().transitionBack();
|
||||||
}
|
}
|
||||||
|
|
||||||
@MenuSlot(slot = { 4, 5 }, material = Material.EMERALD_BLOCK, amount = 1, title = "Save")
|
@MenuSlot(slot = { 5, 5 }, material = Material.EMERALD_BLOCK, amount = 1, title = "<a>Save")
|
||||||
public void onSave(InventoryMenuSlot slot, CitizensInventoryClickEvent event) {
|
public void onSave(InventoryMenuSlot slot, CitizensInventoryClickEvent event) {
|
||||||
original = modified;
|
original = modified;
|
||||||
event.setCancelled(true);
|
event.setCancelled(true);
|
||||||
@ -485,8 +554,20 @@ public class ShopTrait extends Trait {
|
|||||||
SELL;
|
SELL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Persist(value = "npcShops", reify = true, namespace = "shopstrait")
|
private static class StoredShops {
|
||||||
private static Map<String, NPCShop> NPC_SHOPS = Maps.newHashMap();
|
@Persist(value = "global", reify = true)
|
||||||
@Persist(value = "globalShops", reify = true, namespace = "shopstrait")
|
private static Map<String, NPCShop> GLOBAL_SHOPS = Maps.newHashMap();
|
||||||
private static Map<String, NPCShop> SHOPS = Maps.newHashMap();
|
@Persist(value = "npc", reify = true)
|
||||||
|
private static Map<String, NPCShop> NPC_SHOPS = Maps.newHashMap();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void loadShops(DataKey root) {
|
||||||
|
SAVED = PersistenceLoader.load(StoredShops.class, root);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void saveShops(DataKey root) {
|
||||||
|
PersistenceLoader.save(SAVED, root);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static StoredShops SAVED = new StoredShops();
|
||||||
}
|
}
|
@ -95,7 +95,6 @@ public class SkinTrait extends Trait {
|
|||||||
textureRaw = npc.data().get(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);
|
npc.data().remove(NPC.PLAYER_SKIN_TEXTURE_PROPERTIES_METADATA);
|
||||||
update = true;
|
update = true;
|
||||||
|
|
||||||
}
|
}
|
||||||
if (npc.data().has(NPC.PLAYER_SKIN_TEXTURE_PROPERTIES_SIGN_METADATA)) {
|
if (npc.data().has(NPC.PLAYER_SKIN_TEXTURE_PROPERTIES_SIGN_METADATA)) {
|
||||||
signature = npc.data().get(NPC.PLAYER_SKIN_TEXTURE_PROPERTIES_SIGN_METADATA);
|
signature = npc.data().get(NPC.PLAYER_SKIN_TEXTURE_PROPERTIES_SIGN_METADATA);
|
||||||
|
@ -2,15 +2,31 @@ package net.citizensnpcs.trait.shop;
|
|||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
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.entity.HumanEntity;
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.OfflinePlayer;
|
||||||
|
import org.bukkit.entity.Entity;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.inventory.ItemStack;
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
|
|
||||||
|
import net.citizensnpcs.api.gui.InputMenus;
|
||||||
|
import net.citizensnpcs.api.gui.InventoryMenuPage;
|
||||||
import net.citizensnpcs.api.persistence.Persist;
|
import net.citizensnpcs.api.persistence.Persist;
|
||||||
import net.citizensnpcs.api.persistence.PersistenceLoader;
|
import net.citizensnpcs.api.persistence.PersistenceLoader;
|
||||||
import net.citizensnpcs.api.persistence.PersisterRegistry;
|
import net.citizensnpcs.api.persistence.PersisterRegistry;
|
||||||
|
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 {
|
public abstract class NPCShopAction implements Cloneable {
|
||||||
@Override
|
@Override
|
||||||
@ -22,9 +38,17 @@ public abstract class NPCShopAction implements Cloneable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract boolean grant(HumanEntity entity);
|
public abstract PendingAction grant(Entity entity);
|
||||||
|
|
||||||
public abstract boolean take(HumanEntity entity);
|
public abstract PendingAction take(Entity entity);
|
||||||
|
|
||||||
|
public static interface GUI {
|
||||||
|
public InventoryMenuPage createEditor(NPCShopAction previous, Consumer<NPCShopAction> callback);
|
||||||
|
|
||||||
|
public ItemStack createMenuItem();
|
||||||
|
|
||||||
|
public boolean manages(NPCShopAction action);
|
||||||
|
}
|
||||||
|
|
||||||
public static class ItemAction extends NPCShopAction {
|
public static class ItemAction extends NPCShopAction {
|
||||||
@Persist
|
@Persist
|
||||||
@ -42,35 +66,151 @@ public abstract class NPCShopAction implements Cloneable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean grant(HumanEntity entity) {
|
public PendingAction grant(Entity entity) {
|
||||||
return false;
|
return PendingAction.create(() -> {
|
||||||
|
return true;
|
||||||
|
}, () -> {
|
||||||
|
}, () -> {
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean take(HumanEntity entity) {
|
public PendingAction take(Entity entity) {
|
||||||
return false;
|
return PendingAction.create(() -> {
|
||||||
|
return true;
|
||||||
|
}, () -> {
|
||||||
|
}, () -> {
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class ItemActionGUI implements GUI {
|
||||||
|
@Override
|
||||||
|
public InventoryMenuPage createEditor(NPCShopAction previous, Consumer<NPCShopAction> callback) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@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 {
|
public static class MoneyAction extends NPCShopAction {
|
||||||
@Persist
|
@Persist
|
||||||
public int money;
|
public double money;
|
||||||
|
|
||||||
public MoneyAction() {
|
public MoneyAction() {
|
||||||
}
|
}
|
||||||
|
|
||||||
public MoneyAction(int money) {
|
@Override
|
||||||
this.money = money;
|
public PendingAction grant(Entity entity) {
|
||||||
|
if (!(entity instanceof OfflinePlayer))
|
||||||
|
return PendingAction.fail();
|
||||||
|
Economy economy = Bukkit.getServicesManager().getRegistration(Economy.class).getProvider();
|
||||||
|
OfflinePlayer player = (OfflinePlayer) entity;
|
||||||
|
return PendingAction.create(() -> {
|
||||||
|
return true;
|
||||||
|
}, () -> {
|
||||||
|
economy.depositPlayer(player, money);
|
||||||
|
}, () -> {
|
||||||
|
economy.withdrawPlayer(player, money);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean grant(HumanEntity entity) {
|
public PendingAction take(Entity entity) {
|
||||||
return false;
|
if (!(entity instanceof OfflinePlayer))
|
||||||
|
return PendingAction.fail();
|
||||||
|
Economy economy = Bukkit.getServicesManager().getRegistration(Economy.class).getProvider();
|
||||||
|
OfflinePlayer player = (OfflinePlayer) entity;
|
||||||
|
return PendingAction.create(() -> {
|
||||||
|
return economy.has(player, money);
|
||||||
|
}, () -> {
|
||||||
|
economy.withdrawPlayer(player, money);
|
||||||
|
}, () -> {
|
||||||
|
economy.depositPlayer(player, money);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public static class MoneyActionGUI implements GUI {
|
||||||
public boolean take(HumanEntity entity) {
|
private Boolean supported;
|
||||||
return false;
|
|
||||||
|
@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 PendingAction {
|
||||||
|
private final Runnable execute;
|
||||||
|
private final Supplier<Boolean> possible;
|
||||||
|
private final Runnable rollback;
|
||||||
|
|
||||||
|
public PendingAction(Supplier<Boolean> isPossible, Runnable execute, Runnable rollback) {
|
||||||
|
this.possible = isPossible;
|
||||||
|
this.execute = execute;
|
||||||
|
this.rollback = rollback;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isPossible() {
|
||||||
|
return possible.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void rollback() {
|
||||||
|
rollback.run();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void run() {
|
||||||
|
execute.run();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static PendingAction create(Supplier<Boolean> isPossible, Runnable execute, Runnable rollback) {
|
||||||
|
return new PendingAction(isPossible, execute, rollback);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static PendingAction fail() {
|
||||||
|
return new PendingAction(() -> false, () -> {
|
||||||
|
}, () -> {
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -86,20 +226,93 @@ public abstract class NPCShopAction implements Cloneable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean grant(HumanEntity entity) {
|
public PendingAction grant(Entity entity) {
|
||||||
return false;
|
if (!(entity instanceof Player))
|
||||||
|
return PendingAction.fail();
|
||||||
|
Player player = (Player) entity;
|
||||||
|
Permission perm = Bukkit.getServicesManager().getRegistration(Permission.class).getProvider();
|
||||||
|
return PendingAction.create(() -> {
|
||||||
|
return true;
|
||||||
|
}, () -> {
|
||||||
|
for (String permission : permissions) {
|
||||||
|
perm.playerAdd(player, permission);
|
||||||
|
}
|
||||||
|
}, () -> {
|
||||||
|
for (String permission : permissions) {
|
||||||
|
perm.playerRemove(player, permission);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean take(HumanEntity entity) {
|
public PendingAction take(Entity entity) {
|
||||||
return false;
|
if (!(entity instanceof Player))
|
||||||
|
return PendingAction.fail();
|
||||||
|
Player player = (Player) entity;
|
||||||
|
Permission perm = Bukkit.getServicesManager().getRegistration(Permission.class).getProvider();
|
||||||
|
return PendingAction.create(() -> {
|
||||||
|
for (String permission : permissions) {
|
||||||
|
if (!perm.playerHas(player, permission)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}, () -> {
|
||||||
|
for (String permission : permissions) {
|
||||||
|
perm.playerRemove(player, permission);
|
||||||
|
}
|
||||||
|
}, () -> {
|
||||||
|
for (String permission : permissions) {
|
||||||
|
perm.playerAdd(player, permission);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class PermissionActionGUI implements GUI {
|
||||||
|
private Boolean supported;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public InventoryMenuPage createEditor(NPCShopAction previous, Consumer<NPCShopAction> callback) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@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 PersisterRegistry<NPCShopAction> REGISTRY = PersistenceLoader.createRegistry(NPCShopAction.class);
|
public static Iterable<GUI> getGUIs() {
|
||||||
|
return GUI.values();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void register(Class<? extends NPCShopAction> clazz, String type, GUI gui) {
|
||||||
|
REGISTRY.register(type, clazz);
|
||||||
|
GUI.put(clazz, gui);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final Map<Class<? extends NPCShopAction>, GUI> GUI = new WeakHashMap<>();
|
||||||
|
private static final PersisterRegistry<NPCShopAction> REGISTRY = PersistenceLoader
|
||||||
|
.createRegistry(NPCShopAction.class);
|
||||||
static {
|
static {
|
||||||
REGISTRY.register("items", ItemAction.class);
|
register(ItemAction.class, "items", new ItemActionGUI());
|
||||||
REGISTRY.register("permissions", PermissionAction.class);
|
register(PermissionAction.class, "permissions", new PermissionActionGUI());
|
||||||
REGISTRY.register("money", MoneyAction.class);
|
register(MoneyAction.class, "money", new MoneyActionGUI());
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -90,7 +90,8 @@ public class FoxTrait extends Trait {
|
|||||||
if (args.hasValueFlag("type")) {
|
if (args.hasValueFlag("type")) {
|
||||||
Fox.Type type = Util.matchEnum(Fox.Type.values(), args.getFlag("type"));
|
Fox.Type type = Util.matchEnum(Fox.Type.values(), args.getFlag("type"));
|
||||||
if (type == null) {
|
if (type == null) {
|
||||||
throw new CommandUsageException(Messages.INVALID_FOX_TYPE, Util.listValuesPretty(Fox.Type.values()));
|
throw new CommandUsageException(
|
||||||
|
Messaging.tr(Messages.INVALID_FOX_TYPE, Util.listValuesPretty(Fox.Type.values())), null);
|
||||||
}
|
}
|
||||||
trait.setType(type);
|
trait.setType(type);
|
||||||
output += ' ' + Messaging.tr(Messages.FOX_TYPE_SET, args.getFlag("type"));
|
output += ' ' + Messaging.tr(Messages.FOX_TYPE_SET, args.getFlag("type"));
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package net.citizensnpcs.util;
|
package net.citizensnpcs.util;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.EnumSet;
|
import java.util.EnumSet;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
@ -16,6 +17,9 @@ import org.bukkit.entity.LivingEntity;
|
|||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.event.player.PlayerInteractEntityEvent;
|
import org.bukkit.event.player.PlayerInteractEntityEvent;
|
||||||
import org.bukkit.event.player.PlayerInteractEvent;
|
import org.bukkit.event.player.PlayerInteractEvent;
|
||||||
|
import org.bukkit.inventory.ItemFlag;
|
||||||
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
import org.bukkit.inventory.meta.ItemMeta;
|
||||||
import org.bukkit.scoreboard.Scoreboard;
|
import org.bukkit.scoreboard.Scoreboard;
|
||||||
import org.bukkit.util.Vector;
|
import org.bukkit.util.Vector;
|
||||||
|
|
||||||
@ -26,7 +30,9 @@ import net.citizensnpcs.api.event.NPCCollisionEvent;
|
|||||||
import net.citizensnpcs.api.event.NPCPushEvent;
|
import net.citizensnpcs.api.event.NPCPushEvent;
|
||||||
import net.citizensnpcs.api.npc.NPC;
|
import net.citizensnpcs.api.npc.NPC;
|
||||||
import net.citizensnpcs.api.util.BoundingBox;
|
import net.citizensnpcs.api.util.BoundingBox;
|
||||||
|
import net.citizensnpcs.api.util.Colorizer;
|
||||||
import net.citizensnpcs.api.util.SpigotUtil;
|
import net.citizensnpcs.api.util.SpigotUtil;
|
||||||
|
import net.md_5.bungee.api.ChatColor;
|
||||||
|
|
||||||
public class Util {
|
public class Util {
|
||||||
private Util() {
|
private Util() {
|
||||||
@ -69,6 +75,22 @@ public class Util {
|
|||||||
return angle;
|
return angle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static ItemStack createItem(Material mat, String name) {
|
||||||
|
return createItem(mat, name, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ItemStack createItem(Material mat, String name, String description) {
|
||||||
|
ItemStack stack = new ItemStack(mat, 1);
|
||||||
|
ItemMeta meta = stack.getItemMeta();
|
||||||
|
meta.setDisplayName(ChatColor.RESET + Colorizer.parseColors(name));
|
||||||
|
if (description != null) {
|
||||||
|
meta.setLore(Arrays.asList(Colorizer.parseColors(description).split("\n")));
|
||||||
|
}
|
||||||
|
meta.addItemFlags(ItemFlag.HIDE_ATTRIBUTES);
|
||||||
|
stack.setItemMeta(meta);
|
||||||
|
return stack;
|
||||||
|
}
|
||||||
|
|
||||||
public static void face(Entity entity, float yaw, float pitch) {
|
public static void face(Entity entity, float yaw, float pitch) {
|
||||||
double pitchCos = Math.cos(Math.toRadians(pitch));
|
double pitchCos = Math.cos(Math.toRadians(pitch));
|
||||||
Vector vector = new Vector(Math.sin(Math.toRadians(yaw)) * -pitchCos, -Math.sin(Math.toRadians(pitch)),
|
Vector vector = new Vector(Math.sin(Math.toRadians(yaw)) * -pitchCos, -Math.sin(Math.toRadians(pitch)),
|
||||||
|
Loading…
Reference in New Issue
Block a user