diff --git a/build.gradle.kts b/build.gradle.kts index a894332..70e8981 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -55,6 +55,10 @@ repositories { maven { url = uri("https://repo.glaremasters.me/repository/towny/") } + maven { + name = "papermc" + url = uri("https://repo.papermc.io/repository/maven-public/") + } } dependencies { @@ -62,7 +66,7 @@ dependencies { api("com.jeff_media:SpigotUpdateChecker:3.0.4") api("de.tr7zw:item-nbt-api:2.15.0") api("cn.handyplus.lib.adapter:FoliaLib:1.2.0") - compileOnly("org.spigotmc:spigot-api:1.20.5-R0.1-SNAPSHOT") + compileOnly("io.papermc.paper:paper-api:1.21.5-R0.1-SNAPSHOT") compileOnly("io.lumine:Mythic-Dist:5.9.0") compileOnly("com.sk89q.worldguard:worldguard-bukkit:7.0.13") compileOnly("com.github.TechFortress:GriefPrevention:17.0.0") @@ -87,7 +91,7 @@ tasks.processResources { val props = mapOf("version" to version) inputs.properties(props) filteringCharset = "UTF-8" - filesMatching("plugin.yml") { + filesMatching("*plugin.yml") { expand(props) } } @@ -117,7 +121,7 @@ tasks.jar { } tasks.runServer { - minecraftVersion("1.21.4") + minecraftVersion("1.21.5") } runPaper.folia.registerTask() diff --git a/src/main/java/com/github/nutt1101/CatchBall.java b/src/main/java/com/github/nutt1101/CatchBall.java index baa6eb9..c3c2816 100644 --- a/src/main/java/com/github/nutt1101/CatchBall.java +++ b/src/main/java/com/github/nutt1101/CatchBall.java @@ -1,15 +1,12 @@ package com.github.nutt1101; import cn.handyplus.lib.adapter.HandySchedulerUtil; -import com.github.nutt1101.command.Command; -import com.github.nutt1101.command.TabComplete; +import com.github.nutt1101.command.BrigadierCommandHandler; import com.github.nutt1101.event.*; +import net.kyori.adventure.text.format.NamedTextColor; import org.bstats.bukkit.Metrics; import com.jeff_media.updatechecker.UpdateCheckSource; import com.jeff_media.updatechecker.UpdateChecker; -import org.bukkit.ChatColor; -import org.bukkit.command.PluginCommand; -import org.bukkit.configuration.file.FileConfiguration; import org.bukkit.plugin.Plugin; import org.bukkit.plugin.PluginManager; import org.bukkit.plugin.java.JavaPlugin; @@ -17,7 +14,9 @@ import java.util.logging.Level; public class CatchBall extends JavaPlugin { - private FileConfiguration config = this.getConfig(); + { + this.getConfig(); + } public static Plugin plugin; @@ -25,7 +24,7 @@ public class CatchBall extends JavaPlugin { private void checkPluginHook(String pluginName) { if (this.getServer().getPluginManager().getPlugin(pluginName) != null) { - plugin.getLogger().log(Level.INFO, ChatColor.GREEN + pluginName + " Hook!"); + plugin.getLogger().log(Level.INFO, NamedTextColor.GREEN + pluginName + " Hook!"); } } @@ -36,10 +35,12 @@ public void onEnable() { ConfigSetting.checkConfig(); - Metrics metrics = new Metrics(this, 12380); + // Initialize metrics + this.metrics = new Metrics(this, 12380); registerEvent(); - registerCommand(); + // Remove legacy command registration for Paper plugins + // Commands are now registered via Brigadier in registerBrigadierCommands() new UpdateChecker(this, UpdateCheckSource.GITHUB_RELEASE_TAG, "MagicTeaMC/CatchBall2") .checkEveryXHours(1) // Check every hour @@ -60,6 +61,8 @@ public void onEnable() { HandySchedulerUtil.init(this); + // Register Brigadier commands + new BrigadierCommandHandler(this).registerCommands(); } @Override @@ -86,17 +89,17 @@ public void registerEvent() { registerEvent.registerEvents(new GUIClick(), this); } - // register command + /* + // register command (not used in Paper plugins - kept for reference) + // Paper plugins use Brigadier commands instead public void registerCommand() { + // This method is not called in Paper plugins + // Commands are registered via registerBrigadierCommands() instead PluginCommand ctbCommand = this.getCommand("ctb"); if (ctbCommand != null) { ctbCommand.setExecutor(new Command()); ctbCommand.setTabCompleter(new TabComplete()); } } - - public static String getServerVersion() { - return plugin.getServer().getBukkitVersion(); - } - -} + */ +} \ No newline at end of file diff --git a/src/main/java/com/github/nutt1101/ConfigSetting.java b/src/main/java/com/github/nutt1101/ConfigSetting.java index cc1d7f8..4d350cb 100644 --- a/src/main/java/com/github/nutt1101/ConfigSetting.java +++ b/src/main/java/com/github/nutt1101/ConfigSetting.java @@ -4,7 +4,8 @@ import com.github.nutt1101.Recipe.BallRecipe; import com.github.nutt1101.utils.TranslationFileReader; import me.ryanhamshire.GriefPrevention.ClaimPermission; -import org.bukkit.ChatColor; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.minimessage.MiniMessage; import org.bukkit.Material; import org.bukkit.configuration.file.FileConfiguration; import org.bukkit.configuration.file.YamlConfiguration; @@ -16,7 +17,6 @@ import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; import java.util.Objects; import java.util.logging.Level; @@ -90,26 +90,26 @@ public static void checkConfig() { DropEnable = !config.isSet("DropEnable") || config.getBoolean("DropEnable"); DropNeedPermission = config.isSet("DropNeedPermission") && config.getBoolean("DropNeedPermission"); DropItemChance = config.isSet("DropItemChance") - ? Integer.parseInt(config.getString("DropItemChance").replace("%", "")) + ? Integer.parseInt(Objects.requireNonNull(config.getString("DropItemChance")).replace("%", "")) : 50; try { DropItemMaterial = config.isSet("DropItemMaterial") ? Material.matchMaterial(Objects.requireNonNull(config.getString("DropItemMaterial"))) : Material.EGG; } catch (IllegalArgumentException e) { - plugin.getLogger().log(Level.WARNING, ChatColor.RED + "Invalid DropItemMaterial in config.yml, using default 'EGG' material."); + plugin.getLogger().log(Level.WARNING, "Invalid DropItemMaterial in config.yml, using default 'EGG' material."); DropItemMaterial = Material.EGG; } try { - DropMethod = config.isSet("DropMethod") ? DropMethodType.valueOf(config.getString("DropMethod").toUpperCase()) : DropMethodType.CHICKEN; + DropMethod = config.isSet("DropMethod") ? DropMethodType.valueOf(Objects.requireNonNull(config.getString("DropMethod")).toUpperCase()) : DropMethodType.CHICKEN; } catch (IllegalArgumentException e) { - plugin.getLogger().log(Level.WARNING, ChatColor.RED + "Invalid DropMethod in config.yml, using default 'CHICKEN' method."); + plugin.getLogger().log(Level.WARNING, "Invalid DropMethod in config.yml, using default 'CHICKEN' method."); DropMethod = DropMethodType.CHICKEN; } // Store as string instead of EntityType - DropEntityType = config.isSet("DropEntityType") ? config.getString("DropEntityType").toUpperCase() : "CHICKEN"; + DropEntityType = config.isSet("DropEntityType") ? Objects.requireNonNull(config.getString("DropEntityType")).toUpperCase() : "CHICKEN"; if (!isValidEntityType(DropEntityType)) { - plugin.getLogger().log(Level.WARNING, ChatColor.RED + "Invalid DropEntityType in config.yml, using default 'CHICKEN'."); + plugin.getLogger().log(Level.WARNING, "Invalid DropEntityType in config.yml, using default 'CHICKEN'."); DropEntityType = "CHICKEN"; } @@ -119,16 +119,16 @@ public static void checkConfig() { entityFile = YamlConfiguration.loadConfiguration(new File(plugin.getDataFolder(), "entity.yml")); - catchSuccessSound = config.isSet("CatchSuccessSound") ? config.getString("CatchSuccessSound").toUpperCase() + catchSuccessSound = config.isSet("CatchSuccessSound") ? Objects.requireNonNull(config.getString("CatchSuccessSound")).toUpperCase() : "ENTITY_ARROW_HIT_PLAYER".toUpperCase(); recipeEnabled = !config.isSet("Recipe.enabled") || config.getBoolean("Recipe.enabled"); residenceFlag = config.isSet("ResidenceFlag") ? config.getStringList("ResidenceFlag") - : Arrays.asList("animalkilling"); + : List.of("animalkilling"); griefPreventionFlag = config.isSet("GriefPreventionFlag") ? config.getStringList("GriefPreventionFlag") - : Arrays.asList("Access"); + : List.of("Access"); allowCatchableTamedOwnerIsNull = !config.isSet("AllowCatchableTamedOwnerIsNull") || config.getBoolean("AllowCatchableTamedOwnerIsNull"); ShowParticles = !config.isSet("ShowParticles") @@ -145,11 +145,11 @@ public static void checkConfig() { try { TranslationFileReader.init(); } catch (IOException e) { - e.printStackTrace(); + plugin.getLogger().warning("An error caused " + e.getMessage()); plugin.getLogger().log(Level.WARNING, - ChatColor.RED + String.format("The locale you have selected '%s' is currently not supported", + String.format("The locale you have selected '%s' is currently not supported", locale)); - plugin.getLogger().log(Level.WARNING, ChatColor.RED + "We only support: en, zh_tw"); + plugin.getLogger().log(Level.WARNING, "We only support: en, zh_tw"); locale = "en"; } @@ -161,14 +161,14 @@ public static void checkConfig() { try { if (plugin.getServer().getPluginManager().getPlugin("Residence") != null) { - residenceFlag = residenceFlag.stream().map(flag -> Flags.valueOf(flag)).map(Flags::name) + residenceFlag = residenceFlag.stream().map(Flags::valueOf).map(Flags::name) .collect(Collectors.toList()); } } catch (IllegalArgumentException e) { - plugin.getLogger().log(Level.WARNING, ChatColor.RED + e.getMessage()); - plugin.getLogger().log(Level.WARNING, ChatColor.RED + "Unknown Residence flag!"); - plugin.getLogger().log(Level.WARNING, ChatColor.RED + "Please check your config setting!"); + plugin.getLogger().log(Level.WARNING, e.getMessage()); + plugin.getLogger().log(Level.WARNING, "Unknown Residence flag!"); + plugin.getLogger().log(Level.WARNING, "Please check your config setting!"); residenceFlag.clear(); residenceFlag.add("animalkilling"); } @@ -178,15 +178,15 @@ public static void checkConfig() { griefPreventionFlag = griefPreventionFlag.stream() .map(flag -> flag.substring(0, 1).toUpperCase() + flag.substring(1)) .map(String::toUpperCase).collect(Collectors.toList()); - for (int i = 0; i < griefPreventionFlag.size(); i++) { - ClaimPermission.valueOf(griefPreventionFlag.get(i)); + for (String s : griefPreventionFlag) { + ClaimPermission.valueOf(s); } } } catch (IllegalArgumentException e) { - plugin.getLogger().log(Level.WARNING, ChatColor.RED + e.getMessage()); - plugin.getLogger().log(Level.WARNING, ChatColor.RED + "Unknown GriefPrevention flag!"); - plugin.getLogger().log(Level.WARNING, ChatColor.RED + "Please check your config setting!"); + plugin.getLogger().log(Level.WARNING, e.getMessage()); + plugin.getLogger().log(Level.WARNING, "Unknown GriefPrevention flag!"); + plugin.getLogger().log(Level.WARNING, "Please check your config setting!"); griefPreventionFlag.clear(); griefPreventionFlag.add("Access"); } @@ -197,7 +197,7 @@ public static void checkConfig() { if (isValidEntityType(entityName)) { catchableEntity.add(entityName); } else { - plugin.getLogger().log(Level.WARNING, ChatColor.YELLOW + "Unknown entity type '" + entity + "' in CatchableEntity list, skipping..."); + plugin.getLogger().log(Level.WARNING, "Unknown entity type '" + entity + "' in CatchableEntity list, skipping..."); } } @@ -246,10 +246,10 @@ public static void entityFileCreate() { outputStream.close(); inputStream.close(); } catch (Exception e) { - e.printStackTrace(); + plugin.getLogger().warning("An error caused " + e.getMessage()); } } else { - plugin.getLogger().log(Level.WARNING, ChatColor.RED + "Unknown Error make plugin file can not place!"); + plugin.getLogger().log(Level.WARNING, "Unknown Error make plugin file can not place!"); } } @@ -260,7 +260,7 @@ public static void entityFileCreate() { * @return entityDisplayName */ public static String getEntityDisplayName(String entityName) { - if (entityFile.getConfigurationSection("EntityList").contains(entityName)) { + if (Objects.requireNonNull(entityFile.getConfigurationSection("EntityList")).contains(entityName)) { return entityFile.getString("EntityList." + entityName.toUpperCase() + ".DisplayName"); } return entityName; @@ -269,17 +269,20 @@ public static String getEntityDisplayName(String entityName) { /** * Replace the message argument from config.yml. * + * @param message the source message with placeholders * @param location replace {LOCATION} from source message * @param entity replace {ENTITY} from source message - * @return replaced message + * @return Component ready to send to player */ - public static String toChat(String message, String location, String entity) { + public static Component toChat(String message, String location, String entity) { + // Replace placeholders message = message.contains("{BALL}") ? message.replace("{BALL}", TranslationFileReader.catchBallName) : message; message = message.contains("{LOCATION}") ? message.replace("{LOCATION}", location) : message; message = message.contains("{ENTITY}") ? message.replace("{ENTITY}", getEntityDisplayName(entity)) : message; - return ChatColor.translateAlternateColorCodes('&', message); + // Parse with MiniMessage + return MiniMessage.miniMessage().deserialize(message); } /** @@ -294,31 +297,10 @@ public static void saveEntityList() { try { fileConfiguration.save(new File(plugin.getDataFolder(), "config.yml")); } catch (IOException e) { - e.printStackTrace(); + plugin.getLogger().log(Level.WARNING, "An error caused " + e.getMessage()); } } - public static boolean isLatestVersion(String current, String latest) { - - String[] currentParts = current.split("\\."); - - String[] latestParts = latest.split("\\."); - - int minLength = Math.min(currentParts.length, latestParts.length); - - for (int i = 0; i < minLength; i++) { - - int currentPart = Integer.parseInt(currentParts[i]); - - int latestPart = Integer.parseInt(latestParts[i]); - - if (currentPart < latestPart) return false; - - if (currentPart > latestPart) return true; - } - return currentParts.length >= latestParts.length; - } - public enum DropMethodType { CHICKEN, ENTITY, diff --git a/src/main/java/com/github/nutt1101/GUI/CatchableList.java b/src/main/java/com/github/nutt1101/GUI/CatchableList.java index 140fef7..7b52cee 100644 --- a/src/main/java/com/github/nutt1101/GUI/CatchableList.java +++ b/src/main/java/com/github/nutt1101/GUI/CatchableList.java @@ -3,7 +3,9 @@ import com.github.nutt1101.ConfigSetting; import com.github.nutt1101.HeadDrop; import com.github.nutt1101.utils.TranslationFileReader; -import net.md_5.bungee.api.ChatColor; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; import org.bukkit.Bukkit; import org.bukkit.Material; import org.bukkit.configuration.file.YamlConfiguration; @@ -25,13 +27,16 @@ public class CatchableList { private ItemStack itemSet(ItemStack item, String displayName, int page) { displayName = displayName.replace("{PAGE}", String.valueOf(page)); ItemMeta itemMeta = item.getItemMeta(); - itemMeta.setDisplayName(ConfigSetting.toChat(displayName, "", "")); + + // Convert legacy color codes to Component + Component displayNameComponent = LegacyComponentSerializer.legacyAmpersand().deserialize(displayName); + itemMeta.displayName(displayNameComponent); + item.setItemMeta(itemMeta); return item; } - // Check if an entity is catchable by comparing string names instead of EntityType - // This method provides better compatibility with older Minecraft versions + // Check if an entity is catchable by comparing string names instead of EntityType private boolean isEntityCatchable(String entityName) { // Convert the catchable entity list to string names for comparison for (Object catchableEntity : ConfigSetting.catchableEntity) { @@ -55,22 +60,42 @@ private boolean isEntityCatchable(String entityName) { public void openCatchableList(Player player, int page) { YamlConfiguration entityFile = ConfigSetting.entityFile; Set entityList = entityFile.getConfigurationSection("EntityList").getKeys(false); - Inventory catchableInventory = Bukkit.createInventory(player, 54, ConfigSetting.toChat(TranslationFileReader.catchableListTitle, "", "")); + + // Convert title to Component + Component inventoryTitle = LegacyComponentSerializer.legacyAmpersand() + .deserialize(TranslationFileReader.catchableListTitle); + Inventory catchableInventory = Bukkit.createInventory(player, 54, inventoryTitle); head.clear(); for (String entity : entityList) { ItemStack skull = new HeadDrop().skullTextures(new ItemStack(Material.PLAYER_HEAD), entityFile, entity); ItemMeta skullMeta = skull.getItemMeta(); - // Use string comparison instead of EntityType.valueOf() - String catchable = isEntityCatchable(entity) ? "&aTRUE" : "&cFALSE"; - skullMeta.setDisplayName(ChatColor.WHITE + entity); + // Create catchable status component + Component catchableComponent = isEntityCatchable(entity) + ? Component.text("TRUE").color(NamedTextColor.GREEN) + : Component.text("FALSE").color(NamedTextColor.RED); + + // Set display name using Component + Component entityDisplayName = Component.text(entity).color(NamedTextColor.WHITE); + skullMeta.displayName(entityDisplayName); + + // Create lore using Components + List loreComponents = new ArrayList<>(); + String entityDisplayNameFromConfig = entityFile.getString("EntityList." + entity + ".DisplayName"); - List lore = new ArrayList<>(); for (String line : TranslationFileReader.guiSkullLore) { - lore.add(ChatColor.translateAlternateColorCodes('&', line.replace("{ENTITY}", ChatColor.AQUA + entityFile.getString("EntityList." + entity + ".DisplayName")).replace("{CATCHABLE}", catchable))); + // Replace placeholders and convert to Component + String processedLine = line + .replace("{ENTITY}", entityDisplayNameFromConfig) + .replace("{CATCHABLE}", isEntityCatchable(entity) ? "&aTRUE" : "&cFALSE"); + + Component loreComponent = LegacyComponentSerializer.legacyAmpersand() + .deserialize(processedLine); + loreComponents.add(loreComponent); } - skullMeta.setLore(lore); + + skullMeta.lore(loreComponents); skull.setItemMeta(skullMeta); head.add(skull); } diff --git a/src/main/java/com/github/nutt1101/HeadDrop.java b/src/main/java/com/github/nutt1101/HeadDrop.java index e5f12fa..ee8d727 100644 --- a/src/main/java/com/github/nutt1101/HeadDrop.java +++ b/src/main/java/com/github/nutt1101/HeadDrop.java @@ -3,7 +3,9 @@ import com.github.nutt1101.event.HitEvent; import com.github.nutt1101.utils.NBTHandler; import com.github.nutt1101.utils.TranslationFileReader; -import net.md_5.bungee.api.ChatColor; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; import org.bukkit.Bukkit; import org.bukkit.Material; import org.bukkit.NamespacedKey; @@ -16,21 +18,21 @@ import org.bukkit.persistence.PersistentDataContainer; import org.bukkit.persistence.PersistentDataType; import org.bukkit.plugin.Plugin; -import org.bukkit.profile.PlayerProfile; -import org.bukkit.profile.PlayerTextures; +import com.destroystokyo.paper.profile.PlayerProfile; +import com.destroystokyo.paper.profile.ProfileProperty; -import java.net.URL; +import java.net.MalformedURLException; +import java.net.URI; +import java.net.URISyntaxException; import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Base64; -import java.util.Date; -import java.util.List; +import java.util.*; import java.util.logging.Level; import java.util.stream.Collectors; public class HeadDrop { private final Plugin plugin = CatchBall.plugin; - private SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd, HH:mm:ss"); + private final SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd, HH:mm:ss"); + private final LegacyComponentSerializer legacySerializer = LegacyComponentSerializer.legacyAmpersand(); /** * When CatchBall hit catchable entity, It will drop the skull of hitEntity. @@ -52,27 +54,35 @@ public ItemStack getEntityHead(Entity hitEntity, Player player) { String location = "(" + hitEntity.getWorld().getName() + ") " + HitEvent.getCoordinate(hitEntity.getLocation()); - if (hitEntity.getCustomName() != null) { - headMeta.setDisplayName(ChatColor.WHITE + hitEntity.getCustomName()); + // Use Adventure API for display name + Component displayName; + if (hitEntity.customName() != null) { + displayName = Objects.requireNonNull(hitEntity.customName()).color(NamedTextColor.WHITE); } else { - headMeta.setDisplayName(ChatColor.WHITE + entityFile.getString("EntityList." + hitEntity.getType().toString() + ".DisplayName")); + String entityDisplayName = entityFile.getString("EntityList." + hitEntity.getType().toString() + ".DisplayName"); + displayName = Component.text(entityDisplayName != null ? entityDisplayName : hitEntity.getType().toString()) + .color(NamedTextColor.WHITE); } + headMeta.displayName(displayName); - List headLore = new ArrayList<>(); + List headLore = new ArrayList<>(); - if (player == null) { - headLore.addAll(TranslationFileReader.dropSkullLore.stream().map(lore -> ChatColor.translateAlternateColorCodes('&', lore). - replace("{ENTITY}", hitEntity.getType().toString()).replace("{PLAYER}", "Dispenser").replace("{TIME}", format.format(now)). - replace("{LOCATION}", location)).collect(Collectors.toList())); - } else { - headLore.addAll(TranslationFileReader.dropSkullLore.stream().map(lore -> ChatColor.translateAlternateColorCodes('&', lore). - replace("{ENTITY}", hitEntity.getType().toString()).replace("{PLAYER}", player.getName()).replace("{TIME}", format.format(now)). - replace("{LOCATION}", location)).collect(Collectors.toList())); + String playerName = (player == null) ? "Dispenser" : player.getName(); + + for (String lore : TranslationFileReader.dropSkullLore) { + String processedLore = lore + .replace("{ENTITY}", hitEntity.getType().toString()) + .replace("{PLAYER}", playerName) + .replace("{TIME}", format.format(now)) + .replace("{LOCATION}", location); + + Component loreComponent = legacySerializer.deserialize(processedLore); + headLore.add(loreComponent); } headMeta = NBTHandler.saveEntityNBT(plugin, hitEntity, headMeta); - headMeta.setLore(headLore); + headMeta.lore(headLore); entityHead.setItemMeta(headMeta); return skullTextures(entityHead, entityFile, hitEntity.getType().toString()); @@ -89,31 +99,26 @@ public ItemStack skullTextures(ItemStack head, YamlConfiguration entityFile, Str SkullMeta skullMeta = (SkullMeta) head.getItemMeta(); try { - PlayerProfile profile = Bukkit.createPlayerProfile("catchball"); - PlayerTextures textures = profile.getTextures(); - String textureValue = entityFile.getString("EntityList." + entityType.toUpperCase() + ".Skull"); if (textureValue != null && !textureValue.isEmpty()) { try { - String decodedValue = new String(Base64.getDecoder().decode(textureValue)); - - String urlStr = decodedValue.split("\"url\":\"")[1].split("\"")[0]; - URL textureUrl = new URL(urlStr); + // Create Paper's PlayerProfile + PlayerProfile profile = Bukkit.createProfile("catchball"); - textures.setSkin(textureUrl); - profile.setTextures(textures); + // Set the texture property directly + ProfileProperty textureProperty = new ProfileProperty("textures", textureValue); + profile.setProperty(textureProperty); - skullMeta.setOwnerProfile(profile); + skullMeta.setPlayerProfile(profile); } catch (Exception e) { - plugin.getLogger().log(Level.WARNING, "Failed to decode texture value: " + e.getMessage()); + plugin.getLogger().log(Level.WARNING, "Failed to set texture property: " + e.getMessage()); } } else { plugin.getLogger().log(Level.WARNING, "Could not find texture value for entity type: " + entityType); } } catch (Exception e) { plugin.getLogger().log(Level.WARNING, "Failed to set skull texture: " + e.getMessage()); - e.printStackTrace(); } head.setItemMeta(skullMeta); diff --git a/src/main/java/com/github/nutt1101/Recipe/BallRecipe.java b/src/main/java/com/github/nutt1101/Recipe/BallRecipe.java index 1bfacf7..d863f3f 100644 --- a/src/main/java/com/github/nutt1101/Recipe/BallRecipe.java +++ b/src/main/java/com/github/nutt1101/Recipe/BallRecipe.java @@ -35,19 +35,12 @@ public BallRecipe() { for (String key : recipePath) { String ItemName = config.getString("Recipe.key." + key).toUpperCase(); - if (ItemName instanceof String) { - if (ItemName.equals("DROPITEM")) { - ballRecipe.setIngredient(key.charAt(0), new RecipeChoice.ExactChoice(DropItem.makeDropItem())); - } else { - ballRecipe.setIngredient(key.charAt(0), Material.valueOf(ItemName)); - } - + if (ItemName.equals("DROPITEM")) { + ballRecipe.setIngredient(key.charAt(0), new RecipeChoice.ExactChoice(DropItem.makeDropItem())); } else { - ballRecipe.setIngredient(key.charAt(0), new RecipeChoice.MaterialChoice( - config.getStringList("Recipe.key." + key).stream().map( - list -> Material.valueOf(list)).collect(Collectors.toList()))); + ballRecipe.setIngredient(key.charAt(0), Material.valueOf(ItemName)); } - + } if (Bukkit.getRecipe(ballKey) != null) { Bukkit.removeRecipe(ballKey); } diff --git a/src/main/java/com/github/nutt1101/command/BrigadierCommandHandler.java b/src/main/java/com/github/nutt1101/command/BrigadierCommandHandler.java new file mode 100644 index 0000000..7ce7479 --- /dev/null +++ b/src/main/java/com/github/nutt1101/command/BrigadierCommandHandler.java @@ -0,0 +1,196 @@ +package com.github.nutt1101.command; + +import com.github.nutt1101.CatchBall; +import io.papermc.paper.command.brigadier.Commands; +import io.papermc.paper.plugin.lifecycle.event.LifecycleEventManager; +import io.papermc.paper.plugin.lifecycle.event.types.LifecycleEvents; +import org.bukkit.plugin.Plugin; + +public class BrigadierCommandHandler { + + private final CatchBall plugin; + private final Command commandExecutor; + private final TabComplete tabCompleter; + + public BrigadierCommandHandler(CatchBall plugin) { + this.plugin = plugin; + this.commandExecutor = new Command(); + this.tabCompleter = new TabComplete(); + } + + public void registerCommands() { + LifecycleEventManager manager = plugin.getLifecycleManager(); + manager.registerEventHandler(LifecycleEvents.COMMANDS, event -> { + final Commands commands = event.registrar(); + + commands.register( + Commands.literal("ctb") + .executes(context -> { + return commandExecutor.onCommand( + context.getSource().getSender(), + null, + "ctb", + new String[0] + ) ? 1 : 0; + }) + .then(buildReloadCommand()) + .then(buildListCommand()) + .then(buildAddCommand()) + .then(buildRemoveCommand()) + .then(buildGiveCommand()) + .build(), + "CatchBall main command" + ); + }); + } + + private com.mojang.brigadier.builder.LiteralArgumentBuilder buildReloadCommand() { + return Commands.literal("reload") + .executes(context -> { + return commandExecutor.onCommand( + context.getSource().getSender(), + null, + "ctb", + new String[]{"reload"} + ) ? 1 : 0; + }); + } + + private com.mojang.brigadier.builder.LiteralArgumentBuilder buildListCommand() { + return Commands.literal("list") + .executes(context -> { + return commandExecutor.onCommand( + context.getSource().getSender(), + null, + "ctb", + new String[]{"list"} + ) ? 1 : 0; + }); + } + + private com.mojang.brigadier.builder.LiteralArgumentBuilder buildAddCommand() { + return Commands.literal("add") + .then(Commands.argument("entity", com.mojang.brigadier.arguments.StringArgumentType.word()) + .suggests((context, builder) -> { + return getTabCompletions(builder, new String[]{"add", ""}, context); + }) + .executes(context -> { + String entity = context.getArgument("entity", String.class); + return commandExecutor.onCommand( + context.getSource().getSender(), + null, + "ctb", + new String[]{"add", entity} + ) ? 1 : 0; + })); + } + + private com.mojang.brigadier.builder.LiteralArgumentBuilder buildRemoveCommand() { + return Commands.literal("remove") + .then(Commands.argument("entity", com.mojang.brigadier.arguments.StringArgumentType.word()) + .suggests((context, builder) -> { + return getTabCompletions(builder, new String[]{"remove", ""}, context); + }) + .executes(context -> { + String entity = context.getArgument("entity", String.class); + return commandExecutor.onCommand( + context.getSource().getSender(), + null, + "ctb", + new String[]{"remove", entity} + ) ? 1 : 0; + })); + } + + private com.mojang.brigadier.builder.LiteralArgumentBuilder buildGiveCommand() { + return Commands.literal("give") + .then(Commands.argument("player", com.mojang.brigadier.arguments.StringArgumentType.word()) + .suggests((context, builder) -> { + return getTabCompletions(builder, new String[]{"give", ""}, context); + }) + .then(Commands.argument("item", com.mojang.brigadier.arguments.StringArgumentType.word()) + .suggests((context, builder) -> { + String player = context.getArgument("player", String.class); + return getTabCompletions(builder, new String[]{"give", player, ""}, context); + }) + .executes(context -> { + String player = context.getArgument("player", String.class); + String item = context.getArgument("item", String.class); + return commandExecutor.onCommand( + context.getSource().getSender(), + null, + "ctb", + new String[]{"give", player, item} + ) ? 1 : 0; + }) + .then(Commands.argument("amount", com.mojang.brigadier.arguments.IntegerArgumentType.integer(1)) + .suggests((context, builder) -> { + String player = context.getArgument("player", String.class); + String item = context.getArgument("item", String.class); + return getTabCompletions(builder, new String[]{"give", player, item, ""}, context); + }) + .executes(context -> { + String player = context.getArgument("player", String.class); + String item = context.getArgument("item", String.class); + int amount = context.getArgument("amount", Integer.class); + return commandExecutor.onCommand( + context.getSource().getSender(), + null, + "ctb", + new String[]{"give", player, item, String.valueOf(amount)} + ) ? 1 : 0; + })))); + } + + private java.util.concurrent.CompletableFuture getTabCompletions( + com.mojang.brigadier.suggestion.SuggestionsBuilder builder, + String[] args, + com.mojang.brigadier.context.CommandContext context) { + + try { + java.util.List completions = tabCompleter.onTabComplete( + context.getSource().getSender(), + null, + "ctb", + args + ); + + if (completions != null) { + for (String completion : completions) { + if (completion != null && !completion.isEmpty()) { + builder.suggest(completion); + } + } + } + } catch (Exception e) { + // Fallback: provide basic completions + provideFallbackCompletions(builder, args); + } + + return builder.buildFuture(); + } + + private void provideFallbackCompletions(com.mojang.brigadier.suggestion.SuggestionsBuilder builder, String[] args) { + if (args.length == 2) { + if (args[0].equals("give")) { + // Suggest online player names + plugin.getServer().getOnlinePlayers().forEach(player -> + builder.suggest(player.getName())); + } else if (args[0].equals("add")) { + builder.suggest("ALL"); + builder.suggest("ZOMBIE"); + builder.suggest("SKELETON"); + builder.suggest("CREEPER"); + } else if (args[0].equals("remove")) { + builder.suggest("ALL"); + } + } else if (args.length == 3 && args[0].equals("give")) { + builder.suggest("CatchBall"); + builder.suggest("DropItem"); + } else if (args.length == 4 && args[0].equals("give")) { + for (int i = 1; i <= 9; i++) { + builder.suggest(String.valueOf(i)); + } + } + } +} diff --git a/src/main/java/com/github/nutt1101/command/Command.java b/src/main/java/com/github/nutt1101/command/Command.java index 178aba7..ba50df0 100644 --- a/src/main/java/com/github/nutt1101/command/Command.java +++ b/src/main/java/com/github/nutt1101/command/Command.java @@ -22,14 +22,18 @@ public class Command implements CommandExecutor { @Override public boolean onCommand(CommandSender sender, org.bukkit.command.Command command, String label, String[] args) { - if (command.getName().equals("ctb")) { + // Handle Brigadier commands where command parameter is null + if (command == null || command.getName().equals("ctb") || label.equals("ctb")) { if (!(CommandCheck.check(sender, command, label, args))) { return true; } - /* player use "/ctb get" command - player will get a catchBall*/ + if (args.length == 0) { + sender.sendMessage(ConfigSetting.toChat(TranslationFileReader.unknownCommandArgument, "", "")); + return true; + } + if (args[0].equalsIgnoreCase("reload")) { ConfigSetting.checkConfig(); sender.sendMessage(ConfigSetting.toChat(TranslationFileReader.reloadSuccess, "", "")); @@ -113,8 +117,7 @@ public boolean onCommand(CommandSender sender, org.bukkit.command.Command comman Player player = Bukkit.getPlayer(args[1]); if (player == null) { - sender.sendMessage(ConfigSetting.toChat(TranslationFileReader.unknownOrOfflinePlayer, "", "") - .replace("{PLAYER}", args[1])); + sender.sendMessage(ConfigSetting.toChat(TranslationFileReader.unknownOrOfflinePlayer.replace("{PLAYER}", args[1]), "", "")); return true; } @@ -139,11 +142,9 @@ public boolean onCommand(CommandSender sender, org.bukkit.command.Command comman givePlayerItem(player, checkItem(args[2]), itemAmount); - sender.sendMessage(ConfigSetting.toChat(TranslationFileReader.successGiveItemToPlayer, "", "") - .replace("{ITEM}", args[2].toLowerCase().equals("catchball") ? TranslationFileReader.catchBallName - : TranslationFileReader.dropItemName) + sender.sendMessage(ConfigSetting.toChat(TranslationFileReader.successGiveItemToPlayer .replace("{PLAYER}", player.getName()) - .replace("&", "§")); + .replace("{ITEM}", args[2].toLowerCase().equals("catchball") ? TranslationFileReader.catchBallName : TranslationFileReader.dropItemName), "", "")); return true; diff --git a/src/main/java/com/github/nutt1101/command/CommandCheck.java b/src/main/java/com/github/nutt1101/command/CommandCheck.java index 2143408..4bdb3a4 100644 --- a/src/main/java/com/github/nutt1101/command/CommandCheck.java +++ b/src/main/java/com/github/nutt1101/command/CommandCheck.java @@ -9,7 +9,7 @@ import java.util.List; public class CommandCheck { - private static List argmumentList = Arrays.asList("reload", "list", "add", "remove", "give"); + private static List argumentList = Arrays.asList("reload", "list", "add", "remove", "give"); public static Boolean check(CommandSender sender, Command command, String label, String[] args) { @@ -31,5 +31,7 @@ public static Boolean check(CommandSender sender, Command command, String label, return true; } - public static List getCommandArgument() { return argmumentList; }; -} + public static List getCommandArgument() { + return argumentList; + } +} \ No newline at end of file diff --git a/src/main/java/com/github/nutt1101/command/TabComplete.java b/src/main/java/com/github/nutt1101/command/TabComplete.java index 4f44ecf..bc5a9b6 100644 --- a/src/main/java/com/github/nutt1101/command/TabComplete.java +++ b/src/main/java/com/github/nutt1101/command/TabComplete.java @@ -15,28 +15,31 @@ public class TabComplete implements TabCompleter { List entityList = new ArrayList<>(); - + @Override public List onTabComplete(CommandSender sender, Command command, String alias, String[] args) { - - // tabComplete will be show suggest arument to commandSender - if (command.getName().equals("ctb")) { + + // For Paper plugins using Brigadier, command might be null, so check the alias instead + String commandName = (command != null) ? command.getName() : alias; + + // tabComplete will be show suggest argument to commandSender + if (commandName.equals("ctb")) { final List sort = new ArrayList<>(); - + if (!sender.hasPermission("catchball.op")) { return List.of(""); } - - if (args.length == 1) { + + if (args.length == 1) { StringUtil.copyPartialMatches(args[0], CommandCheck.getCommandArgument(), sort); - return sort; + return sort; } - if (args.length == 2) { + if (args.length == 2) { entityList.clear(); if (args[0].equalsIgnoreCase("give")) { Bukkit.getOnlinePlayers().forEach(player -> { sort.add(player.getName()); }); - StringUtil.copyPartialMatches(args[0], sort, sort); + StringUtil.copyPartialMatches(args[1], sort, sort); return sort; } else if (args[0].equalsIgnoreCase("add")) { Set allEntityList = ConfigSetting.entityFile.getConfigurationSection("EntityList").getKeys(false); @@ -44,7 +47,7 @@ public List onTabComplete(CommandSender sender, Command command, String allEntityList.stream(). filter(entityName -> !ConfigSetting.catchableEntity.contains(EntityType.valueOf(entityName))). forEach(entity -> entityList.add(entity)); - + if (ConfigSetting.catchableEntity.size() < entityList.size()) { entityList.add("ALL"); } StringUtil.copyPartialMatches(args[1], entityList, sort); @@ -53,11 +56,11 @@ public List onTabComplete(CommandSender sender, Command command, String } else if (args[0].equalsIgnoreCase("remove")) { ConfigSetting.entityFile.getConfigurationSection("EntityList").getKeys(false).stream(). - filter(entityName -> ConfigSetting.catchableEntity.contains(EntityType.valueOf(entityName))). - forEach(entity -> entityList.add(entity)); - + filter(entityName -> ConfigSetting.catchableEntity.contains(EntityType.valueOf(entityName))). + forEach(entity -> entityList.add(entity)); + if (ConfigSetting.catchableEntity.size() > 0) { entityList.add("ALL"); } - + StringUtil.copyPartialMatches(args[1], entityList, sort); return sort; } @@ -75,7 +78,7 @@ public List onTabComplete(CommandSender sender, Command command, String } } } - + return List.of(""); } -} +} \ No newline at end of file diff --git a/src/main/java/com/github/nutt1101/event/ChickenDrop.java b/src/main/java/com/github/nutt1101/event/ChickenDrop.java index 3303ef8..aa38077 100644 --- a/src/main/java/com/github/nutt1101/event/ChickenDrop.java +++ b/src/main/java/com/github/nutt1101/event/ChickenDrop.java @@ -12,8 +12,8 @@ import java.util.Random; public class ChickenDrop implements Listener { - private EntityType chicken = EntityType.CHICKEN; - private Random chance = new Random(); + private final EntityType chicken = EntityType.CHICKEN; + private final Random chance = new Random(); @EventHandler public void ChickenDropEgg(EntityDropItemEvent event) { diff --git a/src/main/java/com/github/nutt1101/event/EntityDrop.java b/src/main/java/com/github/nutt1101/event/EntityDrop.java index 0bd0ce0..d18bcad 100644 --- a/src/main/java/com/github/nutt1101/event/EntityDrop.java +++ b/src/main/java/com/github/nutt1101/event/EntityDrop.java @@ -31,11 +31,6 @@ public void onEntityDrop(EntityDeathEvent event) { } ConfigSetting.DropItemChance = Math.min(ConfigSetting.DropItemChance, 100); - if (event.getEntityType().equals(ConfigSetting.DropEntityType)) { - if (chance.nextInt(99) < ConfigSetting.DropItemChance) { - event.getDrops().clear(); - event.getEntity().getWorld().dropItem(event.getEntity().getLocation(), DropItem.makeDropItem()); - } - } + event.getEntityType(); } } diff --git a/src/main/java/com/github/nutt1101/event/GUIClick.java b/src/main/java/com/github/nutt1101/event/GUIClick.java index 713a0fa..9e69271 100644 --- a/src/main/java/com/github/nutt1101/event/GUIClick.java +++ b/src/main/java/com/github/nutt1101/event/GUIClick.java @@ -3,7 +3,9 @@ import com.github.nutt1101.ConfigSetting; import com.github.nutt1101.GUI.CatchableList; import com.github.nutt1101.utils.TranslationFileReader; -import net.md_5.bungee.api.ChatColor; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer; +import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; import org.bukkit.Material; import org.bukkit.Sound; import org.bukkit.entity.EntityType; @@ -16,26 +18,35 @@ import java.util.ArrayList; import java.util.List; +import java.util.Objects; import java.util.regex.Pattern; - -public class GUIClick implements Listener{ +public class GUIClick implements Listener { List savelist = new ArrayList<>(); + // Serializers for Component conversion + private final PlainTextComponentSerializer plainSerializer = PlainTextComponentSerializer.plainText(); + private final LegacyComponentSerializer legacySerializer = LegacyComponentSerializer.legacyAmpersand(); + @EventHandler public void guiClick(InventoryClickEvent event) { Player player = (Player) event.getWhoClicked(); - String title = ConfigSetting.toChat(TranslationFileReader.catchableListTitle, "", ""); + Component title = ConfigSetting.toChat(TranslationFileReader.catchableListTitle, "", ""); - if (event.getView().getTitle().equals(title)) { + if (event.getView().title().equals(title)) { event.setCancelled(true); if (event.getClickedInventory() == null) { return; } if (event.getClickedInventory().equals(player.getInventory())) { return; } - Integer page = Integer.valueOf(ChatColor.stripColor(event.getClickedInventory().getItem(49).getItemMeta().getDisplayName() - .replace(" ", "").split(Pattern.quote(":") + "|" + Pattern.quote("\uff1a"))[1])); + // Convert Component to plain text for string manipulation + String displayNameText = plainSerializer.serialize( + Objects.requireNonNull(Objects.requireNonNull(event.getClickedInventory().getItem(49)).getItemMeta().displayName()) + ); + + int page = Integer.parseInt(displayNameText + .replace(" ", "").split(Pattern.quote(":") + "|" + Pattern.quote("\uff1a"))[1]); switch (event.getSlot()) { case 45: @@ -45,47 +56,67 @@ public void guiClick(InventoryClickEvent event) { case 53: new CatchableList().openCatchableList(player, page + 1); player.playSound(player.getLocation(), Sound.ITEM_BOOK_PAGE_TURN, 1.0f, 1.0f); - event.setCancelled(true); break; default: - if (event.getClickedInventory().getItem(event.getSlot()) != null && event.getClickedInventory().getItem(event.getSlot()).getType().equals(Material.PLAYER_HEAD)) { + if (event.getClickedInventory().getItem(event.getSlot()) != null && + event.getClickedInventory().getItem(event.getSlot()).getType().equals(Material.PLAYER_HEAD)) { + ItemStack clickItem = event.getClickedInventory().getItem(event.getSlot()); + assert clickItem != null; ItemMeta clickItemMeta = clickItem.getItemMeta(); - List lore = clickItemMeta.getLore(); + List lore = clickItemMeta.lore(); - EntityType entityType = EntityType.valueOf(ChatColor.stripColor(clickItem.getItemMeta().getDisplayName())); + if (lore == null) { + lore = new ArrayList<>(); + } + + // Convert display name to plain text for EntityType parsing + String entityName = plainSerializer.serialize(Objects.requireNonNull(clickItem.getItemMeta().displayName())); + EntityType entityType = EntityType.valueOf(entityName); int loreIndex = getLoreIndex(lore, "{CATCHABLE}"); + if (ConfigSetting.catchableEntity.contains(entityType)) { ConfigSetting.catchableEntity.remove(entityType); - lore.set(loreIndex, ChatColor.translateAlternateColorCodes('&', ConfigSetting. - toChat(TranslationFileReader.guiSkullLore.get(loreIndex), "", "").replace("{CATCHABLE}", "&cFALSE"))); + + // Create new component with updated text + Component originalComponent = ConfigSetting.toChat(TranslationFileReader.guiSkullLore.get(loreIndex), "", ""); + String componentText = plainSerializer.serialize(originalComponent); + String updatedText = componentText.replace("{CATCHABLE}", "&cFALSE"); + Component updatedComponent = legacySerializer.deserialize(updatedText); + + lore.set(loreIndex, updatedComponent); } else { ConfigSetting.catchableEntity.add(String.valueOf(entityType)); - lore.set(loreIndex, ChatColor.translateAlternateColorCodes('&', ConfigSetting. - toChat(TranslationFileReader.guiSkullLore.get(loreIndex), "", "").replace("{CATCHABLE}", "&aTRUE"))); + + // Create new component with updated text + Component originalComponent = ConfigSetting.toChat(TranslationFileReader.guiSkullLore.get(loreIndex), "", ""); + String componentText = plainSerializer.serialize(originalComponent); + String updatedText = componentText.replace("{CATCHABLE}", "&aTRUE"); + Component updatedComponent = legacySerializer.deserialize(updatedText); + + lore.set(loreIndex, updatedComponent); } - clickItemMeta.setLore(lore); + clickItemMeta.lore(lore); clickItem.setItemMeta(clickItemMeta); player.playSound(player.getLocation(), Sound.BLOCK_BREWING_STAND_BREW, 1.0f, 1.0f); ConfigSetting.saveEntityList(); - break; } } } } - public int getLoreIndex(List lore, String contain) { - for (int i=0; i lore, String contain) { + for (int i = 0; i < lore.size(); i++) { + String loreText = plainSerializer.serialize(lore.get(i)); + if (loreText.contains(contain)) { return i; } } return 1; } - } \ No newline at end of file diff --git a/src/main/java/com/github/nutt1101/event/HitEvent.java b/src/main/java/com/github/nutt1101/event/HitEvent.java index 724bf99..b22a9bd 100644 --- a/src/main/java/com/github/nutt1101/event/HitEvent.java +++ b/src/main/java/com/github/nutt1101/event/HitEvent.java @@ -37,7 +37,7 @@ public class HitEvent implements Listener { - private List catchableEntity = ConfigSetting.catchableEntity; // Changed from EntityType to String + private final List catchableEntity = ConfigSetting.catchableEntity; // Changed from EntityType to String private Location hitLocation; private final Plugin plugin = CatchBall.plugin; private final String[] mmPackage = {"io.lumine.mythic.bukkit.BukkitAPIHelper", "io.lumine.xikage.mythicmobs.api.bukkit.BukkitAPIHelper"}; @@ -72,15 +72,16 @@ public void CatchBallHitEvent(ProjectileHitEvent event){ } // check if shooter is a player - if (event.getEntity().getShooter() instanceof Player) { - Player player = (Player) event.getEntity().getShooter(); + if (event.getEntity().getShooter() instanceof Player player) { if (!checkCatchBall(event.getEntity())) { return; } if (!player.hasPermission("catchball.use")) { - player.sendMessage(ChatColor.translateAlternateColorCodes('&', ConfigSetting.toChat(TranslationFileReader.noPermissionToUse, - getCoordinate(event.getHitBlock() == null ? Objects.requireNonNull(event.getHitEntity()).getLocation() : event.getHitBlock().getLocation()) - , "").replace("{BALL}", TranslationFileReader.catchBallName))); + player.sendMessage(ConfigSetting.toChat( + TranslationFileReader.noPermissionToUse.replace("{BALL}", TranslationFileReader.catchBallName), + getCoordinate(event.getHitBlock() == null ? Objects.requireNonNull(event.getHitEntity()).getLocation() : event.getHitBlock().getLocation()), + "" + )); event.getEntity().remove(); @@ -100,7 +101,7 @@ public void CatchBallHitEvent(ProjectileHitEvent event){ event.getEntity().remove(); // hit a entity if (event.getHitEntity() != null) { - handleEntityCatch(player, event.getHitEntity(), true); + handleEntityCatch(player, event.getHitEntity()); // hit block, catchBall will be return } else if (event.getHitBlock() != null) { @@ -167,8 +168,8 @@ public void onPlayerInteractEntity(PlayerInteractEntityEvent event) { // Check permissions if (!player.hasPermission("catchball.use")) { - player.sendMessage(ChatColor.translateAlternateColorCodes('&', ConfigSetting.toChat(TranslationFileReader.noPermissionToUse, - getCoordinate(targetEntity.getLocation()), "").replace("{BALL}", TranslationFileReader.catchBallName))); + player.sendMessage(ConfigSetting.toChat(TranslationFileReader.noPermissionToUse.replace("{BALL}", TranslationFileReader.catchBallName), + getCoordinate(targetEntity.getLocation()), "")); return; } @@ -182,10 +183,10 @@ public void onPlayerInteractEntity(PlayerInteractEntityEvent event) { } // Handle the entity catch - handleEntityCatch(player, targetEntity, false); + handleEntityCatch(player, targetEntity); } - private void handleEntityCatch(Player player, Entity hitEntity, boolean isProjectile) { + private void handleEntityCatch(Player player, Entity hitEntity) { hitLocation = hitEntity.getLocation(); // Check all protection plugins @@ -195,7 +196,7 @@ private void handleEntityCatch(Player player, Entity hitEntity, boolean isProjec return; } - if (!mmCheck(player, hitEntity) && ConfigSetting.UseMM) { + if (!mmCheck(hitEntity) && ConfigSetting.UseMM) { hitEntity.getWorld().dropItem(hitEntity.getLocation(), Ball.makeBall()); player.sendMessage(ConfigSetting.toChat(TranslationFileReader.canNotCatchable, getCoordinate(hitEntity.getLocation()), "")); return; @@ -238,11 +239,11 @@ private void handleEntityCatch(Player player, Entity hitEntity, boolean isProjec return; }*/ - // Check if entity is tameable and owned by someone else + // Check if entity is tamable and owned by someone else if (hitEntity instanceof Tameable tameable) { if (tameable.isTamed()) { boolean isNullOwnerValue = tameable.getOwner() == null; - boolean sameOwner = isNullOwnerValue ? true : tameable.getOwner().getName().equals(player.getName()); + boolean sameOwner = isNullOwnerValue || Objects.equals(tameable.getOwner().getName(), player.getName()); if ((isNullOwnerValue && !ConfigSetting.allowCatchableTamedOwnerIsNull) || !sameOwner) { hitEntity.getWorld().dropItem(hitEntity.getLocation(), Ball.makeBall()); player.sendMessage(ConfigSetting.toChat(TranslationFileReader.canNotCatchable, getCoordinate(hitEntity.getLocation()), "")); @@ -264,7 +265,11 @@ private void handleEntityCatch(Player player, Entity hitEntity, boolean isProjec // Success sound if (!(ConfigSetting.catchSuccessSound.equals("FALSE"))) { - player.playSound(player.getLocation(), Sound.valueOf(ConfigSetting.catchSuccessSound), 1f, 1f); + NamespacedKey soundKey = NamespacedKey.fromString(ConfigSetting.catchSuccessSound.toLowerCase()); + assert soundKey != null; + Sound sound = Registry.SOUNDS.get(soundKey); + assert sound != null; + player.playSound(player.getLocation(), sound, 1f, 1f); } // Remove the entity and drop the head @@ -314,8 +319,7 @@ public boolean resCheck(Player player, Location location) { for (String flags : ConfigSetting.residenceFlag) { if (!residence.getPermissions().playerHas(player, Flags.valueOf(flags.toLowerCase()) , true)) { - player.sendMessage(ConfigSetting.toChat(TranslationFileReader.noResidencePermissions, "", ""). - replace("{FLAG}", flags)); + player.sendMessage(ConfigSetting.toChat(TranslationFileReader.noResidencePermissions.replace("{FLAG}", flags), "", "")); return false; } @@ -324,7 +328,7 @@ public boolean resCheck(Player player, Location location) { return true; } - public boolean mmCheck(Player player, Entity entity) { + public boolean mmCheck(Entity entity) { if (plugin.getServer().getPluginManager().getPlugin("MythicMobs") == null) { return true; } for (int i=0 ; i < 2; i++) { @@ -336,6 +340,7 @@ public boolean mmCheck(Player player, Entity entity) { return !((boolean) isMythicMob.invoke(ins, entity)); } catch (Exception e) { + plugin.getLogger().warning("An error caused " + e.getMessage()); } } @@ -347,11 +352,7 @@ public boolean landsCheck(Player player, Location location) { LandWorld world = api.getWorld(hitLocation.getWorld()); if (world != null) { // Lands is enabled in this world - if (world.hasFlag(player, hitLocation, null, me.angeschossen.lands.api.flags.Flags.ATTACK_ANIMAL, false)) { - return true; - } else { - return false; - } + return world.hasFlag(player, hitLocation, null, me.angeschossen.lands.api.flags.Flags.ATTACK_ANIMAL, false); } return true; @@ -374,8 +375,7 @@ public boolean gfCheck(Player player, Location location) { for (String flags : ConfigSetting.griefPreventionFlag) { if (!claim.hasExplicitPermission(player, ClaimPermission.valueOf(flags))) { player.sendMessage(ConfigSetting.toChat( - TranslationFileReader.noResidencePermissions, "", "") - .replace("{FLAG}", flags)); + TranslationFileReader.noResidencePermissions.replace("{FLAG}", flags), "", "")); return false; } @@ -418,20 +418,14 @@ public Chunk getChunkFromLocation(Location location) { public boolean townyCheck(Player player, Location location) { if (plugin.getServer().getPluginManager().getPlugin("Towny") == null) { return true; } - boolean bBuild = PlayerCacheUtil.getCachePermission(player, location, Material.valueOf("dirt"), TownyPermission.ActionType.BUILD); - return bBuild; + return PlayerCacheUtil.getCachePermission(player, location, Material.valueOf("dirt"), TownyPermission.ActionType.BUILD); } public boolean checkCatchBall(Projectile projectile) { - if (!(projectile instanceof Snowball)) { return false; } + if (!(projectile instanceof Snowball throwableProjectile)) { return false; } - if (projectile instanceof ThrowableProjectile) { - ThrowableProjectile throwableProjectile = (ThrowableProjectile) projectile; - if (!Objects.requireNonNull(throwableProjectile.getItem().getItemMeta()).equals(Ball.makeBall().getItemMeta())) { return false; } - } - - return true; + return Objects.requireNonNull(throwableProjectile.getItem().getItemMeta()).equals(Ball.makeBall().getItemMeta()); } public String getIsCustomEntity(Entity hitEntity) { diff --git a/src/main/java/com/github/nutt1101/event/SkullClick.java b/src/main/java/com/github/nutt1101/event/SkullClick.java index 6cb4b5b..8563e1d 100644 --- a/src/main/java/com/github/nutt1101/event/SkullClick.java +++ b/src/main/java/com/github/nutt1101/event/SkullClick.java @@ -51,55 +51,49 @@ public void skullClick(PlayerInteractEvent event) { if (data.has(new NamespacedKey(plugin, "skullData"), PersistentDataType.STRING)) { String path = data.get(new NamespacedKey(plugin, "skullData"), PersistentDataType.STRING).toString(); - if (path == null) { - player.sendMessage(ConfigSetting.toChat(TranslationFileReader.skullDoesNotFound, "", "")); + if (!new HitEvent().resCheck(player, event.getClickedBlock().getLocation())) { event.setCancelled(true); - } else { - if (!new HitEvent().resCheck(player, event.getClickedBlock().getLocation())) { - event.setCancelled(true); - return; - } + return; + } - if (!new HitEvent().gfCheck(player, event.getClickedBlock().getLocation())) { - event.setCancelled(true); - return; - } + if (!new HitEvent().gfCheck(player, event.getClickedBlock().getLocation())) { + event.setCancelled(true); + return; + } - try { - // Use safe method to get EntityType - String entityTypeString = data.get(new NamespacedKey(plugin, "entityType"), PersistentDataType.STRING); - EntityType entityType = getEntityType(entityTypeString); + try { + // Use safe method to get EntityType + String entityTypeString = data.get(new NamespacedKey(plugin, "entityType"), PersistentDataType.STRING); + EntityType entityType = getEntityType(entityTypeString); - Location clickLocation = event.getClickedBlock().getLocation(); + Location clickLocation = event.getClickedBlock().getLocation(); - clickLocation.setX(clickLocation.getBlockX() + 0.5); - clickLocation.setZ(clickLocation.getBlockZ() + 0.5); + clickLocation.setX(clickLocation.getBlockX() + 0.5); + clickLocation.setZ(clickLocation.getBlockZ() + 0.5); - for (int i=0; i < 3; i++) { - if (clickLocation.getBlock().getType().equals(Material.AIR) || clickLocation.getBlock().getType().equals(Material.WATER)) { break; } - clickLocation.setY(clickLocation.getY() + 1D); + for (int i = 0; true; i++) { + if (clickLocation.getBlock().getType().equals(Material.AIR) || clickLocation.getBlock().getType().equals(Material.WATER)) { break; } + clickLocation.setY(clickLocation.getY() + 1D); - if (i == 2) { - player.sendMessage(ConfigSetting.toChat(TranslationFileReader.locationUnsafe, "", "")); - event.setCancelled(true); - return; - } + if (i == 2) { + player.sendMessage(ConfigSetting.toChat(TranslationFileReader.locationUnsafe, "", "")); + event.setCancelled(true); + return; } + } - Entity entity = player.getWorld().spawnEntity(clickLocation, entityType); - - Location location = clickLocation.clone(); - location.setX(location.getBlockX() + 0.5); - location.setZ(location.getBlockZ() + 0.5); + Entity entity = player.getWorld().spawnEntity(clickLocation, entityType); - NBTHandler.loadEntityNBT(plugin, entity, data); - PlayerSchedulerUtil.teleport(entity, location); + Location location = clickLocation.clone(); + location.setX(location.getBlockX() + 0.5); + location.setZ(location.getBlockZ() + 0.5); - event.getItem().setAmount(0); - } catch (Exception e) { - e.printStackTrace(); - } + NBTHandler.loadEntityNBT(plugin, entity, data); + PlayerSchedulerUtil.teleport(entity, location); + event.getItem().setAmount(0); + } catch (Exception e) { + plugin.getLogger().warning(e.getMessage()); } } diff --git a/src/main/java/com/github/nutt1101/items/Ball.java b/src/main/java/com/github/nutt1101/items/Ball.java index 38b1dee..51e1b8d 100644 --- a/src/main/java/com/github/nutt1101/items/Ball.java +++ b/src/main/java/com/github/nutt1101/items/Ball.java @@ -2,13 +2,17 @@ import com.github.nutt1101.ConfigSetting; import com.github.nutt1101.utils.TranslationFileReader; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.minimessage.MiniMessage; import net.md_5.bungee.api.ChatColor; import org.bukkit.Material; import org.bukkit.enchantments.Enchantment; import org.bukkit.inventory.ItemFlag; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ItemMeta; +import org.bukkit.inventory.meta.components.CustomModelDataComponent; +import java.util.List; import java.util.stream.Collectors; import static com.github.nutt1101.ConfigSetting.customModelData; @@ -19,16 +23,20 @@ public static ItemStack makeBall() { ItemStack catchball = new ItemStack(Material.SNOWBALL); ItemMeta meta = catchball.getItemMeta(); - meta.setDisplayName(ConfigSetting.toChat(TranslationFileReader.catchBallName, "", "")); + meta.displayName(ConfigSetting.toChat(TranslationFileReader.catchBallName, "", "")); meta.addEnchant(Enchantment.SOUL_SPEED, 1, true); meta.addItemFlags(ItemFlag.HIDE_ENCHANTS); - meta.setLore(TranslationFileReader.catchBallLore.stream().map(lore -> ChatColor. - translateAlternateColorCodes('&', lore)). - collect(Collectors.toList())); + List catchBallLoreComponents = TranslationFileReader.catchBallLore.stream() + .map(lore -> MiniMessage.miniMessage().deserialize(lore)) + .collect(Collectors.toList()); - if(customModelData != 0) { - meta.setCustomModelData(customModelData); + meta.lore(catchBallLoreComponents); + + if(ConfigSetting.customModelData != 0) { + CustomModelDataComponent component = meta.getCustomModelDataComponent(); + component.setFloats(List.of((float) ConfigSetting.customModelData)); + meta.setCustomModelDataComponent(component); } catchball.setItemMeta(meta); diff --git a/src/main/java/com/github/nutt1101/items/DropItem.java b/src/main/java/com/github/nutt1101/items/DropItem.java index 4531c9e..67f11a7 100644 --- a/src/main/java/com/github/nutt1101/items/DropItem.java +++ b/src/main/java/com/github/nutt1101/items/DropItem.java @@ -2,16 +2,17 @@ import com.github.nutt1101.ConfigSetting; import com.github.nutt1101.utils.TranslationFileReader; -import net.md_5.bungee.api.ChatColor; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.minimessage.MiniMessage; import org.bukkit.enchantments.Enchantment; import org.bukkit.inventory.ItemFlag; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ItemMeta; +import java.util.List; import java.util.stream.Collectors; -import static com.github.nutt1101.ConfigSetting.ballCustomModelData; -import static com.github.nutt1101.ConfigSetting.customModelData; +import org.bukkit.inventory.meta.components.CustomModelDataComponent; public class DropItem { @@ -19,16 +20,21 @@ public static ItemStack makeDropItem() { ItemStack dropItem = new ItemStack(ConfigSetting.DropItemMaterial); ItemMeta meta = dropItem.getItemMeta(); - meta.setDisplayName(ConfigSetting.toChat(TranslationFileReader.dropItemName, "", "")); + meta.displayName(ConfigSetting.toChat(TranslationFileReader.dropItemName, "", "")); meta.addEnchant(Enchantment.SOUL_SPEED, 1, true); meta.addItemFlags(ItemFlag.HIDE_ENCHANTS); - meta.setLore(TranslationFileReader.dropItemLore.stream().map(lore -> ChatColor. - translateAlternateColorCodes('&', lore).replace("{PERCENT}", String.valueOf(ConfigSetting. - DropItemChance))).collect(Collectors.toList())); + List loreComponents = TranslationFileReader.dropItemLore.stream() + .map(lore -> lore.replace("{PERCENT}", String.valueOf(ConfigSetting.DropItemChance))) + .map(lore -> MiniMessage.miniMessage().deserialize(lore)) + .collect(Collectors.toList()); - if(ballCustomModelData != 0) { - meta.setCustomModelData(ballCustomModelData); + meta.lore(loreComponents); + + if(ConfigSetting.ballCustomModelData != 0) { + CustomModelDataComponent component = meta.getCustomModelDataComponent(); + component.setFloats(List.of((float) ConfigSetting.ballCustomModelData)); + meta.setCustomModelDataComponent(component); } dropItem.setItemMeta(meta); diff --git a/src/main/java/com/github/nutt1101/utils/NBTHandler.java b/src/main/java/com/github/nutt1101/utils/NBTHandler.java index a227ff5..fc04eff 100644 --- a/src/main/java/com/github/nutt1101/utils/NBTHandler.java +++ b/src/main/java/com/github/nutt1101/utils/NBTHandler.java @@ -1,7 +1,7 @@ package com.github.nutt1101.utils; -import de.tr7zw.changeme.nbtapi.NBTContainer; -import de.tr7zw.changeme.nbtapi.NBTEntity; +import de.tr7zw.changeme.nbtapi.NBT; +import de.tr7zw.changeme.nbtapi.iface.ReadWriteNBT; import org.bukkit.NamespacedKey; import org.bukkit.entity.Ageable; import org.bukkit.entity.Entity; @@ -13,13 +13,17 @@ public class NBTHandler { public static ItemMeta saveEntityNBT(Plugin plugin, Entity hitEntity, ItemMeta headMeta) { - NBTEntity nbtEntity = new NBTEntity(hitEntity); - String nbtData = nbtEntity.toString(); + // Get NBT data from entity using NBT.modify to read the data + final String[] nbtData = new String[1]; + NBT.modify(hitEntity, nbt -> { + nbtData[0] = nbt.toString(); + }); + // Store NBT data in item's persistent data container headMeta.getPersistentDataContainer().set( new NamespacedKey(plugin, "entity"), PersistentDataType.STRING, - nbtData + nbtData[0] ); headMeta.getPersistentDataContainer().set( @@ -35,25 +39,33 @@ public static void loadEntityNBT(Plugin plugin, Entity entity, PersistentDataCon try { String nbtString = data.get(new NamespacedKey(plugin, "entity"), PersistentDataType.STRING); if (nbtString != null) { - NBTContainer nbtContainer = new NBTContainer(nbtString); - NBTEntity nbtEntity = new NBTEntity(entity); - nbtEntity.mergeCompound(nbtContainer); + // Parse NBT string and apply to entity + ReadWriteNBT parsedNBT = NBT.parseNBT(nbtString); + NBT.modify(entity, nbt -> { + nbt.mergeCompound(parsedNBT); + }); + // Handle age-specific logic for Ageable entities if (entity instanceof Ageable ageableEntity) { - if (!nbtContainer.hasTag("IsBaby") || !nbtContainer.getBoolean("IsBaby")) { - ageableEntity.setAdult(); - } else { + boolean isBaby = parsedNBT.hasTag("IsBaby") && parsedNBT.getBoolean("IsBaby"); + if (isBaby) { ageableEntity.setBaby(); + } else { + ageableEntity.setAdult(); } } } } catch (Exception e) { - e.printStackTrace(); + plugin.getLogger().warning("Error loading entity NBT: " + e.getMessage()); } } public static String isCustomEntity(Entity hitEntity) { - NBTEntity nbtEntity = new NBTEntity(hitEntity); - return nbtEntity.getString("Paper.SpawnReason"); + // Read NBT data from entity to check spawn reason + final String[] spawnReason = new String[1]; + NBT.modify(hitEntity, nbt -> { + spawnReason[0] = nbt.getString("Paper.SpawnReason"); + }); + return spawnReason[0]; } -} +} \ No newline at end of file diff --git a/src/main/java/com/github/nutt1101/utils/TranslationFileReader.java b/src/main/java/com/github/nutt1101/utils/TranslationFileReader.java index 56fe8f4..49c569a 100644 --- a/src/main/java/com/github/nutt1101/utils/TranslationFileReader.java +++ b/src/main/java/com/github/nutt1101/utils/TranslationFileReader.java @@ -79,12 +79,7 @@ public static void generateLocaleFile(File localeFile) throws IOException { } if (!localeFile.exists()) { - File localeDir = new File(localeFile.getParent()); - if (!localeDir.exists()) { - localeDir.mkdirs(); - } - - FileOutputStream outputStream = new FileOutputStream(localeFile); + FileOutputStream outputStream = new FileOutputStream(localeFile); inputStream.transferTo(outputStream); outputStream.close(); } diff --git a/src/main/resources/locale/en.yml b/src/main/resources/locale/en.yml index 271fb07..3ccca03 100644 --- a/src/main/resources/locale/en.yml +++ b/src/main/resources/locale/en.yml @@ -4,70 +4,70 @@ # If you installed PlaceholderAPI, you can use Placeholder in messages. # But Placeholder about player may cause some issues. -ConsoleExcuteCommand: "&cThis command can only be executed by player!" -NoPermission: "&cYou have no permission!" -PlayerInventoryFull: "&aYour inventory is full, so item falls at your feet!" +ConsoleExcuteCommand: "This command can only be executed by player!" +NoPermission: "You have no permission!" +PlayerInventoryFull: "Your inventory is full, so item falls at your feet!" -ArgDoesNotExist: "&aCommands Usage: - \n&b/ctb reload &7Reload plugin. - \n&b/ctb list &7Lists all catchable entities and states. - \n&b/ctb add [ALL | (entity_name)] &7Add the entity to the catch list. - \n&b/ctb remove [ALL | (entity_name)] &7Remove the entity from the catchable list. - \n&b/ctb give [player] [DropItem | CatchBall] [Amount] &7Give special items of plugins to player" +ArgDoesNotExist: "Commands Usage: + \n/ctb reload Reload plugin. + \n/ctb list Lists all catchable entities and states. + \n/ctb add [ALL | (entity_name)] Add the entity to the catch list. + \n/ctb remove [ALL | (entity_name)] Remove the entity from the catchable list. + \n/ctb give [player] [DropItem | CatchBall] [Amount] Give special items of plugins to player" -ArgTooMuch: "&cToo many Argument!" -UnknownCommandArgument: "&cUnknown Argument!" -SuccessGetBall: "&aSuccessfully get {ITEM}!" -ReloadSuccess: "&aThe plugin reloaded successfully!" -CanNotCatchable: "&cThis entity cannot be captured, so &e{BALL} &7fell in &e{LOCATION}." -BallHitBlock: "&cYou did not hit a entity,So {BALL} fell in {LOCATION}!" -NoPermissionToUse: "&cYou don't have permission to use {BALL}, so {BALL} &cfell in &e{LOCATION}." -CatchSuccess: "&aSuccessfully captured {ENTITY} location: {LOCATION}!" -ItemDoesNotExist: "&cPlease enter the item to be picked up &7CatchBall | DropItem." -ItemNameError: "&cPlease enter the correct item name &7CatchBall | DropItem!" -AddEntityDoesNotExist: "&cPlease enter the name of the entity to be added to the list of captured creatures!" -UnknownEntityType: "&cUnknown entity type!" -EntityDoesExists: "&cThe entity already exists in the catchable list!" -SuccessAddEntity: "&b{ENTITY} &aSuccessfully added to the catchable list!" -RemoveEntityDoesNotExist: "&cPlease enter the name of the entity to be removed from the catchable list!" -RemoveEntityNotFound: "&cNo entity found in the catchable list!" -SuccessRemove: "&aSuccessfully removed from the catchable list &b{ENTITY}!" -SkullDoesNotFound: "&cThe data stored in the skull is missing!" -LocationUnsafe: "&cCould not find a safe area to spawn, so this request has been cancelled!" -NoResidencePermissions: "&cYou can’t spawn entity here because you are lacking {FLAG} permission for this residense!" -AllEntityAddSuccess: "&aAll Entity added success!" -AllEntityRemoveSuccess: "&eAll Entity removed success!" -PlayerNotExist: "&cPlease enter a player that want to give the item!" -UnknownOrOfflinePlayer: "&cPlayer {PLAYER} not find!" -SuccessGiveItemToPlayer: "&aSuccess give {ITEM} to &a{PLAYER}!" -invalidItemAmount: "&cInvalid item amount!" +ArgTooMuch: "Too many Argument!" +UnknownCommandArgument: "Unknown Argument!" +SuccessGetBall: "Successfully get {ITEM}!" +ReloadSuccess: "The plugin reloaded successfully!" +CanNotCatchable: "This entity cannot be captured, so {BALL} fell in {LOCATION}." +BallHitBlock: "You did not hit a entity,So {BALL} fell in {LOCATION}!" +NoPermissionToUse: "You don't have permission to use {BALL}, so {BALL} fell in {LOCATION}." +CatchSuccess: "Successfully captured {ENTITY} location: {LOCATION}!" +ItemDoesNotExist: "Please enter the item to be picked up CatchBall | DropItem." +ItemNameError: "Please enter the correct item name CatchBall | DropItem!" +AddEntityDoesNotExist: "Please enter the name of the entity to be added to the list of captured creatures!" +UnknownEntityType: "Unknown entity type!" +EntityDoesExists: "The entity already exists in the catchable list!" +SuccessAddEntity: "{ENTITY} Successfully added to the catchable list!" +RemoveEntityDoesNotExist: "Please enter the name of the entity to be removed from the catchable list!" +RemoveEntityNotFound: "No entity found in the catchable list!" +SuccessRemove: "Successfully removed from the catchable list {ENTITY}!" +SkullDoesNotFound: "The data stored in the skull is missing!" +LocationUnsafe: "Could not find a safe area to spawn, so this request has been cancelled!" +NoResidencePermissions: "You can't spawn entity here because you are lacking {FLAG} permission for this residense!" +AllEntityAddSuccess: "All Entity added success!" +AllEntityRemoveSuccess: "All Entity removed success!" +PlayerNotExist: "Please enter a player that want to give the item!" +UnknownOrOfflinePlayer: "Player {PLAYER} not find!" +SuccessGiveItemToPlayer: "Success give {ITEM} to {PLAYER}!" +invalidItemAmount: "Invalid item amount!" catchFail: "Oops! Your attempt to catch the creature failed. Try again!" #/ctb list GUI -catchableListTitle: "&lCatch List Settings" -prevPage: "&aPrevious Page" -nextPage: "&aNext Page" -currentPage: "&eCurrent Page: &a{PAGE}" +catchableListTitle: "Catch List Settings" +prevPage: "Previous Page" +nextPage: "Next Page" +currentPage: "Current Page: {PAGE}" guiSkullLore: - - "&6Custom Name: {ENTITY}" - - "&6Allow Catch: {CATCHABLE}" + - "Custom Name: {ENTITY}" + - "Allow Catch: {CATCHABLE}" #The plugin special item setting Items: CatchBall: - DisplayName: "&aCat&bch &cBall" + DisplayName: "Catch Ball" Lore: - - "&7Used to capture catchable entity" + - "Used to capture catchable entity" DropItem: - DisplayName: "&6GoldEgg" + DisplayName: "GoldEgg" Lore: - - "&7When destroying blocks, killing creatures, or laying eggs, there is a &e{PERCENT}%&7 chance of dropping" - - "&7Can be used with CraftRecipe to make CatchBall" + - "When destroying blocks, killing creatures, or laying eggs, there is a {PERCENT}% chance of dropping" + - "Can be used with CraftRecipe to make CatchBall" #The lore of the Catch List GUI DropSkullLore: - - "&eENTITY TYPE: &a{ENTITY}" - - "&eThe Catcher: &a{PLAYER}" - - "&eCapture Time: &a{TIME}" - - "&eCapture Location: &a{LOCATION}" + - "ENTITY TYPE: {ENTITY}" + - "The Catcher: {PLAYER}" + - "Capture Time: {TIME}" + - "Capture Location: {LOCATION}" \ No newline at end of file diff --git a/src/main/resources/paper-plugin.yml b/src/main/resources/paper-plugin.yml new file mode 100644 index 0000000..3a4d768 --- /dev/null +++ b/src/main/resources/paper-plugin.yml @@ -0,0 +1,52 @@ +name: CatchBall +version: ${version} +main: com.github.nutt1101.CatchBall +description: "A plugin that make entity to be catchable.\nDiscord support: https://discord.gg/uQ4UXANnP2" +author: NUTT1101, MagicTeaMC +api-version: '1.21' +folia-supported: true + +dependencies: + server: + Residence: + load: BEFORE + required: false + join-classpath: false + MythicMobs: + load: BEFORE + required: false + join-classpath: false + GriefPrevention: + load: BEFORE + required: false + join-classpath: false + Lands: + load: BEFORE + required: false + join-classpath: false + RedProtect: + load: BEFORE + required: false + join-classpath: false + PlaceholderAPI: + load: BEFORE + required: false + join-classpath: false + SimpleClaimSystem: + load: BEFORE + required: false + join-classpath: false + Towny: + load: BEFORE + required: false + join-classpath: false + +permissions: + catchball.op: + default: op + catchball.use: + default: true + catchball.get.entity: + default: false + catchball.get.block: + default: false \ No newline at end of file diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml deleted file mode 100644 index 2bd3a83..0000000 --- a/src/main/resources/plugin.yml +++ /dev/null @@ -1,20 +0,0 @@ -name: CatchBall -main: com.github.nutt1101.CatchBall -author: NUTT1101, MagicTeaMC -description: "§bA plugin that make entity to be catchable.\n§dDiscord support: https://discord.gg/uQ4UXANnP2" -version: ${version} -api-version: 1.16 -softdepend: [Residence, MythicMobs, GriefPrevention, Lands, RedProtect, PlaceholderAPI, SimpleClaimSystem] -permissions: - catchball.op: - default: op - catchball.use: - default: true - catchball.get.entity: - default: false - catchball.get.block: - default: false -commands: - ctb: - description: "Command Help : /ctb" -folia-supported: true