From 26f46b18d8a0eb9d6a4d3b6ff7db54bf158499f9 Mon Sep 17 00:00:00 2001 From: ChiyodaXiaoYi Date: Sun, 12 Nov 2023 19:52:42 +0800 Subject: [PATCH] =?UTF-8?q?[1.4.2-dev1]=E6=9B=B4=E6=96=B0CrypticLib,?= =?UTF-8?q?=E5=85=BC=E5=AE=B91.20.2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle.kts | 73 +-- .../craftorithm/bstat/Metrics.java | 3 +- .../craftorithm/util/UpdateUtil.java | 8 +- common/src/main/resources/plugin.yml | 5 - .../craftorithm/Craftorithm.java | 128 +++++ .../arcenciel/ArcencielDispatcher.java | 81 +++ .../craftorithm/cmd/PluginCommand.java | 100 ++++ .../cmd/subcmd/AbstractSubCommand.java | 122 +++++ .../craftorithm/cmd/subcmd/ItemCommand.java | 28 ++ .../craftorithm/cmd/subcmd/ReloadCommand.java | 54 ++ .../cmd/subcmd/RemoveRecipeCommand.java | 146 ++++++ .../cmd/subcmd/VersionCommand.java | 22 + .../cmd/subcmd/item/ItemGiveCommand.java | 74 +++ .../cmd/subcmd/item/ItemSaveCommand.java | 57 +++ .../craftorithm/item/ItemManager.java | 208 ++++++++ .../menu/bukkit/BukkitMenuDispatcher.java | 66 +++ .../impl/recipe/RecipeCreatorMenuHolder.java | 470 ++++++++++++++++++ .../craftorithm/recipe/RecipeManager.java | 286 +++++++++++ .../craftorithm/util/LangUtil.java | 85 ++++ 19 files changed, 1959 insertions(+), 57 deletions(-) create mode 100644 src/main/java/com/github/yufiriamazenta/craftorithm/Craftorithm.java create mode 100644 src/main/java/com/github/yufiriamazenta/craftorithm/arcenciel/ArcencielDispatcher.java create mode 100644 src/main/java/com/github/yufiriamazenta/craftorithm/cmd/PluginCommand.java create mode 100644 src/main/java/com/github/yufiriamazenta/craftorithm/cmd/subcmd/AbstractSubCommand.java create mode 100644 src/main/java/com/github/yufiriamazenta/craftorithm/cmd/subcmd/ItemCommand.java create mode 100644 src/main/java/com/github/yufiriamazenta/craftorithm/cmd/subcmd/ReloadCommand.java create mode 100644 src/main/java/com/github/yufiriamazenta/craftorithm/cmd/subcmd/RemoveRecipeCommand.java create mode 100644 src/main/java/com/github/yufiriamazenta/craftorithm/cmd/subcmd/VersionCommand.java create mode 100644 src/main/java/com/github/yufiriamazenta/craftorithm/cmd/subcmd/item/ItemGiveCommand.java create mode 100644 src/main/java/com/github/yufiriamazenta/craftorithm/cmd/subcmd/item/ItemSaveCommand.java create mode 100644 src/main/java/com/github/yufiriamazenta/craftorithm/item/ItemManager.java create mode 100644 src/main/java/com/github/yufiriamazenta/craftorithm/menu/bukkit/BukkitMenuDispatcher.java create mode 100644 src/main/java/com/github/yufiriamazenta/craftorithm/menu/impl/recipe/RecipeCreatorMenuHolder.java create mode 100644 src/main/java/com/github/yufiriamazenta/craftorithm/recipe/RecipeManager.java create mode 100644 src/main/java/com/github/yufiriamazenta/craftorithm/util/LangUtil.java diff --git a/build.gradle.kts b/build.gradle.kts index a01582a9..446cef68 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -4,27 +4,43 @@ plugins { `java-library` `maven-publish` id("com.github.johnrengelman.shadow").version("7.1.2") - id("io.papermc.paperweight.userdev").version("1.5.5") } repositories { mavenLocal() + maven("https://hub.spigotmc.org/nexus/content/repositories/snapshots/") + maven("https://oss.sonatype.org/content/groups/public/") maven("https://jitpack.io") + maven("https://repo.rosewooddev.io/repository/public/") + maven("https://repo.extendedclip.com/content/repositories/placeholderapi/") + maven("https://repo.maven.apache.org/maven2/") + maven("https://mvn.lumine.io/repository/maven-public/") + maven("https://nexus.phoenixdevt.fr/repository/maven-public/") + maven("http://repo.crypticlib.com:8081/repository/maven-public/") { + isAllowInsecureProtocol = true + } mavenCentral() } dependencies { - implementation("com.github.YufiriaMazenta:CrypticLib:1.0.9") - implementation(project(":common")) - implementation(project(":v1_20_R2")) - paperweight.paperDevBundle("1.20.2-R0.1-SNAPSHOT") + compileOnly("org.jetbrains:annotations:24.0.1") + compileOnly("org.spigotmc:spigot:1.19.4-R0.1-SNAPSHOT") + compileOnly("org.spigotmc:spigot-api:1.20.1-R0.1-SNAPSHOT") + compileOnly("com.github.MilkBowl:VaultAPI:1.7") + compileOnly("org.black_ixx:playerpoints:3.2.5") + compileOnly("net.luckperms:api:5.4") + compileOnly("me.clip:placeholderapi:2.11.1") + compileOnly("com.github.LoneDev6:API-ItemsAdder:3.5.0b") + compileOnly("com.github.oraxen:oraxen:1.160.0") + compileOnly("io.lumine:Mythic-Dist:5.3.5") + implementation("com.crypticlib:CrypticLib:0.0.5") } group = "com.github.yufiriamazenta" -version = "2.0.0-dev2" +version = "1.4.2-dev1" var pluginVersion: String = version.toString() + "-" + SimpleDateFormat("yyyyMMdd").format(System.currentTimeMillis()) -java.sourceCompatibility = JavaVersion.VERSION_17 -java.targetCompatibility = JavaVersion.VERSION_17 +java.sourceCompatibility = JavaVersion.VERSION_1_8 +java.targetCompatibility = JavaVersion.VERSION_1_8 publishing { publications.create("maven") { @@ -43,49 +59,14 @@ tasks { expand(props) } } + build { + dependsOn(shadowJar) + } compileJava { options.encoding = "UTF-8" } - assemble { - dependsOn(shadowJar) - } shadowJar { archiveFileName.set("Craftorithm-$version.jar") relocate("crypticlib", "com.github.yufiriamazenta.craftorithm.crypticlib") } - assemble { - dependsOn(shadowJar) - } -} - -subprojects { - apply(plugin = "java") - apply(plugin = "maven-publish") - tasks { - compileJava { - options.encoding = "UTF-8" - } - } - repositories { - mavenLocal() - maven("https://hub.spigotmc.org/nexus/content/repositories/snapshots/") - maven("https://oss.sonatype.org/content/groups/public/") - maven("https://jitpack.io") - maven("https://repo.rosewooddev.io/repository/public/") - maven("https://repo.extendedclip.com/content/repositories/placeholderapi/") - maven("https://repo.maven.apache.org/maven2/") - maven("https://mvn.lumine.io/repository/maven-public/") - maven("https://nexus.phoenixdevt.fr/repository/maven-public/") - mavenCentral() - } - dependencies { - compileOnly("org.jetbrains:annotations:24.0.1") - compileOnly("org.spigotmc:spigot-api:1.20.1-R0.1-SNAPSHOT") - compileOnly("com.github.YufiriaMazenta:CrypticLib:1.0.9") - } - publishing { - publications.create("maven") { - from(components["java"]) - } - } } \ No newline at end of file diff --git a/common/src/main/java/com/github/yufiriamazenta/craftorithm/bstat/Metrics.java b/common/src/main/java/com/github/yufiriamazenta/craftorithm/bstat/Metrics.java index 50ef307a..efdf98e1 100644 --- a/common/src/main/java/com/github/yufiriamazenta/craftorithm/bstat/Metrics.java +++ b/common/src/main/java/com/github/yufiriamazenta/craftorithm/bstat/Metrics.java @@ -1,5 +1,6 @@ package com.github.yufiriamazenta.craftorithm.bstat; +import com.github.yufiriamazenta.craftorithm.Craftorithm; import crypticlib.CrypticLib; import org.bukkit.Bukkit; import org.bukkit.configuration.file.YamlConfiguration; @@ -78,7 +79,7 @@ public Metrics(JavaPlugin plugin, int serviceId) { enabled, this::appendPlatformData, this::appendServiceData, - submitDataTask -> CrypticLib.platform().scheduler().runTask(plugin, t -> submitDataTask.run()), + submitDataTask -> CrypticLib.platform().scheduler().runTask(plugin, submitDataTask), plugin::isEnabled, (message, error) -> this.plugin.getLogger().log(Level.WARNING, message, error), (message) -> this.plugin.getLogger().log(Level.INFO, message), diff --git a/common/src/main/java/com/github/yufiriamazenta/craftorithm/util/UpdateUtil.java b/common/src/main/java/com/github/yufiriamazenta/craftorithm/util/UpdateUtil.java index 60069fa5..8aa81857 100644 --- a/common/src/main/java/com/github/yufiriamazenta/craftorithm/util/UpdateUtil.java +++ b/common/src/main/java/com/github/yufiriamazenta/craftorithm/util/UpdateUtil.java @@ -1,9 +1,7 @@ package com.github.yufiriamazenta.craftorithm.util; import com.github.yufiriamazenta.craftorithm.Craftorithm; -import com.github.yufiriamazenta.craftorithm.config.Config; import crypticlib.CrypticLib; -import crypticlib.util.MsgUtil; import org.bukkit.Bukkit; import org.bukkit.command.CommandSender; @@ -16,9 +14,9 @@ public class UpdateUtil { public static void checkUpdate(CommandSender sender) { - if (!Config.BooleanConfig.CHECK_UPDATE.value()) + if (!Craftorithm.getInstance().getConfig().getBoolean("check_update")) return; - CrypticLib.platform().scheduler().runTaskAsync(Craftorithm.getInstance(), task -> { + CrypticLib.platform().scheduler().runTaskAsync(Craftorithm.getInstance(), () -> { try { URL url = new URL("https://api.github.com/repos/YufiriaMazenta/Craftorithm/releases/latest"); URLConnection conn = url.openConnection(); @@ -37,7 +35,7 @@ public static void checkUpdate(CommandSender sender) { if (checkVersion(newVersion, ver)) { String finalNewVersion = newVersion; Bukkit.getScheduler().callSyncMethod(Craftorithm.getInstance(), () -> { - MsgUtil.sendMsg(sender, "new_version", ContainerUtil.newHashMap("", finalNewVersion)); + LangUtil.sendMsg(sender, "new_version", ContainerUtil.newHashMap("", finalNewVersion)); return null; }); } diff --git a/common/src/main/resources/plugin.yml b/common/src/main/resources/plugin.yml index 62669112..28c1a452 100644 --- a/common/src/main/resources/plugin.yml +++ b/common/src/main/resources/plugin.yml @@ -7,11 +7,6 @@ softdepend: [ Vault, LuckPerms, PlayerPoints, PlaceholderAPI, ItemsAdder, Oraxen authors: [ YufiriaMazenta ] folia-supported: true website: https://github.com/YufiriaMazenta/Craftorithm -commands: - craftorithm: - aliases: - - craft - permission: craftorithm.command permissions: craftorithm.command: description: Plugin command main permissions \ No newline at end of file diff --git a/src/main/java/com/github/yufiriamazenta/craftorithm/Craftorithm.java b/src/main/java/com/github/yufiriamazenta/craftorithm/Craftorithm.java new file mode 100644 index 00000000..b09ab598 --- /dev/null +++ b/src/main/java/com/github/yufiriamazenta/craftorithm/Craftorithm.java @@ -0,0 +1,128 @@ +package com.github.yufiriamazenta.craftorithm; + +import com.github.yufiriamazenta.craftorithm.arcenciel.ArcencielDispatcher; +import com.github.yufiriamazenta.craftorithm.bstat.Metrics; +import com.github.yufiriamazenta.craftorithm.config.ConfigUpdater; +import com.github.yufiriamazenta.craftorithm.item.ItemManager; +import com.github.yufiriamazenta.craftorithm.listener.*; +import com.github.yufiriamazenta.craftorithm.menu.bukkit.BukkitMenuDispatcher; +import com.github.yufiriamazenta.craftorithm.recipe.RecipeManager; +import com.github.yufiriamazenta.craftorithm.util.LangUtil; +import com.github.yufiriamazenta.craftorithm.util.PluginHookUtil; +import com.github.yufiriamazenta.craftorithm.util.UpdateUtil; +import crypticlib.BukkitPlugin; +import org.bukkit.Bukkit; +import org.bukkit.NamespacedKey; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerJoinEvent; +import org.bukkit.event.server.ServerLoadEvent; +import org.bukkit.inventory.Recipe; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +public final class Craftorithm extends BukkitPlugin implements Listener { + + private static Craftorithm INSTANCE; + private int vanillaVersion; + private boolean hasLoadPluginRecipeMap = false; + + public Craftorithm() { + INSTANCE = this; + } + + @Override + public void enable() { + loadVanillaVersion(); + saveDefaultConfig(); + ConfigUpdater.INSTANCE.updateConfig(); + + ItemManager.loadItemManager(); + RecipeManager.loadRecipeManager(); + regListeners(); + PluginHookUtil.hookPlugins(); + initArcenciel(); + loadBStat(); + + LangUtil.info("load.finish"); + UpdateUtil.checkUpdate(Bukkit.getConsoleSender()); + } + + @Override + public void disable() { + RecipeManager.resetRecipes(); + } + + private void loadVanillaVersion() { + String versionStr = Bukkit.getBukkitVersion(); + int index1 = versionStr.indexOf("."); + int index2 = versionStr.indexOf(".", index1 + 1); + versionStr = versionStr.substring(index1 + 1, index2); + try { + vanillaVersion = Integer.parseInt(versionStr); + } catch (NumberFormatException e) { + vanillaVersion = Integer.parseInt(versionStr.substring(0, versionStr.indexOf("-"))); + } + } + + private void loadBStat() { + Metrics metrics = new Metrics(this, 17821); + metrics.addCustomChart(new Metrics.SingleLineChart("recipes", () -> RecipeManager.getRecipeFileMap().keySet().size())); + } + + private void regListeners() { + Bukkit.getPluginManager().registerEvents(CraftHandler.INSTANCE, this); + Bukkit.getPluginManager().registerEvents(this, this); + Bukkit.getPluginManager().registerEvents(RecipeUnlockHandler.INSTANCE, this); + Bukkit.getPluginManager().registerEvents(AnvilRecipeHandler.INSTANCE, this); + Bukkit.getPluginManager().registerEvents(BukkitMenuDispatcher.INSTANCE, this); + if (getVanillaVersion() >= 14) + Bukkit.getPluginManager().registerEvents(SmithingHandler.INSTANCE, this); + if (getVanillaVersion() >= 17) + Bukkit.getPluginManager().registerEvents(FurnaceSmeltHandler.INSTANCE, this); + } + + private void initArcenciel() { + ArcencielDispatcher.INSTANCE.loadFuncFile(); + } + + public static Craftorithm getInstance() { + return INSTANCE; + } + + public int getVanillaVersion() { + return vanillaVersion; + } + + @EventHandler + public void onPlayerJoin(PlayerJoinEvent event) { + if (event.getPlayer().isOp()) { + UpdateUtil.checkUpdate(event.getPlayer()); + } + } + + @EventHandler + public void onServerLoad(ServerLoadEvent event) { + if (!hasLoadPluginRecipeMap) { + hasLoadPluginRecipeMap = true; + Map> map = CraftorithmAPI.INSTANCE.getPluginRegRecipeMap(); + Iterator iterator = Bukkit.getServer().recipeIterator(); + while (iterator.hasNext()) { + Recipe recipe = iterator.next(); + NamespacedKey key = RecipeManager.getRecipeKey(recipe); + String namespace = key.getNamespace(); + if (map.containsKey(namespace)) { + map.get(namespace).add(recipe); + } else { + List recipes = new ArrayList<>(); + recipes.add(recipe); + map.put(namespace, recipes); + } + } + RecipeManager.loadRecipes(); + } + } +} diff --git a/src/main/java/com/github/yufiriamazenta/craftorithm/arcenciel/ArcencielDispatcher.java b/src/main/java/com/github/yufiriamazenta/craftorithm/arcenciel/ArcencielDispatcher.java new file mode 100644 index 00000000..9bb91712 --- /dev/null +++ b/src/main/java/com/github/yufiriamazenta/craftorithm/arcenciel/ArcencielDispatcher.java @@ -0,0 +1,81 @@ +package com.github.yufiriamazenta.craftorithm.arcenciel; + +import com.github.yufiriamazenta.craftorithm.Craftorithm; +import com.github.yufiriamazenta.craftorithm.arcenciel.block.ListArcencielBlock; +import com.github.yufiriamazenta.craftorithm.arcenciel.block.StringArcencielBlock; +import com.github.yufiriamazenta.craftorithm.arcenciel.obj.ArcencielSignal; +import com.github.yufiriamazenta.craftorithm.arcenciel.obj.ReturnObj; +import com.github.yufiriamazenta.craftorithm.arcenciel.token.*; +import com.github.yufiriamazenta.craftorithm.util.PluginHookUtil; +import crypticlib.config.impl.YamlConfigWrapper; +import org.bukkit.entity.Player; + +import java.util.List; + +public enum ArcencielDispatcher implements IArcencielDispatcher { + + INSTANCE; + private YamlConfigWrapper functionFile; + + ArcencielDispatcher() { + regDefScriptKeyword(); + } + + @Override + public ReturnObj dispatchArcencielBlock(Player player, String arcencielBlockBody) { + if (arcencielBlockBody.contains("\n")) + return new ListArcencielBlock(arcencielBlockBody).exec(player); + else + return new StringArcencielBlock(arcencielBlockBody).exec(player); + } + + @Override + public ReturnObj dispatchArcencielFunc(Player player, List arcencielFuncBody) { + ReturnObj returnObj = new ReturnObj<>(); + for (int i = 0; i < arcencielFuncBody.size(); i++) { + returnObj = dispatchArcencielBlock(player, arcencielFuncBody.get(i)); + if (returnObj.getObj() instanceof Boolean && returnObj.getSignal().equals(ArcencielSignal.IF)) { + if (returnObj.getObj().equals(false) && i + 1 < arcencielFuncBody.size()) + i ++; + } + if (returnObj.getSignal().equals(ArcencielSignal.END)) + break; + } + return returnObj; + } + + private void regDefScriptKeyword() { + StringArcencielBlock.regScriptKeyword(TokenIf.INSTANCE); + StringArcencielBlock.regScriptKeyword(TokenHasPerm.INSTANCE); + StringArcencielBlock.regScriptKeyword(TokenRunCmd.INSTANCE); + StringArcencielBlock.regScriptKeyword(TokenConsole.INSTANCE); + StringArcencielBlock.regScriptKeyword(TokenReturn.INSTANCE); + StringArcencielBlock.regScriptKeyword(TokenAll.INSTANCE); + StringArcencielBlock.regScriptKeyword(TokenAny.INSTANCE); + StringArcencielBlock.regScriptKeyword(TokenLevel.INSTANCE); + StringArcencielBlock.regScriptKeyword(TokenTakeLevel.INSTANCE); + StringArcencielBlock.regScriptKeyword(TokenPapi.INSTANCE); + if (PluginHookUtil.isEconomyLoaded()) { + StringArcencielBlock.regScriptKeyword(TokenMoney.INSTANCE); + StringArcencielBlock.regScriptKeyword(TokenTakeMoney.INSTANCE); + } + if (PluginHookUtil.isPlayerPointsLoaded()) { + StringArcencielBlock.regScriptKeyword(TokenPoints.INSTANCE); + StringArcencielBlock.regScriptKeyword(TokenTakePoints.INSTANCE); + } + } + + public YamlConfigWrapper getFunctionFile() { + return functionFile; + } + + public List getFunc(String funcName) { + return functionFile.config().getStringList(funcName); + } + + public void loadFuncFile() { + if (functionFile == null) + functionFile = new YamlConfigWrapper(Craftorithm.getInstance(), "function.yml"); + } + +} diff --git a/src/main/java/com/github/yufiriamazenta/craftorithm/cmd/PluginCommand.java b/src/main/java/com/github/yufiriamazenta/craftorithm/cmd/PluginCommand.java new file mode 100644 index 00000000..37d7b705 --- /dev/null +++ b/src/main/java/com/github/yufiriamazenta/craftorithm/cmd/PluginCommand.java @@ -0,0 +1,100 @@ +package com.github.yufiriamazenta.craftorithm.cmd; + +import com.github.yufiriamazenta.craftorithm.Craftorithm; +import com.github.yufiriamazenta.craftorithm.cmd.subcmd.*; +import com.github.yufiriamazenta.craftorithm.util.ContainerUtil; +import com.github.yufiriamazenta.craftorithm.util.LangUtil; +import crypticlib.annotations.BukkitCommand; +import crypticlib.command.IPluginCmdExecutor; +import crypticlib.command.ISubCmdExecutor; +import org.bukkit.command.Command; +import org.bukkit.command.CommandSender; +import org.bukkit.plugin.Plugin; + +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; + +@BukkitCommand( + name = "craftorithm", + alias = {"craft"}, + permission = "craftorithm.command" +) +public enum PluginCommand implements IPluginCmdExecutor { + + INSTANCE; + + private final Map subCommandMap; + + PluginCommand() { + subCommandMap = new ConcurrentHashMap<>(); + regDefaultSubCommands(); + } + + @Override + public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { + List argList = Arrays.asList(args); + if (argList.size() < 1) { + LangUtil.sendMsg(sender, "command.not_enough_param", ContainerUtil.newHashMap("", String.valueOf(1))); + return true; + } + ISubCmdExecutor subCommand = subCommandMap.get(argList.get(0)); + if (subCommand != null) { + String perm = subCommand.permission(); + if (perm != null) { + if (!sender.hasPermission(perm)) { + LangUtil.sendMsg(sender, "command.no_perm"); + return true; + } + } + return subCommand.onCommand(sender, argList.subList(1, argList.size())); + } + else { + LangUtil.sendMsg(sender, "command.undefined_subcmd"); + return true; + } + } + + private void regDefaultSubCommands() { + regSubCommand(ReloadCommand.INSTANCE); + regSubCommand(VersionCommand.INSTANCE); + regSubCommand(RemoveRecipeCommand.INSTANCE); + regSubCommand(ItemCommand.INSTANCE); + regSubCommand(RunArcencielCmd.INSTANCE); + regSubCommand(LookRecipeCommand.INSTANCE); + regSubCommand(CreateRecipeCommand.INSTANCE); + } + + @Override + public Plugin getPlugin() { + return Craftorithm.getInstance(); + } + + @Override + public List onTabComplete(CommandSender sender, Command command, String alias, String[] args) { + List argList = Arrays.asList(args); + if (argList.size() <= 1) { + List tabList = new ArrayList<>(); + for (String subCmd : subCommandMap.keySet()) { + ISubCmdExecutor subCommand = subCommandMap.get(subCmd); + if (sender.hasPermission(subCommand.permission())) + tabList.add(subCmd); + } + tabList.removeIf(str -> !str.startsWith(args[0])); + return tabList; + } + ISubCmdExecutor subCommand = subCommandMap.get(argList.get(0)); + if (subCommand != null) { + if (!sender.hasPermission(subCommand.permission())) + return Collections.singletonList(""); + return subCommand.onTabComplete(sender, argList.subList(1, argList.size())); + } + else + return Collections.singletonList(""); + } + + public Map getSubCommandMap() { + return subCommandMap; + } + + +} diff --git a/src/main/java/com/github/yufiriamazenta/craftorithm/cmd/subcmd/AbstractSubCommand.java b/src/main/java/com/github/yufiriamazenta/craftorithm/cmd/subcmd/AbstractSubCommand.java new file mode 100644 index 00000000..f20a2013 --- /dev/null +++ b/src/main/java/com/github/yufiriamazenta/craftorithm/cmd/subcmd/AbstractSubCommand.java @@ -0,0 +1,122 @@ +package com.github.yufiriamazenta.craftorithm.cmd.subcmd; + +import com.github.yufiriamazenta.craftorithm.util.ContainerUtil; +import com.github.yufiriamazenta.craftorithm.util.LangUtil; +import crypticlib.command.ISubCmdExecutor; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +public abstract class AbstractSubCommand implements ISubCmdExecutor { + + private final String command; + private String perm; + private Map subCommandMap; + + protected AbstractSubCommand(String command, Map subCommandMap, String perm) { + this.command = command; + this.subCommandMap = subCommandMap; + this.perm = perm; + } + + protected AbstractSubCommand(String command, String perm) { + this(command, new ConcurrentHashMap<>(), perm); + } + + protected AbstractSubCommand(String command) { + this(command, new ConcurrentHashMap<>(), null); + } + + @Override + public boolean onCommand(CommandSender sender, List args) { + ISubCmdExecutor subCommand = subCommandMap.get(args.get(0)); + if (subCommand == null) { + LangUtil.sendMsg(sender, "command.undefined_subcmd"); + } else { + String perm = subCommand.permission(); + if (perm != null) { + if (!sender.hasPermission(perm)) { + LangUtil.sendMsg(sender, "command.no_perm"); + return true; + } + } + subCommand.onCommand(sender, args.subList(1, args.size())); + } + return true; + } + + @Override + public List onTabComplete(CommandSender sender, List args) { + if (subCommandMap == null) + return Collections.singletonList(""); + if (args.size() <= 1) { + List tabList = new ArrayList<>(); + for (String subCmd : subCommandMap.keySet()) { + ISubCmdExecutor subCommand = subCommandMap.get(subCmd); + if (subCommand.permission() != null) { + if (sender.hasPermission(subCommand.permission())) + tabList.add(subCmd); + } else { + tabList.add(subCmd); + } + } + tabList.removeIf(str -> !str.startsWith(args.get(0))); + return tabList; + } + ISubCmdExecutor subCommand = subCommandMap.get(args.get(0)); + if (subCommand != null) { + if (subCommand.permission() != null) { + if (!sender.hasPermission(subCommand.permission())) + return Collections.singletonList(""); + } + return subCommand.onTabComplete(sender, args.subList(1, args.size())); + } + else + return Collections.singletonList(""); + } + + @Override + public String subCommandName() { + return command; + } + + @Override + public Map subCommands() { + return subCommandMap; + } + + public void setSubCommandMap(Map subCommandMap) { + this.subCommandMap = subCommandMap; + } + + public void sendNotEnoughCmdParamMsg(CommandSender sender, int paramNum) { + sendNotEnoughCmdParamMsg(sender, String.valueOf(paramNum)); + } + + public void sendNotEnoughCmdParamMsg(CommandSender sender, String paramStr) { + LangUtil.sendMsg(sender, "command.not_enough_param", ContainerUtil.newHashMap("", paramStr)); + } + + public boolean checkSenderIsPlayer(CommandSender sender) { + if (sender instanceof Player) { + return true; + } else { + LangUtil.sendMsg(sender, "command.player_only"); + return false; + } + } + + public void filterTabList(List tabList, String input) { + tabList.removeIf(str -> !str.startsWith(input)); + } + + public void setPerm() { + this.perm = perm; + } + +} diff --git a/src/main/java/com/github/yufiriamazenta/craftorithm/cmd/subcmd/ItemCommand.java b/src/main/java/com/github/yufiriamazenta/craftorithm/cmd/subcmd/ItemCommand.java new file mode 100644 index 00000000..2b8a3e78 --- /dev/null +++ b/src/main/java/com/github/yufiriamazenta/craftorithm/cmd/subcmd/ItemCommand.java @@ -0,0 +1,28 @@ +package com.github.yufiriamazenta.craftorithm.cmd.subcmd; + +import com.github.yufiriamazenta.craftorithm.cmd.subcmd.item.ItemGiveCommand; +import com.github.yufiriamazenta.craftorithm.cmd.subcmd.item.ItemSaveCommand; +import crypticlib.command.ISubCmdExecutor; +import org.bukkit.command.CommandSender; + +import java.util.List; + +public final class ItemCommand extends AbstractSubCommand { + + public static final ISubCmdExecutor INSTANCE = new ItemCommand(); + + private ItemCommand() { + super("item", "craftorithm.command.item"); + regSubCommand(ItemSaveCommand.INSTANCE); + regSubCommand(ItemGiveCommand.INSTANCE); + } + + @Override + public boolean onCommand(CommandSender sender, List args) { + if (args.size() < 2) { + sendNotEnoughCmdParamMsg(sender, 2 - args.size()); + return true; + } + return super.onCommand(sender, args); + } +} diff --git a/src/main/java/com/github/yufiriamazenta/craftorithm/cmd/subcmd/ReloadCommand.java b/src/main/java/com/github/yufiriamazenta/craftorithm/cmd/subcmd/ReloadCommand.java new file mode 100644 index 00000000..bde0fa0d --- /dev/null +++ b/src/main/java/com/github/yufiriamazenta/craftorithm/cmd/subcmd/ReloadCommand.java @@ -0,0 +1,54 @@ +package com.github.yufiriamazenta.craftorithm.cmd.subcmd; + +import com.github.yufiriamazenta.craftorithm.Craftorithm; +import com.github.yufiriamazenta.craftorithm.arcenciel.ArcencielDispatcher; +import com.github.yufiriamazenta.craftorithm.item.ItemManager; +import com.github.yufiriamazenta.craftorithm.recipe.RecipeManager; +import com.github.yufiriamazenta.craftorithm.util.ItemUtil; +import com.github.yufiriamazenta.craftorithm.util.LangUtil; +import crypticlib.command.ISubCmdExecutor; +import org.bukkit.command.CommandSender; + +import java.util.List; + +public final class ReloadCommand extends AbstractSubCommand { + + public static final ISubCmdExecutor INSTANCE = new ReloadCommand(); + + private ReloadCommand() { + super("reload", "craftorithm.command.reload"); + } + + @Override + public boolean onCommand(CommandSender sender, List args) { + try { + reloadPlugin(); + LangUtil.sendMsg(sender, "command.reload.success"); + } catch (Exception e) { + e.printStackTrace(); + LangUtil.sendMsg(sender, "command.reload.exception"); + } + return true; + } + + public static void reloadPlugin() { + reloadConfigs(); + ItemManager.loadItems(); + reloadRecipes(); + } + + public static void reloadConfigs() { + Craftorithm.getInstance().reloadConfig(); + LangUtil.reloadMsgConfig(); + RemoveRecipeCommand.getRemovedRecipeConfig().reloadConfig(); + ItemManager.loadItemFiles(); + RecipeManager.loadRecipeFiles(); + ArcencielDispatcher.INSTANCE.getFunctionFile().reloadConfig(); + ItemUtil.reloadCannotCraftLore(); + } + + public static void reloadRecipes() { + RecipeManager.loadRecipes(); + } + +} diff --git a/src/main/java/com/github/yufiriamazenta/craftorithm/cmd/subcmd/RemoveRecipeCommand.java b/src/main/java/com/github/yufiriamazenta/craftorithm/cmd/subcmd/RemoveRecipeCommand.java new file mode 100644 index 00000000..ee844b2e --- /dev/null +++ b/src/main/java/com/github/yufiriamazenta/craftorithm/cmd/subcmd/RemoveRecipeCommand.java @@ -0,0 +1,146 @@ +package com.github.yufiriamazenta.craftorithm.cmd.subcmd; + +import com.github.yufiriamazenta.craftorithm.Craftorithm; +import com.github.yufiriamazenta.craftorithm.recipe.RecipeManager; +import com.github.yufiriamazenta.craftorithm.util.LangUtil; +import crypticlib.command.ISubCmdExecutor; +import crypticlib.config.impl.YamlConfigWrapper; +import org.bukkit.Bukkit; +import org.bukkit.NamespacedKey; +import org.bukkit.command.CommandSender; +import org.bukkit.inventory.Recipe; + +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; + +public class RemoveRecipeCommand extends AbstractSubCommand { + + private static final YamlConfigWrapper removedRecipeConfig = new YamlConfigWrapper(Craftorithm.getInstance(), "removed_recipes.yml"); + private final Map recipeMap; + + public static final ISubCmdExecutor INSTANCE = new RemoveRecipeCommand(); + + private RemoveRecipeCommand() { + super("remove", "craftorithm.command.remove"); + recipeMap = new ConcurrentHashMap<>(); + } + + @Override + public boolean onCommand(CommandSender sender, List args) { + if (args.size() < 1) { + sendNotEnoughCmdParamMsg(sender, 1); + return true; + } + if (removeRecipe(args.get(0), true)) { + LangUtil.sendMsg(sender, "command.remove.success"); + } + else + LangUtil.sendMsg(sender, "command.remove.not_exist"); + return true; + } + + @Override + public List onTabComplete(CommandSender sender, List args) { + if (args.size() <= 1) { + List tabList = new ArrayList<>(); + for (NamespacedKey key : recipeMap.keySet()) { + String str = key.toString(); + if (str.startsWith(args.get(0))) + tabList.add(key.toString()); + } + filterTabList(tabList, args.get(0)); + return tabList; + } + return super.onTabComplete(sender, args); + } + + public void reloadRecipeMap() { + Iterator recipeIterator = Bukkit.recipeIterator(); + recipeMap.clear(); + while (recipeIterator.hasNext()) { + Recipe recipe = recipeIterator.next(); + NamespacedKey key = RecipeManager.getRecipeKey(recipe); + recipeMap.put(key, recipe); + } + } + + public Map getRecipeMap() { + return Collections.unmodifiableMap(recipeMap); + } + + public static YamlConfigWrapper getRemovedRecipeConfig() { + return removedRecipeConfig; + } + + public void removeRecipes(List keyStrList, boolean save2File) { + List keyList = new ArrayList<>(); + for (String str : keyStrList) { + NamespacedKey key = NamespacedKey.fromString(str); + if (key != null) + keyList.add(key); + } + if (keyList.size() < 1) + return; + if (Craftorithm.getInstance().getVanillaVersion() >= 15) { + for (NamespacedKey key : keyList) { + Bukkit.removeRecipe(key); + if (save2File) { + addKey2RemovedConfig(key.toString()); + } + } + } else { + Iterator recipeIterator = Bukkit.recipeIterator(); + while (recipeIterator.hasNext()) { + Recipe recipe1 = recipeIterator.next(); + NamespacedKey key1 = RecipeManager.getRecipeKey(recipe1); + if (key1 == null) + continue; + if (keyList.contains(key1)) { + recipeIterator.remove(); + if (save2File) { + addKey2RemovedConfig(key1.toString()); + } + keyList.remove(key1); + if (keyList.size() <= 0) + break; + } + } + } + reloadRecipeMap(); + } + + public boolean removeRecipe(String keyStr, boolean save2File) { + NamespacedKey key = NamespacedKey.fromString(keyStr); + Iterator recipeIterator = Bukkit.recipeIterator(); + if (key == null) + return false; + if (Craftorithm.getInstance().getVanillaVersion() >= 15) { + if (Bukkit.removeRecipe(key) && save2File) + addKey2RemovedConfig(key.toString()); + reloadRecipeMap(); + } else { + while (recipeIterator.hasNext()) { + Recipe recipe1 = recipeIterator.next(); + NamespacedKey key1 = RecipeManager.getRecipeKey(recipe1); + if (key.equals(key1)) { + recipeIterator.remove(); + if (save2File) { + addKey2RemovedConfig(key.toString()); + } + reloadRecipeMap(); + return true; + } + } + } + return false; + } + + public void addKey2RemovedConfig(String key) { + List removedList = removedRecipeConfig.config().getStringList("recipes"); + if (!removedList.contains(key)) + removedList.add(key); + removedRecipeConfig.config().set("recipes", removedList); + removedRecipeConfig.saveConfig(); + } + +} diff --git a/src/main/java/com/github/yufiriamazenta/craftorithm/cmd/subcmd/VersionCommand.java b/src/main/java/com/github/yufiriamazenta/craftorithm/cmd/subcmd/VersionCommand.java new file mode 100644 index 00000000..5622ce0f --- /dev/null +++ b/src/main/java/com/github/yufiriamazenta/craftorithm/cmd/subcmd/VersionCommand.java @@ -0,0 +1,22 @@ +package com.github.yufiriamazenta.craftorithm.cmd.subcmd; + +import com.github.yufiriamazenta.craftorithm.util.LangUtil; +import crypticlib.command.ISubCmdExecutor; +import org.bukkit.command.CommandSender; + +import java.util.List; + +public class VersionCommand extends AbstractSubCommand { + + public static final ISubCmdExecutor INSTANCE = new VersionCommand(); + + private VersionCommand() { + super("version", "craftorithm.command.version"); + } + + @Override + public boolean onCommand(CommandSender sender, List args) { + LangUtil.sendMsg(sender, "command.version"); + return true; + } +} diff --git a/src/main/java/com/github/yufiriamazenta/craftorithm/cmd/subcmd/item/ItemGiveCommand.java b/src/main/java/com/github/yufiriamazenta/craftorithm/cmd/subcmd/item/ItemGiveCommand.java new file mode 100644 index 00000000..8371aa6e --- /dev/null +++ b/src/main/java/com/github/yufiriamazenta/craftorithm/cmd/subcmd/item/ItemGiveCommand.java @@ -0,0 +1,74 @@ +package com.github.yufiriamazenta.craftorithm.cmd.subcmd.item; + +import com.github.yufiriamazenta.craftorithm.cmd.subcmd.AbstractSubCommand; +import com.github.yufiriamazenta.craftorithm.item.ItemManager; +import com.github.yufiriamazenta.craftorithm.util.ContainerUtil; +import com.github.yufiriamazenta.craftorithm.util.LangUtil; +import crypticlib.command.ISubCmdExecutor; +import org.bukkit.Bukkit; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; + +import java.util.ArrayList; +import java.util.List; + +public class ItemGiveCommand extends AbstractSubCommand { + + public static final ISubCmdExecutor INSTANCE = new ItemGiveCommand(); + + private ItemGiveCommand() { + super("give"); + } + + @Override + public boolean onCommand(CommandSender sender, List args) { + if (args.size() < 1) { + sendNotEnoughCmdParamMsg(sender, 1); + return true; + } + + Player player; + if (args.size() >= 2) { + player = Bukkit.getPlayer(args.get(1)); + if (player == null) { + LangUtil.sendMsg(sender, "command.item.give.player_offline"); + return true; + } + } else { + if (checkSenderIsPlayer(sender)) { + player = (Player) sender; + } else { + LangUtil.sendMsg(sender, "command.player_only"); + return true; + } + } + + if (!ItemManager.isCraftorithmItem(args.get(0))) { + LangUtil.sendMsg(sender, "command.item.give.not_exist_item", ContainerUtil.newHashMap("", args.get(0))); + return true; + } + + player.getInventory().addItem(ItemManager.getCraftorithmItem(args.get(0))); + return true; + } + + @Override + public List onTabComplete(CommandSender sender, List args) { + if (args.size() < 2) { + List tabList = new ArrayList<>(ItemManager.getItemMap().keySet()); + filterTabList(tabList, args.get(0)); + return tabList; + } + else + return getOnlinePlayerNameList(); + } + + private List getOnlinePlayerNameList() { + List onlinePlayerNameList = new ArrayList<>(); + for (Player onlinePlayer : Bukkit.getOnlinePlayers()) { + onlinePlayerNameList.add(onlinePlayer.getName()); + } + return onlinePlayerNameList; + } + +} diff --git a/src/main/java/com/github/yufiriamazenta/craftorithm/cmd/subcmd/item/ItemSaveCommand.java b/src/main/java/com/github/yufiriamazenta/craftorithm/cmd/subcmd/item/ItemSaveCommand.java new file mode 100644 index 00000000..13d17e30 --- /dev/null +++ b/src/main/java/com/github/yufiriamazenta/craftorithm/cmd/subcmd/item/ItemSaveCommand.java @@ -0,0 +1,57 @@ +package com.github.yufiriamazenta.craftorithm.cmd.subcmd.item; + +import com.github.yufiriamazenta.craftorithm.cmd.subcmd.AbstractSubCommand; +import com.github.yufiriamazenta.craftorithm.item.ItemManager; +import com.github.yufiriamazenta.craftorithm.util.LangUtil; +import crypticlib.command.ISubCmdExecutor; +import org.bukkit.Material; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public final class ItemSaveCommand extends AbstractSubCommand { + + public static final ISubCmdExecutor INSTANCE = new ItemSaveCommand(); + + private ItemSaveCommand() { + super("save"); + } + + @Override + public boolean onCommand(CommandSender sender, List args) { + if (args.size() < 2) { + sendNotEnoughCmdParamMsg(sender, 2 - args.size()); + return true; + } + if (!checkSenderIsPlayer(sender)) + return true; + + ItemStack item = ((Player) sender).getInventory().getItemInMainHand(); + if (item.getType().equals(Material.AIR)) { + LangUtil.sendMsg(sender, "command.item.save.failed_save_air"); + return true; + } + + ItemManager.addCraftorithmItem(args.get(0), args.get(1), item.clone()); + LangUtil.sendMsg(sender, "command.item.save.success"); + return true; + } + + @Override + public List onTabComplete(CommandSender sender, List args) { + switch (args.size()) { + case 0: + case 1: + List tabList = new ArrayList<>(ItemManager.getItemFileMap().keySet()); + filterTabList(tabList, args.get(0)); + return tabList; + case 2: + default: + return Collections.singletonList(""); + } + } +} diff --git a/src/main/java/com/github/yufiriamazenta/craftorithm/item/ItemManager.java b/src/main/java/com/github/yufiriamazenta/craftorithm/item/ItemManager.java new file mode 100644 index 00000000..e9f53c40 --- /dev/null +++ b/src/main/java/com/github/yufiriamazenta/craftorithm/item/ItemManager.java @@ -0,0 +1,208 @@ +package com.github.yufiriamazenta.craftorithm.item; + +import com.github.yufiriamazenta.craftorithm.Craftorithm; +import com.github.yufiriamazenta.craftorithm.util.ContainerUtil; +import com.github.yufiriamazenta.craftorithm.util.FileUtil; +import com.github.yufiriamazenta.craftorithm.util.LangUtil; +import crypticlib.config.impl.YamlConfigWrapper; +import crypticlib.nms.item.Item; +import crypticlib.util.ItemUtil; +import dev.lone.itemsadder.api.CustomStack; +import io.lumine.mythic.bukkit.BukkitAdapter; +import io.lumine.mythic.bukkit.MythicBukkit; +import io.lumine.mythic.core.items.ItemExecutor; +import io.lumine.mythic.core.items.MythicItem; +import io.th0rgal.oraxen.api.OraxenItems; +import org.bukkit.Material; +import org.bukkit.inventory.ItemStack; + +import java.io.File; +import java.util.*; +import java.util.concurrent.atomic.AtomicReference; + +public class ItemManager { + + private static final Map itemFileMap = new HashMap<>(); + private static final Map itemMap = new HashMap<>(); + private static final File itemFileFolder = new File(Craftorithm.getInstance().getDataFolder().getPath(), "items"); + + public static void loadItemManager() { + loadItemFiles(); + loadItems(); + } + + public static void loadItems() { + itemMap.clear(); + for (String fileKey : itemFileMap.keySet()) { + YamlConfigWrapper itemFile = itemFileMap.get(fileKey); + Set itemKeySet = itemFile.config().getKeys(false); + for (String itemKey : itemKeySet) { + try { + itemMap.put( + fileKey + ":" + itemKey, + crypticlib.nms.item.ItemManager.item(itemFile.config().getConfigurationSection(itemKey)).buildBukkit() + ); + } catch (Exception e) { + LangUtil.info("load.item_load_exception", ContainerUtil.newHashMap("", fileKey + ":" + itemKey)); + e.printStackTrace(); + } + } + } + } + + public static void addCraftorithmItem(String itemFileName, String itemName, ItemStack item) { + YamlConfigWrapper yamlConfig; + if (!ItemManager.getItemFileMap().containsKey(itemFileName)) { + File itemFile = new File(ItemManager.getItemFileFolder(), itemFileName + ".yml"); + if (!itemFile.exists()) { + FileUtil.createNewFile(itemFile); + } + yamlConfig = new YamlConfigWrapper(itemFile); + itemFileMap.put(itemName, yamlConfig); + } else { + yamlConfig = itemFileMap.get(itemFileName); + } + Item libItem = crypticlib.nms.item.ItemManager.item(item); + yamlConfig.config().set(itemName, libItem.toMap()); + itemMap.put(itemFileName + ":" + itemName, item); + } + + public static boolean isCraftorithmItem(String itemName) { + return itemMap.containsKey(itemName); + } + + public static ItemStack getCraftorithmItem(String itemName) { + return itemMap.getOrDefault(itemName, new ItemStack(Material.AIR)).clone(); + } + + public static void loadItemFiles() { + itemFileMap.clear(); + if (!itemFileFolder.exists()) { + boolean mkdirResult = itemFileFolder.mkdir(); + if (!mkdirResult) + return; + } + List allFiles = FileUtil.getAllFiles(itemFileFolder); + if (allFiles.size() < 1) { + Craftorithm.getInstance().saveResource("items/example_item.yml", false); + allFiles.add(new File(itemFileFolder, "example_item.yml")); + } + for (File file : allFiles) { + String key = file.getPath().substring(itemFileFolder.getPath().length() + 1); + key = key.replace("\\", "/"); + int lastDotIndex = key.lastIndexOf("."); + key = key.substring(0, lastDotIndex); + itemFileMap.put(key, new YamlConfigWrapper(file)); + } + } + + public static Map getItemMap() { + return itemMap; + } + + public static Map getItemFileMap() { + return itemFileMap; + } + + public static File getItemFileFolder() { + return itemFileFolder; + } + + public static ItemStack matchCraftorithmItem(String itemStr) { + ItemStack item; + int lastSpaceIndex = itemStr.lastIndexOf(" "); + int amountScale = 1; + if (lastSpaceIndex > 0) { + amountScale = Integer.parseInt(itemStr.substring(lastSpaceIndex + 1)); + itemStr = itemStr.substring(0, lastSpaceIndex); + } + itemStr = itemStr.replace(" ", ""); + if (itemStr.contains(":")) { + String namespace = itemStr.substring(0, itemStr.indexOf(":")), key = itemStr.substring(itemStr.indexOf(":") + 1); + switch (namespace) { + case "items": + item = getCraftorithmItem(key); + break; + case "items_adder": + item = getItemsAdderItem(key); + break; + case "oraxen": + item = getOraxenItem(key); + break; + case "mythic_mobs": + item = getMythicMobsItem(key); + break; + default: + throw new IllegalArgumentException(namespace + " is not a valid item namespace"); + } + } else { + Material material = Material.matchMaterial(itemStr); + if (material == null) { + throw new IllegalArgumentException(itemStr + " is a not exist item type"); + } + item = new ItemStack(material); + } + + item.setAmount(item.getAmount() * amountScale); + return item; + } + + /** + * 获取一个物品的Craftorithm名字 + * @param item 传入的物品 + * @param ignoreAmount 是否忽略数量 + * @param regNew 如果不存在,是否将此物品注册 + * @param regName 注册的名字 + * @return 传入的物品名字 + */ + public static String getItemName(ItemStack item, boolean ignoreAmount, boolean regNew, String namespace, String regName) { + if (ItemUtil.isItemInvalidate(item)) + return null; + AtomicReference itemName = new AtomicReference<>(""); + itemMap.forEach((key, savedItem) -> { + if (ignoreAmount) { + if (savedItem.isSimilar(item)) { + itemName.set(key); + } + } else { + if (savedItem.equals(item)) { + itemName.set(key); + } + } + }); + if (!itemName.get().isEmpty()) + return itemName.get(); + if (regNew) { + addCraftorithmItem(namespace, regName, item); + return namespace + ":" + regName; + } + return null; + } + + public static ItemStack getItemsAdderItem(String itemStr) { + CustomStack customStack = CustomStack.getInstance(itemStr); + if (customStack == null) { + throw new IllegalArgumentException(itemStr + " is a not exist ItemsAdder item"); + } + return customStack.getItemStack(); + } + + public static ItemStack getOraxenItem(String itemStr) { + if (!OraxenItems.exists(itemStr)) { + throw new IllegalArgumentException(itemStr + " is a not exist Oraxen item"); + } + return OraxenItems.getItemById(itemStr).build(); + } + + public static ItemStack getMythicMobsItem(String itemStr) { + ItemExecutor executor = MythicBukkit.inst().getItemManager(); + Optional itemOptional = executor.getItem(itemStr); + if (!itemOptional.isPresent()) { + throw new IllegalArgumentException(itemStr + " is not a valid MythicMobs item"); + } + MythicItem mythicItem = itemOptional.get(); + int amount = mythicItem.getAmount(); + return BukkitAdapter.adapt(itemOptional.get().generateItemStack(amount)); + } + +} diff --git a/src/main/java/com/github/yufiriamazenta/craftorithm/menu/bukkit/BukkitMenuDispatcher.java b/src/main/java/com/github/yufiriamazenta/craftorithm/menu/bukkit/BukkitMenuDispatcher.java new file mode 100644 index 00000000..c7163847 --- /dev/null +++ b/src/main/java/com/github/yufiriamazenta/craftorithm/menu/bukkit/BukkitMenuDispatcher.java @@ -0,0 +1,66 @@ +package com.github.yufiriamazenta.craftorithm.menu.bukkit; + +import com.github.yufiriamazenta.craftorithm.Craftorithm; +import com.github.yufiriamazenta.craftorithm.menu.impl.recipe.RecipeDisplayMenuHolder; +import crypticlib.CrypticLib; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.inventory.InventoryAction; +import org.bukkit.event.inventory.InventoryClickEvent; +import org.bukkit.event.inventory.InventoryCloseEvent; +import org.bukkit.inventory.InventoryView; + +import java.util.ArrayList; +import java.util.List; + +public enum BukkitMenuDispatcher implements Listener { + + INSTANCE; + + private final List allowedPlayerInvActions; + + BukkitMenuDispatcher() { + allowedPlayerInvActions = new ArrayList<>(); + allowedPlayerInvActions.add(InventoryAction.DROP_ALL_CURSOR); + allowedPlayerInvActions.add(InventoryAction.DROP_ALL_SLOT); + allowedPlayerInvActions.add(InventoryAction.DROP_ONE_CURSOR); + allowedPlayerInvActions.add(InventoryAction.DROP_ONE_SLOT); + allowedPlayerInvActions.add(InventoryAction.NOTHING); + allowedPlayerInvActions.add(InventoryAction.PICKUP_ONE); + allowedPlayerInvActions.add(InventoryAction.PICKUP_HALF); + allowedPlayerInvActions.add(InventoryAction.PICKUP_ALL); + allowedPlayerInvActions.add(InventoryAction.PICKUP_SOME); + allowedPlayerInvActions.add(InventoryAction.PLACE_ONE); + allowedPlayerInvActions.add(InventoryAction.PLACE_ALL); + allowedPlayerInvActions.add(InventoryAction.PLACE_SOME); + } + + @EventHandler + public void onClickInv(InventoryClickEvent event) { + if (event.getClickedInventory() == null) + return; + InventoryView view = event.getView(); + BukkitMenuHandler handler; + if (!(view.getTopInventory().getHolder() instanceof BukkitMenuHandler)) + return; + handler = (BukkitMenuHandler) view.getTopInventory().getHolder(); + if (view.getBottomInventory().equals(event.getClickedInventory())) { + InventoryAction action = event.getAction(); + if (!allowedPlayerInvActions.contains(action)) + event.setCancelled(true); + return; + } + handler.click(event.getSlot(), event); + } + + @EventHandler + public void onCloseRecipeShowMenu(InventoryCloseEvent event) { + if (event.getInventory().getHolder() instanceof RecipeDisplayMenuHolder) { + RecipeDisplayMenuHolder holder = (RecipeDisplayMenuHolder) event.getInventory().getHolder(); + if (holder.getParentMenu() != null) { + CrypticLib.platform().scheduler().runTask(Craftorithm.getInstance(), () -> event.getPlayer().openInventory(holder.getParentMenu().getInventory())); + } + } + } + +} diff --git a/src/main/java/com/github/yufiriamazenta/craftorithm/menu/impl/recipe/RecipeCreatorMenuHolder.java b/src/main/java/com/github/yufiriamazenta/craftorithm/menu/impl/recipe/RecipeCreatorMenuHolder.java new file mode 100644 index 00000000..8ec418a9 --- /dev/null +++ b/src/main/java/com/github/yufiriamazenta/craftorithm/menu/impl/recipe/RecipeCreatorMenuHolder.java @@ -0,0 +1,470 @@ +package com.github.yufiriamazenta.craftorithm.menu.impl.recipe; + +import com.github.yufiriamazenta.craftorithm.Craftorithm; +import com.github.yufiriamazenta.craftorithm.cmd.subcmd.RemoveRecipeCommand; +import com.github.yufiriamazenta.craftorithm.item.ItemManager; +import com.github.yufiriamazenta.craftorithm.menu.bukkit.BukkitMenuHandler; +import com.github.yufiriamazenta.craftorithm.menu.bukkit.ItemDisplayIcon; +import com.github.yufiriamazenta.craftorithm.recipe.RecipeFactory; +import com.github.yufiriamazenta.craftorithm.recipe.RecipeManager; +import com.github.yufiriamazenta.craftorithm.recipe.RecipeType; +import com.github.yufiriamazenta.craftorithm.util.ContainerUtil; +import com.github.yufiriamazenta.craftorithm.util.FileUtil; +import com.github.yufiriamazenta.craftorithm.util.LangUtil; +import crypticlib.config.impl.YamlConfigWrapper; +import crypticlib.util.ItemUtil; +import org.bukkit.Bukkit; +import org.bukkit.Material; +import org.bukkit.NamespacedKey; +import org.bukkit.enchantments.Enchantment; +import org.bukkit.entity.HumanEntity; +import org.bukkit.event.inventory.InventoryClickEvent; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.ItemFlag; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.Recipe; +import org.bukkit.inventory.meta.ItemMeta; +import org.jetbrains.annotations.NotNull; + +import java.io.File; +import java.util.*; + +public class RecipeCreatorMenuHolder extends BukkitMenuHandler { + + private RecipeType recipeType; + private String recipeName; + + public RecipeCreatorMenuHolder(RecipeType recipeType, String recipeName) { + super(); + this.recipeType = recipeType; + this.recipeName = recipeName; + setMenuIcons(); + } + + private void setMenuIcons() { + switch (recipeType) { + case SHAPED: + case SHAPELESS: + setCraftMenuIcons(); + break; + case COOKING: + setCookingMenuIcons(); + break; + case SMITHING: + setSmithingMenuIcons(); + break; + case STONE_CUTTING: + setStoneCuttingMenuIcons(); + break; + case ANVIL: + setAnvilMenuIcons(); + break; + default: + break; + } + } + + private void setAnvilMenuIcons() { + //TODO + } + + private void setStoneCuttingMenuIcons() { + int[] frameSlots = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, + 9, 17, + 18, 19, 20, 21, 23, 24, 25, 26, + 27, 35, + 36, 37, 38, 39, 40, 41, 42, 43, 44 + }; + ItemDisplayIcon frameIcon = ItemDisplayIcon.icon(Material.BLACK_STAINED_GLASS_PANE, LangUtil.lang("menu.recipe_creator.icon.frame")); + for (int frameSlot : frameSlots) { + getMenuIconMap().put(frameSlot, frameIcon); + } + ItemDisplayIcon confirmIcon = ItemDisplayIcon.icon(Material.STONECUTTER, LangUtil.lang("menu.recipe_creator.icon.frame"), + event -> { + event.setCancelled(true); + List sources = new ArrayList<>(); + List results = new ArrayList<>(); + for (int i = 10; i < 17; i++) { + ItemStack item = event.getClickedInventory().getItem(i); + if (item == null || item.getType().equals(Material.AIR)) + continue; + String itemName = getItemName(item, true); + sources.add(itemName); + } + for (int i = 28; i < 35; i++) { + ItemStack item = event.getClickedInventory().getItem(i); + if (item == null || item.getType().equals(Material.AIR)) + continue; + String itemName = getItemName(item, false); + results.add(itemName); + } + File recipeFile = new File(RecipeManager.getRecipeFileFolder(), recipeName + ".yml"); + if (!recipeFile.exists()) { + FileUtil.createNewFile(recipeFile); + } + YamlConfigWrapper recipeConfig = new YamlConfigWrapper(recipeFile); + recipeConfig.config().set("multiple", true); + recipeConfig.config().set("result", results); + recipeConfig.config().set("source", sources); + recipeConfig.config().set("type", "stone_cutting"); + recipeConfig.saveConfig(); + recipeConfig.reloadConfig(); + Recipe[] recipes = RecipeFactory.newMultipleRecipe(recipeConfig.config(), recipeName); + for (Recipe recipe : recipes) { + NamespacedKey key = RecipeManager.getRecipeKey(recipe); + RecipeManager.regRecipe(key, recipe, recipeConfig.config()); + } + event.getWhoClicked().closeInventory(); + sendSuccessMsgAndReloadMap(event.getWhoClicked()); + }); + getMenuIconMap().put(22, confirmIcon); + } + + private void setSmithingMenuIcons() { + int[] frameSlots = { + 0, 1 ,2, 3, 4, 5, 6, 7, 8, + 9, 13, 17, + 18, 26, + 27, 31, 35, + 36, 37, 38, 39, 40, 41, 42, 43, 44 + }; + ItemDisplayIcon frameIcon = ItemDisplayIcon.icon(Material.BLACK_STAINED_GLASS_PANE, LangUtil.lang("menu.recipe_creator.icon.frame")); + for (int slot : frameSlots) { + getMenuIconMap().put(slot, frameIcon); + } + int[] resultFrameSlots = { + 14, 15, 16, + 23, 25, + 32, 33, 34 + }; + ItemDisplayIcon resultFrameIcon = ItemDisplayIcon.icon(Material.LIME_STAINED_GLASS_PANE, LangUtil.lang("menu.recipe_creator.icon.result_frame")); + for (int slot : resultFrameSlots) { + getMenuIconMap().put(slot, resultFrameIcon); + } + int[] smithingFrameSlots; + if (Craftorithm.getInstance().getVanillaVersion() < 20) { + smithingFrameSlots = new int[]{ + 10, 11, 12, + 20, + 28, 29, 30 + }; + } else { + smithingFrameSlots = new int[]{ + 10, 11, 12, + 28, 29, 30 + }; + } + ItemDisplayIcon smithingFrameIcon = ItemDisplayIcon.icon(Material.CYAN_STAINED_GLASS_PANE, LangUtil.lang("menu.recipe_creator.icon.smithing_frame")); + for (int slot : smithingFrameSlots) { + getMenuIconMap().put(slot, smithingFrameIcon); + } + ItemDisplayIcon confirmFrameIcon = ItemDisplayIcon.icon(Material.SMITHING_TABLE, LangUtil.lang("menu.recipe_creator.icon.confirm"), event -> { + event.setCancelled(true); + ItemStack result = event.getClickedInventory().getItem(24); + if (result == null || result.getType().equals(Material.AIR)) { + LangUtil.sendMsg(event.getWhoClicked(), "command.create.null_result"); + return; + } + String resultName = getItemName(result, false); + ItemStack base, addition, template; + String baseName, additionName, templateName = null; + if (Craftorithm.getInstance().getVanillaVersion() < 20) { + base = event.getClickedInventory().getItem(19); + addition = event.getClickedInventory().getItem(21); + } else { + template = event.getClickedInventory().getItem(19); + base = event.getClickedInventory().getItem(20); + addition = event.getClickedInventory().getItem(21); + templateName = getItemName(template, true); + } + baseName = getItemName(base, true); + additionName = getItemName(addition, true); + File recipeFile = new File(RecipeManager.getRecipeFileFolder(), recipeName + ".yml"); + if (!recipeFile.exists()) { + FileUtil.createNewFile(recipeFile); + } + YamlConfigWrapper recipeConfig = new YamlConfigWrapper(recipeFile); + recipeConfig.config().set("result", resultName); + recipeConfig.config().set("source.base", baseName); + recipeConfig.config().set("source.addition", additionName); + recipeConfig.config().set("type", "smithing"); + if (Craftorithm.getInstance().getVanillaVersion() >= 20) { + recipeConfig.config().set("source.type", "transform"); + recipeConfig.config().set("source.template", templateName); + } + recipeConfig.saveConfig(); + recipeConfig.reloadConfig(); + Recipe recipe = RecipeFactory.newRecipe(recipeConfig.config(), recipeName); + RecipeManager.regRecipe(NamespacedKey.fromString(recipeName, Craftorithm.getInstance()), recipe, recipeConfig.config()); + event.getWhoClicked().closeInventory(); + sendSuccessMsgAndReloadMap(event.getWhoClicked()); + }); + getMenuIconMap().put(22, confirmFrameIcon); + } + + private void setCookingMenuIcons() { + int[] frameSlots = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, + 9, 13, 17, + 18, 26, + 27, 31, 35, + 36, 37, 40, 43, 44 + }; + ItemDisplayIcon frameIcon = ItemDisplayIcon.icon(Material.BLACK_STAINED_GLASS_PANE, LangUtil.lang("menu.recipe_creator.icon.frame")); + for (int slot : frameSlots) { + getMenuIconMap().put(slot, frameIcon); + } + int[] resultFrameSlots = { + 14, 15, 16, + 23, 25, + 32, 33, 34 + }; + ItemDisplayIcon resultFrameIcon = ItemDisplayIcon.icon(Material.LIME_STAINED_GLASS_PANE, LangUtil.lang("menu.recipe_creator.icon.result_frame")); + for (int slot : resultFrameSlots) { + getMenuIconMap().put(slot, resultFrameIcon); + } + int[] cookingFrameSlots = { + 10, 11, 12, + 19, 21, + 28, 29, 30 + }; + ItemDisplayIcon cookingFrameIcon = ItemDisplayIcon.icon(Material.CYAN_STAINED_GLASS_PANE, LangUtil.lang("menu.recipe_creator.icon.cooking_frame")); + for (int slot : cookingFrameSlots) { + getMenuIconMap().put(slot, cookingFrameIcon); + } + if (Craftorithm.getInstance().getVanillaVersion() >= 14) { + ItemDisplayIcon furnaceIcon = ItemDisplayIcon.icon(Material.FURNACE, LangUtil.lang("menu.recipe_creator.icon.furnace_toggle"), event -> { + setIconGlowing(38, event); + }); + getMenuIconMap().put(38, furnaceIcon); + ItemDisplayIcon blastingIcon = ItemDisplayIcon.icon(Material.BLAST_FURNACE, LangUtil.lang("menu.recipe_creator.icon.blasting_toggle"), event -> { + setIconGlowing(39, event); + }); + getMenuIconMap().put(39, blastingIcon); + ItemDisplayIcon smokingIcon = ItemDisplayIcon.icon(Material.SMOKER, LangUtil.lang("menu.recipe_creator.icon.smoking_toggle"), event -> { + setIconGlowing(41, event); + }); + getMenuIconMap().put(41, smokingIcon); + ItemDisplayIcon campfireIcon = ItemDisplayIcon.icon(Material.CAMPFIRE, LangUtil.lang("menu.recipe_creator.icon.campfire_toggle"), event -> { + setIconGlowing(42, event); + }); + getMenuIconMap().put(42, campfireIcon); + } + ItemDisplayIcon confirmIcon = ItemDisplayIcon.icon(Material.FURNACE, LangUtil.lang("menu.recipe_creator.icon.confirm"), event -> { + event.setCancelled(true); + ItemStack source = event.getClickedInventory().getItem(20); + String sourceName = getItemName(source, true); + ItemStack result = event.getClickedInventory().getItem(24); + if (result == null || result.getType().equals(Material.AIR)) { + LangUtil.sendMsg(event.getWhoClicked(), "command.create.null_result"); + return; + } + String resultName = getItemName(result, false); + File recipeFile = new File(RecipeManager.getRecipeFileFolder(), recipeName + ".yml"); + if (!recipeFile.exists()) { + FileUtil.createNewFile(recipeFile); + } + YamlConfigWrapper recipeConfig = new YamlConfigWrapper(recipeFile); + recipeConfig.config().set("type", "cooking"); + recipeConfig.config().set("result", resultName); + if (Craftorithm.getInstance().getVanillaVersion() >= 14) { + recipeConfig.config().set("multiple", true); + List> sourceList = new ArrayList<>(); + int []toggleSlots = { 38, 39, 41, 42 }; + for (int slot : toggleSlots) { + ItemStack item = event.getClickedInventory().getItem(slot); + Material material = item.getType(); + boolean toggle = item.containsEnchantment(Enchantment.MENDING); + if (toggle) { + Map sourceMap = new HashMap<>(); + sourceMap.put("block", material.name().toLowerCase(Locale.ROOT)); + sourceMap.put("item", sourceName); + sourceList.add(sourceMap); + } + } + recipeConfig.config().set("source", sourceList); + recipeConfig.saveConfig(); + recipeConfig.reloadConfig(); + Recipe[] multipleRecipes = RecipeFactory.newMultipleRecipe(recipeConfig.config(), recipeName); + for (Recipe recipe : multipleRecipes) { + NamespacedKey key = RecipeManager.getRecipeKey(recipe); + RecipeManager.regRecipe(key, recipe, recipeConfig.config()); + } + } else { + recipeConfig.config().set("source.block", "furnace"); + recipeConfig.config().set("source.item", sourceName); + recipeConfig.saveConfig(); + recipeConfig.reloadConfig(); + Recipe recipe = RecipeFactory.newRecipe(recipeConfig.config(), recipeName); + RecipeManager.regRecipe(NamespacedKey.fromString(recipeName, Craftorithm.getInstance()), recipe, recipeConfig.config()); + } + event.getWhoClicked().closeInventory(); + sendSuccessMsgAndReloadMap(event.getWhoClicked()); + }); + getMenuIconMap().put(22, confirmIcon); + } + + private void setIconGlowing(int slot, InventoryClickEvent event) { + event.setCancelled(true); + RecipeCreatorMenuHolder holder = (RecipeCreatorMenuHolder) event.getClickedInventory().getHolder(); + ItemDisplayIcon icon = holder.getMenuIconMap().get(slot); + ItemStack display = icon.getDisplay(); + if (!display.containsEnchantment(Enchantment.MENDING)) { + display.addUnsafeEnchantment(Enchantment.MENDING, 1); + ItemMeta meta = display.getItemMeta(); + meta.addItemFlags(ItemFlag.HIDE_ENCHANTS); + display.setItemMeta(meta); + event.getClickedInventory().setItem(slot, display); + } else { + display.removeEnchantment(Enchantment.MENDING); + event.getClickedInventory().setItem(slot, display); + } + } + + private void setCraftMenuIcons() { + int[] frameSlots = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, + 9, 13, 17, + 18, 26, + 27, 31, 35, + 36, 37, 38, 39, 40, 41, 42, 43, 44 + }; + ItemDisplayIcon frameIcon = ItemDisplayIcon.icon(Material.BLACK_STAINED_GLASS_PANE, LangUtil.lang("menu.recipe_creator.icon.frame")); + for (int slot : frameSlots) { + getMenuIconMap().put(slot, frameIcon); + } + int[] resultFrameSlots = { + 14, 15, 16, + 23, 25, + 32, 33, 34 + }; + ItemDisplayIcon resultFrameIcon = ItemDisplayIcon.icon(Material.LIME_STAINED_GLASS_PANE, LangUtil.lang("menu.recipe_creator.icon.result_frame")); + for (int slot : resultFrameSlots) { + getMenuIconMap().put(slot, resultFrameIcon); + } + ItemDisplayIcon confirmIcon = ItemDisplayIcon.icon(Material.CRAFTING_TABLE, + LangUtil.lang("menu.recipe_creator.icon.confirm"), + event -> { + event.setCancelled(true); + Inventory inventory = event.getView().getTopInventory(); + ItemStack result = inventory.getItem(24); + if (result == null || result.getType().equals(Material.AIR)) { + LangUtil.sendMsg(event.getWhoClicked(), "command.create.null_result"); + return; + } + String resultName = getItemName(result, false); + int[] sourceSlots = { + 10, 11, 12, + 19, 20, 21, + 28, 29, 30 + }; + List sourceList = new ArrayList<>(); + for (int slot : sourceSlots) { + ItemStack item = inventory.getItem(slot); + if (item == null || item.getType().equals(Material.AIR)) { + sourceList.add(""); + continue; + } + String itemName = getItemName(item, true); + sourceList.add(itemName); + } + File recipeFile = new File(RecipeManager.getRecipeFileFolder(), recipeName + ".yml"); + if (!recipeFile.exists()) { + FileUtil.createNewFile(recipeFile); + } + YamlConfigWrapper recipeConfig = new YamlConfigWrapper(recipeFile); + switch (recipeType) { + case SHAPED: + List shape = new ArrayList<>(Arrays.asList("abc", "def", "ghi")); + Map itemMap = new HashMap<>(); + char[] tmp = "abcdefghi".toCharArray(); + for (int i = 0; i < sourceList.size(); i++) { + if (sourceList.get(i).isEmpty()) { + continue; + } + itemMap.put(tmp[i], sourceList.get(i)); + } + for (int i = 0; i < shape.size(); i++) { + String s = shape.get(i); + for (char c : s.toCharArray()) { + if (!itemMap.containsKey(c)) { + s = s.replace(c, ' '); + } + } + shape.set(i, s); + } + shape.removeIf(s -> s.trim().isEmpty()); + recipeConfig.config().set("type", "shaped"); + recipeConfig.config().set("result", resultName); + recipeConfig.config().set("shape", shape); + recipeConfig.config().set("source", itemMap); + break; + case SHAPELESS: + sourceList.removeIf(String::isEmpty); + recipeConfig.config().set("type", "shapeless"); + recipeConfig.config().set("result", resultName); + recipeConfig.config().set("source", sourceList); + break; + } + recipeConfig.saveConfig(); + recipeConfig.reloadConfig(); + Recipe recipe = RecipeFactory.newRecipe(recipeConfig.config(), recipeName); + RecipeManager.regRecipe(NamespacedKey.fromString(recipeName, Craftorithm.getInstance()), recipe, recipeConfig.config()); + event.getWhoClicked().closeInventory(); + sendSuccessMsgAndReloadMap(event.getWhoClicked()); + }); + getMenuIconMap().put(22, confirmIcon); + } + + @NotNull + @Override + public Inventory getInventory() { + String title = LangUtil.color(LangUtil.lang("menu.recipe_creator.title")); + title = title.replace("", recipeType.name().toLowerCase(Locale.ROOT)); + title = title.replace("", recipeName); + Inventory inventory = Bukkit.createInventory(this, 45, title); + for (Integer slot : getMenuIconMap().keySet()) { + inventory.setItem(slot, getMenuIconMap().get(slot).getDisplay()); + } + return inventory; + } + + public RecipeType getRecipeType() { + return recipeType; + } + + public void setRecipeType(RecipeType recipeType) { + this.recipeType = recipeType; + } + + public String getRecipeName() { + return recipeName; + } + + public void setRecipeName(String recipeName) { + this.recipeName = recipeName; + } + + private String getItemName(ItemStack item, boolean ignoreAmount) { + if (ItemUtil.isItemInvalidate(item)) { + return null; + } + String itemName; + if (item.hasItemMeta()) { + itemName = ItemManager.getItemName(item, ignoreAmount, true, "gui_items", UUID.randomUUID().toString()); + itemName = "items:" + itemName; + } else { + itemName = item.getType().name(); + } + return itemName; + } + + private void sendSuccessMsgAndReloadMap(HumanEntity entity) { + Map replaceMap = ContainerUtil.newHashMap("", recipeType.name().toLowerCase(), + "", recipeName); + LangUtil.sendMsg(entity, "command.create.success", replaceMap); + ((RemoveRecipeCommand) RemoveRecipeCommand.INSTANCE).reloadRecipeMap(); + } + +} diff --git a/src/main/java/com/github/yufiriamazenta/craftorithm/recipe/RecipeManager.java b/src/main/java/com/github/yufiriamazenta/craftorithm/recipe/RecipeManager.java new file mode 100644 index 00000000..71f818d4 --- /dev/null +++ b/src/main/java/com/github/yufiriamazenta/craftorithm/recipe/RecipeManager.java @@ -0,0 +1,286 @@ +package com.github.yufiriamazenta.craftorithm.recipe; + +import com.github.yufiriamazenta.craftorithm.Craftorithm; +import com.github.yufiriamazenta.craftorithm.CraftorithmAPI; +import com.github.yufiriamazenta.craftorithm.cmd.subcmd.RemoveRecipeCommand; +import com.github.yufiriamazenta.craftorithm.recipe.custom.AnvilRecipe; +import com.github.yufiriamazenta.craftorithm.recipe.custom.CustomRecipe; +import com.github.yufiriamazenta.craftorithm.recipe.custom.PotionMixRecipe; +import com.github.yufiriamazenta.craftorithm.util.ContainerUtil; +import com.github.yufiriamazenta.craftorithm.util.FileUtil; +import com.github.yufiriamazenta.craftorithm.util.LangUtil; +import crypticlib.config.impl.YamlConfigWrapper; +import crypticlib.util.MsgUtil; +import org.bukkit.Bukkit; +import org.bukkit.Keyed; +import org.bukkit.NamespacedKey; +import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.inventory.*; + +import java.io.File; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicReference; + +public class RecipeManager { + + private static final Map recipeFileMap = new HashMap<>(); + private static final Map recipeKeyConfigMap = new ConcurrentHashMap<>(); + private static final File recipeFileFolder = new File(Craftorithm.getInstance().getDataFolder().getPath(), "recipes"); + private static final Map recipeUnlockMap; + private static final Map recipeSortIdMap; + private static final Map anvilRecipeMap; + private static final Map recipeTypeMap; + private static final Map recipeKeyMap; + + static { + recipeUnlockMap = new ConcurrentHashMap<>(); + + recipeSortIdMap = new ConcurrentHashMap<>(); + + anvilRecipeMap = new ConcurrentHashMap<>(); + + recipeTypeMap = new ConcurrentHashMap<>(); + + recipeKeyMap = new ConcurrentHashMap<>(); + } + + public static void loadRecipeManager() { + loadRecipeFiles(); + } + + public static void loadRecipeFiles() { + recipeFileMap.clear(); + if (!recipeFileFolder.exists()) { + boolean mkdirResult = recipeFileFolder.mkdir(); + if (!mkdirResult) + return; + } + List allFiles = FileUtil.getAllFiles(recipeFileFolder); + if (allFiles.size() < 1) { + saveDefConfigFile(allFiles); + } + for (File file : allFiles) { + String key = file.getPath().substring(recipeFileFolder.getPath().length() + 1); + key = key.replace("\\", "/"); + int lastDotIndex = key.lastIndexOf("."); + key = key.substring(0, lastDotIndex); + recipeFileMap.put(key, new YamlConfigWrapper(file)); + } + } + + public static void loadCraftorithmRecipes() { + resetRecipes(); + for (String fileName : recipeFileMap.keySet()) { + try { + YamlConfiguration config = recipeFileMap.get(fileName).config(); + boolean multiple = config.getBoolean("multiple", false); + if (multiple) { + Recipe[] multipleRecipes = RecipeFactory.newMultipleRecipe(config, fileName); + for (Recipe recipe : multipleRecipes) { + NamespacedKey key = getRecipeKey(recipe); + regRecipe(key, recipe, config); + } + } else { + Recipe recipe = RecipeFactory.newRecipe(config, fileName); + regRecipe(getRecipeKey(recipe), recipe, config); + } + } catch (Exception e) { + LangUtil.info("load.recipe_load_exception", ContainerUtil.newHashMap("", fileName)); + e.printStackTrace(); + } + } + } + + public static void resetRecipes() { + CraftorithmAPI.INSTANCE.getPluginRegRecipeMap().forEach((plugin, recipes) -> { + if (plugin.equals(NamespacedKey.MINECRAFT)) + return; + List recipeKeyList = new ArrayList<>(); + for (Recipe recipe : recipes) { + recipeKeyList.add(getRecipeKey(recipe).toString()); + } + ((RemoveRecipeCommand) RemoveRecipeCommand.INSTANCE).removeRecipes(recipeKeyList, false); + }); + List recipeKeyList = new ArrayList<>(); + for (NamespacedKey key : getPluginRecipeKeys()) { + recipeKeyList.add(key.toString()); + } + ((RemoveRecipeCommand) RemoveRecipeCommand.INSTANCE).removeRecipes(recipeKeyList, false); + recipeTypeMap.clear(); + recipeKeyMap.clear(); + recipeUnlockMap.clear(); + anvilRecipeMap.clear(); + recipeKeyConfigMap.clear(); + } + + public static void regRecipe(NamespacedKey key, Recipe recipe, YamlConfiguration config) { + if (recipe instanceof CustomRecipe) { + switch (((CustomRecipe) recipe).getRecipeType()) { + case ANVIL: + regAnvilRecipe((AnvilRecipe) recipe); + break; + case POTION: + regPotionMixRecipe((PotionMixRecipe) recipe); + } + } else { + Bukkit.addRecipe(recipe); + boolean defUnlockCondition = Craftorithm.getInstance().getConfig().getBoolean("all_recipe_unlocked", false); + if (config.contains("unlock")) { + recipeUnlockMap.put(key, config.getBoolean("unlock", defUnlockCondition)); + } else { + recipeUnlockMap.put(key, defUnlockCondition); + } + } + recipeKeyConfigMap.put(key, config); + putRecipeTypeMap(recipe); + recipeSortIdMap.put(key, config.getInt("sort_id", 0)); + recipeKeyMap.put(key, recipe); + } + + private static void putRecipeTypeMap(Recipe recipe) { + if (recipe instanceof ShapedRecipe) + recipeTypeMap.put(recipe, RecipeType.SHAPED); + else if (recipe instanceof ShapelessRecipe) + recipeTypeMap.put(recipe, RecipeType.SHAPELESS); + else if (recipe instanceof CookingRecipe) + recipeTypeMap.put(recipe, RecipeType.COOKING); + else if (recipe instanceof SmithingRecipe) + recipeTypeMap.put(recipe, RecipeType.SMITHING); + else if (recipe instanceof StonecuttingRecipe) + recipeTypeMap.put(recipe, RecipeType.STONE_CUTTING); + else if (recipe instanceof AnvilRecipe) + recipeTypeMap.put(recipe, RecipeType.ANVIL); + else + recipeTypeMap.put(recipe, RecipeType.UNKNOWN); + } + + public static void loadRecipes() { + loadCraftorithmRecipes(); + loadRecipeFromOtherPlugins(); + removeRecipes(); + ((RemoveRecipeCommand) RemoveRecipeCommand.INSTANCE).reloadRecipeMap(); + } + + private static void loadRecipeFromOtherPlugins() { + Map> pluginRecipeMap = CraftorithmAPI.INSTANCE.getPluginRegRecipeMap(); + for (String plugin : pluginRecipeMap.keySet()) { + if (plugin.equals(NamespacedKey.MINECRAFT) || plugin.equals(Craftorithm.getInstance().getName())) + continue; + for (Recipe recipe : pluginRecipeMap.get(plugin)) { + Craftorithm.getInstance().getServer().addRecipe(recipe); + } + } + } + + private static void removeRecipes() { + List removedRecipes = RemoveRecipeCommand.getRemovedRecipeConfig().config().getStringList("recipes"); + if (Craftorithm.getInstance().getConfig().getBoolean("remove_all_vanilla_recipe", false)) { + for (NamespacedKey key : ((RemoveRecipeCommand) RemoveRecipeCommand.INSTANCE).getRecipeMap().keySet()) { + if (key.getNamespace().equals("minecraft")) { + if (removedRecipes.contains(key.toString())) + continue; + removedRecipes.add(key.toString()); + } + } + } + ((RemoveRecipeCommand) RemoveRecipeCommand.INSTANCE).removeRecipes(removedRecipes, false); + } + + public static YamlConfiguration getRecipeConfig(Recipe recipe) { + NamespacedKey key = getRecipeKey(recipe); + return key != null ? recipeKeyConfigMap.get(key) : null; + } + + public static Map getPluginRecipeTypeMap() { + return new ConcurrentHashMap<>(recipeTypeMap); + } + + public static Map getRecipeSortIdMap() { + return new ConcurrentHashMap<>(recipeSortIdMap); + } + + public static NamespacedKey getRecipeKey(Recipe recipe) { + if (recipe == null) + return null; + if (recipe instanceof CustomRecipe) { + return ((CustomRecipe) recipe).getKey(); + } + return ((Keyed) recipe).getKey(); + } + + public static Recipe getPluginRecipe(String key) { + if (key.contains(":")) { + return getPluginRecipe(NamespacedKey.fromString(key)); + } else { + return getPluginRecipe(NamespacedKey.fromString(key, Craftorithm.getInstance())); + } + } + + public static Recipe getPluginRecipe(NamespacedKey namespacedKey) { + return recipeKeyMap.get(namespacedKey); + } + + public static List getPluginRecipeKeys() { + return new ArrayList<>(recipeKeyMap.keySet()); + } + + public static RecipeType getPluginRecipeType(Recipe recipe) { + return recipeTypeMap.getOrDefault(recipe, RecipeType.UNKNOWN); + } + + public static Map getRecipeUnlockMap() { + return recipeUnlockMap; + } + + public static Map getRecipeFileMap() { + return recipeFileMap; + } + + public static Map getAnvilRecipeMap() {return anvilRecipeMap;} + + public static AnvilRecipe matchAnvilRecipe(ItemStack base, ItemStack addition) { + if (base == null || addition == null) + return null; + AtomicReference anvilRecipe = new AtomicReference<>(); + anvilRecipeMap.forEach((key, recipe) -> { + if (recipe.checkSource(base, addition)) { + anvilRecipe.set(recipe); + } + }); + return anvilRecipe.get(); + } + + public static File getRecipeFileFolder() { + return recipeFileFolder; + } + + public static void regAnvilRecipe(AnvilRecipe recipe) { + anvilRecipeMap.put(recipe.getKey(), recipe); + } + + private static void regPotionMixRecipe(PotionMixRecipe recipe) { + //TODO + } + + private static void saveDefConfigFile(List allFiles) { + Craftorithm.getInstance().saveResource("recipes/example_shaped.yml", false); + Craftorithm.getInstance().saveResource("recipes/example_shapeless.yml", false); + Craftorithm.getInstance().saveResource("recipes/example_cooking.yml", false); + Craftorithm.getInstance().saveResource("recipes/example_smithing.yml", false); + Craftorithm.getInstance().saveResource("recipes/example_stone_cutting.yml", false); + Craftorithm.getInstance().saveResource("recipes/example_random_cooking.yml", false); + Craftorithm.getInstance().saveResource("recipes/example_anvil.yml", false); + allFiles.add(new File(recipeFileFolder, "example_shaped.yml")); + allFiles.add(new File(recipeFileFolder, "example_shapeless.yml")); + allFiles.add(new File(recipeFileFolder, "example_cooking.yml")); + allFiles.add(new File(recipeFileFolder, "example_smithing.yml")); + allFiles.add(new File(recipeFileFolder, "example_stone_cutting.yml")); + allFiles.add(new File(recipeFileFolder, "example_random_cooking.yml")); + allFiles.add(new File(recipeFileFolder, "example_anvil.yml")); + } + +} diff --git a/src/main/java/com/github/yufiriamazenta/craftorithm/util/LangUtil.java b/src/main/java/com/github/yufiriamazenta/craftorithm/util/LangUtil.java new file mode 100644 index 00000000..cb286d6a --- /dev/null +++ b/src/main/java/com/github/yufiriamazenta/craftorithm/util/LangUtil.java @@ -0,0 +1,85 @@ +package com.github.yufiriamazenta.craftorithm.util; + +import com.github.yufiriamazenta.craftorithm.Craftorithm; +import crypticlib.config.impl.YamlConfigWrapper; +import me.clip.placeholderapi.PlaceholderAPI; +import net.md_5.bungee.api.ChatColor; +import org.bukkit.Bukkit; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; + +import java.util.HashMap; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import static org.bukkit.ChatColor.translateAlternateColorCodes; + +public class LangUtil { + + private static final Pattern colorPattern = Pattern.compile("&#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})"); + private static final YamlConfigWrapper langConfigFile = new YamlConfigWrapper(Craftorithm.getInstance(), "lang.yml"); + private static final Map defaultFormatMap; + + static { + defaultFormatMap = new HashMap<>(); + defaultFormatMap.put("", langConfigFile.config().getString("prefix", "&8[&3Oasis&bRecipe&8]")); + defaultFormatMap.put("", Craftorithm.getInstance().getDescription().getVersion()); + } + + public static void sendMsg(CommandSender sender, String msgKey) { + sendMsg(sender, msgKey, new HashMap<>()); + } + + public static void sendMsg(CommandSender sender, String msgKey, Map formatMap) { + if (sender == null) { + return; + } + formatMap.putAll(defaultFormatMap); + String message = langConfigFile.config().getString(msgKey, msgKey); + for (String formatStr : formatMap.keySet()) { + message = message.replace(formatStr, formatMap.get(formatStr)); + } + if (sender instanceof Player) + message = placeholder((Player) sender, message); + sender.sendMessage(color(message)); + } + + public static String color(String text) { + if (Craftorithm.getInstance().getVanillaVersion() >= 16) { + StringBuilder strBuilder = new StringBuilder(text); + Matcher matcher = colorPattern.matcher(strBuilder); + while (matcher.find()) { + String colorCode = matcher.group(); + String colorStr = ChatColor.of(colorCode.substring(1)).toString(); + strBuilder.replace(matcher.start(), matcher.start() + colorCode.length(), colorStr); + matcher = colorPattern.matcher(strBuilder); + } + text = strBuilder.toString(); + } + return translateAlternateColorCodes('&', text); + } + + public static void info(String msgKey) { + sendMsg(Bukkit.getConsoleSender(), msgKey); + } + + public static void reloadMsgConfig() { + langConfigFile.reloadConfig(); + } + + public static void info(String msgKey, Map map) { + sendMsg(Bukkit.getConsoleSender(), msgKey, map); + } + + public static String lang(String key) { + return langConfigFile.config().getString(key, key); + } + + public static String placeholder(Player player, String source) { + if (Bukkit.getPluginManager().getPlugin("PlaceholderAPI") != null) + source = PlaceholderAPI.setPlaceholders(player, source); + return source; + } + +}