From 592e4598df0a572695a99de2ac31d0dac3cbb44e Mon Sep 17 00:00:00 2001 From: Xiao-MoMi <70987828+Xiao-MoMi@users.noreply.github.com> Date: Sun, 29 May 2022 15:52:41 +0800 Subject: [PATCH] 1.3.1 remake --- .../customcrops/CommandHandler.java | 127 ++ .../customcrops/CommandTabComplete.java | 24 + .../momirealms/customcrops/ConfigManager.java | 134 ++ .../momirealms/customcrops/CustomCrops.java | 101 ++ .../momirealms/customcrops/IAFurniture.java | 32 + .../customcrops/MessageManager.java | 14 + .../momirealms/customcrops/Placeholders.java | 39 + .../customcrops/crops/CropTimer.java | 25 + .../customcrops/crops/TimeCheck.java | 33 + .../customcrops/datamanager/BackUp.java | 53 + .../customcrops/datamanager/CropManager.java | 322 +++++ .../datamanager/MaxCropsPerChunk.java | 42 + .../datamanager/MaxSprinklersPerChunk.java | 43 + .../customcrops/datamanager/NextSeason.java | 29 + .../datamanager/SprinklerManager.java | 223 +++ .../integrations/IntegrationCheck.java | 43 + .../integrations/KingdomsXIntegrations.java | 25 + .../integrations/ResidenceIntegrations.java | 31 + .../integrations/WorldGuardIntegrations.java | 30 + .../customcrops/libs/minedown/MineDown.java | 499 +++++++ .../libs/minedown/MineDownParser.java | 1241 +++++++++++++++++ .../libs/minedown/MineDownStringifier.java | 423 ++++++ .../customcrops/libs/minedown/Replacer.java | 471 +++++++ .../customcrops/libs/minedown/Util.java | 590 ++++++++ .../listener/BreakCustomBlock.java | 46 + .../customcrops/listener/BreakFurniture.java | 30 + .../customcrops/listener/RightClickBlock.java | 99 ++ .../listener/RightClickCustomBlock.java | 344 +++++ 28 files changed, 5113 insertions(+) create mode 100644 src/main/java/net/momirealms/customcrops/CommandHandler.java create mode 100644 src/main/java/net/momirealms/customcrops/CommandTabComplete.java create mode 100644 src/main/java/net/momirealms/customcrops/ConfigManager.java create mode 100644 src/main/java/net/momirealms/customcrops/CustomCrops.java create mode 100644 src/main/java/net/momirealms/customcrops/IAFurniture.java create mode 100644 src/main/java/net/momirealms/customcrops/MessageManager.java create mode 100644 src/main/java/net/momirealms/customcrops/Placeholders.java create mode 100644 src/main/java/net/momirealms/customcrops/crops/CropTimer.java create mode 100644 src/main/java/net/momirealms/customcrops/crops/TimeCheck.java create mode 100644 src/main/java/net/momirealms/customcrops/datamanager/BackUp.java create mode 100644 src/main/java/net/momirealms/customcrops/datamanager/CropManager.java create mode 100644 src/main/java/net/momirealms/customcrops/datamanager/MaxCropsPerChunk.java create mode 100644 src/main/java/net/momirealms/customcrops/datamanager/MaxSprinklersPerChunk.java create mode 100644 src/main/java/net/momirealms/customcrops/datamanager/NextSeason.java create mode 100644 src/main/java/net/momirealms/customcrops/datamanager/SprinklerManager.java create mode 100644 src/main/java/net/momirealms/customcrops/integrations/IntegrationCheck.java create mode 100644 src/main/java/net/momirealms/customcrops/integrations/KingdomsXIntegrations.java create mode 100644 src/main/java/net/momirealms/customcrops/integrations/ResidenceIntegrations.java create mode 100644 src/main/java/net/momirealms/customcrops/integrations/WorldGuardIntegrations.java create mode 100644 src/main/java/net/momirealms/customcrops/libs/minedown/MineDown.java create mode 100644 src/main/java/net/momirealms/customcrops/libs/minedown/MineDownParser.java create mode 100644 src/main/java/net/momirealms/customcrops/libs/minedown/MineDownStringifier.java create mode 100644 src/main/java/net/momirealms/customcrops/libs/minedown/Replacer.java create mode 100644 src/main/java/net/momirealms/customcrops/libs/minedown/Util.java create mode 100644 src/main/java/net/momirealms/customcrops/listener/BreakCustomBlock.java create mode 100644 src/main/java/net/momirealms/customcrops/listener/BreakFurniture.java create mode 100644 src/main/java/net/momirealms/customcrops/listener/RightClickBlock.java create mode 100644 src/main/java/net/momirealms/customcrops/listener/RightClickCustomBlock.java diff --git a/src/main/java/net/momirealms/customcrops/CommandHandler.java b/src/main/java/net/momirealms/customcrops/CommandHandler.java new file mode 100644 index 0000000..37b11cd --- /dev/null +++ b/src/main/java/net/momirealms/customcrops/CommandHandler.java @@ -0,0 +1,127 @@ +package net.momirealms.customcrops; + +import net.momirealms.customcrops.datamanager.BackUp; +import net.momirealms.customcrops.datamanager.CropManager; +import net.momirealms.customcrops.datamanager.NextSeason; +import net.momirealms.customcrops.datamanager.SprinklerManager; +import org.bukkit.Bukkit; +import org.bukkit.command.Command; +import org.bukkit.command.CommandExecutor; +import org.bukkit.command.CommandSender; +import org.bukkit.configuration.file.FileConfiguration; +import org.bukkit.entity.Player; + +import javax.annotation.ParametersAreNonnullByDefault; + +public class CommandHandler implements CommandExecutor { + + + @Override + @ParametersAreNonnullByDefault + public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { + + if(sender instanceof Player && !sender.isOp()){ + return false; + } + + //重载插件 + if(args[0].equalsIgnoreCase("reload")){ + + ConfigManager.Config.ReloadConfig(); + + if(sender instanceof Player){ + MessageManager.playerMessage(ConfigManager.Config.prefix + ConfigManager.Config.reload, (Player) sender); + }else { + MessageManager.consoleMessage(ConfigManager.Config.prefix + ConfigManager.Config.reload, Bukkit.getConsoleSender()); + } + return true; + } + //设置季节 + if(args[0].equalsIgnoreCase("setseason")){ + if(ConfigManager.Config.season){ + + FileConfiguration config = CustomCrops.instance.getConfig(); + config.set("current-season", args[1]); + CustomCrops.instance.saveConfig(); + ConfigManager.Config.current = args[1]; + + if(sender instanceof Player){ + MessageManager.playerMessage(ConfigManager.Config.prefix + ConfigManager.Config.season_set.replace("{Season}",args[1]) + .replace("spring", ConfigManager.Config.spring) + .replace("summer", ConfigManager.Config.summer) + .replace("autumn", ConfigManager.Config.autumn) + .replace("winter", ConfigManager.Config.winter), (Player) sender); + }else { + MessageManager.consoleMessage(config.getString("messages.prefix") + ConfigManager.Config.season_set.replace("{Season}",args[1]) + .replace("spring", ConfigManager.Config.spring) + .replace("summer", ConfigManager.Config.summer) + .replace("autumn", ConfigManager.Config.autumn) + .replace("winter", ConfigManager.Config.winter), Bukkit.getConsoleSender()); + } + + }else{ + if(sender instanceof Player){ + MessageManager.playerMessage(ConfigManager.Config.prefix + ConfigManager.Config.season_disabled, (Player) sender); + }else { + MessageManager.consoleMessage(ConfigManager.Config.prefix + ConfigManager.Config.season_disabled, Bukkit.getConsoleSender()); + } + } + return true; + } + //强制保存 + if(args[0].equalsIgnoreCase("forcesave")){ + CropManager.saveData(); + SprinklerManager.saveData(); + if(sender instanceof Player){ + MessageManager.playerMessage(ConfigManager.Config.prefix + ConfigManager.Config.force_save, (Player) sender); + }else { + MessageManager.consoleMessage(ConfigManager.Config.prefix + ConfigManager.Config.force_save, Bukkit.getConsoleSender()); + } + return true; + } + //强制生长 + if(args[0].equalsIgnoreCase("forcegrow")){ + Bukkit.getScheduler().runTaskAsynchronously(CustomCrops.instance, CropManager::CropGrow); + if(sender instanceof Player){ + MessageManager.playerMessage(ConfigManager.Config.prefix + ConfigManager.Config.force_grow, (Player) sender); + }else { + MessageManager.consoleMessage(ConfigManager.Config.prefix + ConfigManager.Config.force_grow, Bukkit.getConsoleSender()); + } + return true; + } + //强制洒水 + if(args[0].equalsIgnoreCase("forcewater")){ + Bukkit.getScheduler().runTaskAsynchronously(CustomCrops.instance, SprinklerManager::SprinklerWork); + if(sender instanceof Player){ + MessageManager.playerMessage(ConfigManager.Config.prefix + ConfigManager.Config.force_water, (Player) sender); + }else { + MessageManager.consoleMessage(ConfigManager.Config.prefix + ConfigManager.Config.force_water, Bukkit.getConsoleSender()); + } + return true; + } + if(args[0].equalsIgnoreCase("backup")){ + BackUp.backUpData(); + if(sender instanceof Player){ + MessageManager.playerMessage(ConfigManager.Config.prefix + ConfigManager.Config.backup, (Player) sender); + }else { + MessageManager.consoleMessage(ConfigManager.Config.prefix + ConfigManager.Config.backup, Bukkit.getConsoleSender()); + } + return true; + } + if(args[0].equalsIgnoreCase("nextseason")){ + NextSeason.changeSeason(); + if(sender instanceof Player){ + MessageManager.playerMessage(ConfigManager.Config.prefix + ConfigManager.Config.nextSeason, (Player) sender); + }else { + MessageManager.consoleMessage(ConfigManager.Config.prefix + ConfigManager.Config.nextSeason, Bukkit.getConsoleSender()); + } + return true; + } + if(args[0].equalsIgnoreCase("test")){ + CropManager.testData_2(); + SprinklerManager.testData_3(); + return true; + } + return false; + } +} diff --git a/src/main/java/net/momirealms/customcrops/CommandTabComplete.java b/src/main/java/net/momirealms/customcrops/CommandTabComplete.java new file mode 100644 index 0000000..e3e06c1 --- /dev/null +++ b/src/main/java/net/momirealms/customcrops/CommandTabComplete.java @@ -0,0 +1,24 @@ +package net.momirealms.customcrops; + +import org.bukkit.command.Command; +import org.bukkit.command.CommandSender; +import org.bukkit.command.TabCompleter; +import org.jetbrains.annotations.Nullable; + +import javax.annotation.ParametersAreNonnullByDefault; +import java.util.Arrays; +import java.util.List; + +public class CommandTabComplete implements TabCompleter { + @Override + @ParametersAreNonnullByDefault + public @Nullable List onTabComplete(CommandSender sender, Command command, String alias, String[] args) { + if (args.length == 1) { + return Arrays.asList("backup" , "forcegrow", "forcesave", "forcewater", "reload", "setseason" , "nextseason"); + } + if(args[0].equalsIgnoreCase("setseason")){ + return Arrays.asList("spring","summer","autumn","winter"); + } + return null; + } +} diff --git a/src/main/java/net/momirealms/customcrops/ConfigManager.java b/src/main/java/net/momirealms/customcrops/ConfigManager.java new file mode 100644 index 0000000..9e49a9f --- /dev/null +++ b/src/main/java/net/momirealms/customcrops/ConfigManager.java @@ -0,0 +1,134 @@ +package net.momirealms.customcrops; + +import org.bukkit.configuration.file.FileConfiguration; + +import java.util.List; + +public class ConfigManager { + + public static class Config{ + + public static boolean res; + public static boolean wg; + public static boolean king; + public static boolean season; + public static boolean need_water; + public static boolean greenhouse; + public static boolean big; + public static boolean limit; + + public static List worlds; + public static List cropGrowTimeList; + public static List sprinklerWorkTimeList; + + public static String current; + public static String prefix; + public static String bad_place; + public static String reload; + public static String force_save; + public static String nextSeason; + public static String no_such_seed; + public static String wrong_season; + public static String season_set; + public static String season_disabled; + public static String force_grow; + public static String force_water; + public static String limit_crop; + public static String limit_sprinkler; + public static String backup; + public static String spring; + public static String summer; + public static String autumn; + public static String winter; + public static String can_full; + public static String pot; + public static String watered_pot; + public static String watering_can_1; + public static String watering_can_2; + public static String watering_can_3; + public static String glass; + public static String sprinkler_1; + public static String sprinkler_2; + public static String sprinkler_1i; + public static String sprinkler_2i; + public static String dead; + public static String success; + public static String failure; + + public static double bone_chance; + public static double grow_chance; + public static double big_chance; + + public static int range; + public static int maxh; + public static int minh; + public static int max_crop; + public static int max_sprinkler; + + public static void ReloadConfig(){ + + CustomCrops.instance.reloadConfig(); + FileConfiguration configuration = CustomCrops.instance.getConfig(); + + //处理配置 + Config.res = configuration.getBoolean("integration.residence"); + Config.king = configuration.getBoolean("integration.kingdomsX"); + Config.wg = configuration.getBoolean("integration.worldguard"); + Config.season = configuration.getBoolean("enable-season"); + Config.need_water = configuration.getBoolean("config.bone-meal-consume-water"); + Config.greenhouse = configuration.getBoolean("config.enable-greenhouse"); + Config.big = configuration.getBoolean("config.gigantic.enable"); + Config.limit = configuration.getBoolean("config.enable-limit"); + + Config.bone_chance = configuration.getDouble("config.bone-meal-chance"); + Config.grow_chance = configuration.getDouble("config.grow-success-chance"); + Config.big_chance = configuration.getDouble("config.gigantic.chance"); + + Config.range = configuration.getInt("config.greenhouse-range"); + Config.maxh = configuration.getInt("config.height.max"); + Config.minh = configuration.getInt("config.height.min"); + Config.max_crop = configuration.getInt("config.max-crops"); + Config.max_sprinkler = configuration.getInt("config.max-sprinklers"); + + Config.current = configuration.getString("current-season"); + Config.pot = configuration.getString("config.pot"); + Config.watered_pot = configuration.getString("config.watered-pot"); + Config.watering_can_1 = configuration.getString("config.watering-can-1"); + Config.watering_can_2 = configuration.getString("config.watering-can-2"); + Config.watering_can_3 = configuration.getString("config.watering-can-3"); + Config.glass = configuration.getString("config.greenhouse-glass"); + Config.sprinkler_1 = configuration.getString("config.sprinkler-1"); + Config.sprinkler_2 = configuration.getString("config.sprinkler-2"); + Config.sprinkler_1i = configuration.getString("config.sprinkler-1-item"); + Config.sprinkler_2i = configuration.getString("config.sprinkler-2-item"); + Config.dead = configuration.getString("config.dead-crop"); + Config.success = configuration.getString("config.particle.success"); + Config.failure = configuration.getString("config.particle.failure"); + + Config.worlds = configuration.getStringList("config.whitelist-worlds"); + Config.cropGrowTimeList = configuration.getLongList("config.grow-time"); + Config.sprinklerWorkTimeList = configuration.getLongList("config.sprinkler-time"); + + //处理消息 + Config.prefix = configuration.getString("messages.prefix"); + Config.bad_place = configuration.getString("messages.not-a-good-place"); + Config.reload = configuration.getString("messages.reload"); + Config.force_save = configuration.getString("messages.force-save"); + Config.nextSeason = configuration.getString("messages.nextseason"); + Config.no_such_seed = configuration.getString("messages.no-such-seed"); + Config.wrong_season = configuration.getString("messages.wrong-season"); + Config.season_set = configuration.getString("messages.season-set"); + Config.season_disabled = configuration.getString("messages.season-disabled"); + Config.force_grow = configuration.getString("messages.force-grow"); + Config.force_water = configuration.getString("messages.force-water"); + Config.limit_crop = configuration.getString("messages.reach-limit-crop"); + Config.limit_sprinkler = configuration.getString("messages.reach-limit-sprinkler"); + Config.can_full = configuration.getString("messages.can-full"); + Config.backup = configuration.getString("messages.backup"); + Config.spring = configuration.getString("messages.spring"); + Config.summer = configuration.getString("messages.summer"); + Config.autumn = configuration.getString("messages.autumn"); + Config.winter = configuration.getString("messages.winter"); + } + } +} diff --git a/src/main/java/net/momirealms/customcrops/CustomCrops.java b/src/main/java/net/momirealms/customcrops/CustomCrops.java new file mode 100644 index 0000000..014dcdf --- /dev/null +++ b/src/main/java/net/momirealms/customcrops/CustomCrops.java @@ -0,0 +1,101 @@ +package net.momirealms.customcrops; + +import com.comphenix.protocol.ProtocolManager; +import net.momirealms.customcrops.crops.CropTimer; +import net.momirealms.customcrops.datamanager.BackUp; +import net.momirealms.customcrops.datamanager.CropManager; +import net.momirealms.customcrops.datamanager.SprinklerManager; +import net.momirealms.customcrops.listener.BreakCustomBlock; +import net.momirealms.customcrops.listener.BreakFurniture; +import net.momirealms.customcrops.listener.RightClickBlock; +import net.momirealms.customcrops.listener.RightClickCustomBlock; +import org.bukkit.Bukkit; +import org.bukkit.configuration.file.FileConfiguration; +import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.plugin.java.JavaPlugin; + +import java.io.File; +import java.io.IOException; +import java.util.Objects; + +public final class CustomCrops extends JavaPlugin { + + public static JavaPlugin instance; + public static ProtocolManager manager; + public static CropTimer timer; + public static CropManager cropManager; + public static SprinklerManager sprinklerManager; + + @Override + public void onEnable() { + instance = this; + saveDefaultConfig(); + + //加载配置文件 + ConfigManager.Config.ReloadConfig(); + + //指令注册 + Objects.requireNonNull(Bukkit.getPluginCommand("customcrops")).setExecutor(new CommandHandler()); + Objects.requireNonNull(Bukkit.getPluginCommand("customcrops")).setTabCompleter(new CommandTabComplete()); + Bukkit.getPluginManager().registerEvents(new RightClickCustomBlock(),this); + Bukkit.getPluginManager().registerEvents(new BreakCustomBlock(),this); + Bukkit.getPluginManager().registerEvents(new RightClickBlock(),this); + Bukkit.getPluginManager().registerEvents(new BreakFurniture(),this); + + //开始计时任务 + CustomCrops.timer = new CropTimer(); + + //新建data文件 + File crop_file = new File(CustomCrops.instance.getDataFolder(), "crop-data.yml"); + File sprinkler_file = new File(CustomCrops.instance.getDataFolder(), "sprinkler-data.yml"); + if(!crop_file.exists()){ + try { + crop_file.createNewFile(); + } catch (IOException e) { + e.printStackTrace(); + MessageManager.consoleMessage("&c[CustomCrops] 农作物数据文件生成失败!",Bukkit.getConsoleSender()); + } + } + if(!sprinkler_file.exists()){ + try { + sprinkler_file.createNewFile(); + } catch (IOException e) { + e.printStackTrace(); + MessageManager.consoleMessage("&c[CustomCrops] 洒水器数据文件生成失败!",Bukkit.getConsoleSender()); + } + } + + //载入data数据 + FileConfiguration crop_data; + FileConfiguration sprinkler_data; + crop_data = YamlConfiguration.loadConfiguration(crop_file); + sprinkler_data = YamlConfiguration.loadConfiguration(sprinkler_file); + CustomCrops.cropManager = new CropManager(crop_data); + CustomCrops.sprinklerManager = new SprinklerManager(sprinkler_data); + + //检测papi依赖 + if(Bukkit.getPluginManager().getPlugin("PlaceholderAPI") != null){ + new Placeholders(this).register(); + MessageManager.consoleMessage("&#ccfbff-#ef96c5&[CustomCrops] 检测到PlaceHolderAPI 已启用季节变量!",Bukkit.getConsoleSender()); + } + //启动成功 + MessageManager.consoleMessage("&#ccfbff-#ef96c5&[CustomCrops] 自定义农作物插件已启用!作者:小默米 QQ:3266959688",Bukkit.getConsoleSender()); + //this.getLogger().info("自定义农作物插件已启用!作者:小默米 QQ:3266959688"); + } + + @Override + public void onDisable() { + //关闭定时任务 + if (CustomCrops.timer != null) { + CropTimer.stopTimer(CustomCrops.timer.getTaskID()); + } + + //保存缓存中的数据 + CropManager.saveData(); + SprinklerManager.saveData(); + + //备份 + BackUp.backUpData(); + MessageManager.consoleMessage(("&#ccfbff-#ef96c5&[CustomCrops] 自定义农作物插件已卸载!作者:小默米 QQ:3266959688"),Bukkit.getConsoleSender()); + } +} diff --git a/src/main/java/net/momirealms/customcrops/IAFurniture.java b/src/main/java/net/momirealms/customcrops/IAFurniture.java new file mode 100644 index 0000000..51a6a14 --- /dev/null +++ b/src/main/java/net/momirealms/customcrops/IAFurniture.java @@ -0,0 +1,32 @@ +package net.momirealms.customcrops; + +import dev.lone.itemsadder.api.CustomFurniture; +import org.bukkit.Location; +import org.bukkit.World; +import org.bukkit.configuration.file.FileConfiguration; +import org.bukkit.entity.ArmorStand; +import org.bukkit.entity.Entity; + +public class IAFurniture { + + static FileConfiguration config = CustomCrops.instance.getConfig(); + + //放置IA自定义家具 + public static void placeFurniture(String name, Location location){ + CustomFurniture.spawn(name,location.getWorld().getBlockAt(location)); + } + + //根据位置获取盔甲架,如果是洒水器返回true,否则返回false + public static boolean getFromLocation(Location location, World world){ + for(Entity entity : world.getNearbyEntities(location,0,0,0)){ + if(entity instanceof ArmorStand){ + if(CustomFurniture.byAlreadySpawned((ArmorStand) entity) != null){ + if(CustomFurniture.byAlreadySpawned((ArmorStand) entity).getNamespacedID().equalsIgnoreCase(config.getString("config.sprinkler-1")) || CustomFurniture.byAlreadySpawned((ArmorStand) entity).getNamespacedID().equalsIgnoreCase(config.getString("config.sprinkler-2"))){ + return true; + } + } + } + } + return false; + } +} \ No newline at end of file diff --git a/src/main/java/net/momirealms/customcrops/MessageManager.java b/src/main/java/net/momirealms/customcrops/MessageManager.java new file mode 100644 index 0000000..3da9a27 --- /dev/null +++ b/src/main/java/net/momirealms/customcrops/MessageManager.java @@ -0,0 +1,14 @@ +package net.momirealms.customcrops; + +import net.momirealms.customcrops.Libs.minedown.MineDown; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; + +public class MessageManager { + public static void consoleMessage(String s, CommandSender sender) { + sender.spigot().sendMessage(MineDown.parse(s)); + } + public static void playerMessage(String s, Player player){ + player.spigot().sendMessage(MineDown.parse(s)); + } +} diff --git a/src/main/java/net/momirealms/customcrops/Placeholders.java b/src/main/java/net/momirealms/customcrops/Placeholders.java new file mode 100644 index 0000000..0d55e35 --- /dev/null +++ b/src/main/java/net/momirealms/customcrops/Placeholders.java @@ -0,0 +1,39 @@ +package net.momirealms.customcrops; + +import me.clip.placeholderapi.expansion.PlaceholderExpansion; +import org.bukkit.OfflinePlayer; +import org.jetbrains.annotations.NotNull; + +public class Placeholders extends PlaceholderExpansion{ + + public Placeholders(CustomCrops customCrops) { + } + + @Override + public @NotNull String getIdentifier() { + return "customcrops"; + } + + @Override + public @NotNull String getAuthor() { + return "XiaoMoMi"; + } + + @Override + public @NotNull String getVersion() { + return "1.0"; + } + + @Override + public String onRequest(OfflinePlayer player, String params) { + + if(params.equalsIgnoreCase("season")){ + return ConfigManager.Config.current + .replace("spring", ConfigManager.Config.spring) + .replace("summer", ConfigManager.Config.summer) + .replace("autumn", ConfigManager.Config.autumn) + .replace("winter", ConfigManager.Config.winter); + } + return null; + } +} diff --git a/src/main/java/net/momirealms/customcrops/crops/CropTimer.java b/src/main/java/net/momirealms/customcrops/crops/CropTimer.java new file mode 100644 index 0000000..045980d --- /dev/null +++ b/src/main/java/net/momirealms/customcrops/crops/CropTimer.java @@ -0,0 +1,25 @@ +package net.momirealms.customcrops.crops; + +import net.momirealms.customcrops.CustomCrops; +import org.bukkit.Bukkit; +import org.bukkit.scheduler.BukkitTask; + +public class CropTimer { + + int taskID; + + public static void stopTimer(int ID) { + Bukkit.getScheduler().cancelTask(ID); + Bukkit.getServer().getScheduler().cancelTask(ID); + } + + public CropTimer() { + TimeCheck tc = new TimeCheck(); + BukkitTask task = tc.runTaskTimer(CustomCrops.instance, 1,1); + this.taskID = task.getTaskId(); + } + + public int getTaskID() { + return this.taskID; + } +} diff --git a/src/main/java/net/momirealms/customcrops/crops/TimeCheck.java b/src/main/java/net/momirealms/customcrops/crops/TimeCheck.java new file mode 100644 index 0000000..3c2fe49 --- /dev/null +++ b/src/main/java/net/momirealms/customcrops/crops/TimeCheck.java @@ -0,0 +1,33 @@ +package net.momirealms.customcrops.crops; + +import net.momirealms.customcrops.ConfigManager; +import net.momirealms.customcrops.CustomCrops; +import net.momirealms.customcrops.datamanager.CropManager; +import net.momirealms.customcrops.datamanager.SprinklerManager; +import org.bukkit.Bukkit; +import org.bukkit.scheduler.BukkitRunnable; +import org.bukkit.scheduler.BukkitScheduler; + +public class TimeCheck extends BukkitRunnable { + + BukkitScheduler bukkitScheduler = Bukkit.getScheduler(); + + @Override + public void run() { + + ConfigManager.Config.worlds.forEach(world ->{ + long time = Bukkit.getWorld(world).getTime(); + + ConfigManager.Config.cropGrowTimeList.forEach(cropGrowTime -> { + if(time == cropGrowTime){ + bukkitScheduler.runTaskAsynchronously(CustomCrops.instance, CropManager::CropGrow); + } + }); + ConfigManager.Config.sprinklerWorkTimeList.forEach(sprinklerTime -> { + if(time == sprinklerTime){ + bukkitScheduler.runTaskAsynchronously(CustomCrops.instance, SprinklerManager::SprinklerWork); + } + }); + }); + } +} \ No newline at end of file diff --git a/src/main/java/net/momirealms/customcrops/datamanager/BackUp.java b/src/main/java/net/momirealms/customcrops/datamanager/BackUp.java new file mode 100644 index 0000000..e056d87 --- /dev/null +++ b/src/main/java/net/momirealms/customcrops/datamanager/BackUp.java @@ -0,0 +1,53 @@ +package net.momirealms.customcrops.datamanager; + +import net.momirealms.customcrops.CustomCrops; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.text.SimpleDateFormat; +import java.util.Date; + +public class BackUp { + + public static void backUpData(){ + + Date date = new Date(); + SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss"); + + File crop_data = new File(CustomCrops.instance.getDataFolder(), "crop-data.yml"); + File cropBackUp = new File(CustomCrops.instance.getDataFolder(), "backups/"+ format.format(date) + "/" + "crop-data.yml"); + File sprinkler_data = new File(CustomCrops.instance.getDataFolder(), "sprinkler-data.yml"); + File sprinklerBackUp = new File(CustomCrops.instance.getDataFolder(), "backups/"+ format.format(date) + "/" + "sprinkler-data.yml"); + + try { + BackUp.backUp(crop_data,cropBackUp); + } catch (IOException e) { + e.printStackTrace(); + } + try { + BackUp.backUp(sprinkler_data,sprinklerBackUp); + } catch (IOException e) { + e.printStackTrace(); + } + } + + private static void backUp(File file_from, File file_to) throws IOException { + if(!file_to.exists()){ + file_to.getParentFile().mkdirs(); + } + FileInputStream fis = new FileInputStream(file_from); + if(!file_to.exists()){ + file_to.createNewFile(); + } + FileOutputStream fos = new FileOutputStream(file_to); + byte[] b = new byte[1024]; + int len; + while ((len = fis.read(b))!= -1){ + fos.write(b,0,len); + } + fos.close(); + fis.close(); + } +} diff --git a/src/main/java/net/momirealms/customcrops/datamanager/CropManager.java b/src/main/java/net/momirealms/customcrops/datamanager/CropManager.java new file mode 100644 index 0000000..c024c9f --- /dev/null +++ b/src/main/java/net/momirealms/customcrops/datamanager/CropManager.java @@ -0,0 +1,322 @@ +package net.momirealms.customcrops.datamanager; + +import dev.lone.itemsadder.api.CustomBlock; +import net.momirealms.customcrops.ConfigManager; +import net.momirealms.customcrops.CustomCrops; +import net.momirealms.customcrops.MessageManager; +import org.apache.commons.lang.StringUtils; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.World; +import org.bukkit.block.Block; +import org.bukkit.configuration.file.FileConfiguration; +import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.scheduler.BukkitScheduler; + +import java.io.File; +import java.io.IOException; +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; + +public class CropManager { + + public static ConcurrentHashMap instances; + + //4W性能测试 + public static void testData_1(){ + for(int i = -100; i < 100; i++){ + for(int j = -100; j < 100; j++){ + Location tempLoc = new Location(Bukkit.getWorld("world"),i,100,j); + String name = "spring"; + instances.put(tempLoc, name); + } + } + } + //20W性能测试 + public static void testData_2(){ + for(int i = -100000; i < 100000; i++){ + Location tempLoc = new Location(Bukkit.getWorld("world"),i,100,i); + String name = "spring"; + instances.put(tempLoc, name); + } + } + + //开服的时候将文件的数据读入 + public CropManager(FileConfiguration data) { + FileConfiguration config = CustomCrops.instance.getConfig(); + File file = new File(CustomCrops.instance.getDataFolder(), "crop-data.yml"); + data = YamlConfiguration.loadConfiguration(file); + try { + for (String world : config.getStringList("config.whitelist-worlds")) { + CropManager.instances = new ConcurrentHashMap(); + if(data.getConfigurationSection(world) != null){ + for (String coordinate : data.getConfigurationSection(world).getKeys(false)) { + Location tempLocation = new Location(Bukkit.getWorld(world), (double)Integer.parseInt(coordinate.split(",")[0]), (double)Integer.parseInt(coordinate.split(",")[1]), (double)Integer.parseInt(coordinate.split(",")[2])); + String season = data.getString(world + "." + coordinate); + CropManager.instances.put(tempLocation, season); + } + } + } + } + catch (Exception e) { + CropManager.instances = new ConcurrentHashMap(); + e.printStackTrace(); + } + saveData(); + } + /* + //根据世界名获取所有的农作物 + public static List getCrops(World world){ + FileConfiguration config = CustomCrops.instance.getConfig(); + File file = new File(CustomCrops.instance.getDataFolder(), "crop-data.yml"); + FileConfiguration data; + data = YamlConfiguration.loadConfiguration(file); + List locations = new ArrayList(); + if (config.getStringList("config.whitelist-worlds").contains(world.getName())){ + if(data.contains(world.getName())){ + data.getConfigurationSection(world.getName()).getKeys(false).forEach(key ->{ + String[] string_list = key.split(","); + if (config.getBoolean("config.only-grow-in-loaded-chunks")){ + if (world.isChunkLoaded(Integer.parseInt(string_list[0])/16, Integer.parseInt(string_list[2])/16)){ + locations.add(new Location(world, Double.parseDouble(string_list[0]),Double.parseDouble(string_list[1]),Double.parseDouble(string_list[2]))); + } + }else { + locations.add(new Location(world, Double.parseDouble(string_list[0]),Double.parseDouble(string_list[1]),Double.parseDouble(string_list[2]))); + } + }); + } + } + return locations; + } + */ + //保存数据 + public static void saveData(){ + File file = new File(CustomCrops.instance.getDataFolder(), "crop-data.yml"); + FileConfiguration data; + data = YamlConfiguration.loadConfiguration(file); + if (CropManager.instances != null) { + //性能更高 + Set> en = instances.entrySet(); + for(Map.Entry entry : en){ + data.set(entry.getKey().getWorld().getName() + "." + entry.getKey().getBlockX() + "," + entry.getKey().getBlockY()+ ","+entry.getKey().getBlockZ(), entry.getValue()); + } + } + else { + CropManager.instances = new ConcurrentHashMap(); + Bukkit.getConsoleSender().sendMessage("错误:空数据"); + } + try { + data.save(file); + } + catch (IOException e) { + e.printStackTrace(); + CustomCrops.instance.getLogger().warning("农作物数据保存出错"); + } + } + public static void putInstance(Location location, String season) { + CropManager.instances.put(location, season); + } + //清理无效的农作物并生长 + public static void CropGrow() { + /* + 阶段1:更新数据 + */ + long start1 = System.currentTimeMillis(); + FileConfiguration config = CustomCrops.instance.getConfig(); + File file = new File(CustomCrops.instance.getDataFolder(), "crop-data.yml"); + FileConfiguration data; + data = YamlConfiguration.loadConfiguration(file); + if (CropManager.instances != null) { + //性能更高 + Set> en = instances.entrySet(); + for(Map.Entry entry : en){ + Location key = entry.getKey(); + data.set(key.getWorld().getName() + "." + key.getBlockX() + "," + key.getBlockY()+ ","+ key.getBlockZ(), entry.getValue()); + } + } + long finish1 = System.currentTimeMillis(); + MessageManager.consoleMessage("&#ccfbff-#ef96c5&[CustomCrops|性能监测] &f农作物数据更新耗时&a" + String.valueOf(finish1-start1) + "&fms",Bukkit.getConsoleSender()); + /* + 阶段2:清理数据内无效的农作物 + */ + long start2 = System.currentTimeMillis(); + + List locations = new ArrayList(); + + ConfigManager.Config.worlds.forEach(worldName ->{ + if(data.contains(worldName)){ + World world = Bukkit.getWorld(worldName); + data.getConfigurationSection(worldName).getKeys(false).forEach(key ->{ + String[] string_list = StringUtils.split(key,","); + if (world.isChunkLoaded(Integer.parseInt(string_list[0])/16, Integer.parseInt(string_list[2])/16)){ + Location tempLoc = new Location(world,Double.parseDouble(string_list[0]),Double.parseDouble(string_list[1]),Double.parseDouble(string_list[2])); + if(tempLoc.getBlock().getType() != Material.TRIPWIRE){ + CropManager.instances.remove(tempLoc); + data.set(worldName+"."+string_list[0]+","+string_list[1]+","+string_list[2], null); + }else { + locations.add(new Location(world, Double.parseDouble(string_list[0]),Double.parseDouble(string_list[1]),Double.parseDouble(string_list[2]))); + } + } + }); + } + }); + long finish2 = System.currentTimeMillis(); + MessageManager.consoleMessage("&#ccfbff-#ef96c5&[CustomCrops|性能监测] &f农作物缓存清理耗时&a" + String.valueOf(finish2-start2) + "&fms",Bukkit.getConsoleSender()); + /* + 阶段3:保存文件 + */ + try{ + data.save(file); + }catch (IOException e){ + e.printStackTrace(); + CustomCrops.instance.getLogger().warning("农作物缓存清理保存出错!"); + } + /* + 阶段4:农作物生长判断 + */ + long start3 = System.currentTimeMillis(); + BukkitScheduler bukkitScheduler = Bukkit.getScheduler(); + ConfigManager.Config.worlds.forEach(worldName -> { + + World world = Bukkit.getWorld(worldName); + locations.forEach(seedLocation -> { + + Location potLocation = seedLocation.clone().subtract(0,1,0); + Block seedBlock = seedLocation.getBlock(); + Block potBlock = potLocation.getBlock(); + + String[] seasons = StringUtils.split(data.getString(worldName + "." + seedLocation.getBlockX() + "," + seedLocation.getBlockY() + "," + seedLocation.getBlockZ()),","); + + if (CustomBlock.byAlreadyPlaced(potBlock) != null && CustomBlock.byAlreadyPlaced(seedBlock) != null){ + String seedNamespace = CustomBlock.byAlreadyPlaced(seedBlock).getNamespacedID(); + if (CustomBlock.byAlreadyPlaced(potBlock).getNamespacedID().equalsIgnoreCase(ConfigManager.Config.watered_pot) && seedNamespace.contains("stage")){ + if (seedNamespace.equalsIgnoreCase(ConfigManager.Config.dead)){ + return; + } + + String[] split = StringUtils.split(seedNamespace,":"); + String[] cropNameList = StringUtils.split(split[1],"_"); + + Label_out: + if(ConfigManager.Config.season){ + if(ConfigManager.Config.greenhouse){ + for(int i = 1; i <= ConfigManager.Config.range; i++){ + Location tempLocation = seedLocation.clone().add(0,i,0); + if (CustomBlock.byAlreadyPlaced(tempLocation.getBlock()) != null){ + if(CustomBlock.byAlreadyPlaced(tempLocation.getBlock()).getNamespacedID().equalsIgnoreCase(ConfigManager.Config.glass)){ + break Label_out; + } + } + } + } + boolean wrongSeason = true; + for(String season : seasons){ + if (Objects.equals(season, ConfigManager.Config.current)) { + wrongSeason = false; + break; + } + } + if(wrongSeason){ + bukkitScheduler.callSyncMethod(CustomCrops.instance, () -> { + CustomBlock.remove(seedLocation); + CustomBlock.place(ConfigManager.Config.dead, seedLocation); + return null; + }); + return; + } + } + int nextStage = Integer.parseInt(cropNameList[2]) + 1; + if (CustomBlock.getInstance( split[0] +":"+cropNameList[0] + "_stage_" + nextStage) != null) { + bukkitScheduler.callSyncMethod(CustomCrops.instance, () ->{ + CustomBlock.remove(potLocation); + CustomBlock.place(ConfigManager.Config.pot, potLocation); + if(Math.random()< ConfigManager.Config.grow_chance){ + CustomBlock.remove(seedLocation); + CustomBlock.place(split[0] + ":" + cropNameList[0] + "_stage_" + nextStage,seedLocation); + } + return null; + }); + }else if(ConfigManager.Config.big){ + //农作物巨大化 + if(config.getConfigurationSection("crops." + cropNameList[0]).getKeys(false).contains("gigantic")){ + bukkitScheduler.callSyncMethod(CustomCrops.instance, () ->{ + CustomBlock.remove(potLocation); + CustomBlock.place(ConfigManager.Config.pot, potLocation); + if(ConfigManager.Config.big_chance > Math.random()){ + CustomBlock.remove(seedLocation); + CustomBlock.place(config.getString("crops." + cropNameList[0] + ".gigantic"),seedLocation); + } + return null; + }); + } + } + }else if(CustomBlock.byAlreadyPlaced(potBlock).getNamespacedID().equalsIgnoreCase(ConfigManager.Config.pot) && seedNamespace.contains("stage")){ + if (seedNamespace.equalsIgnoreCase(ConfigManager.Config.dead)){ + return; + } + if(ConfigManager.Config.season) { + if(ConfigManager.Config.greenhouse){ + for(int i = 1; i <= ConfigManager.Config.range; i++){ + Location tempLocation = seedLocation.clone().add(0,i,0); + if (CustomBlock.byAlreadyPlaced(tempLocation.getBlock()) != null){ + if(CustomBlock.byAlreadyPlaced(tempLocation.getBlock()).getNamespacedID().equalsIgnoreCase(ConfigManager.Config.glass)){ + return; + } + } + } + } + boolean wrongSeason = true; + for (String season : seasons) { + if (Objects.equals(season, ConfigManager.Config.current)) { + wrongSeason = false; + break; + } + } + if (wrongSeason) { + bukkitScheduler.callSyncMethod(CustomCrops.instance, () -> { + CustomBlock.remove(seedLocation); + CustomBlock.place(ConfigManager.Config.dead, seedLocation); + return null; + }); + } + } + } + } + }); + }); + long finish3 = System.currentTimeMillis(); + MessageManager.consoleMessage("&#ccfbff-#ef96c5&[CustomCrops|性能监测] &f农作物生长判断耗时&a" + String.valueOf(finish3-start3) + "&fms",Bukkit.getConsoleSender()); + } + /* + //清理无效的农作物 + public static void cleanLoadedCache() { + + File file = new File(CustomCrops.instance.getDataFolder(), "crop-data.yml"); + FileConfiguration data; + data = YamlConfiguration.loadConfiguration(file); + + ConfigManager.Config.worlds.forEach(worldName ->{ + if(data.contains(worldName)){ + World world = Bukkit.getWorld(worldName); + data.getConfigurationSection(worldName).getKeys(false).forEach(key ->{ + String[] string_list = StringUtils.split(key,","); + if (world.isChunkLoaded(Integer.parseInt(string_list[0])/16, Integer.parseInt(string_list[2])/16)){ + Location tempLoc = new Location(world,Double.parseDouble(string_list[0]),Double.parseDouble(string_list[1]),Double.parseDouble(string_list[2])); + if(world.getBlockAt(tempLoc).getType() != Material.TRIPWIRE){ + CropManager.instances.remove(tempLoc); + data.set(worldName+"."+string_list[0]+","+string_list[1]+","+string_list[2], null); + } + } + }); + } + }); + try{ + data.save(file); + }catch (IOException e){ + e.printStackTrace(); + CustomCrops.instance.getLogger().warning("农作物缓存清理保存出错!"); + } + } + */ +} diff --git a/src/main/java/net/momirealms/customcrops/datamanager/MaxCropsPerChunk.java b/src/main/java/net/momirealms/customcrops/datamanager/MaxCropsPerChunk.java new file mode 100644 index 0000000..07a51dd --- /dev/null +++ b/src/main/java/net/momirealms/customcrops/datamanager/MaxCropsPerChunk.java @@ -0,0 +1,42 @@ +package net.momirealms.customcrops.datamanager; + +import dev.lone.itemsadder.api.CustomBlock; +import net.momirealms.customcrops.ConfigManager; +import org.bukkit.Location; +import org.bukkit.block.Block; + +public class MaxCropsPerChunk { + + public static boolean maxCropsPerChunk(Location location){ + + if(!ConfigManager.Config.limit){ + return false; + } + int maxY = ConfigManager.Config.maxh; + int minY = ConfigManager.Config.minh; + int maxAmount = ConfigManager.Config.max_crop; + + int n = 1; + + Location chunkLocation = new Location(location.getWorld(),location.getChunk().getX()*16,minY,location.getChunk().getZ()*16); + + Label_out: + for (int i = 0; i < 16; ++i) { + for (int j = 0; j < 16; ++j) { + Location square = chunkLocation.clone().add(i, 0.0, j); + for (int k = minY; k <= maxY; ++k) { + square.add(0.0, 1.0, 0.0); + Block b = square.getBlock(); + if(CustomBlock.byAlreadyPlaced(b)!= null){ + if (CustomBlock.byAlreadyPlaced(b).getNamespacedID().contains("stage")) { + if (n++ > maxAmount) { + break Label_out; + } + } + } + } + } + } + return n > maxAmount; + } +} diff --git a/src/main/java/net/momirealms/customcrops/datamanager/MaxSprinklersPerChunk.java b/src/main/java/net/momirealms/customcrops/datamanager/MaxSprinklersPerChunk.java new file mode 100644 index 0000000..f31110e --- /dev/null +++ b/src/main/java/net/momirealms/customcrops/datamanager/MaxSprinklersPerChunk.java @@ -0,0 +1,43 @@ +package net.momirealms.customcrops.datamanager; + +import net.momirealms.customcrops.ConfigManager; +import net.momirealms.customcrops.IAFurniture; +import org.bukkit.Location; +import org.bukkit.World; + +public class MaxSprinklersPerChunk { + + public static boolean maxSprinklersPerChunk(Location location){ + + if(!ConfigManager.Config.limit){ + return false; + } + int maxY = ConfigManager.Config.maxh; + int minY = ConfigManager.Config.minh; + int maxAmount = ConfigManager.Config.max_sprinkler; + + int n = 1; + + Location chunkLocation = new Location(location.getWorld(),location.getChunk().getX()*16,minY,location.getChunk().getZ()*16); + World world = location.getWorld(); + + Label_out: + for (int i = 0; i < 16; ++i) { + for (int j = 0; j < 16; ++j) { + Location square = chunkLocation.clone().add(i+0.5, 0.5, j+0.5); + for (int k = minY; k <= maxY; ++k) { + square.add(0.0, 1.0, 0.0); + if(IAFurniture.getFromLocation(square, world)){ + if (n++ > maxAmount) { + break Label_out; + } + } + } + } + } + return n > maxAmount; + } + public static boolean alreadyPlaced(Location location){ + return IAFurniture.getFromLocation(location.clone().add(0.5, 1.5, 0.5), location.getWorld()); + } +} diff --git a/src/main/java/net/momirealms/customcrops/datamanager/NextSeason.java b/src/main/java/net/momirealms/customcrops/datamanager/NextSeason.java new file mode 100644 index 0000000..b1e139f --- /dev/null +++ b/src/main/java/net/momirealms/customcrops/datamanager/NextSeason.java @@ -0,0 +1,29 @@ +package net.momirealms.customcrops.datamanager; + +import net.momirealms.customcrops.ConfigManager; +import net.momirealms.customcrops.CustomCrops; +import org.bukkit.configuration.file.FileConfiguration; + +import java.util.Objects; + +public class NextSeason { + public static void changeSeason(){ + + FileConfiguration config = CustomCrops.instance.getConfig(); + String currentSeason = ConfigManager.Config.current; + String nextSeason = switch (Objects.requireNonNull(currentSeason)) { + case "spring" -> "summer"; + case "summer" -> "autumn"; + case "autumn" -> "winter"; + case "winter" -> "spring"; + default -> null; + }; + if(nextSeason != null){ + config.set("current-season", nextSeason); + ConfigManager.Config.current = nextSeason; + CustomCrops.instance.saveConfig(); + }else { + CustomCrops.instance.getLogger().warning("季节配置文件出错!"); + } + } +} diff --git a/src/main/java/net/momirealms/customcrops/datamanager/SprinklerManager.java b/src/main/java/net/momirealms/customcrops/datamanager/SprinklerManager.java new file mode 100644 index 0000000..e709fe2 --- /dev/null +++ b/src/main/java/net/momirealms/customcrops/datamanager/SprinklerManager.java @@ -0,0 +1,223 @@ +package net.momirealms.customcrops.datamanager; + +import dev.lone.itemsadder.api.CustomBlock; +import net.momirealms.customcrops.ConfigManager; +import net.momirealms.customcrops.CustomCrops; +import net.momirealms.customcrops.IAFurniture; +import net.momirealms.customcrops.MessageManager; +import org.apache.commons.lang.StringUtils; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.World; +import org.bukkit.configuration.file.FileConfiguration; +import org.bukkit.configuration.file.YamlConfiguration; + +import java.io.File; +import java.io.IOException; +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; + +public class SprinklerManager { + + public static ConcurrentHashMap instances; + + //10W性能测试 + public static void testData_3(){ + for(int i = -50000; i < 50000; i++){ + Location tempLoc = new Location(Bukkit.getWorld("world"),i,100,i); + String name = "s1"; + instances.put(tempLoc, name); + } + } + + //开服的时候将文件的数据读入 + public SprinklerManager(FileConfiguration data) { + + FileConfiguration config = CustomCrops.instance.getConfig(); + File file = new File(CustomCrops.instance.getDataFolder(), "sprinkler-data.yml"); + data = YamlConfiguration.loadConfiguration(file); + + try { + for (String world : config.getStringList("config.whitelist-worlds")) { + SprinklerManager.instances = new ConcurrentHashMap(); + if(data.getConfigurationSection(world) != null){ + for (String coordinate : data.getConfigurationSection(world).getKeys(false)) { + Location tempLocation = new Location(Bukkit.getWorld(world), Integer.parseInt(coordinate.split(",")[0]), Integer.parseInt(coordinate.split(",")[1]), Integer.parseInt(coordinate.split(",")[2])); + String type = data.getString(world + "." + coordinate); + SprinklerManager.instances.put(tempLocation, type); + } + } + } + } + catch (Exception e) { + SprinklerManager.instances = new ConcurrentHashMap(); + e.printStackTrace(); + } + saveData(); + } + /* + //根据世界名获取所有的洒水器 + public static List getSprinklers(World world){ + FileConfiguration config = CustomCrops.instance.getConfig(); + File file = new File(CustomCrops.instance.getDataFolder(), "sprinkler-data.yml"); + FileConfiguration data; + data = YamlConfiguration.loadConfiguration(file); + List locations = new ArrayList(); + if (config.getStringList("config.whitelist-worlds").contains(world.getName())){ + if(data.contains(world.getName())){ + data.getConfigurationSection(world.getName()).getKeys(false).forEach(key ->{ + String[] string_list = key.split(","); + //只返回被加载的区块中的洒水器坐标 + if (config.getBoolean("config.only-grow-in-loaded-chunks")){ + if (world.isChunkLoaded(Integer.parseInt(string_list[0])/16, Integer.parseInt(string_list[2])/16)){ + locations.add(new Location(world, Double.parseDouble(string_list[0]),Double.parseDouble(string_list[1]),Double.parseDouble(string_list[2]))); + } + }else { + locations.add(new Location(world, Double.parseDouble(string_list[0]),Double.parseDouble(string_list[1]),Double.parseDouble(string_list[2]))); + } + }); + } + } + return locations; + } + */ + //保存数据 + public static void saveData(){ + File file = new File(CustomCrops.instance.getDataFolder(), "sprinkler-data.yml"); + FileConfiguration data; + data = YamlConfiguration.loadConfiguration(file); + if (SprinklerManager.instances != null) { + //性能更高 + Set> en = instances.entrySet(); + for(Map.Entry entry : en){ + data.set(entry.getKey().getWorld().getName() + "." + entry.getKey().getBlockX() + "," + entry.getKey().getBlockY()+ ","+entry.getKey().getBlockZ(), entry.getValue()); + } + } + else { + SprinklerManager.instances = new ConcurrentHashMap(); + Bukkit.getConsoleSender().sendMessage("错误:空数据"); + } + try { + data.save(file); + } + catch (IOException e) { + e.printStackTrace(); + CustomCrops.instance.getLogger().warning("洒水器数据保存出错"); + } + } + public static void putInstance(Location location, String type) { + SprinklerManager.instances.put(location, type); + } + public static void SprinklerWork() { + /* + 阶段1:更新数据 + */ + long start1 = System.currentTimeMillis(); + File file = new File(CustomCrops.instance.getDataFolder(), "sprinkler-data.yml"); + FileConfiguration data; + data = YamlConfiguration.loadConfiguration(file); + if (SprinklerManager.instances != null) { + //性能更高 + Set> en = instances.entrySet(); + for(Map.Entry entry : en){ + data.set(entry.getKey().getWorld().getName() + "." + entry.getKey().getBlockX() + "," + entry.getKey().getBlockY()+ ","+entry.getKey().getBlockZ(), entry.getValue()); + } + } + long finish1 = System.currentTimeMillis(); + MessageManager.consoleMessage("&#ccfbff-#ef96c5&[CustomCrops|性能监测] &f洒水器数据更新耗时&a" + String.valueOf(finish1-start1) + "&fms",Bukkit.getConsoleSender()); + /* + 阶段2:清理数据内无效的农作物 + */ + Bukkit.getScheduler().callSyncMethod(CustomCrops.instance,()->{ + long start2 = System.currentTimeMillis(); + //map不能一边循环一边删除 + //创建一个新的HashSet,用作循环 + //检测碰撞体积需要同步 + List locations = new ArrayList(); + + ConfigManager.Config.worlds.forEach(worldName ->{ + if(data.contains(worldName)){ + World world = Bukkit.getWorld(worldName); + data.getConfigurationSection(worldName).getKeys(false).forEach(key ->{ + String[] string_list = StringUtils.split(key,","); + if (world.isChunkLoaded(Integer.parseInt(string_list[0])/16, Integer.parseInt(string_list[2])/16)){ + Location tempLoc = new Location(world,Double.parseDouble(string_list[0])+0.5,Double.parseDouble(string_list[1])+0.5,Double.parseDouble(string_list[2])+0.5); + if(!IAFurniture.getFromLocation(tempLoc, world)){ + SprinklerManager.instances.remove(tempLoc); + data.set(worldName+"."+string_list[0]+","+string_list[1]+","+string_list[2], null); + }else { + locations.add(new Location(world, Double.parseDouble(string_list[0]),Double.parseDouble(string_list[1]),Double.parseDouble(string_list[2]))); + } + } + }); + } + }); + /* + Set key = new HashSet(instances.keySet()); + for(Location u_key : key) { + if (!IAFurniture.getFromLocation(u_key.clone().add(0.5,0.5,0.5), u_key.getWorld())){ + SprinklerManager.instances.remove(u_key); + data.set(u_key.getWorld().getName()+"."+u_key.getBlockX()+","+u_key.getBlockY()+","+u_key.getBlockZ(), null); + }else { + locations.add(new Location(world, Double.parseDouble(string_list[0]),Double.parseDouble(string_list[1]),Double.parseDouble(string_list[2]))); + } + } + */ + long finish2 = System.currentTimeMillis(); + MessageManager.consoleMessage("&#ccfbff-#ef96c5&[CustomCrops|性能监测] &f洒水器缓存清理耗时&a" + String.valueOf(finish2-start2) + "&fms",Bukkit.getConsoleSender()); + + Bukkit.getScheduler().runTaskAsynchronously(CustomCrops.instance,()->{ + /* + 阶段3:保存数据 + */ + try{ + data.save(file); + }catch (IOException e){ + e.printStackTrace(); + CustomCrops.instance.getLogger().warning("洒水器缓存清理保存出错!"); + } + /* + 阶段4:洒水器工作 + */ + long start3 = System.currentTimeMillis(); + ConfigManager.Config.worlds.forEach(worldName -> { + + World world = Bukkit.getWorld(worldName); + locations.forEach(location -> { + + String type = data.getString(worldName + "." + location.getBlockX() + "," + location.getBlockY() + "," + location.getBlockZ()); + if(type.equals("s1")){ + for(int i = -1; i <= 1;i++){ + for (int j = -1; j <= 1; j++){ + Location tempLoc = location.clone().add(i,-1,j); + waterPot(tempLoc, world); + } + } + }else{ + for(int i = -2; i <= 2;i++){ + for (int j = -2; j <= 2; j++){ + Location tempLoc = location.clone().add(i,-1,j); + waterPot(tempLoc, world); + } + } + } + }); + }); + long finish3 = System.currentTimeMillis(); + MessageManager.consoleMessage("&#ccfbff-#ef96c5&[CustomCrops|性能监测] &f洒水器工作耗时&a" + String.valueOf(finish3-start3) + "&fms",Bukkit.getConsoleSender()); + }); + return null; + }); + } + private static void waterPot(Location tempLoc, World world) { + if(CustomBlock.byAlreadyPlaced(tempLoc.getBlock()) != null){ + if(CustomBlock.byAlreadyPlaced(tempLoc.getBlock()).getNamespacedID().equalsIgnoreCase(ConfigManager.Config.pot)){ + Bukkit.getScheduler().callSyncMethod(CustomCrops.instance,()->{ + CustomBlock.remove(tempLoc); + CustomBlock.place((ConfigManager.Config.watered_pot), tempLoc); + return null; + }); + } + } + } +} diff --git a/src/main/java/net/momirealms/customcrops/integrations/IntegrationCheck.java b/src/main/java/net/momirealms/customcrops/integrations/IntegrationCheck.java new file mode 100644 index 0000000..eca0e63 --- /dev/null +++ b/src/main/java/net/momirealms/customcrops/integrations/IntegrationCheck.java @@ -0,0 +1,43 @@ +package net.momirealms.customcrops.integrations; + +import net.momirealms.customcrops.ConfigManager; +import org.bukkit.Location; +import org.bukkit.entity.Player; + +public class IntegrationCheck { + + //收获权限检测 + public static boolean HarvestCheck(Location location, Player player){ + if(ConfigManager.Config.king){ + if(KingdomsXIntegrations.checkKDBuild(location,player)){ + return true; + } + } + if(ConfigManager.Config.res){ + if(ResidenceIntegrations.checkResHarvest(location,player)){ + return true; + } + } + if(ConfigManager.Config.wg){ + return WorldGuardIntegrations.checkWGHarvest(location, player); + } + return false; + } + //种植等权限检测 + public static boolean PlaceCheck(Location location, Player player){ + if(ConfigManager.Config.king){ + if(KingdomsXIntegrations.checkKDBuild(location,player)){ + return true; + } + } + if(ConfigManager.Config.res){ + if(ResidenceIntegrations.checkResBuild(location,player)){ + return true; + } + } + if(ConfigManager.Config.wg){ + return WorldGuardIntegrations.checkWGBuild(location, player); + } + return false; + } +} diff --git a/src/main/java/net/momirealms/customcrops/integrations/KingdomsXIntegrations.java b/src/main/java/net/momirealms/customcrops/integrations/KingdomsXIntegrations.java new file mode 100644 index 0000000..8d77dd3 --- /dev/null +++ b/src/main/java/net/momirealms/customcrops/integrations/KingdomsXIntegrations.java @@ -0,0 +1,25 @@ +package net.momirealms.customcrops.integrations; + +import org.bukkit.Location; +import org.bukkit.entity.Player; +import org.kingdoms.constants.group.Kingdom; +import org.kingdoms.constants.land.Land; +import org.kingdoms.constants.player.KingdomPlayer; + +public class KingdomsXIntegrations { + public static boolean checkKDBuild(Location location, Player player){ + KingdomPlayer kp = KingdomPlayer.getKingdomPlayer(player); + Land land = Land.getLand(location); + if (land == null) return false; + if (land.isClaimed()) { + Kingdom cropKingdom = land.getKingdom(); + if (kp.getKingdom() != null) { + Kingdom kingdom = kp.getKingdom(); + return kingdom != cropKingdom; + }else { + return true; + } + } + return false; + } +} diff --git a/src/main/java/net/momirealms/customcrops/integrations/ResidenceIntegrations.java b/src/main/java/net/momirealms/customcrops/integrations/ResidenceIntegrations.java new file mode 100644 index 0000000..358ccd6 --- /dev/null +++ b/src/main/java/net/momirealms/customcrops/integrations/ResidenceIntegrations.java @@ -0,0 +1,31 @@ +package net.momirealms.customcrops.integrations; + +import com.bekvon.bukkit.residence.containers.Flags; +import com.bekvon.bukkit.residence.protection.ClaimedResidence; +import com.bekvon.bukkit.residence.protection.FlagPermissions; +import com.bekvon.bukkit.residence.protection.ResidencePermissions; +import org.bukkit.Location; +import org.bukkit.entity.Player; + +public class ResidenceIntegrations { + public static boolean checkResBuild(Location location, Player player){ + FlagPermissions.addFlag("build"); + ClaimedResidence res = com.bekvon.bukkit.residence.Residence.getInstance().getResidenceManager().getByLoc(location); + if(res!=null){ + ResidencePermissions perms = res.getPermissions(); + boolean hasPermission = perms.playerHas(player, Flags.build, true); + return !hasPermission; + } + return false; + } + public static boolean checkResHarvest(Location location, Player player){ + FlagPermissions.addFlag("harvest"); + ClaimedResidence res = com.bekvon.bukkit.residence.Residence.getInstance().getResidenceManager().getByLoc(location); + if(res!=null){ + ResidencePermissions perms = res.getPermissions(); + boolean hasPermission = perms.playerHas(player, Flags.harvest, true); + return !hasPermission; + } + return false; + } +} diff --git a/src/main/java/net/momirealms/customcrops/integrations/WorldGuardIntegrations.java b/src/main/java/net/momirealms/customcrops/integrations/WorldGuardIntegrations.java new file mode 100644 index 0000000..6b0b958 --- /dev/null +++ b/src/main/java/net/momirealms/customcrops/integrations/WorldGuardIntegrations.java @@ -0,0 +1,30 @@ +package net.momirealms.customcrops.integrations; + +import com.sk89q.worldedit.bukkit.BukkitAdapter; +import com.sk89q.worldguard.LocalPlayer; +import com.sk89q.worldguard.WorldGuard; +import com.sk89q.worldguard.bukkit.WorldGuardPlugin; +import com.sk89q.worldguard.protection.flags.Flags; +import com.sk89q.worldguard.protection.regions.RegionContainer; +import com.sk89q.worldguard.protection.regions.RegionQuery; +import org.bukkit.Location; +import org.bukkit.entity.Player; + +public class WorldGuardIntegrations { + public static boolean checkWGBuild(Location loc,Player player){ + + LocalPlayer localPlayer = WorldGuardPlugin.inst().wrapPlayer(player); + RegionContainer container = WorldGuard.getInstance().getPlatform().getRegionContainer(); + RegionQuery query = container.createQuery(); + + return !query.testState(BukkitAdapter.adapt(loc), localPlayer, Flags.BUILD); + } + public static boolean checkWGHarvest(Location loc,Player player){ + + LocalPlayer localPlayer = WorldGuardPlugin.inst().wrapPlayer(player); + RegionContainer container = WorldGuard.getInstance().getPlatform().getRegionContainer(); + RegionQuery query = container.createQuery(); + + return !query.testState(BukkitAdapter.adapt(loc), localPlayer, Flags.BLOCK_BREAK); + } +} diff --git a/src/main/java/net/momirealms/customcrops/libs/minedown/MineDown.java b/src/main/java/net/momirealms/customcrops/libs/minedown/MineDown.java new file mode 100644 index 0000000..1e0847a --- /dev/null +++ b/src/main/java/net/momirealms/customcrops/libs/minedown/MineDown.java @@ -0,0 +1,499 @@ +package net.momirealms.customcrops.Libs.minedown; + +/* + * Copyright (c) 2017 Max Lee (https://github.com/Phoenix616) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +import net.md_5.bungee.api.ChatColor; +import net.md_5.bungee.api.chat.BaseComponent; +import net.md_5.bungee.api.chat.ClickEvent; +import net.md_5.bungee.api.chat.HoverEvent; + +import java.util.Map; + +/** + *

MineDown

+ * A MarkDown inspired markup for Minecraft chat components + *

+ * This lets you convert string messages into chat components by using a custom mark up syntax + * which is loosely based on MarkDown while still supporting legacy formatting codes. + * + * + * + * + * + * + * + * + * + * + * + * + *
Inline Formatting
Color legacy &6Text {@link ChatColor} codes
Color &gold&Text {@link ChatColor} codes
RGB Hex Color &ff00ff&Text Full hexadecimal format
RGB Hex Color &f0f&Text Short format (equivalent to long one)
Bold **Text**
Italic ##Text##
Underlined __Text__
Strikethrough ~~Text~~
Obfuscated ??Text??
+ * + *

Events

+ * You can define click and hover events with the commonly used MarkDown link syntax. + *

+ * + * + * + * + * + * + * + *
Simple Syntax
General syntax [Text](text-color text-formatting... link hover text)
Simple Link [Text](https://example.com)
Simple Command [Text](/command to run)
Link + Hover [Text](https://example.com Hover Text)
Text formatting + Link + Hover [Text](blue underline https://example.com Hover Text)
+ *

+ * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Advanced Syntax
General syntax [Text](action=value) {@link ClickEvent.Action}, {@link HoverEvent.Action}
Link [Text](open_url=https://example.com)
Color [Text](color=red)
RGB Hex Color [Text](color=#ff00ff) Full hexadecimal format
RGB Hex Color [Text](color=#f0f) Short format (equivalent to long one)
Formatting [Text](format=underline,bold)
Font [Text](format=underline,bold)
Run Command [Text](run_command=/command string)
Suggest Command [Text](suggest_command=/command)
Simple Hover [Text](hover=Hover Text)
Hover Text [Text](show_text=Hover Text)
Hover Entity Info [Text](show_entity=uuid:pig Name)
Hover Item Info [Text](show_item=stone*2 nbt...)
+ *

+ * All advanced settings can be chained/included in a event definition. + * You can't however add multiple different colors or click and hover actions! + */ +public class MineDown { + public static final String FONT_PREFIX = "font="; + public static final String COLOR_PREFIX = "color="; + public static final String FORMAT_PREFIX = "format="; + public static final String HOVER_PREFIX = "hover="; + public static final String INSERTION_PREFIX = "insert="; + + private String message; + private final Replacer replacer = new Replacer(); + private final MineDownParser parser = new MineDownParser(); + private BaseComponent[] baseComponents = null; + private boolean replaceFirst = Boolean.getBoolean("de.themoep.minedown.replacefirst"); + + /** + * Create a new MineDown builder with a certain message + * @param message The message to parse + */ + public MineDown(String message) { + this.message = message; + } + + /** + * Parse a MineDown string to components + * @param message The message to translate + * @param replacements Optional placeholder replacements + * @return The parsed components + */ + public static BaseComponent[] parse(String message, String... replacements) { + return new MineDown(message).replace(replacements).toComponent(); + } + + /** + * Convert components to a MineDown string + * @param components The components to convert + * @return The components represented as a MineDown string + */ + public static String stringify(BaseComponent[] components) { + return new MineDownStringifier().stringify(components); + } + + /** + * Parse and convert the message to the component + * @return The parsed component message + */ + public BaseComponent[] toComponent() { + if (baseComponents() == null) { + if (replaceFirst()) { + Replacer componentReplacer = new Replacer(); + for (Map.Entry entry : replacer().componentReplacements().entrySet()) { + componentReplacer.replace(entry.getKey(), stringify(entry.getValue())); + } + baseComponents = parser().parse(componentReplacer.replaceIn(replacer().replaceIn(message()))).create(); + } else { + baseComponents = replacer().replaceIn(parser().parse(message()).create()); + } + } + return baseComponents(); + } + + /** + * Remove a cached component and re-parse the next time {@link #toComponent} is called + */ + private void reset() { + baseComponents = null; + } + + /** + * Set whether or not replacements should be replaced before or after the components are created. + * When replacing first it will not replace any placeholders with component replacement values! + * Default is after. (replaceFirst = false) + * @param replaceFirst Whether or not to replace first or parse first + * @return The MineDown instance + */ + public MineDown replaceFirst(boolean replaceFirst) { + reset(); + this.replaceFirst = replaceFirst; + return this; + } + + /** + * Get whether or not replacements should be replaced before or after the components are created. + * When replacing first it will not replace any placeholders with component replacement values! + * Default is after. (replaceFirst = false) + * @return Whether or not to replace first or parse first + */ + public boolean replaceFirst() { + return replaceFirst; + } + + /** + * Add an array with placeholders and values that should get replaced in the message + * @param replacements The replacements, nth element is the placeholder, n+1th the value + * @return The MineDown instance + */ + public MineDown replace(String... replacements) { + reset(); + replacer().replace(replacements); + return this; + } + + /** + * Add a map with placeholders and values that should get replaced in the message + * @param replacements The replacements mapped placeholder to value + * @return The MineDown instance + */ + public MineDown replace(Map replacements) { + reset(); + replacer().replace(replacements); + return this; + } + + /** + * Add a placeholder to component mapping that should get replaced in the message + * @param placeholder The placeholder to replace + * @param replacement The replacement components + * @return The Replacer instance + */ + public MineDown replace(String placeholder, BaseComponent... replacement) { + reset(); + replacer().replace(placeholder,replacement); + return this; + } + + /** + * Set the placeholder indicator for both prefix and suffix + * @param placeholderIndicator The character to use as a placeholder indicator + * @return The MineDown instance + */ + public MineDown placeholderIndicator(String placeholderIndicator) { + placeholderPrefix(placeholderIndicator); + placeholderSuffix(placeholderIndicator); + return this; + } + + /** + * Set the placeholder indicator's prefix character + * @param placeholderPrefix The character to use as the placeholder indicator's prefix + * @return The MineDown instance + */ + public MineDown placeholderPrefix(String placeholderPrefix) { + reset(); + replacer().placeholderPrefix(placeholderPrefix); + return this; + } + + /** + * Get the placeholder indicator's prefix character + * @return The placeholder indicator's prefix character + */ + public String placeholderPrefix() { + return replacer().placeholderPrefix(); + } + + /** + * Set the placeholder indicator's suffix character + * @param placeholderSuffix The character to use as the placeholder indicator's suffix + * @return The MineDown instance + */ + public MineDown placeholderSuffix(String placeholderSuffix) { + reset(); + replacer().placeholderSuffix(placeholderSuffix); + return this; + } + + /** + * Get the placeholder indicator's suffix character + * @return The placeholder indicator's suffix character + */ + public String placeholderSuffix() { + return replacer().placeholderSuffix(); + } + + /** + * Set whether or not the case of the placeholder should be ignored when replacing + * @param ignorePlaceholderCase Whether or not to ignore the case of the placeholders + * @return The MineDown instance + */ + public MineDown ignorePlaceholderCase(boolean ignorePlaceholderCase) { + reset(); + replacer().ignorePlaceholderCase(ignorePlaceholderCase); + return this; + } + + /** + * Get whether or not the case of the placeholder should be ignored when replacing + * @return Whether or not to ignore the case of the placeholders + */ + public boolean ignorePlaceholderCase() { + return replacer().ignorePlaceholderCase(); + } + + /** + * Enable or disable the translation of legacy color codes + * @param translateLegacyColors Whether or not to translate legacy color codes (Default: true) + * @return The MineDown instance + * @deprecated Use {@link #enable(MineDownParser.Option)} and {@link #disable(MineDownParser.Option)} + */ + @Deprecated + public MineDown translateLegacyColors(boolean translateLegacyColors) { + reset(); + parser().translateLegacyColors(translateLegacyColors); + return this; + } + + /** + * Detect urls in strings and add events to them? (Default: true) + * @param enabled Whether or not to detect URLs and add events to them + * @return The MineDown instance + */ + public MineDown urlDetection(boolean enabled) { + reset(); + parser().urlDetection(enabled); + return this; + } + + /** + * Automatically add http to values of open_url when there doesn't exist any? (Default: true) + * @param enabled Whether or not to automatically add http when missing + * @return The MineDown instance + */ + public MineDown autoAddUrlPrefix(boolean enabled) { + reset(); + parser().autoAddUrlPrefix(enabled); + return this; + } + + /** + * The text to display when hovering over an URL + * @param text The text to display when hovering over an URL + * @return The MineDown instance + */ + public MineDown urlHoverText(String text) { + reset(); + parser().urlHoverText(text); + return this; + } + + /** + * Set the max width the hover text should have. + * Minecraft itself will wrap after 60 characters. + * Won't apply if the text already includes new lines. + * @param hoverTextWidth The url hover text length + * @return The MineDown instance + */ + public MineDown hoverTextWidth(int hoverTextWidth) { + reset(); + parser().hoverTextWidth(hoverTextWidth); + return this; + } + + /** + * Enable an option. Unfilter it if you filtered it before. + * @param option The option to enable + * @return The MineDown instance + */ + public MineDown enable(MineDownParser.Option option) { + reset(); + parser().enable(option); + return this; + } + + /** + * Disable an option. Disabling an option will stop the parser from replacing + * this option's chars in the string. Use {@link #filter(MineDownParser.Option)} to completely + * remove the characters used by this option from the message instead. + * @param option The option to disable + * @return The MineDown instance + */ + public MineDown disable(MineDownParser.Option option) { + reset(); + parser().disable(option); + return this; + } + + /** + * Filter an option. This completely removes the characters of this option from + * the string ignoring whether the option is enabled or not. + * @param option The option to add to the filter + * @return The MineDown instance + */ + public MineDown filter(MineDownParser.Option option) { + reset(); + parser().filter(option); + return this; + } + + /** + * Unfilter an option. Does not enable it! + * @param option The option to remove from the filter + * @return The MineDown instance + */ + public MineDown unfilter(MineDownParser.Option option) { + reset(); + parser().unfilter(option); + return this; + } + + /** + * Set a special character to replace color codes by if translating legacy colors is enabled. + * @param colorChar The character to use as a special color code. (Default: ampersand &) + * @return The MineDown instance + */ + public MineDown colorChar(char colorChar) { + reset(); + parser().colorChar(colorChar); + return this; + } + + /** + * Get the set message that is to be parsed + * @return The to be parsed message + */ + public String message() { + return this.message; + } + + /** + * Set the message that is to be parsed + * @param message The message to be parsed + * @return The MineDown instance + */ + public MineDown message(String message) { + this.message = message; + reset(); + return this; + } + + /** + * Get the replacer instance that is currently used + * @return The currently used replacer instance + */ + public Replacer replacer() { + return this.replacer; + } + + /** + * Get the parser instance that is currently used + * @return The currently used parser instance + */ + public MineDownParser parser() { + return this.parser; + } + + protected BaseComponent[] baseComponents() { + return this.baseComponents; + } + + /** + * Copy all MineDown settings to a new instance + * @return The new MineDown instance with all settings copied + */ + public MineDown copy() { + return new MineDown(message()).copy(this); + } + + /** + * Copy all MineDown settings from another one + * @param from The MineDown to copy from + * @return This MineDown instance + */ + public MineDown copy(MineDown from) { + replacer().copy(from.replacer()); + parser().copy(from.parser()); + return this; + } + + /** + * Get the string that represents the format in MineDown + * @param format The format + * @return The MineDown string or an empty one if it's not a format + */ + public static String getFormatString(ChatColor format) { + if (format == ChatColor.BOLD) { + return "**"; + } else if (format == ChatColor.ITALIC) { + return "##"; + } else if (format == ChatColor.UNDERLINE) { + return "__"; + } else if (format == ChatColor.STRIKETHROUGH) { + return "~~"; + } else if (format == ChatColor.MAGIC) { + return "??"; + } + return ""; + } + + /** + * Get the ChatColor format from a MineDown string + * @param c The character + * @return The ChatColor of that format or null it none was found + */ + public static ChatColor getFormatFromChar(char c) { + switch (c) { + case '~': + return ChatColor.STRIKETHROUGH; + case '_': + return ChatColor.UNDERLINE; + case '*': + return ChatColor.BOLD; + case '#': + return ChatColor.ITALIC; + case '?': + return ChatColor.MAGIC; + } + return null; + } + + /** + * Escape all MineDown formatting in a string. This will escape backslashes too! + * @param string The string to escape in + * @return The string with formatting escaped + */ + public static String escape(String string) { + return new MineDown(string).parser().escape(string); + } +} diff --git a/src/main/java/net/momirealms/customcrops/libs/minedown/MineDownParser.java b/src/main/java/net/momirealms/customcrops/libs/minedown/MineDownParser.java new file mode 100644 index 0000000..5751122 --- /dev/null +++ b/src/main/java/net/momirealms/customcrops/libs/minedown/MineDownParser.java @@ -0,0 +1,1241 @@ +package net.momirealms.customcrops.Libs.minedown; + +/* + * Copyright (c) 2017 Max Lee (https://github.com/Phoenix616) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +import net.md_5.bungee.api.ChatColor; +import net.md_5.bungee.api.chat.BaseComponent; +import net.md_5.bungee.api.chat.ClickEvent; +import net.md_5.bungee.api.chat.ComponentBuilder; +import net.md_5.bungee.api.chat.HoverEvent; +import net.md_5.bungee.api.chat.ItemTag; +import net.md_5.bungee.api.chat.TextComponent; +import net.md_5.bungee.api.chat.hover.content.Entity; +import net.md_5.bungee.api.chat.hover.content.Item; +import net.md_5.bungee.api.chat.hover.content.Text; + +import java.awt.Color; +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.Collections; +import java.util.EnumSet; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.PrimitiveIterator; +import java.util.Set; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + +import static net.momirealms.customcrops.Libs.minedown.MineDown.COLOR_PREFIX; +import static net.momirealms.customcrops.Libs.minedown.MineDown.FONT_PREFIX; +import static net.momirealms.customcrops.Libs.minedown.MineDown.FORMAT_PREFIX; +import static net.momirealms.customcrops.Libs.minedown.MineDown.HOVER_PREFIX; +import static net.momirealms.customcrops.Libs.minedown.MineDown.INSERTION_PREFIX; + +public class MineDownParser { + private static final String RAINBOW = "rainbow"; + + private static final boolean HAS_APPEND_SUPPORT = Util.hasMethod(ComponentBuilder.class, "append", BaseComponent[].class); + private static final boolean HAS_RGB_SUPPORT = Util.hasMethod(ChatColor.class, "of", String.class); + private static final boolean HAS_FONT_SUPPORT = Util.hasMethod(ComponentBuilder.class, "font", String.class); + private static final boolean HAS_INSERTION_SUPPORT = Util.hasMethod(ComponentBuilder.class, "insertion", String.class); + private static final boolean HAS_HOVER_CONTENT_SUPPORT = Util.hasMethod(HoverEvent.class, "getContents"); + + /** + * The character to use as a special color code. (Default: ampersand &) + */ + private char colorChar = '&'; + + /** + * All enabled options + */ + private Set