diff --git a/lib/ProtocolLib-3.6.5-SNAPSHOT.jar b/lib/ProtocolLib-3.6.5.jar similarity index 100% rename from lib/ProtocolLib-3.6.5-SNAPSHOT.jar rename to lib/ProtocolLib-3.6.5.jar diff --git a/lib/ProtocolLib-4.1.jar b/lib/ProtocolLib-4.1.jar new file mode 100644 index 0000000..4e8a0f8 Binary files /dev/null and b/lib/ProtocolLib-4.1.jar differ diff --git a/pom.xml b/pom.xml index cf50440..11ef6ca 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ 4.0.0 org.maxgamer QuickShop - 1.9.3 + 1.9.4 快捷商店重置版本... ${project.name} @@ -31,12 +31,12 @@ true - cn.citycraft:PluginHelper + pw.yumc:YumCore - cn.citycraft.PluginHelper + pw.yumc.YumCore ${project.groupId}.${project.artifactId} @@ -60,9 +60,9 @@ DEBUG &a全新版本 &c虚拟悬浮物(橙子提供 对 就是那个汉化COI的逗比)&e7老板修复逗比BUG... + &b1.9.4 - &a1.9+兼容虚拟悬浮物...; &b1.9.3 - &a木牌第一行显示配置文件的guititle内容...; &b1.9.2 - &c修复一个在删除商店时导致的报错...; - &b1.9.1 - &c修复同一个玩家的商店直接漏洞不能传递的问题...; UTF-8 @@ -84,7 +84,7 @@ org.spigotmc spigot-api jar - 1.9-R0.1-SNAPSHOT + 1.10.2-R0.1-SNAPSHOT net.milkbowl.vault @@ -93,8 +93,8 @@ 1.5.6 - cn.citycraft - PluginHelper + pw.yumc + YumCore jar 1.0 @@ -113,9 +113,16 @@ com.comphenix.protocol ProtocolLib - 3.6.5-SNAPSHOT + 3.6.5 system - ${project.basedir}/lib/ProtocolLib-3.6.5-SNAPSHOT.jar + ${project.basedir}/lib/ProtocolLib-3.6.5.jar + + + com.comphenix.protocol + ProtocolLib + 4.1 + system + ${project.basedir}/lib/ProtocolLib-4.1.jar \ No newline at end of file diff --git a/src/main/java/org/maxgamer/QuickShop/Command/QuickShopCommands.java b/src/main/java/org/maxgamer/QuickShop/Command/QuickShopCommands.java index 6b48e79..4334bd1 100644 --- a/src/main/java/org/maxgamer/QuickShop/Command/QuickShopCommands.java +++ b/src/main/java/org/maxgamer/QuickShop/Command/QuickShopCommands.java @@ -24,30 +24,32 @@ import org.maxgamer.QuickShop.Shop.ShopChunk; import org.maxgamer.QuickShop.Shop.ShopType; import org.maxgamer.QuickShop.Util.MsgUtil; -import cn.citycraft.PluginHelper.commands.HandlerCommand; -import cn.citycraft.PluginHelper.commands.HandlerCommands; -import cn.citycraft.PluginHelper.commands.HandlerDescription; -import cn.citycraft.PluginHelper.commands.InvokeCommandEvent; -import cn.citycraft.PluginHelper.commands.InvokeSubCommand; -import cn.citycraft.PluginHelper.utils.StringUtil; +import pw.yumc.YumCore.bukkit.P; +import pw.yumc.YumCore.commands.CommandArgument; +import pw.yumc.YumCore.commands.CommandExecutor; +import pw.yumc.YumCore.commands.CommandHelpParse; +import pw.yumc.YumCore.commands.CommandManager; +import pw.yumc.YumCore.commands.annotation.Cmd; +import pw.yumc.YumCore.commands.annotation.Cmd.Executor; +import pw.yumc.YumCore.commands.annotation.Help; +import pw.yumc.YumCore.kit.StrKit; -public class QuickShopCommands implements HandlerCommands, HandlerDescription { - QuickShop plugin; +public class QuickShopCommands implements CommandExecutor, CommandHelpParse { + QuickShop plugin = P.getPlugin(); - public QuickShopCommands(final QuickShop plugin) { - this.plugin = plugin; - final InvokeSubCommand ics = new InvokeSubCommand(plugin, "qs"); - ics.registerCommands(this); - ics.setHandlerDescription(this); + public QuickShopCommands() { + new CommandManager("qs", this).setHelpParse(this); } - @HandlerCommand(name = "buy", aliases = { "b" }, permission = "quickshop.create.buy", onlyPlayerExecutable = true, description = "command.description.buy") - public void buy(final InvokeCommandEvent e) { + @Cmd(aliases = "b", permission = "quickshop.create.buy", executor = Executor.PLAYER) + @Help("command.description.buy") + public void buy(final CommandArgument e) { changeShopType(e.getSender(), ShopType.BUYING); } - @HandlerCommand(name = "clean", aliases = "c", permission = "quickshop.clean", description = "command.description.clean") - public void clean(final InvokeCommandEvent e) { + @Cmd(aliases = "c", permission = "quickshop.clean") + @Help("command.description.clean") + public void clean(final CommandArgument e) { final CommandSender sender = e.getSender(); sender.sendMessage(MsgUtil.p("command.cleaning")); final Iterator shIt = plugin.getShopManager().getShopIterator(); @@ -71,8 +73,9 @@ public class QuickShopCommands implements HandlerCommands, HandlerDescription { sender.sendMessage(MsgUtil.p("command.cleaned", "" + i)); } - @HandlerCommand(name = "empty", aliases = "e", permission = "quickshop.empty", description = "command.description.empty") - public void empty(final InvokeCommandEvent e) { + @Cmd(aliases = "e", permission = "quickshop.empty") + @Help("command.description.empty") + public void empty(final CommandArgument e) { final CommandSender sender = e.getSender(); final BlockIterator bIt = new BlockIterator((Player) sender, 10); while (bIt.hasNext()) { @@ -93,8 +96,9 @@ public class QuickShopCommands implements HandlerCommands, HandlerDescription { return; } - @HandlerCommand(name = "export", minimumArguments = 1, possibleArguments = "[mysql|sqlite]", permission = "quickshop.export", description = "command.description.export") - public void export(final InvokeCommandEvent e) { + @Cmd(minimumArguments = 1, permission = "quickshop.export") + @Help(value = "command.description.export", possibleArguments = "[mysql|sqlite]") + public void export(final CommandArgument e) { final CommandSender sender = e.getSender(); final String type = e.getArgs()[0].toLowerCase(); if (type.startsWith("mysql")) { @@ -144,10 +148,11 @@ public class QuickShopCommands implements HandlerCommands, HandlerDescription { } } - @HandlerCommand(name = "find", aliases = "f", minimumArguments = 2, onlyPlayerExecutable = true, permission = "quickshop.find", description = "command.description.find") - public void find(final InvokeCommandEvent e) { + @Cmd(aliases = "f", minimumArguments = 2, permission = "quickshop.find", executor = Executor.PLAYER) + @Help("command.description.find") + public void find(final CommandArgument e) { final CommandSender sender = e.getSender(); - String lookFor = StringUtil.consolidateStrings(e.getArgs(), 0); + String lookFor = StrKit.consolidateStrings(e.getArgs(), 0); lookFor = lookFor.toLowerCase(); final Player p = (Player) sender; final Location loc = p.getEyeLocation().clone(); @@ -182,13 +187,9 @@ public class QuickShopCommands implements HandlerCommands, HandlerDescription { return; } - @Override - public String handler(final String arg0) { - return MsgUtil.p(arg0); - } - - @HandlerCommand(name = "info", aliases = "i", permission = "quickshop.info", description = "command.description.info") - public void info(final InvokeCommandEvent e) { + @Cmd(aliases = "i", permission = "quickshop.info") + @Help("command.description.info") + public void info(final CommandArgument e) { final CommandSender sender = e.getSender(); int buying, selling, doubles, chunks, worlds, unlimited; buying = selling = doubles = chunks = worlds = unlimited = 0; @@ -223,8 +224,14 @@ public class QuickShopCommands implements HandlerCommands, HandlerDescription { sender.sendMessage(MsgUtil.p("info.canclean", nostock)); } - @HandlerCommand(name = "price", aliases = "p", minimumArguments = 1, onlyPlayerExecutable = true, possibleArguments = "<价格>", permission = "quickshop.create.changeprice", description = "command.description.price") - public void price(final InvokeCommandEvent e) { + @Override + public String parse(final String str) { + return MsgUtil.p(str); + } + + @Cmd(aliases = "p", minimumArguments = 1, permission = "quickshop.create.changeprice") + @Help(value = "command.description.price", possibleArguments = "<价格>") + public void price(final CommandArgument e) { final CommandSender sender = e.getSender(); final Player p = (Player) sender; double price; @@ -294,8 +301,9 @@ public class QuickShopCommands implements HandlerCommands, HandlerDescription { return; } - @HandlerCommand(name = "refill", minimumArguments = 1, possibleArguments = "<数量>", permission = "quickshop.refill", description = "command.description.refill") - public void refill(final InvokeCommandEvent e) { + @Cmd(minimumArguments = 1, permission = "quickshop.refill", executor = Executor.PLAYER) + @Help(value = "command.description.refill", possibleArguments = "<数量>") + public void refill(final CommandArgument e) { final CommandSender sender = e.getSender(); int add; try { @@ -318,18 +326,19 @@ public class QuickShopCommands implements HandlerCommands, HandlerDescription { return; } - @HandlerCommand(name = "reload", permission = "quickshop.reload", description = "command.description.reload") - public void reload(final InvokeCommandEvent e) { + @Cmd(permission = "quickshop.reload") + @Help("command.description.reload") + public void reload(final CommandArgument e) { final CommandSender sender = e.getSender(); sender.sendMessage(MsgUtil.p("command.reloading")); plugin.reloadConfig(); Bukkit.getPluginManager().disablePlugin(plugin); Bukkit.getPluginManager().enablePlugin(plugin); - return; } - @HandlerCommand(name = "remove", aliases = "r", onlyPlayerExecutable = true, permission = "quickshop.delete", description = "command.description.remove") - public void remove(final InvokeCommandEvent e) { + @Cmd(aliases = "r", permission = "quickshop.delete", executor = Executor.PLAYER) + @Help("command.description.remove") + public void remove(final CommandArgument e) { final Player p = (Player) e.getSender(); final BlockIterator bIt = new BlockIterator(p, 10); while (bIt.hasNext()) { @@ -348,13 +357,15 @@ public class QuickShopCommands implements HandlerCommands, HandlerDescription { p.sendMessage(ChatColor.RED + "未找到商店!"); } - @HandlerCommand(name = "sell", aliases = { "s" }, permission = "quickshop.create.sell", onlyPlayerExecutable = true, description = "command.description.sell") - public void sell(final InvokeCommandEvent e) { + @Cmd(aliases = "s", permission = "quickshop.create.sell") + @Help("command.description.sell") + public void sell(final CommandArgument e) { changeShopType(e.getSender(), ShopType.SELLING); } - @HandlerCommand(name = "setowner", aliases = "so", onlyPlayerExecutable = true, minimumArguments = 1, permission = "quickshop.setowner", description = "command.description.setowner") - public void setowner(final InvokeCommandEvent e) { + @Cmd(aliases = "so", minimumArguments = 1, permission = "quickshop.setowner", executor = Executor.PLAYER) + @Help("command.description.setowner") + public void setowner(final CommandArgument e) { final CommandSender sender = e.getSender(); final String owner = e.getArgs()[0]; final BlockIterator bIt = new BlockIterator((Player) sender, 10); @@ -369,11 +380,11 @@ public class QuickShopCommands implements HandlerCommands, HandlerDescription { } } sender.sendMessage(MsgUtil.p("not-looking-at-shop")); - return; } - @HandlerCommand(name = "unlimited", onlyPlayerExecutable = true, permission = "quickshop.unlimited", description = "command.description.unlimited") - public void unlimited(final InvokeCommandEvent e) { + @Cmd(permission = "quickshop.unlimited", executor = Executor.PLAYER) + @Help("command.description.unlimited") + public void unlimited(final CommandArgument e) { final CommandSender sender = e.getSender(); final BlockIterator bIt = new BlockIterator((Player) sender, 10); while (bIt.hasNext()) { @@ -387,7 +398,6 @@ public class QuickShopCommands implements HandlerCommands, HandlerDescription { } } sender.sendMessage(MsgUtil.p("not-looking-at-shop")); - return; } private void changeShopType(final CommandSender sender, final ShopType shopType) { diff --git a/src/main/java/org/maxgamer/QuickShop/Config/ConfigManager.java b/src/main/java/org/maxgamer/QuickShop/Config/ConfigManager.java index 163d615..1367f67 100644 --- a/src/main/java/org/maxgamer/QuickShop/Config/ConfigManager.java +++ b/src/main/java/org/maxgamer/QuickShop/Config/ConfigManager.java @@ -9,10 +9,12 @@ import org.bukkit.Material; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.inventory.ItemStack; import org.maxgamer.QuickShop.QuickShop; -import org.maxgamer.QuickShop.Shop.FakeItem; +import org.maxgamer.QuickShop.Shop.Item.FakeItem_17; +import org.maxgamer.QuickShop.Shop.Item.FakeItem_18_110; -import cn.citycraft.PluginHelper.config.FileConfig; -import cn.citycraft.PluginHelper.tellraw.FancyMessage; +import pw.yumc.YumCore.bukkit.Log; +import pw.yumc.YumCore.config.FileConfig; +import pw.yumc.YumCore.tellraw.Tellraw; public class ConfigManager { private boolean enableMagicLib = false; @@ -88,23 +90,31 @@ public class ConfigManager { if (config.getBoolean("fakeitem", true)) { try { plugin.getLogger().info("启用虚拟悬浮物 尝试启动中..."); - FakeItem.register(plugin); - plugin.getLogger().info("虚拟悬浮物功能测试正常..."); + FakeItem_18_110.register(plugin); + plugin.getLogger().info("虚拟悬浮物功能测试正常(1.8-1.10.2)..."); fakeItem = true; - } catch (final Error | Exception e) { - plugin.getLogger().warning("+========================================="); - plugin.getLogger().warning("| 警告: 启动虚拟物品失败 使用原版悬浮物品..."); - plugin.getLogger().warning("+========================================="); + } catch (final Throwable e) { + Log.debug(e); + try { + FakeItem_17.register(plugin); + plugin.getLogger().info("虚拟悬浮物功能测试正常(1.7)..."); + fakeItem = true; + } catch (final Throwable e2) { + plugin.getLogger().warning("+========================================="); + plugin.getLogger().warning("| 警告: 启动虚拟物品失败 使用原版悬浮物品..."); + plugin.getLogger().warning("+========================================="); + Log.debug(e2); + } } } if (config.getBoolean("usemagiclib", true)) { try { plugin.getLogger().info("启用魔改库 尝试启动中..."); - final FancyMessage fm = FancyMessage.newFM("test"); - fm.then("item").itemTooltip(new ItemStack(Material.DIAMOND_SWORD)); - fm.then("link").link("ci.citycraft.cn"); + final Tellraw fm = Tellraw.create("test"); + fm.then("item").item(new ItemStack(Material.DIAMOND_SWORD)); + fm.then("link").link("yumc.pw"); fm.then("suggest").suggest("qs help"); - fm.toJSONString(); + fm.toJsonString(); plugin.getLogger().info("魔改库功能测试正常..."); this.enableMagicLib = true; } catch (final Error | Exception e) { diff --git a/src/main/java/org/maxgamer/QuickShop/QuickShop.java b/src/main/java/org/maxgamer/QuickShop/QuickShop.java index 32f804b..110e2f0 100644 --- a/src/main/java/org/maxgamer/QuickShop/QuickShop.java +++ b/src/main/java/org/maxgamer/QuickShop/QuickShop.java @@ -8,12 +8,12 @@ import java.sql.SQLException; import java.sql.Timestamp; import java.util.Calendar; import java.util.Date; -import java.util.Iterator; import java.util.Map.Entry; import org.bukkit.Bukkit; import org.bukkit.ChatColor; import org.bukkit.Location; +import org.bukkit.Material; import org.bukkit.World; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.file.FileConfiguration; @@ -51,9 +51,9 @@ import org.maxgamer.QuickShop.Util.Util; import org.maxgamer.QuickShop.Watcher.ItemWatcher; import org.maxgamer.QuickShop.Watcher.LogWatcher; -import cn.citycraft.PluginHelper.config.FileConfig; -import cn.citycraft.PluginHelper.utils.LocalUtil; -import cn.citycraft.PluginHelper.utils.VersionChecker; +import pw.yumc.YumCore.config.FileConfig; +import pw.yumc.YumCore.misc.L10N; +import pw.yumc.YumCore.update.SubscribeTask; public class QuickShop extends JavaPlugin { /** 初始化 QuickShop 的接口 */ @@ -151,33 +151,6 @@ public class QuickShop extends JavaPlugin { } public void loadShop() { - if (!LocalUtil.isInit()) { - this.getLogger().warning("本地化工具尚未初始化完成 商店汉化信息将在稍后刷新..."); - this.getServer().getScheduler().runTaskAsynchronously(this, new Runnable() { - @Override - public void run() { - int error = 0; - try { - while (!LocalUtil.isInit()) { - try { - Thread.sleep(500); - } catch (final InterruptedException e) { - } - } - getLogger().info("本地化工具载入完成 刷新汉化信息..."); - final Iterator shops = shopManager.getShopIterator(); - while (shops.hasNext()) { - shops.next().onClick(); - } - } catch (final Exception e) { - error++; - } - if (error != 0) { - getLogger().info("信息刷新完成 期间发生 " + error + " 个错误 已忽略(不是BUG 无需反馈)..."); - } - } - }); - } /* 从数据库载入商店信息到内存 */ int count = 0; // 商店个数 int unload = 0; @@ -289,7 +262,6 @@ public class QuickShop extends JavaPlugin { return; } configManager = new ConfigManager(this); - LocalUtil.init(this); // Initialize Util Util.initialize(); // Create the shop manager. @@ -359,26 +331,27 @@ public class QuickShop extends JavaPlugin { } // Command handlers - new QuickShopCommands(this); + new QuickShopCommands(); if (configManager.getFindDistance() > 100) { getLogger().warning("商店查找半径过大 可能导致服务器Lag! 推荐使用低于 100 的配置!"); } this.getLogger().info("载入完成! 版本: " + this.getDescription().getVersion() + " 重制 by 喵♂呜"); - new VersionChecker(this); + new SubscribeTask(); } @Override public void onLoad() { instance = this; - config = new FileConfig(this); + config = new FileConfig(); MsgUtil.init(this); + L10N.getItemName(new ItemStack(Material.AIR)); } /** Reloads QuickShops config */ @Override public void reloadConfig() { config.reload(); - LocalUtil.reload(this); + L10N.reload(); } } \ No newline at end of file diff --git a/src/main/java/org/maxgamer/QuickShop/Shop/ContainerShop.java b/src/main/java/org/maxgamer/QuickShop/Shop/ContainerShop.java index 5d59f71..b73dadd 100644 --- a/src/main/java/org/maxgamer/QuickShop/Shop/ContainerShop.java +++ b/src/main/java/org/maxgamer/QuickShop/Shop/ContainerShop.java @@ -5,6 +5,7 @@ import java.util.List; import java.util.Map; import java.util.logging.Level; +import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.block.Block; @@ -17,11 +18,13 @@ import org.bukkit.inventory.Inventory; import org.bukkit.inventory.InventoryHolder; import org.bukkit.inventory.ItemStack; import org.maxgamer.QuickShop.QuickShop; +import org.maxgamer.QuickShop.Shop.Item.DisplayItem; +import org.maxgamer.QuickShop.Shop.Item.FakeItem_17; +import org.maxgamer.QuickShop.Shop.Item.NormalItem; import org.maxgamer.QuickShop.Util.MsgUtil; import org.maxgamer.QuickShop.Util.Util; -import cn.citycraft.PluginHelper.kit.P; -import cn.citycraft.PluginHelper.kit.PluginKit; +import pw.yumc.YumCore.bukkit.P; public class ContainerShop implements Shop { private final QuickShop plugin = (QuickShop) P.instance; @@ -53,13 +56,7 @@ public class ContainerShop implements Shop { this.owner = owner; this.item = item.clone(); this.item.setAmount(1); - if (plugin.getConfigManager().isDisplay()) { - if (plugin.getConfigManager().isFakeItem()) { - this.displayItem = new FakeItem(this, this.getItem()); - } else { - this.displayItem = new NormalItem(this, this.getItem()); - } - } + this.displayItem = DisplayItem.create(this); this.shopType = ShopType.SELLING; } @@ -360,7 +357,7 @@ public class ContainerShop implements Shop { */ @Override public List getSigns() { - final ArrayList signs = new ArrayList(1); + final ArrayList signs = new ArrayList<>(1); if (this.getLocation().getWorld() == null) { return signs; } @@ -518,7 +515,7 @@ public class ContainerShop implements Shop { this.buy(p, -amount); } // Items to drop on floor - final ArrayList floor = new ArrayList(5); + final ArrayList floor = new ArrayList<>(5); final Inventory pInv = p.getInventory(); if (this.isUnlimited()) { final ItemStack item = this.item.clone(); @@ -604,7 +601,7 @@ public class ContainerShop implements Shop { } final ContainerShop shop = this; // 1.9不能异步修改木牌 - PluginKit.runTask(new Runnable() { + Bukkit.getScheduler().runTask(plugin, new Runnable() { @Override public void run() { final String[] lines = new String[4]; @@ -637,7 +634,7 @@ public class ContainerShop implements Shop { } final List signs = this.getSigns(); // 1.9不能异步修改木牌 - PluginKit.runTask(new Runnable() { + Bukkit.getScheduler().runTask(plugin, new Runnable() { @Override public void run() { for (final Sign sign : signs) { @@ -657,7 +654,15 @@ public class ContainerShop implements Shop { @Override public String toString() { - final StringBuilder sb = new StringBuilder("商店 " + (loc.getWorld() == null ? "世界尚未载入" : "坐标: " + loc.getWorld().getName()) + "(" + loc.getBlockX() + ", " + loc.getBlockY() + ", " + loc.getBlockZ() + ")"); + final StringBuilder sb = new StringBuilder("商店 " + + (loc.getWorld() == null ? "世界尚未载入" : "坐标: " + loc.getWorld().getName()) + + "(" + + loc.getBlockX() + + ", " + + loc.getBlockY() + + ", " + + loc.getBlockZ() + + ")"); sb.append(" 所有者: " + getOwner()); if (isUnlimited()) { sb.append(" 无限模式: true"); @@ -697,7 +702,7 @@ public class ContainerShop implements Shop { final boolean trans = Util.isTransparent(getLocation().clone().add(0.5, 1.2, 0.5).getBlock().getType()); if (trans && this.getDisplayItem() == null) { if (plugin.getConfigManager().isFakeItem()) { - this.displayItem = new FakeItem(this, this.getItem()); + this.displayItem = new FakeItem_17(this, this.getItem()); } else { this.displayItem = new NormalItem(this, this.getItem()); } diff --git a/src/main/java/org/maxgamer/QuickShop/Shop/DisplayItem.java b/src/main/java/org/maxgamer/QuickShop/Shop/DisplayItem.java deleted file mode 100644 index b5a1975..0000000 --- a/src/main/java/org/maxgamer/QuickShop/Shop/DisplayItem.java +++ /dev/null @@ -1,44 +0,0 @@ -package org.maxgamer.QuickShop.Shop; - -import org.bukkit.Location; -import org.bukkit.entity.Item; - -/** - * @author Netherfoam A display item, that spawns a block above the chest and - * cannot be interacted with. - */ -public interface DisplayItem { - /** - * 获得悬浮物地点 - * - * @return 获得悬浮地点 - */ - public Location getDisplayLocation(); - - /** - * @return {@link Item} - */ - public Item getItem(); - - /** - * 移除悬浮物 - */ - public void remove(); - - /** - * 移除多余物品 - * - * @return - */ - public boolean removeDupe(); - - /** - * 更新悬浮物 - */ - public void respawn(); - - /** - * 刷出悬浮物 - */ - public void spawn(); -} \ No newline at end of file diff --git a/src/main/java/org/maxgamer/QuickShop/Shop/Item/DisplayItem.java b/src/main/java/org/maxgamer/QuickShop/Shop/Item/DisplayItem.java new file mode 100644 index 0000000..b6b9378 --- /dev/null +++ b/src/main/java/org/maxgamer/QuickShop/Shop/Item/DisplayItem.java @@ -0,0 +1,70 @@ +package org.maxgamer.QuickShop.Shop.Item; + +import org.bukkit.Location; +import org.bukkit.entity.Item; +import org.maxgamer.QuickShop.QuickShop; +import org.maxgamer.QuickShop.Shop.ContainerShop; + +import pw.yumc.YumCore.bukkit.Log; +import pw.yumc.YumCore.bukkit.P; + +/** + * @author Netherfoam A display item, that spawns a block above the chest and + * cannot be interacted with. + */ +public abstract class DisplayItem { + public static QuickShop plugin = P.getPlugin(); + + public static DisplayItem create(final ContainerShop shop) { + if (plugin.getConfigManager().isDisplay()) { + if (plugin.getConfigManager().isFakeItem()) { + try { + return new FakeItem_18_110(shop, shop.getItem()); + } catch (final Throwable e) { + Log.debug(e); + try { + return new FakeItem_17(shop, shop.getItem()); + } catch (final Throwable e2) { + Log.debug(e2); + return new NormalItem(shop, shop.getItem()); + } + } + } + } + return null; + } + + /** + * 获得悬浮物地点 + * + * @return 获得悬浮地点 + */ + public abstract Location getDisplayLocation(); + + /** + * @return {@link Item} + */ + public abstract Item getItem(); + + /** + * 移除悬浮物 + */ + public abstract void remove(); + + /** + * 移除多余物品 + * + * @return + */ + public abstract boolean removeDupe(); + + /** + * 更新悬浮物 + */ + public abstract void respawn(); + + /** + * 刷出悬浮物 + */ + public abstract void spawn(); +} \ No newline at end of file diff --git a/src/main/java/org/maxgamer/QuickShop/Shop/FakeItem.java b/src/main/java/org/maxgamer/QuickShop/Shop/Item/FakeItem_17.java similarity index 87% rename from src/main/java/org/maxgamer/QuickShop/Shop/FakeItem.java rename to src/main/java/org/maxgamer/QuickShop/Shop/Item/FakeItem_17.java index e4417e8..83b8d2c 100644 --- a/src/main/java/org/maxgamer/QuickShop/Shop/FakeItem.java +++ b/src/main/java/org/maxgamer/QuickShop/Shop/Item/FakeItem_17.java @@ -1,4 +1,4 @@ -package org.maxgamer.QuickShop.Shop; +package org.maxgamer.QuickShop.Shop.Item; import java.util.ArrayList; import java.util.HashMap; @@ -13,6 +13,7 @@ import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; import org.bukkit.plugin.Plugin; import org.bukkit.plugin.PluginManager; +import org.maxgamer.QuickShop.Shop.ContainerShop; import com.comphenix.protocol.PacketType; import com.comphenix.protocol.ProtocolLibrary; @@ -28,9 +29,9 @@ import com.comphenix.protocol.wrappers.WrappedWatchableObject; * @author 橙子(chengzi) * @version 1.0.1 */ -public class FakeItem implements DisplayItem { +public class FakeItem_17 extends DisplayItem { - private static Map> fakes = new HashMap>(); + private static Map> fakes = new HashMap<>(); private static boolean registered = false; private static int lastId = Integer.MAX_VALUE; @@ -39,6 +40,13 @@ public class FakeItem implements DisplayItem { private final int eid; private boolean created = false; + public FakeItem_17(final ContainerShop containerShop, final ItemStack item) { + this.itemStack = item; + this.location = containerShop.getLocation().clone().add(0.5, 1, 0.5); + this.eid = getFakeEntityId(); + create(); + } + public static boolean isRegistered() { return registered; } @@ -67,9 +75,9 @@ public class FakeItem implements DisplayItem { final Player p = event.getPlayer(); final int chunkX = packet.getIntegers().read(0); final int chunkZ = packet.getIntegers().read(1); - final List fakesInChunk = fakes.get(getChunkIdentifyString(p.getWorld().getChunkAt(chunkX, chunkZ))); + final List fakesInChunk = fakes.get(getChunkIdentifyString(p.getWorld().getChunkAt(chunkX, chunkZ))); if (fakesInChunk != null) { - for (final FakeItem fake : fakesInChunk) { + for (final FakeItem_17 fake : fakesInChunk) { ProtocolLibrary.getProtocolManager().sendServerPacket(p, fake.getSpawnPacket()); ProtocolLibrary.getProtocolManager().sendServerPacket(p, fake.getVelocityPacket()); ProtocolLibrary.getProtocolManager().sendServerPacket(p, fake.getMetadataPacket()); @@ -88,9 +96,9 @@ public class FakeItem implements DisplayItem { final int[] chunksX = packet.getIntegerArrays().read(0); final int[] chunksZ = packet.getIntegerArrays().read(1); for (int i = 0; i < chunksX.length; i++) { - final List fakesInChunk = fakes.get(getChunkIdentifyString(p.getWorld().getChunkAt(chunksX[i], chunksZ[i]))); + final List fakesInChunk = fakes.get(getChunkIdentifyString(p.getWorld().getChunkAt(chunksX[i], chunksZ[i]))); if (fakesInChunk != null) { - for (final FakeItem fake : fakesInChunk) { + for (final FakeItem_17 fake : fakesInChunk) { ProtocolLibrary.getProtocolManager().sendServerPacket(p, fake.getSpawnPacket()); ProtocolLibrary.getProtocolManager().sendServerPacket(p, fake.getVelocityPacket()); ProtocolLibrary.getProtocolManager().sendServerPacket(p, fake.getMetadataPacket()); @@ -119,12 +127,6 @@ public class FakeItem implements DisplayItem { return (int) Math.floor(value * 32.0D); } - public FakeItem(final ContainerShop containerShop, final ItemStack item) { - this.itemStack = item; - this.location = containerShop.getLocation().clone().add(0.5, 1, 0.5); - this.eid = getFakeEntityId(); - } - @Override public Location getDisplayLocation() { return location; @@ -170,9 +172,9 @@ public class FakeItem implements DisplayItem { ProtocolLibrary.getProtocolManager().broadcastServerPacket(getMetadataPacket()); final String chunkId = getChunkIdentifyString(location.getChunk()); - List fakesInChunk = fakes.get(chunkId); + List fakesInChunk = fakes.get(chunkId); if (fakesInChunk == null) { - fakesInChunk = new ArrayList(); + fakesInChunk = new ArrayList<>(); } fakesInChunk.add(this); fakes.put(chunkId, fakesInChunk); @@ -186,7 +188,7 @@ public class FakeItem implements DisplayItem { ProtocolLibrary.getProtocolManager().broadcastServerPacket(getDestoryPacket()); final String chunkId = getChunkIdentifyString(location.getChunk()); - final List fakesInChunk = fakes.get(chunkId); + final List fakesInChunk = fakes.get(chunkId); if (fakesInChunk == null) { // NOTE: This is what should not happens if everything is correct. created = false; @@ -207,7 +209,7 @@ public class FakeItem implements DisplayItem { final PacketContainer fakePacket = ProtocolLibrary.getProtocolManager().createPacket(PacketType.Play.Server.ENTITY_METADATA); fakePacket.getIntegers().write(0, eid); final WrappedWatchableObject itemMeta = new WrappedWatchableObject(10, itemStack); - final List entityMetaList = new ArrayList(1); + final List entityMetaList = new ArrayList<>(1); entityMetaList.add(itemMeta); fakePacket.getWatchableCollectionModifier().write(0, entityMetaList); return fakePacket; diff --git a/src/main/java/org/maxgamer/QuickShop/Shop/Item/FakeItem_18_110.java b/src/main/java/org/maxgamer/QuickShop/Shop/Item/FakeItem_18_110.java new file mode 100644 index 0000000..4f0b6ab --- /dev/null +++ b/src/main/java/org/maxgamer/QuickShop/Shop/Item/FakeItem_18_110.java @@ -0,0 +1,226 @@ +package org.maxgamer.QuickShop.Shop.Item; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +import org.bukkit.Bukkit; +import org.bukkit.Chunk; +import org.bukkit.Location; +import org.bukkit.entity.Item; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; +import org.bukkit.plugin.Plugin; +import org.bukkit.plugin.PluginManager; +import org.maxgamer.QuickShop.Shop.ContainerShop; + +import com.comphenix.protocol.PacketType; +import com.comphenix.protocol.ProtocolLibrary; +import com.comphenix.protocol.events.PacketAdapter; +import com.comphenix.protocol.events.PacketContainer; +import com.comphenix.protocol.events.PacketEvent; +import com.comphenix.protocol.wrappers.WrappedDataWatcher; +import com.comphenix.protocol.wrappers.WrappedDataWatcher.Serializer; +import com.comphenix.protocol.wrappers.WrappedDataWatcher.WrappedDataWatcherObject; +import com.google.common.base.Optional; + +/** + * Minecraft 虚拟悬浮物品工具类 + * 需要depend ProtocolLib 4.x + * + * @author 橙子(chengzi) + * @version 1.1.0 + */ +public class FakeItem_18_110 extends DisplayItem { + + private static Map> fakes = new HashMap<>(); + private static boolean registered = false; + private static int lastId = Integer.MAX_VALUE; + + private final ItemStack itemStack; + private final Location location; + private final int eid; + private final UUID uuid; + private boolean created = false; + + public FakeItem_18_110(final ContainerShop containerShop, final ItemStack item) { + this.itemStack = item; + this.location = containerShop.getLocation().clone().add(0.5, 1, 0.5); + this.eid = getFakeEntityId(); + this.uuid = UUID.randomUUID(); + } + + public static boolean isRegistered() { + return registered; + } + + public static void register(final Plugin plugin) { + if (registered) { + return; + } + final PluginManager pm = Bukkit.getPluginManager(); + final Plugin p = pm.getPlugin("ProtocolLib"); + if (p != null) { + if (!p.isEnabled()) { + pm.enablePlugin(p); + } + if (!p.isEnabled()) { + throw new IllegalStateException("前置插件ProtocolLib启动失败 请检查版本."); + } + } else { + throw new IllegalStateException("服务器未找到前置插件ProtocolLib."); + } + final PacketAdapter chunkPacketListener = new PacketAdapter(plugin, PacketType.Play.Server.MAP_CHUNK) { + @Override + public void onPacketSending(final PacketEvent event) { + try { + final PacketContainer packet = event.getPacket(); + final Player p = event.getPlayer(); + final int chunkX = packet.getIntegers().read(0); + final int chunkZ = packet.getIntegers().read(1); + final List fakesInChunk = fakes.get(getChunkIdentifyString(p.getWorld().getChunkAt(chunkX, chunkZ))); + if (fakesInChunk != null) { + for (final FakeItem_18_110 fake : fakesInChunk) { + ProtocolLibrary.getProtocolManager().sendServerPacket(p, fake.getSpawnPacket()); + ProtocolLibrary.getProtocolManager().sendServerPacket(p, fake.getMetadataPacket()); + } + } + } catch (final Exception e) { + } + } + }; + final PacketAdapter chunkBulkPacketListener = new PacketAdapter(plugin, PacketType.Play.Server.MAP_CHUNK) { + @Override + public void onPacketSending(final PacketEvent event) { + try { + final PacketContainer packet = event.getPacket(); + final Player p = event.getPlayer(); + final int[] chunksX = packet.getIntegerArrays().read(0); + final int[] chunksZ = packet.getIntegerArrays().read(1); + for (int i = 0; i < chunksX.length; i++) { + final List fakesInChunk = fakes.get(getChunkIdentifyString(p.getWorld().getChunkAt(chunksX[i], chunksZ[i]))); + if (fakesInChunk != null) { + for (final FakeItem_18_110 fake : fakesInChunk) { + ProtocolLibrary.getProtocolManager().sendServerPacket(p, fake.getSpawnPacket()); + ProtocolLibrary.getProtocolManager().sendServerPacket(p, fake.getMetadataPacket()); + } + + } + } + } catch (final Exception e) { + } + } + }; + ProtocolLibrary.getProtocolManager().addPacketListener(chunkPacketListener); + ProtocolLibrary.getProtocolManager().addPacketListener(chunkBulkPacketListener); + registered = true; + } + + private static String getChunkIdentifyString(final Chunk chunk) { + return chunk.getWorld().getName() + "@@" + chunk.getX() + "@@" + chunk.getZ(); + } + + private static int getFakeEntityId() { + return lastId--; + } + + @Override + public Location getDisplayLocation() { + return location; + } + + @Override + public Item getItem() { + return null; + } + + @Override + public void remove() { + destory(); + } + + @Override + public boolean removeDupe() { + return true; + } + + @Override + public void respawn() { + ProtocolLibrary.getProtocolManager().broadcastServerPacket(getDestoryPacket()); + ProtocolLibrary.getProtocolManager().broadcastServerPacket(getSpawnPacket()); + ProtocolLibrary.getProtocolManager().broadcastServerPacket(getMetadataPacket()); + } + + @Override + public void spawn() { + create(); + } + + private void create() { + if (!registered) { + throw new IllegalStateException("You have to call the register method first."); + } + if (created) { + return; + } + ProtocolLibrary.getProtocolManager().broadcastServerPacket(getSpawnPacket()); + ProtocolLibrary.getProtocolManager().broadcastServerPacket(getMetadataPacket()); + + final String chunkId = getChunkIdentifyString(location.getChunk()); + List fakesInChunk = fakes.get(chunkId); + if (fakesInChunk == null) { + fakesInChunk = new ArrayList<>(); + } + fakesInChunk.add(this); + fakes.put(chunkId, fakesInChunk); + created = true; + } + + private void destory() { + if (!created) { + return; + } + ProtocolLibrary.getProtocolManager().broadcastServerPacket(getDestoryPacket()); + + final String chunkId = getChunkIdentifyString(location.getChunk()); + final List fakesInChunk = fakes.get(chunkId); + if (fakesInChunk == null) { + // NOTE: This is what should not happens if everything is correct. + created = false; + return; + } + fakesInChunk.remove(this); + fakes.put(chunkId, fakesInChunk); + created = false; + } + + private PacketContainer getDestoryPacket() { + final PacketContainer fakePacket = ProtocolLibrary.getProtocolManager().createPacket(PacketType.Play.Server.ENTITY_DESTROY, true); + fakePacket.getIntegerArrays().write(0, new int[] { eid }); + return fakePacket; + } + + private PacketContainer getMetadataPacket() { + final PacketContainer fakePacket = ProtocolLibrary.getProtocolManager().createPacket(PacketType.Play.Server.ENTITY_METADATA); + fakePacket.getIntegers().write(0, eid); + final WrappedDataWatcher wr = new WrappedDataWatcher(); + final Serializer serializer = WrappedDataWatcher.Registry.getItemStackSerializer(true); + final WrappedDataWatcherObject object = new WrappedDataWatcher.WrappedDataWatcherObject(6, serializer); + wr.setObject(object, Optional.of(itemStack)); + fakePacket.getWatchableCollectionModifier().write(0, wr.getWatchableObjects()); + return fakePacket; + } + + private PacketContainer getSpawnPacket() { + final PacketContainer fakePacket = ProtocolLibrary.getProtocolManager().createPacket(PacketType.Play.Server.SPAWN_ENTITY); + fakePacket.getIntegers().write(0, eid); + fakePacket.getModifier().write(1, uuid); + fakePacket.getDoubles().write(0, location.getX()); + fakePacket.getDoubles().write(1, location.getY()); + fakePacket.getDoubles().write(2, location.getZ()); + fakePacket.getIntegers().write(6, 2); + return fakePacket; + } +} diff --git a/src/main/java/org/maxgamer/QuickShop/Shop/NormalItem.java b/src/main/java/org/maxgamer/QuickShop/Shop/Item/NormalItem.java similarity index 96% rename from src/main/java/org/maxgamer/QuickShop/Shop/NormalItem.java rename to src/main/java/org/maxgamer/QuickShop/Shop/Item/NormalItem.java index 2eeb145..2870da5 100644 --- a/src/main/java/org/maxgamer/QuickShop/Shop/NormalItem.java +++ b/src/main/java/org/maxgamer/QuickShop/Shop/Item/NormalItem.java @@ -1,4 +1,4 @@ -package org.maxgamer.QuickShop.Shop; +package org.maxgamer.QuickShop.Shop.Item; import org.bukkit.Chunk; import org.bukkit.Location; @@ -6,13 +6,14 @@ import org.bukkit.entity.Entity; import org.bukkit.entity.Item; import org.bukkit.inventory.ItemStack; import org.bukkit.util.Vector; +import org.maxgamer.QuickShop.Shop.Shop; import org.maxgamer.QuickShop.Util.NMS; /** * @author Netherfoam A display item, that spawns a block above the chest and * cannot be interacted with. */ -public class NormalItem implements DisplayItem { +public class NormalItem extends DisplayItem { private final ItemStack iStack; private Item item; private final Shop shop; diff --git a/src/main/java/org/maxgamer/QuickShop/Shop/ShopManager.java b/src/main/java/org/maxgamer/QuickShop/Shop/ShopManager.java index be7bcce..9fff9c0 100644 --- a/src/main/java/org/maxgamer/QuickShop/Shop/ShopManager.java +++ b/src/main/java/org/maxgamer/QuickShop/Shop/ShopManager.java @@ -24,13 +24,11 @@ import org.maxgamer.QuickShop.Database.Database; import org.maxgamer.QuickShop.Util.MsgUtil; import org.maxgamer.QuickShop.Util.Util; -import cn.citycraft.PluginHelper.kit.PluginKit; - public class ShopManager { - private final HashMap actions = new HashMap(); + private final HashMap actions = new HashMap<>(); private final QuickShop plugin; - private final HashMap>> shops = new HashMap>>(); + private final HashMap>> shops = new HashMap<>(); public ShopManager(final QuickShop plugin) { this.plugin = plugin; @@ -226,108 +224,8 @@ public class ShopManager { } /* Creation handling */ if (info.getAction() == ShopAction.CREATE) { - try { - // Checking the shop can be created - if (plugin.getShopManager().getShop(info.getLocation()) != null) { - p.sendMessage(MsgUtil.p("shop-already-owned")); - return; - } - if (Util.getSecondHalf(info.getLocation().getBlock()) != null && !p.hasPermission("quickshop.create.double")) { - p.sendMessage(MsgUtil.p("no-double-chests")); - return; - } - if (Util.canBeShop(info.getLocation().getBlock()) == false) { - p.sendMessage(MsgUtil.p("chest-was-removed")); - return; - } - // Price per item - double price; - if (plugin.getConfig().getBoolean("whole-number-prices-only")) { - price = Integer.parseInt(message); - } else { - price = Double.parseDouble(message); - } - if (price < 0.01) { - p.sendMessage(MsgUtil.p("price-too-cheap")); - return; - } - final double tax = plugin.getConfig().getDouble("shop.cost"); - // Tax refers to the cost to create a shop. Not actual - // tax, that would be silly - if (tax != 0 && plugin.getEcon().getBalance(p.getName()) < tax) { - p.sendMessage(MsgUtil.p("you-cant-afford-a-new-shop", format(tax))); - return; - } - // Create the sample shop. - final Shop shop = new ContainerShop(info.getLocation(), price, info.getItem(), p.getName()); - // This must be called after the event has been called. - // Else, if the event is cancelled, they won't get their - // money back. - if (tax != 0) { - if (!plugin.getEcon().withdraw(p.getName(), tax)) { - p.sendMessage(MsgUtil.p("you-cant-afford-a-new-shop", format(tax))); - return; - } - plugin.getEcon().deposit(plugin.getConfig().getString("tax-account"), tax); - } - final ShopCreateEvent e = new ShopCreateEvent(shop, p); - Bukkit.getPluginManager().callEvent(e); - if (e.isCancelled()) { - return; - } - shop.onLoad(); - /* The shop has hereforth been successfully created */ - createShop(shop); - p.sendMessage(MsgUtil.p("success-created-shop")); - final Location loc = shop.getLocation(); - plugin.log(String.format("玩家: %s 创建了一个 %s 商店 在 (%s - %s, %s, %s)", p.getName(), shop.getDataName(), loc.getWorld().getName(), loc.getX(), loc.getY(), loc.getZ())); - if (!plugin.getConfig().getBoolean("shop.lock")) { - // Warn them if they haven't been warned since - // reboot - final Set warings = plugin.getConfigManager().getWarnings(); - if (!warings.contains(p.getName())) { - p.sendMessage(MsgUtil.p("shops-arent-locked")); - warings.add(p.getName()); - } - } - // Figures out which way we should put the sign on and - // sets its text. - if (info.getSignBlock() != null && info.getSignBlock().getType() == Material.AIR && plugin.getConfig().getBoolean("shop.auto-sign")) { - final BlockState bs = info.getSignBlock().getState(); - final BlockFace bf = info.getLocation().getBlock().getFace(info.getSignBlock()); - bs.setType(Material.WALL_SIGN); - final Sign sign = (Sign) bs.getData(); - sign.setFacingDirection(bf); - PluginKit.runTask(new Runnable() { - @Override - public void run() { - bs.update(true); - } - }); - shop.setSignText(); - } - if (shop instanceof ContainerShop) { - final ContainerShop cs = (ContainerShop) shop; - if (cs.isDoubleShop()) { - final Shop nextTo = cs.getAttachedShop(); - if (nextTo.getPrice() > shop.getPrice()) { - // The one next to it must always be a - // buying shop. - p.sendMessage(MsgUtil.p("buying-more-than-selling")); - } - } - } - } - /* They didn't enter a number. */ - catch (final NumberFormatException ex) { - p.sendMessage(MsgUtil.p("shop-creation-cancelled")); - return; - } - } - /* Purchase Handling */ - else if (info.getAction() == ShopAction.BUY) - - { + create(p, info, message); + } else if (/* Purchase Handling */info.getAction() == ShopAction.BUY) { int amount = 0; try { amount = Integer.parseInt(message); @@ -347,140 +245,15 @@ public class ShopManager { return; } if (shop.isSelling()) { - final int stock = shop.getRemainingStock(); - if (stock < amount) { - p.sendMessage(MsgUtil.p("shop-stock-too-low", "" + shop.getRemainingStock(), shop.getDataName())); - return; - } - if (amount == 0) { - // Dumb. - MsgUtil.sendPurchaseSuccess(p, shop, amount); - return; - } else if (amount < 0) { - // & Dumber - p.sendMessage(MsgUtil.p("negative-amount")); - return; - } - final int pSpace = Util.countSpace(p.getInventory(), shop.getItem()); - if (amount > pSpace) { - p.sendMessage(MsgUtil.p("not-enough-space", "" + pSpace)); - return; - } - final ShopPurchaseEvent e = new ShopPurchaseEvent(shop, p, amount); - Bukkit.getPluginManager().callEvent(e); - if (e.isCancelled()) { - return; // Cancelled - } - // Money handling - if (!p.getName().equals(shop.getOwner())) { - // Check their balance. Works with *most* economy - // plugins* - if (plugin.getEcon().getBalance(p.getName()) < amount * shop.getPrice()) { - p.sendMessage(MsgUtil.p("you-cant-afford-to-buy", format(amount * shop.getPrice()), format(plugin.getEcon().getBalance(p.getName())))); - return; - } - // Don't tax them if they're purchasing from - // themselves. - // Do charge an amount of tax though. - final double tax = plugin.getConfigManager().getTax(); - final double total = amount * shop.getPrice(); - if (!plugin.getEcon().withdraw(p.getName(), total)) { - p.sendMessage(MsgUtil.p("you-cant-afford-to-buy", format(amount * shop.getPrice()), format(plugin.getEcon().getBalance(p.getName())))); - return; - } - if (!shop.isUnlimited() || plugin.getConfig().getBoolean("shop.pay-unlimited-shop-owners")) { - plugin.getEcon().deposit(shop.getOwner(), total * (1 - tax)); - if (tax != 0) { - plugin.getEcon().deposit(plugin.getConfigManager().getTaxAccount(), total * tax); - } - } - // Notify the shop owner - if (plugin.getConfigManager().isShowTax()) { - String msg = MsgUtil.p("player-bought-from-your-store-tax", p.getName(), "" + amount, shop.getDataName(), Util.format((tax * total))); - if (stock == amount) { - msg += "\n" - + MsgUtil.p("shop-out-of-stock", "" + shop.getLocation().getBlockX(), "" + shop.getLocation().getBlockY(), "" + shop.getLocation().getBlockZ(), shop.getDataName()); - } - MsgUtil.send(shop.getOwner(), msg); - } else { - String msg = MsgUtil.p("player-bought-from-your-store", p.getName(), "" + amount, shop.getDataName()); - if (stock == amount) { - msg += "\n" - + MsgUtil.p("shop-out-of-stock", "" + shop.getLocation().getBlockX(), "" + shop.getLocation().getBlockY(), "" + shop.getLocation().getBlockZ(), shop.getDataName()); - } - MsgUtil.send(shop.getOwner(), msg); - } - } - // Transfers the item from A to B - shop.sell(p, amount); - MsgUtil.sendPurchaseSuccess(p, shop, amount); - plugin.log(String.format("玩家: %s 从 %s 购买了 %s 件商品 花费 %s", p.getName(), shop.toString(), amount, shop.getPrice() * amount)); + sale(p, shop, amount); } else if (shop.isBuying()) { - final int space = shop.getRemainingSpace(); - if (space < amount) { - p.sendMessage(MsgUtil.p("shop-has-no-space", "" + space, shop.getDataName())); - return; - } - final int count = Util.countItems(p.getInventory(), shop.getItem()); - // Not enough items - if (amount > count) { - p.sendMessage(MsgUtil.p("you-dont-have-that-many-items", "" + count, shop.getDataName())); - return; - } - if (amount == 0) { - // Dumb. - MsgUtil.sendPurchaseSuccess(p, shop, amount); - return; - } else if (amount < 0) { - // & Dumber - p.sendMessage(MsgUtil.p("negative-amount")); - return; - } - // Money handling - if (!p.getName().equals(shop.getOwner())) { - // Don't tax them if they're purchasing from - // themselves. - // Do charge an amount of tax though. - final double tax = plugin.getConfigManager().getTax(); - final double total = amount * shop.getPrice(); - if (!shop.isUnlimited() || plugin.getConfig().getBoolean("shop.pay-unlimited-shop-owners")) { - // Tries to check their balance nicely to see if - // they can afford it. - if (plugin.getEcon().getBalance(shop.getOwner()) < amount * shop.getPrice()) { - p.sendMessage(MsgUtil.p("the-owner-cant-afford-to-buy-from-you", format(amount * shop.getPrice()), format(plugin.getEcon().getBalance(shop.getOwner())))); - return; - } - // Check for plugins faking econ.has(amount) - if (!plugin.getEcon().withdraw(shop.getOwner(), total)) { - p.sendMessage(MsgUtil.p("the-owner-cant-afford-to-buy-from-you", format(amount * shop.getPrice()), format(plugin.getEcon().getBalance(shop.getOwner())))); - return; - } - if (tax != 0) { - plugin.getEcon().deposit(plugin.getConfigManager().getTaxAccount(), total * tax); - } - } - // Give them the money after we know we succeeded - plugin.getEcon().deposit(p.getName(), total * (1 - tax)); - // Notify the owner of the purchase. - String msg = MsgUtil.p("player-sold-to-your-store", p.getName(), "" + amount, shop.getDataName()); - if (space == amount) { - msg += "\n" + MsgUtil.p("shop-out-of-space", "" + shop.getLocation().getBlockX(), "" + shop.getLocation().getBlockY(), "" + shop.getLocation().getBlockZ()); - } - MsgUtil.send(shop.getOwner(), msg); - } - shop.buy(p, amount); - MsgUtil.sendSellSuccess(p, shop, amount); - plugin.log(String.format("玩家: %s 出售了 %s 件商品 到 %s 获得 %s", p.getName(), amount, shop.toString(), shop.getPrice() * amount)); + buy(p, shop, amount); } shop.setSignText(); // Update the signs count - } - /* If it was already cancelled (from destroyed) */ - else - - { + } else { + /* If it was already cancelled (from destroyed) */ return; // It was cancelled, go away. } - } /** @@ -527,7 +300,7 @@ public class ShopManager { HashMap> inWorld = this.getShops().get(world); // There's no world storage yet. We need to create that hashmap. if (inWorld == null) { - inWorld = new HashMap>(3); + inWorld = new HashMap<>(3); // Put it in the data universe this.getShops().put(world, inWorld); } @@ -540,7 +313,7 @@ public class ShopManager { HashMap inChunk = inWorld.get(shopChunk); // That chunk data hasn't been created yet - Create it! if (inChunk == null) { - inChunk = new HashMap(1); + inChunk = new HashMap<>(1); // Put it in the world inWorld.put(shopChunk, inChunk); } @@ -548,6 +321,233 @@ public class ShopManager { inChunk.put(shop.getLocation(), shop); } + private void buy(final Player p, final Shop shop, final int amount) { + final int space = shop.getRemainingSpace(); + if (space < amount) { + p.sendMessage(MsgUtil.p("shop-has-no-space", "" + space, shop.getDataName())); + return; + } + final int count = Util.countItems(p.getInventory(), shop.getItem()); + // Not enough items + if (amount > count) { + p.sendMessage(MsgUtil.p("you-dont-have-that-many-items", "" + count, shop.getDataName())); + return; + } + if (amount == 0) { + // Dumb. + MsgUtil.sendPurchaseSuccess(p, shop, amount); + return; + } else if (amount < 0) { + // & Dumber + p.sendMessage(MsgUtil.p("negative-amount")); + return; + } + // Money handling + if (!p.getName().equals(shop.getOwner())) { + // Don't tax them if they're purchasing from + // themselves. + // Do charge an amount of tax though. + final double tax = plugin.getConfigManager().getTax(); + final double total = amount * shop.getPrice(); + if (!shop.isUnlimited() || plugin.getConfig().getBoolean("shop.pay-unlimited-shop-owners")) { + // Tries to check their balance nicely to see if + // they can afford it. + if (plugin.getEcon().getBalance(shop.getOwner()) < amount * shop.getPrice()) { + p.sendMessage(MsgUtil.p("the-owner-cant-afford-to-buy-from-you", format(amount * shop.getPrice()), format(plugin.getEcon().getBalance(shop.getOwner())))); + return; + } + // Check for plugins faking econ.has(amount) + if (!plugin.getEcon().withdraw(shop.getOwner(), total)) { + p.sendMessage(MsgUtil.p("the-owner-cant-afford-to-buy-from-you", format(amount * shop.getPrice()), format(plugin.getEcon().getBalance(shop.getOwner())))); + return; + } + if (tax != 0) { + plugin.getEcon().deposit(plugin.getConfigManager().getTaxAccount(), total * tax); + } + } + // Give them the money after we know we succeeded + plugin.getEcon().deposit(p.getName(), total * (1 - tax)); + // Notify the owner of the purchase. + String msg = MsgUtil.p("player-sold-to-your-store", p.getName(), "" + amount, shop.getDataName()); + if (space == amount) { + msg += "\n" + MsgUtil.p("shop-out-of-space", "" + shop.getLocation().getBlockX(), "" + shop.getLocation().getBlockY(), "" + shop.getLocation().getBlockZ()); + } + MsgUtil.send(shop.getOwner(), msg); + } + shop.buy(p, amount); + MsgUtil.sendSellSuccess(p, shop, amount); + plugin.log(String.format("玩家: %s 出售了 %s 件商品 到 %s 获得 %s", p.getName(), amount, shop.toString(), shop.getPrice() * amount)); + } + + private void create(final Player p, final Info info, final String message) { + try { + // Checking the shop can be created + if (plugin.getShopManager().getShop(info.getLocation()) != null) { + p.sendMessage(MsgUtil.p("shop-already-owned")); + return; + } + if (Util.getSecondHalf(info.getLocation().getBlock()) != null && !p.hasPermission("quickshop.create.double")) { + p.sendMessage(MsgUtil.p("no-double-chests")); + return; + } + if (Util.canBeShop(info.getLocation().getBlock()) == false) { + p.sendMessage(MsgUtil.p("chest-was-removed")); + return; + } + // Price per item + double price; + if (plugin.getConfig().getBoolean("whole-number-prices-only")) { + price = Integer.parseInt(message); + } else { + price = Double.parseDouble(message); + } + if (price < 0.01) { + p.sendMessage(MsgUtil.p("price-too-cheap")); + return; + } + final double tax = plugin.getConfig().getDouble("shop.cost"); + // Tax refers to the cost to create a shop. Not actual + // tax, that would be silly + if (tax != 0 && plugin.getEcon().getBalance(p.getName()) < tax) { + p.sendMessage(MsgUtil.p("you-cant-afford-a-new-shop", format(tax))); + return; + } + // Create the sample shop. + final Shop shop = new ContainerShop(info.getLocation(), price, info.getItem(), p.getName()); + // This must be called after the event has been called. + // Else, if the event is cancelled, they won't get their + // money back. + if (tax != 0) { + if (!plugin.getEcon().withdraw(p.getName(), tax)) { + p.sendMessage(MsgUtil.p("you-cant-afford-a-new-shop", format(tax))); + return; + } + plugin.getEcon().deposit(plugin.getConfig().getString("tax-account"), tax); + } + final ShopCreateEvent e = new ShopCreateEvent(shop, p); + Bukkit.getPluginManager().callEvent(e); + if (e.isCancelled()) { + return; + } + shop.onLoad(); + /* The shop has hereforth been successfully created */ + createShop(shop); + p.sendMessage(MsgUtil.p("success-created-shop")); + final Location loc = shop.getLocation(); + plugin.log(String.format("玩家: %s 创建了一个 %s 商店 在 (%s - %s, %s, %s)", p.getName(), shop.getDataName(), loc.getWorld().getName(), loc.getX(), loc.getY(), loc.getZ())); + if (!plugin.getConfig().getBoolean("shop.lock")) { + // Warn them if they haven't been warned since + // reboot + final Set warings = plugin.getConfigManager().getWarnings(); + if (!warings.contains(p.getName())) { + p.sendMessage(MsgUtil.p("shops-arent-locked")); + warings.add(p.getName()); + } + } + // Figures out which way we should put the sign on and + // sets its text. + if (info.getSignBlock() != null && info.getSignBlock().getType() == Material.AIR && plugin.getConfig().getBoolean("shop.auto-sign")) { + final BlockState bs = info.getSignBlock().getState(); + final BlockFace bf = info.getLocation().getBlock().getFace(info.getSignBlock()); + bs.setType(Material.WALL_SIGN); + final Sign sign = (Sign) bs.getData(); + sign.setFacingDirection(bf); + Bukkit.getScheduler().runTask(plugin, new Runnable() { + @Override + public void run() { + bs.update(true); + } + }); + shop.setSignText(); + } + if (shop instanceof ContainerShop) { + final ContainerShop cs = (ContainerShop) shop; + if (cs.isDoubleShop()) { + final Shop nextTo = cs.getAttachedShop(); + if (nextTo.getPrice() > shop.getPrice()) { + // The one next to it must always be a + // buying shop. + p.sendMessage(MsgUtil.p("buying-more-than-selling")); + } + } + } + } + /* They didn't enter a number. */ + catch (final NumberFormatException ex) { + p.sendMessage(MsgUtil.p("shop-creation-cancelled")); + return; + } + } + + private void sale(final Player p, final Shop shop, final int amount) { + final int stock = shop.getRemainingStock(); + if (stock < amount) { + p.sendMessage(MsgUtil.p("shop-stock-too-low", "" + shop.getRemainingStock(), shop.getDataName())); + return; + } + if (amount == 0) { + // Dumb. + MsgUtil.sendPurchaseSuccess(p, shop, amount); + return; + } else if (amount < 0) { + // & Dumber + p.sendMessage(MsgUtil.p("negative-amount")); + return; + } + final int pSpace = Util.countSpace(p.getInventory(), shop.getItem()); + if (amount > pSpace) { + p.sendMessage(MsgUtil.p("not-enough-space", "" + pSpace)); + return; + } + final ShopPurchaseEvent e = new ShopPurchaseEvent(shop, p, amount); + Bukkit.getPluginManager().callEvent(e); + if (e.isCancelled()) { + return; // Cancelled + } + // Money handling + if (!p.getName().equals(shop.getOwner())) { + // Check their balance. Works with *most* economy + // plugins* + if (plugin.getEcon().getBalance(p.getName()) < amount * shop.getPrice()) { + p.sendMessage(MsgUtil.p("you-cant-afford-to-buy", format(amount * shop.getPrice()), format(plugin.getEcon().getBalance(p.getName())))); + return; + } + // Don't tax them if they're purchasing from + // themselves. + // Do charge an amount of tax though. + final double tax = plugin.getConfigManager().getTax(); + final double total = amount * shop.getPrice(); + if (!plugin.getEcon().withdraw(p.getName(), total)) { + p.sendMessage(MsgUtil.p("you-cant-afford-to-buy", format(amount * shop.getPrice()), format(plugin.getEcon().getBalance(p.getName())))); + return; + } + if (!shop.isUnlimited() || plugin.getConfig().getBoolean("shop.pay-unlimited-shop-owners")) { + plugin.getEcon().deposit(shop.getOwner(), total * (1 - tax)); + if (tax != 0) { + plugin.getEcon().deposit(plugin.getConfigManager().getTaxAccount(), total * tax); + } + } + // Notify the shop owner + if (plugin.getConfigManager().isShowTax()) { + String msg = MsgUtil.p("player-bought-from-your-store-tax", p.getName(), "" + amount, shop.getDataName(), Util.format((tax * total))); + if (stock == amount) { + msg += "\n" + MsgUtil.p("shop-out-of-stock", "" + shop.getLocation().getBlockX(), "" + shop.getLocation().getBlockY(), "" + shop.getLocation().getBlockZ(), shop.getDataName()); + } + MsgUtil.send(shop.getOwner(), msg); + } else { + String msg = MsgUtil.p("player-bought-from-your-store", p.getName(), "" + amount, shop.getDataName()); + if (stock == amount) { + msg += "\n" + MsgUtil.p("shop-out-of-stock", "" + shop.getLocation().getBlockX(), "" + shop.getLocation().getBlockY(), "" + shop.getLocation().getBlockZ(), shop.getDataName()); + } + MsgUtil.send(shop.getOwner(), msg); + } + } + // Transfers the item from A to B + shop.sell(p, amount); + MsgUtil.sendPurchaseSuccess(p, shop, amount); + plugin.log(String.format("玩家: %s 从 %s 购买了 %s 件商品 花费 %s", p.getName(), shop.toString(), amount, shop.getPrice() * amount)); + } + public class ShopIterator implements Iterator { private Iterator> chunks; private Shop current; diff --git a/src/main/java/org/maxgamer/QuickShop/Util/MsgUtil.java b/src/main/java/org/maxgamer/QuickShop/Util/MsgUtil.java index 6ac31a3..00b063c 100644 --- a/src/main/java/org/maxgamer/QuickShop/Util/MsgUtil.java +++ b/src/main/java/org/maxgamer/QuickShop/Util/MsgUtil.java @@ -13,12 +13,12 @@ import org.bukkit.inventory.ItemStack; import org.maxgamer.QuickShop.QuickShop; import org.maxgamer.QuickShop.Shop.Shop; -import cn.citycraft.PluginHelper.config.FileConfig; -import cn.citycraft.PluginHelper.tellraw.FancyMessage; +import pw.yumc.YumCore.config.FileConfig; +import pw.yumc.YumCore.tellraw.Tellraw; public class MsgUtil { private static FileConfig messages; - private static HashMap> player_messages = new HashMap>(); + private static HashMap> player_messages = new HashMap<>(); private static QuickShop plugin; /** @@ -58,7 +58,7 @@ public class MsgUtil { public static void init(final QuickShop plugin) { MsgUtil.plugin = plugin; // Load messages.yml - messages = new FileConfig(plugin, "messages.yml"); + messages = new FileConfig("messages.yml"); // Parse colour codes Util.parseColours(messages); } @@ -75,7 +75,7 @@ public class MsgUtil { final String message = rs.getString("message"); LinkedList msgs = player_messages.get(owner); if (msgs == null) { - msgs = new LinkedList(); + msgs = new LinkedList<>(); player_messages.put(owner, msgs); } msgs.add(message); @@ -122,7 +122,7 @@ public class MsgUtil { if (p == null || !p.isOnline()) { LinkedList msgs = player_messages.get(player); if (msgs == null) { - msgs = new LinkedList(); + msgs = new LinkedList<>(); player_messages.put(player, msgs); } msgs.add(message); @@ -137,8 +137,8 @@ public class MsgUtil { public static void sendItemMessage(final Player p, final ItemStack is, final String msg) { try { - final FancyMessage fm = FancyMessage.newFM(); - fm.text(msg).itemTooltip(is).send(p); + final Tellraw fm = Tellraw.create(); + fm.text(msg).item(is).send(p); } catch (Exception | NoClassDefFoundError | NoSuchMethodError e) { plugin.getConfigManager().setEnableMagicLib(false); p.sendMessage(msg); @@ -188,7 +188,8 @@ public class MsgUtil { p.sendMessage(ChatColor.DARK_PURPLE + "| " + MsgUtil.p("menu.shop-information")); p.sendMessage(ChatColor.DARK_PURPLE + "| " - + MsgUtil.p("menu.owner", Bukkit.getOfflinePlayer(shop.getOwner()).getName() == null ? (shop.isUnlimited() ? "系统商店" : "未知") : Bukkit.getOfflinePlayer(shop.getOwner()).getName())); + + MsgUtil.p("menu.owner", + Bukkit.getOfflinePlayer(shop.getOwner()).getName() == null ? (shop.isUnlimited() ? "系统商店" : "未知") : Bukkit.getOfflinePlayer(shop.getOwner()).getName())); final String msg = ChatColor.DARK_PURPLE + "| " + MsgUtil.p("menu.item", shop.getDataName()); sendItemMessage(p, shop.getItem(), msg); if (Util.isTool(item.getType())) { diff --git a/src/main/java/org/maxgamer/QuickShop/Util/Util.java b/src/main/java/org/maxgamer/QuickShop/Util/Util.java index 179c44a..55c088d 100644 --- a/src/main/java/org/maxgamer/QuickShop/Util/Util.java +++ b/src/main/java/org/maxgamer/QuickShop/Util/Util.java @@ -23,16 +23,16 @@ import org.bukkit.material.MaterialData; import org.bukkit.material.Sign; import org.maxgamer.QuickShop.QuickShop; -import cn.citycraft.PluginHelper.utils.LocalUtil; +import pw.yumc.YumCore.misc.L10N; @SuppressWarnings("deprecation") public class Util { - private static HashSet blacklist = new HashSet(); + private static HashSet blacklist = new HashSet<>(); private static final DecimalFormat DECIMAL_FORMAT = new DecimalFormat("#.##"); private static QuickShop plugin; - private static HashSet shoppables = new HashSet(); - private static HashSet tools = new HashSet(); - private static HashSet transparent = new HashSet(); + private static HashSet shoppables = new HashSet<>(); + private static HashSet tools = new HashSet<>(); + private static HashSet transparent = new HashSet<>(); public static void addTransparentBlock(final Material m) { if (transparent.add(m) == false) { @@ -162,7 +162,7 @@ public class Util { * @return The human readable item name. */ public static String getName(final ItemStack i) { - final String vanillaName = LocalUtil.getItemFullName(i); + final String vanillaName = L10N.getItemFullName(i); return vanillaName; }