From 46633409c32ad0d125cf6e8f2900343cc78ece4a Mon Sep 17 00:00:00 2001 From: fullwall Date: Thu, 16 Mar 2023 22:01:04 +0800 Subject: [PATCH] Adjust command costs so that they are only charged after checking that the command can be used, adjust itemcost algorithm --- .../main/java/net/citizensnpcs/Citizens.java | 2 + .../citizensnpcs/commands/NPCCommands.java | 4 +- .../npc/ai/CitizensNavigator.java | 3 +- .../net/citizensnpcs/trait/CommandTrait.java | 74 +++++++-------- .../net/citizensnpcs/trait/ShopTrait.java | 3 + .../trait/shop/ExperienceAction.java | 92 +++++++++++++++++++ .../citizensnpcs/trait/shop/MoneyAction.java | 4 + .../trait/shop/NPCShopAction.java | 8 +- 8 files changed, 143 insertions(+), 47 deletions(-) create mode 100644 main/src/main/java/net/citizensnpcs/trait/shop/ExperienceAction.java diff --git a/main/src/main/java/net/citizensnpcs/Citizens.java b/main/src/main/java/net/citizensnpcs/Citizens.java index 8e3653e61..95aabefc8 100644 --- a/main/src/main/java/net/citizensnpcs/Citizens.java +++ b/main/src/main/java/net/citizensnpcs/Citizens.java @@ -335,6 +335,8 @@ public class Citizens extends JavaPlugin implements CitizensPlugin { .relocate("net{}kyori", "clib{}net{}kyori").build()); lib.loadLibrary(Library.builder().groupId("net{}kyori").artifactId("examination-string").version("1.3.0") .relocate("net{}kyori", "clib{}net{}kyori").build()); + lib.loadLibrary(Library.builder().groupId("org{}joml").artifactId("joml").version("1.10.5") + .relocate("org{}joml", "clib{}org{}joml").build()); } @Override diff --git a/main/src/main/java/net/citizensnpcs/commands/NPCCommands.java b/main/src/main/java/net/citizensnpcs/commands/NPCCommands.java index e53f6735e..b11359495 100644 --- a/main/src/main/java/net/citizensnpcs/commands/NPCCommands.java +++ b/main/src/main/java/net/citizensnpcs/commands/NPCCommands.java @@ -541,8 +541,8 @@ public class NPCCommands { commands.setCost(args.getDouble(2)); Messaging.sendTr(sender, Messages.COMMAND_COST_SET, args.getDouble(2)); } else if (action.equalsIgnoreCase("expcost")) { - commands.setExperienceCost((float) args.getDouble(2)); - Messaging.sendTr(sender, Messages.COMMAND_EXPERIENCE_COST_SET, args.getDouble(2)); + commands.setExperienceCost(args.getInteger(2)); + Messaging.sendTr(sender, Messages.COMMAND_EXPERIENCE_COST_SET, args.getInteger(2)); } else if (action.equalsIgnoreCase("hideerrors")) { commands.setHideErrorMessages(!commands.isHideErrorMessages()); Messaging.sendTr(sender, commands.isHideErrorMessages() ? Messages.COMMAND_HIDE_ERROR_MESSAGES_SET diff --git a/main/src/main/java/net/citizensnpcs/npc/ai/CitizensNavigator.java b/main/src/main/java/net/citizensnpcs/npc/ai/CitizensNavigator.java index 11a68be4e..c30f9b3d2 100644 --- a/main/src/main/java/net/citizensnpcs/npc/ai/CitizensNavigator.java +++ b/main/src/main/java/net/citizensnpcs/npc/ai/CitizensNavigator.java @@ -36,6 +36,7 @@ import net.citizensnpcs.api.astar.pathfinder.MinecraftBlockExaminer; import net.citizensnpcs.api.astar.pathfinder.SwimmingExaminer; import net.citizensnpcs.api.npc.NPC; import net.citizensnpcs.api.util.DataKey; +import net.citizensnpcs.api.util.SpigotUtil; import net.citizensnpcs.npc.ai.AStarNavigationStrategy.AStarPlanner; import net.citizensnpcs.npc.ai.MCNavigationStrategy.MCNavigator; import net.citizensnpcs.trait.RotationTrait; @@ -498,7 +499,7 @@ public class CitizensNavigator implements Navigator, Runnable { if (localParams.stationaryTicks() < 0) return false; Location current = npc.getEntity().getLocation(STATIONARY_LOCATION); - if (current.getY() < -6) { + if (!SpigotUtil.checkYSafe(current.getY(), current.getWorld())) { stopNavigating(CancelReason.STUCK); return true; } diff --git a/main/src/main/java/net/citizensnpcs/trait/CommandTrait.java b/main/src/main/java/net/citizensnpcs/trait/CommandTrait.java index bf1092197..55d8b881a 100644 --- a/main/src/main/java/net/citizensnpcs/trait/CommandTrait.java +++ b/main/src/main/java/net/citizensnpcs/trait/CommandTrait.java @@ -23,7 +23,6 @@ import org.bukkit.event.inventory.InventoryType; import org.bukkit.inventory.Inventory; import org.bukkit.inventory.ItemStack; import org.bukkit.permissions.PermissionAttachment; -import org.bukkit.plugin.RegisteredServiceProvider; import com.google.common.base.Splitter; import com.google.common.collect.Iterables; @@ -48,10 +47,14 @@ import net.citizensnpcs.api.trait.TraitName; import net.citizensnpcs.api.util.DataKey; import net.citizensnpcs.api.util.Messaging; import net.citizensnpcs.api.util.Translator; +import net.citizensnpcs.trait.shop.ExperienceAction; +import net.citizensnpcs.trait.shop.ItemAction; +import net.citizensnpcs.trait.shop.MoneyAction; +import net.citizensnpcs.trait.shop.NPCShopAction; +import net.citizensnpcs.trait.shop.NPCShopAction.Transaction; import net.citizensnpcs.util.Messages; import net.citizensnpcs.util.StringHelper; import net.citizensnpcs.util.Util; -import net.milkbowl.vault.economy.Economy; @TraitName("commandtrait") public class CommandTrait extends Trait { @@ -66,7 +69,7 @@ public class CommandTrait extends Trait { @Persist private ExecutionMode executionMode = ExecutionMode.LINEAR; @Persist - private float experienceCost = -1; + private int experienceCost = -1; @Persist(valueType = Long.class) private final Map globalCooldowns = Maps.newHashMap(); @Persist @@ -90,50 +93,29 @@ public class CommandTrait extends Trait { return id; } - private boolean chargeCommandCosts(Player player, Hand hand) { + private Transaction chargeCommandCosts(Player player, Hand hand) { + NPCShopAction action = null; if (cost > 0) { - try { - RegisteredServiceProvider provider = Bukkit.getServicesManager() - .getRegistration(Economy.class); - if (provider != null && provider.getProvider() != null) { - Economy economy = provider.getProvider(); - if (!economy.has(player, cost)) { - sendErrorMessage(player, CommandTraitError.MISSING_MONEY, null, cost); - return false; - } - economy.withdrawPlayer(player, cost); - } - } catch (NoClassDefFoundError e) { - Messaging.severe("Unable to find Vault when checking command cost - is it installed?"); + action = new MoneyAction(cost); + if (!action.take(player).isPossible()) { + sendErrorMessage(player, CommandTraitError.MISSING_MONEY, null, cost); } } if (experienceCost > 0) { - if (player.getLevel() < experienceCost) { + action = new ExperienceAction(experienceCost); + if (!action.take(player).isPossible()) { sendErrorMessage(player, CommandTraitError.MISSING_EXPERIENCE, null, experienceCost); - return false; } - player.setLevel((int) (player.getLevel() - experienceCost)); } if (itemRequirements.size() > 0) { - List req = Lists.newArrayList(itemRequirements); - Inventory tempInventory = Bukkit.createInventory(null, 54); - for (int i = 0; i < player.getInventory().getSize(); i++) { - tempInventory.setItem(i, player.getInventory().getItem(i)); - } - for (ItemStack stack : req) { - if (tempInventory.containsAtLeast(stack, stack.getAmount())) { - tempInventory.removeItem(stack); - } else { - sendErrorMessage(player, CommandTraitError.MISSING_ITEM, null, Util.prettyEnum(stack.getType()), - stack.getAmount()); - return false; - } - } - for (int i = 0; i < player.getInventory().getSize(); i++) { - player.getInventory().setItem(i, tempInventory.getItem(i)); + action = new ItemAction(itemRequirements); + if (!action.take(player).isPossible()) { + ItemStack stack = itemRequirements.get(0); + sendErrorMessage(player, CommandTraitError.MISSING_ITEM, null, Util.prettyEnum(stack.getType()), + stack.getAmount()); } } - return true; + return action == null ? Transaction.success() : action.take(player); } public void clearHistory(CommandTraitError which, Player who) { @@ -288,16 +270,22 @@ public class CommandTrait extends Trait { || PlayerNPCCommand.requiresTracking(command))) { playerTracking.put(player.getUniqueId(), info = new PlayerNPCCommand()); } - if (info != null && !info.canUse(CommandTrait.this, player, command)) { - return; - } + Transaction charge = null; if (charged == null) { - if (!chargeCommandCosts(player, hand)) { + charge = chargeCommandCosts(player, hand); + if (!charge.isPossible()) { charged = false; return; } - charged = true; } + + if (info != null && !info.canUse(CommandTrait.this, player, command)) + return; + + if (charged == null) { + charge.run(); + } + PermissionAttachment attachment = player.addAttachment(CitizensAPI.getPlugin()); if (temporaryPermissions.size() > 0) { for (String permission : temporaryPermissions) { @@ -406,7 +394,7 @@ public class CommandTrait extends Trait { this.executionMode = mode; } - public void setExperienceCost(float experienceCost) { + public void setExperienceCost(int experienceCost) { this.experienceCost = experienceCost; } diff --git a/main/src/main/java/net/citizensnpcs/trait/ShopTrait.java b/main/src/main/java/net/citizensnpcs/trait/ShopTrait.java index 00dec7cc0..1271d04bd 100644 --- a/main/src/main/java/net/citizensnpcs/trait/ShopTrait.java +++ b/main/src/main/java/net/citizensnpcs/trait/ShopTrait.java @@ -48,6 +48,8 @@ import net.citizensnpcs.api.util.Messaging; import net.citizensnpcs.api.util.Placeholders; import net.citizensnpcs.trait.shop.CommandAction; import net.citizensnpcs.trait.shop.CommandAction.CommandActionGUI; +import net.citizensnpcs.trait.shop.ExperienceAction; +import net.citizensnpcs.trait.shop.ExperienceAction.ExperienceActionGUI; import net.citizensnpcs.trait.shop.ItemAction; import net.citizensnpcs.trait.shop.ItemAction.ItemActionGUI; import net.citizensnpcs.trait.shop.MoneyAction; @@ -714,5 +716,6 @@ public class ShopTrait extends Trait { NPCShopAction.register(PermissionAction.class, "permissions", new PermissionActionGUI()); NPCShopAction.register(MoneyAction.class, "money", new MoneyActionGUI()); NPCShopAction.register(CommandAction.class, "command", new CommandActionGUI()); + NPCShopAction.register(ExperienceAction.class, "experience", new ExperienceActionGUI()); } } \ No newline at end of file diff --git a/main/src/main/java/net/citizensnpcs/trait/shop/ExperienceAction.java b/main/src/main/java/net/citizensnpcs/trait/shop/ExperienceAction.java new file mode 100644 index 000000000..5ea9fe314 --- /dev/null +++ b/main/src/main/java/net/citizensnpcs/trait/shop/ExperienceAction.java @@ -0,0 +1,92 @@ +package net.citizensnpcs.trait.shop; + +import java.util.function.Consumer; + +import org.bukkit.Material; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Player; +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; + +public class ExperienceAction extends NPCShopAction { + @Persist + public int exp; + + public ExperienceAction() { + } + + public ExperienceAction(int cost) { + this.exp = cost; + } + + @Override + public String describe() { + return exp + " XP"; + } + + @Override + public Transaction grant(Entity entity) { + if (!(entity instanceof Player)) + return Transaction.fail(); + Player player = (Player) entity; + return Transaction.create(() -> { + return true; + }, () -> { + player.setLevel(player.getLevel() + exp); + }, () -> { + player.setLevel(player.getLevel() - exp); + }); + } + + @Override + public Transaction take(Entity entity) { + if (!(entity instanceof Player)) + return Transaction.fail(); + Player player = (Player) entity; + return Transaction.create(() -> { + return player.getLevel() >= exp; + }, () -> { + player.setLevel(player.getLevel() - exp); + }, () -> { + player.setLevel(player.getLevel() + exp); + }); + } + + public static class ExperienceActionGUI implements GUI { + @Override + public InventoryMenuPage createEditor(NPCShopAction previous, Consumer callback) { + final ExperienceAction action = previous == null ? new ExperienceAction() : (ExperienceAction) previous; + return InputMenus.filteredStringSetter(() -> Integer.toString(action.exp), s -> { + try { + int result = Integer.parseInt(s); + if (result < 0) + return false; + action.exp = result; + } catch (NumberFormatException nfe) { + return false; + } + callback.accept(action); + return true; + }); + } + + @Override + public ItemStack createMenuItem(NPCShopAction previous) { + String description = null; + if (previous != null) { + ExperienceAction old = (ExperienceAction) previous; + description = old.describe(); + } + return Util.createItem(Material.EXPERIENCE_BOTTLE, "Experience", description); + } + + @Override + public boolean manages(NPCShopAction action) { + return action instanceof ExperienceAction; + } + } +} \ No newline at end of file diff --git a/main/src/main/java/net/citizensnpcs/trait/shop/MoneyAction.java b/main/src/main/java/net/citizensnpcs/trait/shop/MoneyAction.java index b77a58b6a..0f72b79cf 100644 --- a/main/src/main/java/net/citizensnpcs/trait/shop/MoneyAction.java +++ b/main/src/main/java/net/citizensnpcs/trait/shop/MoneyAction.java @@ -21,6 +21,10 @@ public class MoneyAction extends NPCShopAction { public MoneyAction() { } + public MoneyAction(double cost) { + this.money = cost; + } + @Override public String describe() { Economy economy = Bukkit.getServicesManager().getRegistration(Economy.class).getProvider(); diff --git a/main/src/main/java/net/citizensnpcs/trait/shop/NPCShopAction.java b/main/src/main/java/net/citizensnpcs/trait/shop/NPCShopAction.java index 73a29a18c..3bfa65e72 100644 --- a/main/src/main/java/net/citizensnpcs/trait/shop/NPCShopAction.java +++ b/main/src/main/java/net/citizensnpcs/trait/shop/NPCShopAction.java @@ -64,7 +64,13 @@ public abstract class NPCShopAction implements Cloneable { } public static Transaction fail() { - return new Transaction(() -> false, () -> { + return create(() -> false, () -> { + }, () -> { + }); + } + + public static Transaction success() { + return create(() -> true, () -> { }, () -> { }); }