From b4aa5ce75580dea7f94c240a4dd8756a96636dc9 Mon Sep 17 00:00:00 2001 From: PinozenTH Date: Mon, 6 Oct 2025 23:53:02 +0700 Subject: [PATCH 01/13] remove deprecated class --- .../pinont/singularitylib/plugin/DevTool.java | 1402 ----------------- .../singularitylib/plugin/cmd/FlySpeed.java | 71 - .../singularitylib/plugin/cmd/Vanish.java | 45 - 3 files changed, 1518 deletions(-) delete mode 100644 src/main/java/com/github/pinont/singularitylib/plugin/DevTool.java delete mode 100644 src/main/java/com/github/pinont/singularitylib/plugin/cmd/FlySpeed.java delete mode 100644 src/main/java/com/github/pinont/singularitylib/plugin/cmd/Vanish.java diff --git a/src/main/java/com/github/pinont/singularitylib/plugin/DevTool.java b/src/main/java/com/github/pinont/singularitylib/plugin/DevTool.java deleted file mode 100644 index 213582f..0000000 --- a/src/main/java/com/github/pinont/singularitylib/plugin/DevTool.java +++ /dev/null @@ -1,1402 +0,0 @@ -package com.github.pinont.singularitylib.plugin; - -import com.github.pinont.singularitylib.api.command.SimpleCommand; -import com.github.pinont.singularitylib.api.items.CustomItem; -import com.github.pinont.singularitylib.api.items.ItemCreator; -import com.github.pinont.singularitylib.api.items.ItemHeadCreator; -import com.github.pinont.singularitylib.api.items.ItemInteraction; -import com.github.pinont.singularitylib.api.manager.WorldManager; -import com.github.pinont.singularitylib.api.ui.Button; -import com.github.pinont.singularitylib.api.ui.Layout; -import com.github.pinont.singularitylib.api.ui.Menu; -import io.papermc.paper.command.brigadier.CommandSourceStack; -import org.bukkit.*; -import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; -import org.bukkit.event.EventHandler; -import org.bukkit.event.Listener; -import org.bukkit.event.block.Action; -import org.bukkit.event.player.PlayerChatEvent; -import org.bukkit.inventory.ItemStack; -import org.bukkit.metadata.FixedMetadataValue; -import org.jetbrains.annotations.NotNull; - -import java.util.*; - -import static com.github.pinont.singularitylib.plugin.CorePlugin.getAPIVersion; -import static com.github.pinont.singularitylib.plugin.CorePlugin.getInstance; - -/** - * Developer tool for testing and debugging plugin functionality. - * Provides a comprehensive interface for developers to test various features - * including world management, teleportation, and other debugging utilities. - * - * @deprecated since 2.1.0, will be removed in future versions - */ -@Deprecated(since = "2.1.0", forRemoval = true) -public class DevTool extends CustomItem implements SimpleCommand, Listener { - - private final String version = getAPIVersion(); - - /** - * Default constructor for DevTool. - */ - public DevTool() { - } - - @Override - public ItemCreator register() { - return new ItemCreator(Material.DIAMOND).setName(ChatColor.DARK_RED + "Developer Tool").setUnstackable(true).addInteraction( - new ItemInteraction() { - @Override - public String getName() { - return "DevTool"; - } - - @Override - public Set getAction() { - return Set.of(Action.LEFT_CLICK_AIR, Action.LEFT_CLICK_BLOCK, Action.RIGHT_CLICK_AIR, Action.RIGHT_CLICK_BLOCK); - } - - @Override - public void execute(Player player) { - openDevTool(player); - } - } - ); - } - - /** - * Opens the developer tool interface for the specified player. - * - * @param player the player to open the interface for - */ - public void openDevTool(Player player) { - Menu devMenu = new Menu(ChatColor.DARK_RED + "Developer Tools " + ChatColor.GRAY + "(" + version + ")", 9*5); - devMenu.setLayout("=========", "====i====", "=========", "==w=p=t==", "========="); - devMenu.setKey( - blank(), - new Layout() { - - @Override - public char getKey() { - return 'i'; - } - - @Override - public Button getButton() { - return new Button() { - - @Override - public ItemStack getItem() { - return new ItemCreator(new ItemStack(Material.GRASS_BLOCK)).setName(ChatColor.GREEN + "Server Info").addLore(ChatColor.GRAY + "Server: " + ChatColor.YELLOW + Bukkit.getServer().getName(), ChatColor.GRAY + "Version: " + ChatColor.YELLOW + Bukkit.getServer().getVersion(), ChatColor.GRAY + "Plugins (" + ChatColor.YELLOW + Bukkit.getServer().getPluginManager().getPlugins().length + ChatColor.GRAY + ")").create(); - } - - @Override - public void onClick(Player player) { - - } - }; - } - }, - new Layout() { - @Override - public char getKey() { - return 'p'; - } - - @Override - public Button getButton() { - return new Button() { - @Override - public ItemStack getItem() { - return new ItemHeadCreator(new ItemStack(Material.PLAYER_HEAD)).setOwner(player.getName()).setName("Player List").create(); - } - - @Override - public void onClick(Player player) { - showServerPlayerManager(player); - } - }; - } - }, - new Layout() { - @Override - public char getKey() { - return 'w'; // worldcreator - } - - @Override - public Button getButton() { - return new Button() { - @Override - public ItemStack getItem() { - return new ItemCreator(new ItemStack(Material.COARSE_DIRT)).setName("Worlds").create(); - } - - @Override - public void onClick(Player player) { - showServerWorldManger(player); - } - }; - } - }, - new Layout() { - @Override - public char getKey() { - return 't'; // tools - } - - @Override - public Button getButton() { - return new Button() { - @Override - public ItemStack getItem() { - return new ItemCreator(Material.STICK).setName("Tools").addLore("More Tools").create(); - } - - @Override - public void onClick(Player player) { - showOtherTools(player); - } - }; - } - } - ); - devMenu.show(player); - } - - private void showOtherTools(Player player) { - new Menu("Heldable Tool", 9 * 3).setLayout("=========", "==m=w=o==", "=========").setKey( - blank(), - new Layout() { - @Override - public char getKey() { - return 'm'; // mobCreator - } - - @Override - public Button getButton() { - return null; - } - }, - new Layout() { - @Override - public char getKey() { - return 'o'; // itemCreator - } - - @Override - public Button getButton() { - return null; - } - }, - new Layout() { - @Override - public char getKey() { - return 'w'; // later - } - - @Override - public Button getButton() { - return null; - } - } - ).show(player); - - } - - private ItemStack getWorldEnvironmentBlock(World world) { - return getWorldEnvironmentBlock(world.getEnvironment()); - } - - private ItemStack getWorldEnvironmentBlock(World.Environment worldEnv) { - return switch (worldEnv) { - case NORMAL -> new ItemStack(Material.GRASS_BLOCK); - case NETHER -> new ItemStack(Material.NETHERRACK); - case THE_END -> new ItemStack(Material.END_STONE); - default -> new ItemStack(Material.COMMAND_BLOCK); - }; - } - - private void showServerWorldManger(Player p) { - Menu worldManagerMenu = new Menu("World Manager", 9); - int count = 0; - for (World world : Bukkit.getWorlds()) { - int finalCount = count; - worldManagerMenu.addButton(new Button() { - @Override - public int getSlot() { - return finalCount; - } - - @Override - public ItemStack getItem() { - return new ItemCreator(getWorldEnvironmentBlock(world)).setName(properWorldName(world)).addLore(ChatColor.BOLD + "" + ChatColor.YELLOW + "Click to edit").create(); - } - - @Override - public void onClick(Player player) { - showSingleWorldManager(world, player); - } - }); - count++; - } - int finalCount = count; - worldManagerMenu.addButton(new Button() { - @Override - public int getSlot() { - return finalCount; - } - - @Override - public ItemStack getItem() { - return new ItemCreator(new ItemStack(Material.BEDROCK)).setName(ChatColor.YELLOW + "Click to create new world").create(); - } - - @Override - public void onClick(Player player) { - showWorldCreator(player); - } - }); - worldManagerMenu.show(p); - } - - private void showWorldCreator(Player player) { - getWorldCreatorMenu(null, World.Environment.NORMAL, WorldType.NORMAL, true, 1000, Difficulty.EASY, new Random().nextLong(System.currentTimeMillis())).show(player); - } - - /** - * Shows the world creator interface with specified parameters. - * - * @param player the player to show the interface to - * @param world_name the name of the world to create - * @param environment the world environment type - * @param worldType the world type - * @param generate_structure whether to generate structures - * @param borderSize the world border size - * @param difficulty the world difficulty - * @param seed the world seed - */ - public void showWorldCreator(Player player, String world_name, World.Environment environment, WorldType worldType, boolean generate_structure, int borderSize, Difficulty difficulty, long seed) { - getWorldCreatorMenu(world_name, environment, worldType, generate_structure, borderSize, difficulty, seed).show(player); - } - - /** - * Interface for capturing world creator content and user input. - * Used to maintain state during world creation process when players input values via chat. - */ - public interface WorldCreatorContent { - /** - * Gets the type of input content being processed. - * - * @return the input content type - */ - String getInputContent(); - - /** - * Gets the name of the world being created. - * - * @return the world name - */ - String getWorldName(); - - /** - * Gets the world environment type. - * - * @return the world environment - */ - World.Environment getEnvironment(); - - /** - * Gets the world type for generation. - * - * @return the world type - */ - WorldType getWorldType(); - - /** - * Gets whether structures should be generated in the world. - * - * @return true if structures should be generated, false otherwise - */ - boolean getGenerateStructure(); - - /** - * Gets the world border size. - * - * @return the border size in blocks - */ - int getBorderSize(); - - /** - * Gets the world difficulty setting. - * - * @return the difficulty level - */ - Difficulty getDifficulty(); - - /** - * Gets the world seed for generation. - * - * @return the world seed - */ - Long getSeed(); - } - - private Menu getWorldCreatorMenu(String name, World.Environment environment, WorldType worldType, boolean generate_structure, int borderSize, Difficulty difficulty, Long seed) { - Menu worldCreatorMenu = new Menu("World Creator").setLayout("----w----", "-=n=e=t=-", "-=g=b=s=-", "----c----"); - return worldCreatorMenu.setKey( - blank(), - new Layout() { - @Override - public char getKey() { - return '-'; - } // border - - @Override - public Button getButton() { - return new Button() { - @Override - public ItemStack getItem() { - return new ItemCreator(Material.YELLOW_STAINED_GLASS_PANE).setName(" ").create(); - } - - @Override - public void onClick(Player player) { - - } - }; - } - }, - new Layout() { - @Override - public char getKey() { - return 'w'; - } // world creator icon - - @Override - public Button getButton() { - return new Button() { - @Override - public ItemStack getItem() { - return new ItemCreator(new ItemStack(Material.GOLD_BLOCK)).setName(ChatColor.BOLD + "" + ChatColor.YELLOW + "World Creator").addLore( - ChatColor.GRAY + "Name: " + ChatColor.YELLOW + (name == null ? ChatColor.RED + "Not Set" : name), - ChatColor.GRAY + "Environment Type: " + ChatColor.YELLOW + (environment == null ? ChatColor.RED + "Not Set" : environment), - ChatColor.GRAY + "World Type: " + ChatColor.YELLOW + (worldType == null ? ChatColor.RED + "Not Set" : worldType), - ChatColor.GRAY + "Difficulty: " + ChatColor.YELLOW + difficulty, - ChatColor.GRAY + "Generate Structure: " + ChatColor.YELLOW + (generate_structure ? "True" : "False"), - ChatColor.GRAY + "Border Size: " + ChatColor.YELLOW + borderSize, - ChatColor.GRAY + "Seed: " + ChatColor.YELLOW + (seed == null ? ChatColor.RED + "RANDOM" : seed) - ).create(); - } - - @Override - public void onClick(Player player) { - player.closeInventory(); - player.sendMessage(ChatColor.YELLOW + "World '" + name + "' is Creating..."); - createWorld(name, environment, worldType, generate_structure, borderSize, difficulty, seed); - player.sendMessage(ChatColor.GREEN + "World '" + name + "' has been created!"); - } - }; - } - }, - new Layout() { - @Override - public char getKey() { - return 'n'; - } // set world name - - @Override - public Button getButton() { - return new Button() { - @Override - public ItemStack getItem() { - if (name == null) { - return new ItemCreator(Material.OAK_SIGN).setName("Set World Name").addLore(ChatColor.YELLOW + "Click to set world name.").create(); - } - return new ItemCreator(Material.BIRCH_SIGN).setName(name).addLore(ChatColor.YELLOW + "Click to change world name.").create(); - } - - @Override - public void onClick(Player player) { - player.sendMessage(ChatColor.GRAY + "Please send a world name into chat."); - player.setMetadata("devTool", new FixedMetadataValue(getInstance(), new WorldCreatorContent() { - @Override - public String getInputContent() { - return "worldName"; - } - - @Override - public String getWorldName() { - return name; - } - - @Override - public World.Environment getEnvironment() { - return environment; - } - - @Override - public WorldType getWorldType() { - return worldType; - } - - @Override - public boolean getGenerateStructure() { - return generate_structure; - } - - @Override - public int getBorderSize() { - return borderSize; - } - - @Override - public Difficulty getDifficulty() { - return difficulty; - } - - @Override - public Long getSeed() { - return seed; - } - })); - player.closeInventory(); - } - }; - } - }, - new Layout() { - @Override - public char getKey() { - return 'e'; // environment - } - - @Override - public Button getButton() { - return new Button() { - @Override - public ItemStack getItem() { - if (environment == null) { - return new ItemCreator(Material.COMMAND_BLOCK).setName("Set World Environment").addLore(ChatColor.YELLOW + "Click to change world environment.").create(); - } - return new ItemCreator(getWorldEnvironmentBlock(environment)).setName(environment.name()).addLore(ChatColor.YELLOW + "Click to change world environment.").create(); - } - - @Override - public void onClick(Player player) { - World.Environment[] environments = World.Environment.values(); - int currentIndex = environment == null ? -1 : java.util.Arrays.asList(environments).indexOf(environment); - int nextIndex = (currentIndex + 1) % environments.length; - showWorldCreator(player, name, environments[nextIndex], worldType, generate_structure, borderSize, difficulty, seed); - } - }; - } - }, - new Layout() { - @Override - public char getKey() { - return 't'; // world type - } - - @Override - public Button getButton() { - return new Button() { - @Override - public ItemStack getItem() { - if (worldType == null) { - return new ItemCreator(Material.OAK_SAPLING).setName("Set World Type").addLore(ChatColor.YELLOW + "Click to change world type.").create(); - } - return new ItemCreator(Material.CHERRY_SAPLING).setName(worldType.getName()).addLore(ChatColor.YELLOW + "Click to change world type").create(); - } - - @Override - public void onClick(Player player) { - WorldType[] worldTypes = WorldType.values(); - int currentTypeIndex = worldType == null ? -1 : java.util.Arrays.asList(worldTypes).indexOf(worldType); - int nextTypeIndex = (currentTypeIndex + 1) % worldTypes.length; - - showWorldCreator(player, name, environment, worldTypes[nextTypeIndex], generate_structure, borderSize, difficulty, seed); - } - }; - } - }, - new Layout() { - @Override - public char getKey() { - return 'g'; // generate structure? def = true - } - - @Override - public Button getButton() { - return new Button() { - @Override - public ItemStack getItem() { - if (generate_structure) return new ItemCreator(Material.BIRCH_STAIRS).setName(ChatColor.GRAY + "Generate Structure: " + ChatColor.GREEN + "True").create(); - return new ItemCreator(Material.ACACIA_STAIRS).setName(ChatColor.GRAY + "Generate Structure: " + ChatColor.GREEN + "False").create(); - } - - @Override - public void onClick(Player player) { - showWorldCreator(player, name, environment, worldType, !generate_structure, borderSize, difficulty, seed); - } - }; - } - }, - new Layout() { - @Override - public char getKey() { - return 'b'; // border size? def = default - } - - @Override - public Button getButton() { - return new Button() { - @Override - public ItemStack getItem() { - return new ItemCreator(Material.STRUCTURE_VOID).setName(ChatColor.GRAY + "World Border Size: " + ChatColor.YELLOW + borderSize).create(); - } - - @Override - public void onClick(Player player) { - player.sendMessage(ChatColor.GRAY + "Please send a world border size into chat."); - player.setMetadata("devTool", new FixedMetadataValue(getInstance(), new WorldCreatorContent() { - @Override - public String getInputContent() { - return "worldBorder"; - } - - @Override - public String getWorldName() { - return name; - } - - @Override - public World.Environment getEnvironment() { - return environment; - } - - @Override - public WorldType getWorldType() { - return worldType; - } - - @Override - public boolean getGenerateStructure() { - return generate_structure; - } - - @Override - public int getBorderSize() { - return borderSize; - } - - @Override - public Difficulty getDifficulty() { - return difficulty; - } - - @Override - public Long getSeed() { - return seed; - } - })); - player.closeInventory(); - } - }; - } - }, - new Layout() { - @Override - public char getKey() { - return 's'; // seed? def = default - } - - @Override - public Button getButton() { - return new Button() { - @Override - public ItemStack getItem() { - return new ItemCreator(Material.WHEAT_SEEDS).setName(ChatColor.GRAY + "Seed: " + ChatColor.YELLOW + seed).create(); - } - - @Override - public void onClick(Player player) { - player.sendMessage(ChatColor.GRAY + "Please send a seed number into chat."); - player.setMetadata("devTool", new FixedMetadataValue(getInstance(), new WorldCreatorContent() { - @Override - public String getInputContent() { - return "worldSeed"; - } - - @Override - public String getWorldName() { - return name; - } - - @Override - public World.Environment getEnvironment() { - return environment; - } - - @Override - public WorldType getWorldType() { - return worldType; - } - - @Override - public boolean getGenerateStructure() { - return generate_structure; - } - - @Override - public int getBorderSize() { - return borderSize; - } - - @Override - public Difficulty getDifficulty() { - return difficulty; - } - - @Override - public Long getSeed() { - return seed; - } - })); - player.closeInventory(); - } - }; - } - }, - new Layout() { - @Override - public char getKey() { - return 'c'; // create button - } - - @Override - public Button getButton() { - return new Button() { - @Override - public ItemStack getItem() { - return new ItemCreator(Material.DIAMOND).setName(ChatColor.WHITE + "Create World").addLore(ChatColor.YELLOW + "Click to create world.").create(); - } - - @Override - public void onClick(Player player) { - player.closeInventory(); - player.sendMessage(ChatColor.YELLOW + "World '" + name + "' is Creating..."); - createWorld(name, environment, worldType, generate_structure, borderSize, difficulty, seed); - player.sendMessage(ChatColor.GREEN + "World '" + name + "' has been created!"); - } - }; - } - } - ); - } - - private void createWorld(String name, World.Environment environment, WorldType worldType, boolean generate_structure, int borderSize, Difficulty difficulty, Long seed) { - if (name == null) { - name = "custom_world_" + environment.name() + "_" + worldType.getName() + "_" + System.currentTimeMillis(); - } - new WorldManager(name).create(worldType, environment, generate_structure, borderSize, difficulty, seed); - } - - private void showSingleWorldManager(World world, Player player) { - Menu worldManagerMenu = new Menu(world.getName() + ": World Manager"); - worldManagerMenu.setLayout("=========", "====w====", "=========", "==t=d=r==", "========="); - worldManagerMenu.setKey( - blank(), - new Layout() { - - @Override - public char getKey() { - return 'w'; - } - - @Override - public Button getButton() { - return new Button() { // world info - - @Override - public ItemStack getItem() { - - return new ItemCreator(getWorldEnvironmentBlock(world)).setName(ChatColor.GREEN + "World Info").addLore(ChatColor.GRAY + "Name: " + ChatColor.YELLOW + properWorldName(world), ChatColor.GRAY + "Difficulty: " + ChatColor.YELLOW + world.getDifficulty(), ChatColor.GRAY + "Environment Type: " + ChatColor.YELLOW + world.getEnvironment()).create(); - } - - @Override - public void onClick(Player player) { - - } - }; - } - }, - new Layout() { - @Override - public char getKey() { - return 't'; // teleport - } - - @Override - public Button getButton() { - return new Button() { - @Override - public ItemStack getItem() { - return new ItemCreator(new ItemStack(Material.BEACON)).setName("Teleport").addLore(ChatColor.BOLD + "" + ChatColor.YELLOW + "Click to Teleport").create(); - } - - @Override - public void onClick(Player player) { - if (player.getWorld() != world) { - player.sendMessage(ChatColor.GRAY + "Teleporting to " + properWorldName(world) + "..."); - player.teleport(world.getSpawnLocation()); - } else { - player.sendMessage(ChatColor.RED + "You are already in this world!"); - } - } - }; - } - }, - new Layout() { - @Override - public char getKey() { - return 'r'; // gamerules - } - - @Override - public Button getButton() { - return null; - } - }, - worldDeleteButton(world) - ).show(player); - } - - private Layout worldDeleteButton(World world) { - if (world.hasMetadata("loader")) { - return new Layout() { - @Override - public char getKey() { - return 'd'; - } - - @Override - public Button getButton() { - return new Button() { - @Override - public ItemStack getItem() { - return new ItemCreator(Material.RED_STAINED_GLASS).setName(ChatColor.RED +"Delete").addLore(ChatColor.RED + "Click here to delete this world").create(); - } - - @Override - public void onClick(Player player) { - showDeleteWorldApproval(player, world); - } - }; - } - }; - } - return new Layout() { - @Override - public char getKey() { - return 'd'; - } - - @Override - public Button getButton() { - return new Button() { - @Override - public ItemStack getItem() { - return new ItemCreator(Material.AIR).create(); - } - - @Override - public void onClick(Player player) { - - } - }; - } - }; - } - - private void showDeleteWorldApproval(Player player, World targetWorld) { - new Menu(ChatColor.RED + "Are you sure to delete " + targetWorld.getName() + "?") - .setLayout("=========", "====w====", "=========", "==a===d==", "=========") - .setKey(blank(), - new Layout() { - @Override - public char getKey() { - return 'w'; - } - - @Override - public Button getButton() { - return new Button() { - @Override - public ItemStack getItem() { - return new ItemCreator(new ItemStack(getWorldEnvironmentBlock(targetWorld))).setName(ChatColor.RED + "Are you sure to delete " + targetWorld.getName() + "?").create(); - } - - @Override - public void onClick(Player player) { - - } - }; - } - }, - new Layout() { - @Override - public char getKey() { - return 'a'; - } - - @Override - public Button getButton() { - return new Button() { - @Override - public ItemStack getItem() { - return new ItemCreator(Material.GREEN_STAINED_GLASS).setName(ChatColor.GREEN + "ACCEPT").create(); - } - - @Override - public void onClick(Player player) { - WorldManager.delete(targetWorld.getName()); - player.sendMessage(ChatColor.RED + targetWorld.getName() + " is now mark for removal!"); - showServerWorldManger(player); - } - }; - } - }, - new Layout() { - @Override - public char getKey() { - return 'd'; - } - - @Override - public Button getButton() { - return new Button() { - @Override - public ItemStack getItem() { - return new ItemCreator(Material.RED_STAINED_GLASS).setName(ChatColor.RED + "DENY").create(); - } - - @Override - public void onClick(Player player) { - showSingleWorldManager(targetWorld, player); - } - }; - } - } - ).show(player); - } - - private String properWorldName(World world) { - String formattedName = world.getName().replace("_", " "); - StringBuilder result = new StringBuilder(); - boolean capitalizeNext = true; - - for (char c : formattedName.toCharArray()) { - if (capitalizeNext && Character.isLetter(c)) { - result.append(Character.toUpperCase(c)); - capitalizeNext = false; - } else { - result.append(c); - } - if (c == ' ') { - capitalizeNext = true; - } - } - - return result.toString(); - } - - private Layout blank() { - return new Layout() { - @Override - public char getKey() { - return '='; - } - - @Override - public Button getButton() { - return new Button() { - @Override - public ItemStack getItem() { - return new ItemStack(Material.AIR); - } - - @Override - public void onClick(Player player) { - - } - }; - } - }; - } - - private void showServerPlayerManager(Player origin) { -// int max = 45; - Menu playerManager = new Menu("Player Manager", 9); // temp - for (int i = 0; i < Bukkit.getOnlinePlayers().size(); i++) { - Player player = (Player) Bukkit.getOnlinePlayers().toArray()[i]; - int finalI = i; - playerManager.addButton(new Button() { - @Override - public int getSlot() { - return finalI; - } - - @Override - public ItemStack getItem() { - return new ItemHeadCreator(new ItemStack(Material.PLAYER_HEAD)).setOwner(player.getName()).setName(player.getName()).create(); - } - - @Override - public void onClick(Player player) { - showSpecificPlayerManager(origin, player); - } - }); - } - playerManager.show(origin); - } - - private void showSpecificPlayerManager(Player origin, Player target) { - Menu playerManager = new Menu("Player Manager", 9 * 5); - playerManager.setLayout("====p====", "=========", "==t=i=o==", "==b=k=n==", "====v====", "========="); - playerManager.setKey( - blank(), - new Layout() { - @Override - public char getKey() { - return 'p'; - } - - @Override - public Button getButton() { - return new Button() { - @Override - public ItemStack getItem() { - String firstPlayedDate = new java.text.SimpleDateFormat("dd/MM/yyyy HH:mm") - .format(new java.util.Date(target.getFirstPlayed())); - return new ItemHeadCreator(new ItemStack(Material.PLAYER_HEAD)) - .setOwner(target.getName()) - .setName(target.getName()) - .addLore(ChatColor.BOLD + "" + ChatColor.GRAY + "First Joined: " + ChatColor.YELLOW + firstPlayedDate) - .create(); - } - - @Override - public void onClick(Player player) { - } - }; - } - }, - new Layout() { - @Override - public char getKey() { - return 't'; // teleport - } - - @Override - public Button getButton() { - return new Button() { - @Override - public ItemStack getItem() { - return new ItemCreator(new ItemStack(Material.BEACON)).setName("Teleport").addLore(ChatColor.BOLD + "" + ChatColor.YELLOW + "Click to Teleport").create(); - } - - @Override - public void onClick(Player player) { - player.teleport(target.getLocation()); - player.closeInventory(); - } - }; - } - }, - new Layout() { - @Override - public char getKey() { - return 'i'; // player Inventory - } - - @Override - public Button getButton() { - return null; - } - }, - new Layout() { - @Override - public char getKey() { - return 'b'; - } - - @Override - public Button getButton() { - return new Button() { - @Override - public ItemStack getItem() { - return new ItemCreator(Material.ANVIL).setName(ChatColor.RED + "Ban").addLore(ChatColor.RED + "Click to ban.").create(); - } - - @Override - public void onClick(Player player) { - showBanPlayerApproval(player, target); - } - }; - } - }, - new Layout() { - @Override - public char getKey() { - return 'k'; - } - - @Override - public Button getButton() { - return new Button() { - @Override - public ItemStack getItem() { - return new ItemCreator(Material.REDSTONE).setName(ChatColor.RED + "Kick").addLore(ChatColor.RED + "Click to kick.").create(); - } - - @Override - public void onClick(Player player) { - showKickPlayerApproval(player, target); - } - }; - } - }, - new Layout() { - @Override - public char getKey() { - return 'o'; // op Player - } - - @Override - public Button getButton() { - return null; - } - }, - new Layout() { - @Override - public char getKey() { - return 'n'; // invincibility - } - - @Override - public Button getButton() { - return new Button() { - @Override - public ItemStack getItem() { - return new ItemCreator(Material.TOTEM_OF_UNDYING).setName("God: " + target.isInvulnerable()).create(); - } - - @Override - public void onClick(Player player) { - target.setInvulnerable(!target.isInvulnerable()); - if (Bukkit.getServer().getAllowFlight()) { - target.setAllowFlight(target.isInvulnerable()); - } - else - player.sendMessage(ChatColor.RED + "You need to enable flight to use flying feature."); - showSpecificPlayerManager(player, target); - } - }; - } - }, - new Layout() { - @Override - public char getKey() { // vanish - return 'v'; - } - - @Override - public Button getButton() { - return null; - } - } - ).show(origin); - } - - private void showBanPlayerApproval(Player origin, Player target) { - new Menu(ChatColor.RED + "Are you sure to ban " + target.getName() + "?", 9 * 5) - .setLayout("=========", "====p====", "=========", "==a===d==", "=========") - .setKey(blank(), - new Layout() { - @Override - public char getKey() { - return 'p'; - } - - @Override - public Button getButton() { - return new Button() { - @Override - public ItemStack getItem() { - return new ItemHeadCreator(new ItemStack(Material.PLAYER_HEAD)).setOwner(target.getName()).setName(ChatColor.RED + "Are you sure to ban " + target.getName() + "?").create(); - } - - @Override - public void onClick(Player player) { - - } - }; - } - }, - new Layout() { - @Override - public char getKey() { - return 'a'; - } - - @Override - public Button getButton() { - return new Button() { - @Override - public ItemStack getItem() { - return new ItemCreator(Material.GREEN_STAINED_GLASS).setName(ChatColor.GREEN + "ACCEPT").create(); - } - - @Override - public void onClick(Player player) { - target.ban("You have been banned from this server.", (Date) null, player.getName(), true); - showServerPlayerManager(origin); - } - }; - } - }, - new Layout() { - @Override - public char getKey() { - return 'd'; - } - - @Override - public Button getButton() { - return new Button() { - @Override - public ItemStack getItem() { - return new ItemCreator(Material.RED_STAINED_GLASS).setName(ChatColor.RED + "DENY").create(); - } - - @Override - public void onClick(Player player) { - showSpecificPlayerManager(player, target); - } - }; - } - } - ).show(origin); - } - - private void showKickPlayerApproval(Player origin, Player target) { - new Menu(ChatColor.RED + "Are you sure to kick " + target.getName() + "?", 9 * 5) - .setLayout("=========", "====p====", "=========", "==a===d==", "=========") - .setKey(blank(), - new Layout() { - @Override - public char getKey() { - return 'p'; - } - - @Override - public Button getButton() { - return new Button() { - @Override - public ItemStack getItem() { - return new ItemHeadCreator(new ItemStack(Material.PLAYER_HEAD)).setOwner(target.getName()).setName(ChatColor.RED + "Are you sure to kick " + target.getName() + "?").create(); - } - - @Override - public void onClick(Player player) { - - } - }; - } - }, - new Layout() { - @Override - public char getKey() { - return 'a'; - } - - @Override - public Button getButton() { - return new Button() { - @Override - public ItemStack getItem() { - return new ItemCreator(Material.GREEN_STAINED_GLASS).setName(ChatColor.GREEN + "ACCEPT").create(); - } - - @Override - public void onClick(Player player) { - target.kick(); - showServerPlayerManager(origin); - } - }; - } - }, - new Layout() { - @Override - public char getKey() { - return 'd'; - } - - @Override - public Button getButton() { - return new Button() { - @Override - public ItemStack getItem() { - return new ItemCreator(Material.RED_STAINED_GLASS).setName(ChatColor.RED + "DENY").create(); - } - - @Override - public void onClick(Player player) { - showSpecificPlayerManager(player, target); - } - }; - } - } - ).show(origin); - } - - /** - * Handles player chat events for world creator input. - * Processes user input for world creation parameters when players are in world creator mode. - * - * @param event the player chat event - */ - @EventHandler - public void sendChat(PlayerChatEvent event) { - Player player = event.getPlayer(); - if (player.hasMetadata("devTool")) { - DevTool.WorldCreatorContent worldCreatorContent = (DevTool.WorldCreatorContent) player.getMetadata("devTool").getFirst().value(); - if (worldCreatorContent.getInputContent() == null) { - player.sendMessage(ChatColor.RED + "Seem like devTool World creator has occur an error."); - return; - } - event.setCancelled(true); - switch (worldCreatorContent.getInputContent()) { - case "worldName": { - new DevTool().showWorldCreator(player, event.getMessage(), worldCreatorContent.getEnvironment(), worldCreatorContent.getWorldType(), worldCreatorContent.getGenerateStructure(), worldCreatorContent.getBorderSize(), worldCreatorContent.getDifficulty(), worldCreatorContent.getSeed()); - break; - } - case "worldBorder": { - try { - int borderSize = Integer.parseInt(event.getMessage()); - if (borderSize <= 0) { - player.sendMessage(ChatColor.RED + "World border size must be greater than 0"); - new DevTool().showWorldCreator(player, worldCreatorContent.getWorldName(), worldCreatorContent.getEnvironment(), worldCreatorContent.getWorldType(), worldCreatorContent.getGenerateStructure(), worldCreatorContent.getBorderSize(), worldCreatorContent.getDifficulty(), worldCreatorContent.getSeed()); - return; - } - new DevTool().showWorldCreator(player, worldCreatorContent.getWorldName(), worldCreatorContent.getEnvironment(), worldCreatorContent.getWorldType(), worldCreatorContent.getGenerateStructure(), borderSize, worldCreatorContent.getDifficulty(), worldCreatorContent.getSeed()); - } catch (NumberFormatException e) { - player.sendMessage(ChatColor.RED + "World border size must be a number."); - new DevTool().showWorldCreator(player, worldCreatorContent.getWorldName(), worldCreatorContent.getEnvironment(), worldCreatorContent.getWorldType(), worldCreatorContent.getGenerateStructure(), worldCreatorContent.getBorderSize(), worldCreatorContent.getDifficulty(), worldCreatorContent.getSeed()); - } - break; - } - case "worldSeed": { - try { - long seed = Long.parseLong(event.getMessage()); - new DevTool().showWorldCreator(player, worldCreatorContent.getWorldName(), worldCreatorContent.getEnvironment(), worldCreatorContent.getWorldType(), worldCreatorContent.getGenerateStructure(), worldCreatorContent.getBorderSize(), worldCreatorContent.getDifficulty(), seed); - } catch (NumberFormatException e) { - player.sendMessage(ChatColor.RED + "World border size must be a number."); - new DevTool().showWorldCreator(player, worldCreatorContent.getWorldName(), worldCreatorContent.getEnvironment(), worldCreatorContent.getWorldType(), worldCreatorContent.getGenerateStructure(), worldCreatorContent.getBorderSize(), worldCreatorContent.getDifficulty(), worldCreatorContent.getSeed()); - } - break; - } - } - if (player.hasMetadata("devTool")) { - player.removeMetadata("devTool", getInstance()); - } - } - } - - /// Commands - - @Override - public void execute(@NotNull CommandSourceStack commandSourceStack, String @NotNull [] strings) { - if (commandSourceStack.getSender() instanceof Player player) { - switch (strings.length) { - case 0: { - this.openDevTool(player); - break; - } - case 1: { - ItemStack devToolItem = this.getItem(); - if (strings[0].equalsIgnoreCase("get") || strings[0].equalsIgnoreCase("getItem")) { - player.getInventory().addItem(devToolItem); - } - break; - } - case 3: { - if (strings[0].equalsIgnoreCase("world")) { - if (strings[1].equalsIgnoreCase("teleport")) { - World world = Bukkit.getWorld(strings[2]); - if (world != null) { - player.teleport(world.getSpawnLocation()); - player.sendMessage(ChatColor.GRAY + "Teleporting to " + world.getName() + "..."); - } else { - player.sendMessage(ChatColor.RED + "World not found!"); - } - } - break; - } - } - } - return; - } - commandSourceStack.getSender().sendMessage("This command can only be executed by a player!"); - } - - @Override - public @NotNull Collection suggest(@NotNull CommandSourceStack commandSourceStack, String @NotNull [] args) { - switch (args.length) { - case 0, 1: { - return List.of("get", "getItem", "world"); - } - case 2: { - if (args[0].equalsIgnoreCase("world")) { - return List.of("teleport"); - } - break; - } - case 3: { - if (args[0].equalsIgnoreCase("world") && args[1].equalsIgnoreCase("teleport")) { - return List.of(Bukkit.getWorlds().stream().map(World::getName).toArray(String[]::new)); - } - break; - } - } - return List.of(); - } - - - @Override - public boolean canUse(@NotNull CommandSender sender) { - if (sender instanceof Player) { - return sender.hasPermission("pinont.devtool"); - } else { - return false; - } - } - - @Override - public String getName() { - return "devTool"; - } - - @Override - public ItemInteraction getInteraction() { - return null; - } - - @Override - public String description() { - return "SingularityLib Developer Tools"; - } -} diff --git a/src/main/java/com/github/pinont/singularitylib/plugin/cmd/FlySpeed.java b/src/main/java/com/github/pinont/singularitylib/plugin/cmd/FlySpeed.java deleted file mode 100644 index 0f48f4c..0000000 --- a/src/main/java/com/github/pinont/singularitylib/plugin/cmd/FlySpeed.java +++ /dev/null @@ -1,71 +0,0 @@ -package com.github.pinont.singularitylib.plugin.cmd; - -import com.github.pinont.singularitylib.api.command.SimpleCommand; -import io.papermc.paper.command.brigadier.CommandSourceStack; -import org.bukkit.ChatColor; -import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; - -import java.util.Collection; -import java.util.List; - -/** - * Command for setting player flying speed. - * Allows players to adjust their flying speed or reset it to default. - * - * @deprecated since 2.1.0, will be removed in future versions - */ -@Deprecated(since = "2.1.0", forRemoval = true) -public class FlySpeed implements SimpleCommand { - - /** - * Default constructor for FlySpeed command. - */ - public FlySpeed() { - } - - @Override - public String getName() { - return "flyspeed:fs"; - } - - @Override - public String description() { - return "Set Player Flying speed"; - } - - @Override - public void execute(CommandSourceStack commandSourceStack, String[] strings) { - Player player = (Player) commandSourceStack.getSender(); - if (strings.length == 0) { - player.sendMessage("Your current fly speed is: " + player.getFlySpeed()); - } else if (strings[0].equalsIgnoreCase("reset")) { - player.setFlySpeed(0.1f); - player.sendMessage("§aFly speed reset to default."); - } else { - try { - float speed = Float.parseFloat(strings[0])/10; - if (speed > 1f || speed < -1f) { - player.sendMessage(ChatColor.RED + "Speed must be between -10 and 10."); - return; - } - player.setFlySpeed(speed); - player.sendMessage("§aFly speed set to " + speed*10); - } catch (NumberFormatException e) { - player.sendMessage("§cInvalid speed value."); - } - } - } - - @Override - public boolean canUse(CommandSender sender) { - return sender instanceof Player && sender.hasPermission("singularity.flyspeed.use"); - } - - @Override - public Collection suggest(CommandSourceStack commandSourceStack, String[] strings) { - if (strings.length == 1) { - return List.of("|reset"); - } return List.of(); - } -} \ No newline at end of file diff --git a/src/main/java/com/github/pinont/singularitylib/plugin/cmd/Vanish.java b/src/main/java/com/github/pinont/singularitylib/plugin/cmd/Vanish.java deleted file mode 100644 index 2562654..0000000 --- a/src/main/java/com/github/pinont/singularitylib/plugin/cmd/Vanish.java +++ /dev/null @@ -1,45 +0,0 @@ -package com.github.pinont.singularitylib.plugin.cmd; - -import com.github.pinont.singularitylib.api.command.SimpleCommand; -import io.papermc.paper.command.brigadier.CommandSourceStack; -import org.bukkit.command.CommandSender; - -import java.util.Collection; - -/** - * Command for toggling player vanish mode. - * Allows players to become invisible to other players. - */ -@Deprecated(since = "2.1.0", forRemoval = true) -public class Vanish implements SimpleCommand { - /** - * Default constructor for Vanish command. - */ - public Vanish() { - } - - @Override - public String getName() { - return "vanish:v"; - } - - @Override - public String description() { - return "Vanish player"; - } - - @Override - public void execute(CommandSourceStack commandSourceStack, String[] strings) { - - } - - @Override - public Collection suggest(CommandSourceStack commandSourceStack, String[] args) { - return SimpleCommand.super.suggest(commandSourceStack, args); - } - - @Override - public boolean canUse(CommandSender sender) { - return SimpleCommand.super.canUse(sender); - } -} From da83ce235cbc91e56ae623d3bd19ac7b0df190f4 Mon Sep 17 00:00:00 2001 From: PinozenTH Date: Tue, 7 Oct 2025 00:47:19 +0700 Subject: [PATCH 02/13] feat: integrate SingularityDevTool for enhanced custom item management and registration --- pom.xml | 10 ++ .../api/manager/CustomItemManager.java | 127 +++++++++++++++++- .../plugin/register/Register.java | 1 + 3 files changed, 134 insertions(+), 4 deletions(-) diff --git a/pom.xml b/pom.xml index 6e9b8fb..d7a648f 100644 --- a/pom.xml +++ b/pom.xml @@ -74,6 +74,10 @@ sonatype https://oss.sonatype.org/content/groups/public/ + + jitpack.io + https://jitpack.io + @@ -174,5 +178,11 @@ 2.0.16 test + + com.github.Pinont + Singularity-DevTool + cbd0e31e44 + provided + \ No newline at end of file diff --git a/src/main/java/com/github/pinont/singularitylib/api/manager/CustomItemManager.java b/src/main/java/com/github/pinont/singularitylib/api/manager/CustomItemManager.java index 7ce4a38..f3dfc33 100644 --- a/src/main/java/com/github/pinont/singularitylib/api/manager/CustomItemManager.java +++ b/src/main/java/com/github/pinont/singularitylib/api/manager/CustomItemManager.java @@ -1,5 +1,6 @@ package com.github.pinont.singularitylib.api.manager; +import com.github.pinont.devtool.api.CItemManager; import com.github.pinont.singularitylib.api.command.SimpleCommand; import com.github.pinont.singularitylib.api.items.CustomItem; import com.github.pinont.singularitylib.api.utils.Common; @@ -25,12 +26,22 @@ public class CustomItemManager implements SimpleCommand { /** - * List of registered custom items. + * List of registered custom items managed by this manager. + * This list contains all custom items that have been registered + * and are available for use in commands and other operations. */ public List customItems = new ArrayList<>(); + /** + * Integration manager for SingularityDevTool plugin. + * Used when the dev tool plugin is present to provide additional + * development and debugging features for custom items. + */ + private final CItemManager customItemManager = new CItemManager(); + /** * Default constructor for CustomItemManager. + * Initializes the manager with empty collections ready for item registration. */ public CustomItemManager() { } @@ -38,7 +49,7 @@ public CustomItemManager() { /** * Gets the list of registered custom items. * - * @return the list of custom items + * @return an unmodifiable view of the list of custom items currently registered */ public List getCustomItems() { return customItems; @@ -47,13 +58,57 @@ public List getCustomItems() { /** * Registers a list of custom items with the manager. * - * @param item the list of custom items to register + *

This method performs the following operations:

+ *
    + *
  • Validates the input list is not empty
  • + *
  • Logs the registration process to console
  • + *
  • Checks for SingularityDevTool plugin integration
  • + *
  • Registers items with dev tool if available
  • + *
  • Initializes item interactions and properties
  • + *
+ * + * @param item the list of custom items to register, must not be null or empty + * @throws IllegalArgumentException if the item list is null */ public void register(List item) { if (item.isEmpty()) return; sendConsoleMessage("Registering " + item.size() + " custom items"); - for (CustomItem customItem : item) { + if (getInstance().getServer().getPluginManager().getPlugin("SingularityDevTool") != null) { + registerAllItems(item, true); + } + registerAllItems(item); + } + + /** + * Internal method to register all items without dev tool integration. + * + * @param items the list of items to register + */ + private void registerAllItems(List items) { + registerAllItems(items, false); + } + + /** + * Internal method to register all items with optional dev tool integration. + * + *

For each custom item, this method:

+ *
    + *
  • Adds the item to the internal registry
  • + *
  • Registers with dev tool if requested and available
  • + *
  • Calls the item's register method for initialization
  • + *
  • Ensures the item stack is created and interactions are set up
  • + *
  • Logs interaction registration if present
  • + *
+ * + * @param items the list of items to register + * @param forDevTool whether to register items with the development tool + */ + private void registerAllItems(List items, boolean forDevTool) { + for (CustomItem customItem : items) { customItems.add(customItem); + if (forDevTool) { + customItemManager.registerCustomItems(customItem); + } customItem.register(); // call register to ensure the item is properly initialized customItem.getItem(); // ensure the item is created and interaction is set up if (customItem.getInteraction() != null) { @@ -62,16 +117,48 @@ public void register(List item) { } } + /** + * Gets the name of this command. + * + * @return the command name "give" + */ @Override public String getName() { return "give"; } + /** + * Gets the description of this command. + * + * @return a brief description of what this command does + */ @Override public String description() { return "Give item to player"; } + /** + * Executes the give command with the provided arguments. + * + *

Command syntax: /give <player> <item> [count]

+ * + *

Supported player selectors:

+ *
    + *
  • @a - All players
  • + *
  • @r - Random player
  • + *
  • @s - Command sender (self)
  • + *
  • player_name - Specific player by name
  • + *
+ * + *

Supported item formats:

+ *
    + *
  • minecraft:item_name - Vanilla Minecraft items
  • + *
  • plugin_name:item_name - Custom plugin items
  • + *
+ * + * @param commandSourceStack the source of the command execution + * @param strings the command arguments [player, item, count] + */ @Override public void execute(CommandSourceStack commandSourceStack, String[] strings) { if (strings.length < 2) { @@ -123,6 +210,15 @@ public void execute(CommandSourceStack commandSourceStack, String[] strings) { } } + /** + * Gives an item to a specific player and sends a confirmation message. + * + *

This method adds the item to the player's inventory and sends + * a confirmation message showing the item name, quantity, and recipient.

+ * + * @param player the player to receive the item, must not be null + * @param item the item stack to give, must not be null + */ private void giveItemToPlayer(Player player, ItemStack item) { if (player != null) { player.getInventory().addItem(item); @@ -132,6 +228,20 @@ private void giveItemToPlayer(Player player, ItemStack item) { } } + /** + * Provides command suggestions for tab completion. + * + *

Suggestions provided:

+ *
    + *
  • Argument 1: Player names and selectors (@a, @s, @r)
  • + *
  • Argument 2: Available items (minecraft: and plugin: prefixed)
  • + *
  • Argument 3: Count placeholder
  • + *
+ * + * @param commandSourceStack the source of the command execution + * @param args the current command arguments being typed + * @return a collection of suggested completions for the current argument + */ @Override public @NotNull Collection suggest(CommandSourceStack commandSourceStack, String[] args) { return switch (args.length) { @@ -161,6 +271,15 @@ private void giveItemToPlayer(Player player, ItemStack item) { }; } + /** + * Determines if a command sender can use this command. + * + *

Currently, only players are allowed to use the give command. + * Console and other command senders are not permitted.

+ * + * @param sender the command sender to check permissions for + * @return true if the sender is a player, false otherwise + */ @Override public boolean canUse(CommandSender sender) { return sender instanceof Player; diff --git a/src/main/java/com/github/pinont/singularitylib/plugin/register/Register.java b/src/main/java/com/github/pinont/singularitylib/plugin/register/Register.java index e5c93e0..dbefea9 100644 --- a/src/main/java/com/github/pinont/singularitylib/plugin/register/Register.java +++ b/src/main/java/com/github/pinont/singularitylib/plugin/register/Register.java @@ -1,5 +1,6 @@ package com.github.pinont.singularitylib.plugin.register; +import com.github.pinont.devtool.api.CItemManager; import com.github.pinont.singularitylib.api.annotation.AutoRegister; import com.github.pinont.singularitylib.api.command.SimpleCommand; import com.github.pinont.singularitylib.api.items.CustomItem; From 6361216811f226d2eb44fded73a9a24fa6c4b481 Mon Sep 17 00:00:00 2001 From: PinozenTH Date: Tue, 7 Oct 2025 00:51:04 +0700 Subject: [PATCH 03/13] feat: enhance tab completion suggestions with intelligent filtering and detailed documentation --- .../api/manager/CustomItemManager.java | 57 +++++++++++++++---- 1 file changed, 47 insertions(+), 10 deletions(-) diff --git a/src/main/java/com/github/pinont/singularitylib/api/manager/CustomItemManager.java b/src/main/java/com/github/pinont/singularitylib/api/manager/CustomItemManager.java index f3dfc33..5003a98 100644 --- a/src/main/java/com/github/pinont/singularitylib/api/manager/CustomItemManager.java +++ b/src/main/java/com/github/pinont/singularitylib/api/manager/CustomItemManager.java @@ -229,19 +229,56 @@ private void giveItemToPlayer(Player player, ItemStack item) { } /** - * Provides command suggestions for tab completion. + * Provides intelligent tab completion suggestions for the give command. * - *

Suggestions provided:

- *
    - *
  • Argument 1: Player names and selectors (@a, @s, @r)
  • - *
  • Argument 2: Available items (minecraft: and plugin: prefixed)
  • - *
  • Argument 3: Count placeholder
  • - *
+ *

This method dynamically generates context-aware suggestions based on the current + * argument position and existing input, enhancing the user experience by providing + * relevant completions for each stage of command construction.

* - * @param commandSourceStack the source of the command execution - * @param args the current command arguments being typed - * @return a collection of suggested completions for the current argument + *

Tab Completion Behavior:

+ * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Argument PositionSuggestions ProvidedDescription
1 (Player)Online player names + selectorsAll currently connected players, plus @a (all), @s (self), @r (random)
2 (Item)Available items with namespacesMinecraft items (minecraft:) and registered custom items (plugin:)
3 (Count)<count> placeholderVisual hint indicating numeric quantity expected
+ * + *

Intelligent Filtering:

+ *

For item suggestions (argument 2), the method applies smart filtering when partial + * input is detected, matching against the item name portion after the namespace prefix. + * This allows for efficient item discovery through progressive typing.

+ * + *

Performance Considerations:

+ *

The method efficiently streams and filters large collections of materials and + * custom items, ensuring responsive tab completion even with extensive item registries.

+ * + * @param commandSourceStack the command execution context providing sender information + * @param args the array of command arguments currently being typed by the user + * @return a collection of contextually relevant completion suggestions, never null + * + * @since 1.0.0 + * @deprecated since 1.1.0, scheduled for removal - use new completion system + * + * @see #execute(CommandSourceStack, String[]) for command execution logic + * @see CustomItem#getName() for custom item name retrieval */ + @Deprecated(since = "1.1.0", forRemoval = true) @Override public @NotNull Collection suggest(CommandSourceStack commandSourceStack, String[] args) { return switch (args.length) { From e988185e098f99a10f8bf1759ecb2a9ecad544c1 Mon Sep 17 00:00:00 2001 From: Nont Nonnipat Date: Sun, 19 Oct 2025 00:56:55 +0700 Subject: [PATCH 04/13] feat: add EntityDamageListener and PlayerDamageByPlayerEvent for player damage handling --- .../api/event/PlayerDamageByPlayerEvent.java | 53 + .../pinont/singularitylib/plugin/DevTool.java | 1402 ----------------- .../plugin/listener/EntityDamageListener.java | 21 + 3 files changed, 74 insertions(+), 1402 deletions(-) create mode 100644 src/main/java/com/github/pinont/singularitylib/api/event/PlayerDamageByPlayerEvent.java delete mode 100644 src/main/java/com/github/pinont/singularitylib/plugin/DevTool.java create mode 100644 src/main/java/com/github/pinont/singularitylib/plugin/listener/EntityDamageListener.java diff --git a/src/main/java/com/github/pinont/singularitylib/api/event/PlayerDamageByPlayerEvent.java b/src/main/java/com/github/pinont/singularitylib/api/event/PlayerDamageByPlayerEvent.java new file mode 100644 index 0000000..6c42216 --- /dev/null +++ b/src/main/java/com/github/pinont/singularitylib/api/event/PlayerDamageByPlayerEvent.java @@ -0,0 +1,53 @@ +package com.github.pinont.singularitylib.api.event; + +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; +import org.bukkit.event.Cancellable; +import org.bukkit.event.Event; +import org.bukkit.event.HandlerList; +import org.jetbrains.annotations.NotNull; + +public class PlayerDamageByPlayerEvent extends Event implements Cancellable { + + private static final HandlerList handlers = new HandlerList(); + private boolean isCancelled = false; + private final Player player; + private final Player damager; + + public PlayerDamageByPlayerEvent(Player player, Player hitter) { + this.player = player; + this.damager = hitter; + } + + public Player getPlayer() { + return this.player; + } + + public Player getDamager() { + return this.damager; + } + + public boolean callEvent() { + Bukkit.getPluginManager().callEvent(this); + return this.isCancelled(); + } + + @Override + public boolean isCancelled() { + return isCancelled; + } + + @Override + public void setCancelled(boolean b) { + this.isCancelled = b; + } + + @Override + public @NotNull HandlerList getHandlers() { + return handlers; + } + + public static HandlerList getHandlerList() { + return handlers; + } +} diff --git a/src/main/java/com/github/pinont/singularitylib/plugin/DevTool.java b/src/main/java/com/github/pinont/singularitylib/plugin/DevTool.java deleted file mode 100644 index 213582f..0000000 --- a/src/main/java/com/github/pinont/singularitylib/plugin/DevTool.java +++ /dev/null @@ -1,1402 +0,0 @@ -package com.github.pinont.singularitylib.plugin; - -import com.github.pinont.singularitylib.api.command.SimpleCommand; -import com.github.pinont.singularitylib.api.items.CustomItem; -import com.github.pinont.singularitylib.api.items.ItemCreator; -import com.github.pinont.singularitylib.api.items.ItemHeadCreator; -import com.github.pinont.singularitylib.api.items.ItemInteraction; -import com.github.pinont.singularitylib.api.manager.WorldManager; -import com.github.pinont.singularitylib.api.ui.Button; -import com.github.pinont.singularitylib.api.ui.Layout; -import com.github.pinont.singularitylib.api.ui.Menu; -import io.papermc.paper.command.brigadier.CommandSourceStack; -import org.bukkit.*; -import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; -import org.bukkit.event.EventHandler; -import org.bukkit.event.Listener; -import org.bukkit.event.block.Action; -import org.bukkit.event.player.PlayerChatEvent; -import org.bukkit.inventory.ItemStack; -import org.bukkit.metadata.FixedMetadataValue; -import org.jetbrains.annotations.NotNull; - -import java.util.*; - -import static com.github.pinont.singularitylib.plugin.CorePlugin.getAPIVersion; -import static com.github.pinont.singularitylib.plugin.CorePlugin.getInstance; - -/** - * Developer tool for testing and debugging plugin functionality. - * Provides a comprehensive interface for developers to test various features - * including world management, teleportation, and other debugging utilities. - * - * @deprecated since 2.1.0, will be removed in future versions - */ -@Deprecated(since = "2.1.0", forRemoval = true) -public class DevTool extends CustomItem implements SimpleCommand, Listener { - - private final String version = getAPIVersion(); - - /** - * Default constructor for DevTool. - */ - public DevTool() { - } - - @Override - public ItemCreator register() { - return new ItemCreator(Material.DIAMOND).setName(ChatColor.DARK_RED + "Developer Tool").setUnstackable(true).addInteraction( - new ItemInteraction() { - @Override - public String getName() { - return "DevTool"; - } - - @Override - public Set getAction() { - return Set.of(Action.LEFT_CLICK_AIR, Action.LEFT_CLICK_BLOCK, Action.RIGHT_CLICK_AIR, Action.RIGHT_CLICK_BLOCK); - } - - @Override - public void execute(Player player) { - openDevTool(player); - } - } - ); - } - - /** - * Opens the developer tool interface for the specified player. - * - * @param player the player to open the interface for - */ - public void openDevTool(Player player) { - Menu devMenu = new Menu(ChatColor.DARK_RED + "Developer Tools " + ChatColor.GRAY + "(" + version + ")", 9*5); - devMenu.setLayout("=========", "====i====", "=========", "==w=p=t==", "========="); - devMenu.setKey( - blank(), - new Layout() { - - @Override - public char getKey() { - return 'i'; - } - - @Override - public Button getButton() { - return new Button() { - - @Override - public ItemStack getItem() { - return new ItemCreator(new ItemStack(Material.GRASS_BLOCK)).setName(ChatColor.GREEN + "Server Info").addLore(ChatColor.GRAY + "Server: " + ChatColor.YELLOW + Bukkit.getServer().getName(), ChatColor.GRAY + "Version: " + ChatColor.YELLOW + Bukkit.getServer().getVersion(), ChatColor.GRAY + "Plugins (" + ChatColor.YELLOW + Bukkit.getServer().getPluginManager().getPlugins().length + ChatColor.GRAY + ")").create(); - } - - @Override - public void onClick(Player player) { - - } - }; - } - }, - new Layout() { - @Override - public char getKey() { - return 'p'; - } - - @Override - public Button getButton() { - return new Button() { - @Override - public ItemStack getItem() { - return new ItemHeadCreator(new ItemStack(Material.PLAYER_HEAD)).setOwner(player.getName()).setName("Player List").create(); - } - - @Override - public void onClick(Player player) { - showServerPlayerManager(player); - } - }; - } - }, - new Layout() { - @Override - public char getKey() { - return 'w'; // worldcreator - } - - @Override - public Button getButton() { - return new Button() { - @Override - public ItemStack getItem() { - return new ItemCreator(new ItemStack(Material.COARSE_DIRT)).setName("Worlds").create(); - } - - @Override - public void onClick(Player player) { - showServerWorldManger(player); - } - }; - } - }, - new Layout() { - @Override - public char getKey() { - return 't'; // tools - } - - @Override - public Button getButton() { - return new Button() { - @Override - public ItemStack getItem() { - return new ItemCreator(Material.STICK).setName("Tools").addLore("More Tools").create(); - } - - @Override - public void onClick(Player player) { - showOtherTools(player); - } - }; - } - } - ); - devMenu.show(player); - } - - private void showOtherTools(Player player) { - new Menu("Heldable Tool", 9 * 3).setLayout("=========", "==m=w=o==", "=========").setKey( - blank(), - new Layout() { - @Override - public char getKey() { - return 'm'; // mobCreator - } - - @Override - public Button getButton() { - return null; - } - }, - new Layout() { - @Override - public char getKey() { - return 'o'; // itemCreator - } - - @Override - public Button getButton() { - return null; - } - }, - new Layout() { - @Override - public char getKey() { - return 'w'; // later - } - - @Override - public Button getButton() { - return null; - } - } - ).show(player); - - } - - private ItemStack getWorldEnvironmentBlock(World world) { - return getWorldEnvironmentBlock(world.getEnvironment()); - } - - private ItemStack getWorldEnvironmentBlock(World.Environment worldEnv) { - return switch (worldEnv) { - case NORMAL -> new ItemStack(Material.GRASS_BLOCK); - case NETHER -> new ItemStack(Material.NETHERRACK); - case THE_END -> new ItemStack(Material.END_STONE); - default -> new ItemStack(Material.COMMAND_BLOCK); - }; - } - - private void showServerWorldManger(Player p) { - Menu worldManagerMenu = new Menu("World Manager", 9); - int count = 0; - for (World world : Bukkit.getWorlds()) { - int finalCount = count; - worldManagerMenu.addButton(new Button() { - @Override - public int getSlot() { - return finalCount; - } - - @Override - public ItemStack getItem() { - return new ItemCreator(getWorldEnvironmentBlock(world)).setName(properWorldName(world)).addLore(ChatColor.BOLD + "" + ChatColor.YELLOW + "Click to edit").create(); - } - - @Override - public void onClick(Player player) { - showSingleWorldManager(world, player); - } - }); - count++; - } - int finalCount = count; - worldManagerMenu.addButton(new Button() { - @Override - public int getSlot() { - return finalCount; - } - - @Override - public ItemStack getItem() { - return new ItemCreator(new ItemStack(Material.BEDROCK)).setName(ChatColor.YELLOW + "Click to create new world").create(); - } - - @Override - public void onClick(Player player) { - showWorldCreator(player); - } - }); - worldManagerMenu.show(p); - } - - private void showWorldCreator(Player player) { - getWorldCreatorMenu(null, World.Environment.NORMAL, WorldType.NORMAL, true, 1000, Difficulty.EASY, new Random().nextLong(System.currentTimeMillis())).show(player); - } - - /** - * Shows the world creator interface with specified parameters. - * - * @param player the player to show the interface to - * @param world_name the name of the world to create - * @param environment the world environment type - * @param worldType the world type - * @param generate_structure whether to generate structures - * @param borderSize the world border size - * @param difficulty the world difficulty - * @param seed the world seed - */ - public void showWorldCreator(Player player, String world_name, World.Environment environment, WorldType worldType, boolean generate_structure, int borderSize, Difficulty difficulty, long seed) { - getWorldCreatorMenu(world_name, environment, worldType, generate_structure, borderSize, difficulty, seed).show(player); - } - - /** - * Interface for capturing world creator content and user input. - * Used to maintain state during world creation process when players input values via chat. - */ - public interface WorldCreatorContent { - /** - * Gets the type of input content being processed. - * - * @return the input content type - */ - String getInputContent(); - - /** - * Gets the name of the world being created. - * - * @return the world name - */ - String getWorldName(); - - /** - * Gets the world environment type. - * - * @return the world environment - */ - World.Environment getEnvironment(); - - /** - * Gets the world type for generation. - * - * @return the world type - */ - WorldType getWorldType(); - - /** - * Gets whether structures should be generated in the world. - * - * @return true if structures should be generated, false otherwise - */ - boolean getGenerateStructure(); - - /** - * Gets the world border size. - * - * @return the border size in blocks - */ - int getBorderSize(); - - /** - * Gets the world difficulty setting. - * - * @return the difficulty level - */ - Difficulty getDifficulty(); - - /** - * Gets the world seed for generation. - * - * @return the world seed - */ - Long getSeed(); - } - - private Menu getWorldCreatorMenu(String name, World.Environment environment, WorldType worldType, boolean generate_structure, int borderSize, Difficulty difficulty, Long seed) { - Menu worldCreatorMenu = new Menu("World Creator").setLayout("----w----", "-=n=e=t=-", "-=g=b=s=-", "----c----"); - return worldCreatorMenu.setKey( - blank(), - new Layout() { - @Override - public char getKey() { - return '-'; - } // border - - @Override - public Button getButton() { - return new Button() { - @Override - public ItemStack getItem() { - return new ItemCreator(Material.YELLOW_STAINED_GLASS_PANE).setName(" ").create(); - } - - @Override - public void onClick(Player player) { - - } - }; - } - }, - new Layout() { - @Override - public char getKey() { - return 'w'; - } // world creator icon - - @Override - public Button getButton() { - return new Button() { - @Override - public ItemStack getItem() { - return new ItemCreator(new ItemStack(Material.GOLD_BLOCK)).setName(ChatColor.BOLD + "" + ChatColor.YELLOW + "World Creator").addLore( - ChatColor.GRAY + "Name: " + ChatColor.YELLOW + (name == null ? ChatColor.RED + "Not Set" : name), - ChatColor.GRAY + "Environment Type: " + ChatColor.YELLOW + (environment == null ? ChatColor.RED + "Not Set" : environment), - ChatColor.GRAY + "World Type: " + ChatColor.YELLOW + (worldType == null ? ChatColor.RED + "Not Set" : worldType), - ChatColor.GRAY + "Difficulty: " + ChatColor.YELLOW + difficulty, - ChatColor.GRAY + "Generate Structure: " + ChatColor.YELLOW + (generate_structure ? "True" : "False"), - ChatColor.GRAY + "Border Size: " + ChatColor.YELLOW + borderSize, - ChatColor.GRAY + "Seed: " + ChatColor.YELLOW + (seed == null ? ChatColor.RED + "RANDOM" : seed) - ).create(); - } - - @Override - public void onClick(Player player) { - player.closeInventory(); - player.sendMessage(ChatColor.YELLOW + "World '" + name + "' is Creating..."); - createWorld(name, environment, worldType, generate_structure, borderSize, difficulty, seed); - player.sendMessage(ChatColor.GREEN + "World '" + name + "' has been created!"); - } - }; - } - }, - new Layout() { - @Override - public char getKey() { - return 'n'; - } // set world name - - @Override - public Button getButton() { - return new Button() { - @Override - public ItemStack getItem() { - if (name == null) { - return new ItemCreator(Material.OAK_SIGN).setName("Set World Name").addLore(ChatColor.YELLOW + "Click to set world name.").create(); - } - return new ItemCreator(Material.BIRCH_SIGN).setName(name).addLore(ChatColor.YELLOW + "Click to change world name.").create(); - } - - @Override - public void onClick(Player player) { - player.sendMessage(ChatColor.GRAY + "Please send a world name into chat."); - player.setMetadata("devTool", new FixedMetadataValue(getInstance(), new WorldCreatorContent() { - @Override - public String getInputContent() { - return "worldName"; - } - - @Override - public String getWorldName() { - return name; - } - - @Override - public World.Environment getEnvironment() { - return environment; - } - - @Override - public WorldType getWorldType() { - return worldType; - } - - @Override - public boolean getGenerateStructure() { - return generate_structure; - } - - @Override - public int getBorderSize() { - return borderSize; - } - - @Override - public Difficulty getDifficulty() { - return difficulty; - } - - @Override - public Long getSeed() { - return seed; - } - })); - player.closeInventory(); - } - }; - } - }, - new Layout() { - @Override - public char getKey() { - return 'e'; // environment - } - - @Override - public Button getButton() { - return new Button() { - @Override - public ItemStack getItem() { - if (environment == null) { - return new ItemCreator(Material.COMMAND_BLOCK).setName("Set World Environment").addLore(ChatColor.YELLOW + "Click to change world environment.").create(); - } - return new ItemCreator(getWorldEnvironmentBlock(environment)).setName(environment.name()).addLore(ChatColor.YELLOW + "Click to change world environment.").create(); - } - - @Override - public void onClick(Player player) { - World.Environment[] environments = World.Environment.values(); - int currentIndex = environment == null ? -1 : java.util.Arrays.asList(environments).indexOf(environment); - int nextIndex = (currentIndex + 1) % environments.length; - showWorldCreator(player, name, environments[nextIndex], worldType, generate_structure, borderSize, difficulty, seed); - } - }; - } - }, - new Layout() { - @Override - public char getKey() { - return 't'; // world type - } - - @Override - public Button getButton() { - return new Button() { - @Override - public ItemStack getItem() { - if (worldType == null) { - return new ItemCreator(Material.OAK_SAPLING).setName("Set World Type").addLore(ChatColor.YELLOW + "Click to change world type.").create(); - } - return new ItemCreator(Material.CHERRY_SAPLING).setName(worldType.getName()).addLore(ChatColor.YELLOW + "Click to change world type").create(); - } - - @Override - public void onClick(Player player) { - WorldType[] worldTypes = WorldType.values(); - int currentTypeIndex = worldType == null ? -1 : java.util.Arrays.asList(worldTypes).indexOf(worldType); - int nextTypeIndex = (currentTypeIndex + 1) % worldTypes.length; - - showWorldCreator(player, name, environment, worldTypes[nextTypeIndex], generate_structure, borderSize, difficulty, seed); - } - }; - } - }, - new Layout() { - @Override - public char getKey() { - return 'g'; // generate structure? def = true - } - - @Override - public Button getButton() { - return new Button() { - @Override - public ItemStack getItem() { - if (generate_structure) return new ItemCreator(Material.BIRCH_STAIRS).setName(ChatColor.GRAY + "Generate Structure: " + ChatColor.GREEN + "True").create(); - return new ItemCreator(Material.ACACIA_STAIRS).setName(ChatColor.GRAY + "Generate Structure: " + ChatColor.GREEN + "False").create(); - } - - @Override - public void onClick(Player player) { - showWorldCreator(player, name, environment, worldType, !generate_structure, borderSize, difficulty, seed); - } - }; - } - }, - new Layout() { - @Override - public char getKey() { - return 'b'; // border size? def = default - } - - @Override - public Button getButton() { - return new Button() { - @Override - public ItemStack getItem() { - return new ItemCreator(Material.STRUCTURE_VOID).setName(ChatColor.GRAY + "World Border Size: " + ChatColor.YELLOW + borderSize).create(); - } - - @Override - public void onClick(Player player) { - player.sendMessage(ChatColor.GRAY + "Please send a world border size into chat."); - player.setMetadata("devTool", new FixedMetadataValue(getInstance(), new WorldCreatorContent() { - @Override - public String getInputContent() { - return "worldBorder"; - } - - @Override - public String getWorldName() { - return name; - } - - @Override - public World.Environment getEnvironment() { - return environment; - } - - @Override - public WorldType getWorldType() { - return worldType; - } - - @Override - public boolean getGenerateStructure() { - return generate_structure; - } - - @Override - public int getBorderSize() { - return borderSize; - } - - @Override - public Difficulty getDifficulty() { - return difficulty; - } - - @Override - public Long getSeed() { - return seed; - } - })); - player.closeInventory(); - } - }; - } - }, - new Layout() { - @Override - public char getKey() { - return 's'; // seed? def = default - } - - @Override - public Button getButton() { - return new Button() { - @Override - public ItemStack getItem() { - return new ItemCreator(Material.WHEAT_SEEDS).setName(ChatColor.GRAY + "Seed: " + ChatColor.YELLOW + seed).create(); - } - - @Override - public void onClick(Player player) { - player.sendMessage(ChatColor.GRAY + "Please send a seed number into chat."); - player.setMetadata("devTool", new FixedMetadataValue(getInstance(), new WorldCreatorContent() { - @Override - public String getInputContent() { - return "worldSeed"; - } - - @Override - public String getWorldName() { - return name; - } - - @Override - public World.Environment getEnvironment() { - return environment; - } - - @Override - public WorldType getWorldType() { - return worldType; - } - - @Override - public boolean getGenerateStructure() { - return generate_structure; - } - - @Override - public int getBorderSize() { - return borderSize; - } - - @Override - public Difficulty getDifficulty() { - return difficulty; - } - - @Override - public Long getSeed() { - return seed; - } - })); - player.closeInventory(); - } - }; - } - }, - new Layout() { - @Override - public char getKey() { - return 'c'; // create button - } - - @Override - public Button getButton() { - return new Button() { - @Override - public ItemStack getItem() { - return new ItemCreator(Material.DIAMOND).setName(ChatColor.WHITE + "Create World").addLore(ChatColor.YELLOW + "Click to create world.").create(); - } - - @Override - public void onClick(Player player) { - player.closeInventory(); - player.sendMessage(ChatColor.YELLOW + "World '" + name + "' is Creating..."); - createWorld(name, environment, worldType, generate_structure, borderSize, difficulty, seed); - player.sendMessage(ChatColor.GREEN + "World '" + name + "' has been created!"); - } - }; - } - } - ); - } - - private void createWorld(String name, World.Environment environment, WorldType worldType, boolean generate_structure, int borderSize, Difficulty difficulty, Long seed) { - if (name == null) { - name = "custom_world_" + environment.name() + "_" + worldType.getName() + "_" + System.currentTimeMillis(); - } - new WorldManager(name).create(worldType, environment, generate_structure, borderSize, difficulty, seed); - } - - private void showSingleWorldManager(World world, Player player) { - Menu worldManagerMenu = new Menu(world.getName() + ": World Manager"); - worldManagerMenu.setLayout("=========", "====w====", "=========", "==t=d=r==", "========="); - worldManagerMenu.setKey( - blank(), - new Layout() { - - @Override - public char getKey() { - return 'w'; - } - - @Override - public Button getButton() { - return new Button() { // world info - - @Override - public ItemStack getItem() { - - return new ItemCreator(getWorldEnvironmentBlock(world)).setName(ChatColor.GREEN + "World Info").addLore(ChatColor.GRAY + "Name: " + ChatColor.YELLOW + properWorldName(world), ChatColor.GRAY + "Difficulty: " + ChatColor.YELLOW + world.getDifficulty(), ChatColor.GRAY + "Environment Type: " + ChatColor.YELLOW + world.getEnvironment()).create(); - } - - @Override - public void onClick(Player player) { - - } - }; - } - }, - new Layout() { - @Override - public char getKey() { - return 't'; // teleport - } - - @Override - public Button getButton() { - return new Button() { - @Override - public ItemStack getItem() { - return new ItemCreator(new ItemStack(Material.BEACON)).setName("Teleport").addLore(ChatColor.BOLD + "" + ChatColor.YELLOW + "Click to Teleport").create(); - } - - @Override - public void onClick(Player player) { - if (player.getWorld() != world) { - player.sendMessage(ChatColor.GRAY + "Teleporting to " + properWorldName(world) + "..."); - player.teleport(world.getSpawnLocation()); - } else { - player.sendMessage(ChatColor.RED + "You are already in this world!"); - } - } - }; - } - }, - new Layout() { - @Override - public char getKey() { - return 'r'; // gamerules - } - - @Override - public Button getButton() { - return null; - } - }, - worldDeleteButton(world) - ).show(player); - } - - private Layout worldDeleteButton(World world) { - if (world.hasMetadata("loader")) { - return new Layout() { - @Override - public char getKey() { - return 'd'; - } - - @Override - public Button getButton() { - return new Button() { - @Override - public ItemStack getItem() { - return new ItemCreator(Material.RED_STAINED_GLASS).setName(ChatColor.RED +"Delete").addLore(ChatColor.RED + "Click here to delete this world").create(); - } - - @Override - public void onClick(Player player) { - showDeleteWorldApproval(player, world); - } - }; - } - }; - } - return new Layout() { - @Override - public char getKey() { - return 'd'; - } - - @Override - public Button getButton() { - return new Button() { - @Override - public ItemStack getItem() { - return new ItemCreator(Material.AIR).create(); - } - - @Override - public void onClick(Player player) { - - } - }; - } - }; - } - - private void showDeleteWorldApproval(Player player, World targetWorld) { - new Menu(ChatColor.RED + "Are you sure to delete " + targetWorld.getName() + "?") - .setLayout("=========", "====w====", "=========", "==a===d==", "=========") - .setKey(blank(), - new Layout() { - @Override - public char getKey() { - return 'w'; - } - - @Override - public Button getButton() { - return new Button() { - @Override - public ItemStack getItem() { - return new ItemCreator(new ItemStack(getWorldEnvironmentBlock(targetWorld))).setName(ChatColor.RED + "Are you sure to delete " + targetWorld.getName() + "?").create(); - } - - @Override - public void onClick(Player player) { - - } - }; - } - }, - new Layout() { - @Override - public char getKey() { - return 'a'; - } - - @Override - public Button getButton() { - return new Button() { - @Override - public ItemStack getItem() { - return new ItemCreator(Material.GREEN_STAINED_GLASS).setName(ChatColor.GREEN + "ACCEPT").create(); - } - - @Override - public void onClick(Player player) { - WorldManager.delete(targetWorld.getName()); - player.sendMessage(ChatColor.RED + targetWorld.getName() + " is now mark for removal!"); - showServerWorldManger(player); - } - }; - } - }, - new Layout() { - @Override - public char getKey() { - return 'd'; - } - - @Override - public Button getButton() { - return new Button() { - @Override - public ItemStack getItem() { - return new ItemCreator(Material.RED_STAINED_GLASS).setName(ChatColor.RED + "DENY").create(); - } - - @Override - public void onClick(Player player) { - showSingleWorldManager(targetWorld, player); - } - }; - } - } - ).show(player); - } - - private String properWorldName(World world) { - String formattedName = world.getName().replace("_", " "); - StringBuilder result = new StringBuilder(); - boolean capitalizeNext = true; - - for (char c : formattedName.toCharArray()) { - if (capitalizeNext && Character.isLetter(c)) { - result.append(Character.toUpperCase(c)); - capitalizeNext = false; - } else { - result.append(c); - } - if (c == ' ') { - capitalizeNext = true; - } - } - - return result.toString(); - } - - private Layout blank() { - return new Layout() { - @Override - public char getKey() { - return '='; - } - - @Override - public Button getButton() { - return new Button() { - @Override - public ItemStack getItem() { - return new ItemStack(Material.AIR); - } - - @Override - public void onClick(Player player) { - - } - }; - } - }; - } - - private void showServerPlayerManager(Player origin) { -// int max = 45; - Menu playerManager = new Menu("Player Manager", 9); // temp - for (int i = 0; i < Bukkit.getOnlinePlayers().size(); i++) { - Player player = (Player) Bukkit.getOnlinePlayers().toArray()[i]; - int finalI = i; - playerManager.addButton(new Button() { - @Override - public int getSlot() { - return finalI; - } - - @Override - public ItemStack getItem() { - return new ItemHeadCreator(new ItemStack(Material.PLAYER_HEAD)).setOwner(player.getName()).setName(player.getName()).create(); - } - - @Override - public void onClick(Player player) { - showSpecificPlayerManager(origin, player); - } - }); - } - playerManager.show(origin); - } - - private void showSpecificPlayerManager(Player origin, Player target) { - Menu playerManager = new Menu("Player Manager", 9 * 5); - playerManager.setLayout("====p====", "=========", "==t=i=o==", "==b=k=n==", "====v====", "========="); - playerManager.setKey( - blank(), - new Layout() { - @Override - public char getKey() { - return 'p'; - } - - @Override - public Button getButton() { - return new Button() { - @Override - public ItemStack getItem() { - String firstPlayedDate = new java.text.SimpleDateFormat("dd/MM/yyyy HH:mm") - .format(new java.util.Date(target.getFirstPlayed())); - return new ItemHeadCreator(new ItemStack(Material.PLAYER_HEAD)) - .setOwner(target.getName()) - .setName(target.getName()) - .addLore(ChatColor.BOLD + "" + ChatColor.GRAY + "First Joined: " + ChatColor.YELLOW + firstPlayedDate) - .create(); - } - - @Override - public void onClick(Player player) { - } - }; - } - }, - new Layout() { - @Override - public char getKey() { - return 't'; // teleport - } - - @Override - public Button getButton() { - return new Button() { - @Override - public ItemStack getItem() { - return new ItemCreator(new ItemStack(Material.BEACON)).setName("Teleport").addLore(ChatColor.BOLD + "" + ChatColor.YELLOW + "Click to Teleport").create(); - } - - @Override - public void onClick(Player player) { - player.teleport(target.getLocation()); - player.closeInventory(); - } - }; - } - }, - new Layout() { - @Override - public char getKey() { - return 'i'; // player Inventory - } - - @Override - public Button getButton() { - return null; - } - }, - new Layout() { - @Override - public char getKey() { - return 'b'; - } - - @Override - public Button getButton() { - return new Button() { - @Override - public ItemStack getItem() { - return new ItemCreator(Material.ANVIL).setName(ChatColor.RED + "Ban").addLore(ChatColor.RED + "Click to ban.").create(); - } - - @Override - public void onClick(Player player) { - showBanPlayerApproval(player, target); - } - }; - } - }, - new Layout() { - @Override - public char getKey() { - return 'k'; - } - - @Override - public Button getButton() { - return new Button() { - @Override - public ItemStack getItem() { - return new ItemCreator(Material.REDSTONE).setName(ChatColor.RED + "Kick").addLore(ChatColor.RED + "Click to kick.").create(); - } - - @Override - public void onClick(Player player) { - showKickPlayerApproval(player, target); - } - }; - } - }, - new Layout() { - @Override - public char getKey() { - return 'o'; // op Player - } - - @Override - public Button getButton() { - return null; - } - }, - new Layout() { - @Override - public char getKey() { - return 'n'; // invincibility - } - - @Override - public Button getButton() { - return new Button() { - @Override - public ItemStack getItem() { - return new ItemCreator(Material.TOTEM_OF_UNDYING).setName("God: " + target.isInvulnerable()).create(); - } - - @Override - public void onClick(Player player) { - target.setInvulnerable(!target.isInvulnerable()); - if (Bukkit.getServer().getAllowFlight()) { - target.setAllowFlight(target.isInvulnerable()); - } - else - player.sendMessage(ChatColor.RED + "You need to enable flight to use flying feature."); - showSpecificPlayerManager(player, target); - } - }; - } - }, - new Layout() { - @Override - public char getKey() { // vanish - return 'v'; - } - - @Override - public Button getButton() { - return null; - } - } - ).show(origin); - } - - private void showBanPlayerApproval(Player origin, Player target) { - new Menu(ChatColor.RED + "Are you sure to ban " + target.getName() + "?", 9 * 5) - .setLayout("=========", "====p====", "=========", "==a===d==", "=========") - .setKey(blank(), - new Layout() { - @Override - public char getKey() { - return 'p'; - } - - @Override - public Button getButton() { - return new Button() { - @Override - public ItemStack getItem() { - return new ItemHeadCreator(new ItemStack(Material.PLAYER_HEAD)).setOwner(target.getName()).setName(ChatColor.RED + "Are you sure to ban " + target.getName() + "?").create(); - } - - @Override - public void onClick(Player player) { - - } - }; - } - }, - new Layout() { - @Override - public char getKey() { - return 'a'; - } - - @Override - public Button getButton() { - return new Button() { - @Override - public ItemStack getItem() { - return new ItemCreator(Material.GREEN_STAINED_GLASS).setName(ChatColor.GREEN + "ACCEPT").create(); - } - - @Override - public void onClick(Player player) { - target.ban("You have been banned from this server.", (Date) null, player.getName(), true); - showServerPlayerManager(origin); - } - }; - } - }, - new Layout() { - @Override - public char getKey() { - return 'd'; - } - - @Override - public Button getButton() { - return new Button() { - @Override - public ItemStack getItem() { - return new ItemCreator(Material.RED_STAINED_GLASS).setName(ChatColor.RED + "DENY").create(); - } - - @Override - public void onClick(Player player) { - showSpecificPlayerManager(player, target); - } - }; - } - } - ).show(origin); - } - - private void showKickPlayerApproval(Player origin, Player target) { - new Menu(ChatColor.RED + "Are you sure to kick " + target.getName() + "?", 9 * 5) - .setLayout("=========", "====p====", "=========", "==a===d==", "=========") - .setKey(blank(), - new Layout() { - @Override - public char getKey() { - return 'p'; - } - - @Override - public Button getButton() { - return new Button() { - @Override - public ItemStack getItem() { - return new ItemHeadCreator(new ItemStack(Material.PLAYER_HEAD)).setOwner(target.getName()).setName(ChatColor.RED + "Are you sure to kick " + target.getName() + "?").create(); - } - - @Override - public void onClick(Player player) { - - } - }; - } - }, - new Layout() { - @Override - public char getKey() { - return 'a'; - } - - @Override - public Button getButton() { - return new Button() { - @Override - public ItemStack getItem() { - return new ItemCreator(Material.GREEN_STAINED_GLASS).setName(ChatColor.GREEN + "ACCEPT").create(); - } - - @Override - public void onClick(Player player) { - target.kick(); - showServerPlayerManager(origin); - } - }; - } - }, - new Layout() { - @Override - public char getKey() { - return 'd'; - } - - @Override - public Button getButton() { - return new Button() { - @Override - public ItemStack getItem() { - return new ItemCreator(Material.RED_STAINED_GLASS).setName(ChatColor.RED + "DENY").create(); - } - - @Override - public void onClick(Player player) { - showSpecificPlayerManager(player, target); - } - }; - } - } - ).show(origin); - } - - /** - * Handles player chat events for world creator input. - * Processes user input for world creation parameters when players are in world creator mode. - * - * @param event the player chat event - */ - @EventHandler - public void sendChat(PlayerChatEvent event) { - Player player = event.getPlayer(); - if (player.hasMetadata("devTool")) { - DevTool.WorldCreatorContent worldCreatorContent = (DevTool.WorldCreatorContent) player.getMetadata("devTool").getFirst().value(); - if (worldCreatorContent.getInputContent() == null) { - player.sendMessage(ChatColor.RED + "Seem like devTool World creator has occur an error."); - return; - } - event.setCancelled(true); - switch (worldCreatorContent.getInputContent()) { - case "worldName": { - new DevTool().showWorldCreator(player, event.getMessage(), worldCreatorContent.getEnvironment(), worldCreatorContent.getWorldType(), worldCreatorContent.getGenerateStructure(), worldCreatorContent.getBorderSize(), worldCreatorContent.getDifficulty(), worldCreatorContent.getSeed()); - break; - } - case "worldBorder": { - try { - int borderSize = Integer.parseInt(event.getMessage()); - if (borderSize <= 0) { - player.sendMessage(ChatColor.RED + "World border size must be greater than 0"); - new DevTool().showWorldCreator(player, worldCreatorContent.getWorldName(), worldCreatorContent.getEnvironment(), worldCreatorContent.getWorldType(), worldCreatorContent.getGenerateStructure(), worldCreatorContent.getBorderSize(), worldCreatorContent.getDifficulty(), worldCreatorContent.getSeed()); - return; - } - new DevTool().showWorldCreator(player, worldCreatorContent.getWorldName(), worldCreatorContent.getEnvironment(), worldCreatorContent.getWorldType(), worldCreatorContent.getGenerateStructure(), borderSize, worldCreatorContent.getDifficulty(), worldCreatorContent.getSeed()); - } catch (NumberFormatException e) { - player.sendMessage(ChatColor.RED + "World border size must be a number."); - new DevTool().showWorldCreator(player, worldCreatorContent.getWorldName(), worldCreatorContent.getEnvironment(), worldCreatorContent.getWorldType(), worldCreatorContent.getGenerateStructure(), worldCreatorContent.getBorderSize(), worldCreatorContent.getDifficulty(), worldCreatorContent.getSeed()); - } - break; - } - case "worldSeed": { - try { - long seed = Long.parseLong(event.getMessage()); - new DevTool().showWorldCreator(player, worldCreatorContent.getWorldName(), worldCreatorContent.getEnvironment(), worldCreatorContent.getWorldType(), worldCreatorContent.getGenerateStructure(), worldCreatorContent.getBorderSize(), worldCreatorContent.getDifficulty(), seed); - } catch (NumberFormatException e) { - player.sendMessage(ChatColor.RED + "World border size must be a number."); - new DevTool().showWorldCreator(player, worldCreatorContent.getWorldName(), worldCreatorContent.getEnvironment(), worldCreatorContent.getWorldType(), worldCreatorContent.getGenerateStructure(), worldCreatorContent.getBorderSize(), worldCreatorContent.getDifficulty(), worldCreatorContent.getSeed()); - } - break; - } - } - if (player.hasMetadata("devTool")) { - player.removeMetadata("devTool", getInstance()); - } - } - } - - /// Commands - - @Override - public void execute(@NotNull CommandSourceStack commandSourceStack, String @NotNull [] strings) { - if (commandSourceStack.getSender() instanceof Player player) { - switch (strings.length) { - case 0: { - this.openDevTool(player); - break; - } - case 1: { - ItemStack devToolItem = this.getItem(); - if (strings[0].equalsIgnoreCase("get") || strings[0].equalsIgnoreCase("getItem")) { - player.getInventory().addItem(devToolItem); - } - break; - } - case 3: { - if (strings[0].equalsIgnoreCase("world")) { - if (strings[1].equalsIgnoreCase("teleport")) { - World world = Bukkit.getWorld(strings[2]); - if (world != null) { - player.teleport(world.getSpawnLocation()); - player.sendMessage(ChatColor.GRAY + "Teleporting to " + world.getName() + "..."); - } else { - player.sendMessage(ChatColor.RED + "World not found!"); - } - } - break; - } - } - } - return; - } - commandSourceStack.getSender().sendMessage("This command can only be executed by a player!"); - } - - @Override - public @NotNull Collection suggest(@NotNull CommandSourceStack commandSourceStack, String @NotNull [] args) { - switch (args.length) { - case 0, 1: { - return List.of("get", "getItem", "world"); - } - case 2: { - if (args[0].equalsIgnoreCase("world")) { - return List.of("teleport"); - } - break; - } - case 3: { - if (args[0].equalsIgnoreCase("world") && args[1].equalsIgnoreCase("teleport")) { - return List.of(Bukkit.getWorlds().stream().map(World::getName).toArray(String[]::new)); - } - break; - } - } - return List.of(); - } - - - @Override - public boolean canUse(@NotNull CommandSender sender) { - if (sender instanceof Player) { - return sender.hasPermission("pinont.devtool"); - } else { - return false; - } - } - - @Override - public String getName() { - return "devTool"; - } - - @Override - public ItemInteraction getInteraction() { - return null; - } - - @Override - public String description() { - return "SingularityLib Developer Tools"; - } -} diff --git a/src/main/java/com/github/pinont/singularitylib/plugin/listener/EntityDamageListener.java b/src/main/java/com/github/pinont/singularitylib/plugin/listener/EntityDamageListener.java new file mode 100644 index 0000000..4b51e94 --- /dev/null +++ b/src/main/java/com/github/pinont/singularitylib/plugin/listener/EntityDamageListener.java @@ -0,0 +1,21 @@ +package com.github.pinont.singularitylib.plugin.listener; + +import com.github.pinont.singularitylib.api.annotation.AutoRegister; +import com.github.pinont.singularitylib.api.event.PlayerDamageByPlayerEvent; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.entity.EntityDamageByEntityEvent; + +@AutoRegister +public class EntityDamageListener implements Listener { + + @EventHandler + public void onEntityDamage(EntityDamageByEntityEvent event) { + if (event.getEntity() instanceof Player player && event.getDamager() instanceof Player damager) { + PlayerDamageByPlayerEvent playerDamageEvent = new PlayerDamageByPlayerEvent(player, damager); + event.setCancelled(playerDamageEvent.callEvent()); + } + } + +} From c9161d4946e83f9546d8166a268583989ab5f67d Mon Sep 17 00:00:00 2001 From: Nont Nonnipat Date: Thu, 23 Oct 2025 02:00:10 +0700 Subject: [PATCH 05/13] feat: enhance AutoRegister annotation and improve ConfigManager with file initialization and reload functionality --- .../api/annotation/AutoRegister.java | 5 ++ .../api/manager/ConfigManager.java | 82 ++++++++++++------- 2 files changed, 56 insertions(+), 31 deletions(-) diff --git a/src/main/java/com/github/pinont/singularitylib/api/annotation/AutoRegister.java b/src/main/java/com/github/pinont/singularitylib/api/annotation/AutoRegister.java index 5fe750b..adb95e4 100644 --- a/src/main/java/com/github/pinont/singularitylib/api/annotation/AutoRegister.java +++ b/src/main/java/com/github/pinont/singularitylib/api/annotation/AutoRegister.java @@ -1,5 +1,8 @@ package com.github.pinont.singularitylib.api.annotation; +import java.lang.annotation.ElementType; +import java.lang.annotation.Target; + /** * Annotation to mark classes for automatic registration by the plugin. * This annotation is used to mark classes that need to be registered during the plugin's startup process. @@ -9,6 +12,8 @@ * Hint: Use this annotation to register commands, events, or custom items. * It should only be used when the class extends {@code CustomItem}, {@code SimpleCommand}, or {@code Listener}. */ + +@Target({ElementType.TYPE}) public @interface AutoRegister { /** * Indicates that the annotated class should be automatically registered by the plugin. diff --git a/src/main/java/com/github/pinont/singularitylib/api/manager/ConfigManager.java b/src/main/java/com/github/pinont/singularitylib/api/manager/ConfigManager.java index bced8ec..0352b94 100644 --- a/src/main/java/com/github/pinont/singularitylib/api/manager/ConfigManager.java +++ b/src/main/java/com/github/pinont/singularitylib/api/manager/ConfigManager.java @@ -12,14 +12,25 @@ /** * Manages configuration files for the plugin. - * This class provides functionality to create, load, save, and manipulate YAML configuration files. + *

+ * This class provides functionality to create, load, save, reload, and manipulate YAML configuration files + * in the plugin's data folder or subfolders. */ public class ConfigManager { + /** The configuration file on disk */ private final File configFile; - private final FileConfiguration config; + + /** The in-memory representation of the YAML configuration */ + private FileConfiguration config; + + /** The name of the configuration file */ private final String fileName; + + /** Reference to the plugin instance */ private final Plugin plugin = getInstance(); + + /** True if the config file was just created (first load) */ private boolean isFirstLoad; /** @@ -29,26 +40,29 @@ public class ConfigManager { */ public ConfigManager(String fileName) { this.fileName = fileName; - configFile = new File(plugin.getDataFolder(), fileName); - if (!configFile.exists()) { - try { - configFile.getParentFile().mkdirs(); - configFile.createNewFile(); - isFirstLoad = true; - } catch (IOException e) { - Bukkit.getLogger().warning(e.getMessage()); - } - } else { - isFirstLoad = false; - } - config = YamlConfiguration.loadConfiguration(configFile); + this.configFile = new File(plugin.getDataFolder(), fileName); + initializeFile(); + this.config = YamlConfiguration.loadConfiguration(configFile); + } + + /** + * Creates a ConfigManager for a configuration file in a specific subfolder. + * + * @param subFolder the subfolder where the configuration file should be located + * @param fileName the name of the configuration file + */ + public ConfigManager(String subFolder, String fileName) { + this.fileName = fileName; + this.configFile = new File(plugin.getDataFolder() + "/" + subFolder, fileName); + initializeFile(); + this.config = YamlConfiguration.loadConfiguration(configFile); } /** * Checks if a configuration file exists in a specific subfolder. * * @param subFolder the subfolder to check in - * @param fileName the name of the configuration file + * @param fileName the name of the configuration file * @return true if the file exists, false otherwise */ public static boolean isExists(String subFolder, String fileName) { @@ -56,32 +70,26 @@ public static boolean isExists(String subFolder, String fileName) { } /** - * Creates a ConfigManager for a configuration file in a specific subfolder. - * - * @param subFolder the subfolder where the configuration file should be located - * @param fileName the name of the configuration file + * Initializes the configuration file by creating it if it does not exist. */ - public ConfigManager(String subFolder, String fileName) { - this.fileName = fileName; - configFile = new File(plugin.getDataFolder() + "/" + subFolder, fileName); + private void initializeFile() { if (!configFile.exists()) { try { configFile.getParentFile().mkdirs(); configFile.createNewFile(); isFirstLoad = true; } catch (IOException e) { - Bukkit.getLogger().warning(e.getMessage()); + Bukkit.getLogger().warning("Failed to create config file: " + e.getMessage()); } } else { isFirstLoad = false; } - config = YamlConfiguration.loadConfiguration(configFile); } /** * Sets a value at the specified path in the configuration. * - * @param path the configuration path + * @param path the configuration path * @param value the value to set */ public void set(String path, Object value) { @@ -100,14 +108,27 @@ public Object get(String path) { /** * Saves the configuration to the file. - * This method writes all changes made to the configuration back to the file. + *

+ * Writes all changes made to the configuration back to the disk. */ public void saveConfig() { try { config.save(configFile); - config.options().copyDefaults(true); } catch (IOException e) { - Bukkit.getLogger().warning(e.getMessage()); + Bukkit.getLogger().warning("Failed to save config file: " + e.getMessage()); + } + } + + /** + * Reloads the configuration from disk. + *

+ * Useful when the file is manually modified while the server is running. + */ + public void reloadConfig() { + if (configFile.exists()) { + config = YamlConfiguration.loadConfiguration(configFile); + } else { + Bukkit.getLogger().warning("Config file does not exist: " + fileName); } } @@ -119,7 +140,6 @@ public void saveConfig() { public FileConfiguration getConfig() { if (config == null) { Bukkit.getLogger().warning("An error occurred while loading the config file: " + fileName); - return null; } return config; } @@ -132,4 +152,4 @@ public FileConfiguration getConfig() { public boolean isFirstLoad() { return isFirstLoad; } -} \ No newline at end of file +} From d7e821dcac0b80d76085460f9cb4faea90a55a88 Mon Sep 17 00:00:00 2001 From: Nont Nonnipat Date: Thu, 23 Oct 2025 02:13:51 +0700 Subject: [PATCH 06/13] feat: refactor ConfigManager for improved file initialization and error handling --- .../api/manager/ConfigManager.java | 91 +++++++++---------- 1 file changed, 42 insertions(+), 49 deletions(-) diff --git a/src/main/java/com/github/pinont/singularitylib/api/manager/ConfigManager.java b/src/main/java/com/github/pinont/singularitylib/api/manager/ConfigManager.java index 0352b94..51465e3 100644 --- a/src/main/java/com/github/pinont/singularitylib/api/manager/ConfigManager.java +++ b/src/main/java/com/github/pinont/singularitylib/api/manager/ConfigManager.java @@ -12,25 +12,14 @@ /** * Manages configuration files for the plugin. - *

- * This class provides functionality to create, load, save, reload, and manipulate YAML configuration files - * in the plugin's data folder or subfolders. + * This class provides functionality to create, load, save, and manipulate YAML configuration files. */ public class ConfigManager { - /** The configuration file on disk */ private final File configFile; - - /** The in-memory representation of the YAML configuration */ private FileConfiguration config; - - /** The name of the configuration file */ private final String fileName; - - /** Reference to the plugin instance */ private final Plugin plugin = getInstance(); - - /** True if the config file was just created (first load) */ private boolean isFirstLoad; /** @@ -40,29 +29,26 @@ public class ConfigManager { */ public ConfigManager(String fileName) { this.fileName = fileName; - this.configFile = new File(plugin.getDataFolder(), fileName); - initializeFile(); - this.config = YamlConfiguration.loadConfiguration(configFile); - } - - /** - * Creates a ConfigManager for a configuration file in a specific subfolder. - * - * @param subFolder the subfolder where the configuration file should be located - * @param fileName the name of the configuration file - */ - public ConfigManager(String subFolder, String fileName) { - this.fileName = fileName; - this.configFile = new File(plugin.getDataFolder() + "/" + subFolder, fileName); - initializeFile(); - this.config = YamlConfiguration.loadConfiguration(configFile); + configFile = new File(plugin.getDataFolder(), fileName); + if (!configFile.exists()) { + try { + configFile.getParentFile().mkdirs(); + configFile.createNewFile(); + isFirstLoad = true; + } catch (IOException e) { + Bukkit.getLogger().warning(e.getMessage()); + } + } else { + isFirstLoad = false; + } + config = YamlConfiguration.loadConfiguration(configFile); } /** * Checks if a configuration file exists in a specific subfolder. * * @param subFolder the subfolder to check in - * @param fileName the name of the configuration file + * @param fileName the name of the configuration file * @return true if the file exists, false otherwise */ public static boolean isExists(String subFolder, String fileName) { @@ -70,26 +56,32 @@ public static boolean isExists(String subFolder, String fileName) { } /** - * Initializes the configuration file by creating it if it does not exist. + * Creates a ConfigManager for a configuration file in a specific subfolder. + * + * @param subFolder the subfolder where the configuration file should be located + * @param fileName the name of the configuration file */ - private void initializeFile() { + public ConfigManager(String subFolder, String fileName) { + this.fileName = fileName; + configFile = new File(plugin.getDataFolder() + "/" + subFolder, fileName); if (!configFile.exists()) { try { configFile.getParentFile().mkdirs(); configFile.createNewFile(); isFirstLoad = true; } catch (IOException e) { - Bukkit.getLogger().warning("Failed to create config file: " + e.getMessage()); + Bukkit.getLogger().warning(e.getMessage()); } } else { isFirstLoad = false; } + config = YamlConfiguration.loadConfiguration(configFile); } /** * Sets a value at the specified path in the configuration. * - * @param path the configuration path + * @param path the configuration path * @param value the value to set */ public void set(String path, Object value) { @@ -108,15 +100,28 @@ public Object get(String path) { /** * Saves the configuration to the file. - *

- * Writes all changes made to the configuration back to the disk. + * This method writes all changes made to the configuration back to the file. */ public void saveConfig() { try { config.save(configFile); + config.options().copyDefaults(true); } catch (IOException e) { - Bukkit.getLogger().warning("Failed to save config file: " + e.getMessage()); + Bukkit.getLogger().warning(e.getMessage()); + } + } + + /** + * Gets the FileConfiguration instance. + * + * @return the FileConfiguration instance, or null if there was an error loading + */ + public FileConfiguration getConfig() { + if (config == null) { + Bukkit.getLogger().warning("An error occurred while loading the config file: " + fileName); + return null; } + return config; } /** @@ -132,18 +137,6 @@ public void reloadConfig() { } } - /** - * Gets the FileConfiguration instance. - * - * @return the FileConfiguration instance, or null if there was an error loading - */ - public FileConfiguration getConfig() { - if (config == null) { - Bukkit.getLogger().warning("An error occurred while loading the config file: " + fileName); - } - return config; - } - /** * Checks if this is the first time the configuration file is being loaded. * @@ -152,4 +145,4 @@ public FileConfiguration getConfig() { public boolean isFirstLoad() { return isFirstLoad; } -} +} \ No newline at end of file From c8acdbbf0a2a76f9901baa63644cc64ab1fee333 Mon Sep 17 00:00:00 2001 From: Nont Nonnipat Date: Thu, 23 Oct 2025 02:14:48 +0700 Subject: [PATCH 07/13] feat: simplify AutoRegister annotation by removing unnecessary imports --- .../pinont/singularitylib/api/annotation/AutoRegister.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/main/java/com/github/pinont/singularitylib/api/annotation/AutoRegister.java b/src/main/java/com/github/pinont/singularitylib/api/annotation/AutoRegister.java index adb95e4..c221bc4 100644 --- a/src/main/java/com/github/pinont/singularitylib/api/annotation/AutoRegister.java +++ b/src/main/java/com/github/pinont/singularitylib/api/annotation/AutoRegister.java @@ -1,8 +1,5 @@ package com.github.pinont.singularitylib.api.annotation; -import java.lang.annotation.ElementType; -import java.lang.annotation.Target; - /** * Annotation to mark classes for automatic registration by the plugin. * This annotation is used to mark classes that need to be registered during the plugin's startup process. @@ -13,7 +10,6 @@ * It should only be used when the class extends {@code CustomItem}, {@code SimpleCommand}, or {@code Listener}. */ -@Target({ElementType.TYPE}) public @interface AutoRegister { /** * Indicates that the annotated class should be automatically registered by the plugin. From eb5433e9020f8418e75868315c6f1b099dcbedc8 Mon Sep 17 00:00:00 2001 From: Nont Nonnipat Date: Thu, 23 Oct 2025 11:13:55 +0700 Subject: [PATCH 08/13] feat: enhance AutoRegister annotation and refactor CustomItemManager for improved initialization --- .../pinont/singularitylib/api/annotation/AutoRegister.java | 4 ++++ .../singularitylib/api/manager/CustomItemManager.java | 7 +++++-- .../pinont/singularitylib/plugin/register/Register.java | 1 - 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/github/pinont/singularitylib/api/annotation/AutoRegister.java b/src/main/java/com/github/pinont/singularitylib/api/annotation/AutoRegister.java index c221bc4..adb95e4 100644 --- a/src/main/java/com/github/pinont/singularitylib/api/annotation/AutoRegister.java +++ b/src/main/java/com/github/pinont/singularitylib/api/annotation/AutoRegister.java @@ -1,5 +1,8 @@ package com.github.pinont.singularitylib.api.annotation; +import java.lang.annotation.ElementType; +import java.lang.annotation.Target; + /** * Annotation to mark classes for automatic registration by the plugin. * This annotation is used to mark classes that need to be registered during the plugin's startup process. @@ -10,6 +13,7 @@ * It should only be used when the class extends {@code CustomItem}, {@code SimpleCommand}, or {@code Listener}. */ +@Target({ElementType.TYPE}) public @interface AutoRegister { /** * Indicates that the annotated class should be automatically registered by the plugin. diff --git a/src/main/java/com/github/pinont/singularitylib/api/manager/CustomItemManager.java b/src/main/java/com/github/pinont/singularitylib/api/manager/CustomItemManager.java index 5003a98..a89f1af 100644 --- a/src/main/java/com/github/pinont/singularitylib/api/manager/CustomItemManager.java +++ b/src/main/java/com/github/pinont/singularitylib/api/manager/CustomItemManager.java @@ -37,7 +37,7 @@ public class CustomItemManager implements SimpleCommand { * Used when the dev tool plugin is present to provide additional * development and debugging features for custom items. */ - private final CItemManager customItemManager = new CItemManager(); + private CItemManager customItemManager; /** * Default constructor for CustomItemManager. @@ -73,7 +73,7 @@ public List getCustomItems() { public void register(List item) { if (item.isEmpty()) return; sendConsoleMessage("Registering " + item.size() + " custom items"); - if (getInstance().getServer().getPluginManager().getPlugin("SingularityDevTool") != null) { + if (Common.plugin != null) { registerAllItems(item, true); } registerAllItems(item); @@ -104,6 +104,9 @@ private void registerAllItems(List items) { * @param forDevTool whether to register items with the development tool */ private void registerAllItems(List items, boolean forDevTool) { + if (forDevTool) { + customItemManager = new CItemManager(); + } for (CustomItem customItem : items) { customItems.add(customItem); if (forDevTool) { diff --git a/src/main/java/com/github/pinont/singularitylib/plugin/register/Register.java b/src/main/java/com/github/pinont/singularitylib/plugin/register/Register.java index dbefea9..e5c93e0 100644 --- a/src/main/java/com/github/pinont/singularitylib/plugin/register/Register.java +++ b/src/main/java/com/github/pinont/singularitylib/plugin/register/Register.java @@ -1,6 +1,5 @@ package com.github.pinont.singularitylib.plugin.register; -import com.github.pinont.devtool.api.CItemManager; import com.github.pinont.singularitylib.api.annotation.AutoRegister; import com.github.pinont.singularitylib.api.command.SimpleCommand; import com.github.pinont.singularitylib.api.items.CustomItem; From 55b1c7ed4d4ee0a9e7b5850e16668d50118ca309 Mon Sep 17 00:00:00 2001 From: Nont Nonnipat Date: Thu, 23 Oct 2025 13:50:47 +0700 Subject: [PATCH 09/13] feat: add Folia compatibility and enhance scheduling functionality --- pom.xml | 9 +- .../singularitylib/api/runnable/Runner.java | 5 + .../api/runnable/Scheduler.java | 126 ++++++++++++++++++ .../singularitylib/api/utils/Common.java | 11 ++ .../singularitylib/plugin/CorePlugin.java | 23 +++- 5 files changed, 171 insertions(+), 3 deletions(-) create mode 100644 src/main/java/com/github/pinont/singularitylib/api/runnable/Runner.java create mode 100644 src/main/java/com/github/pinont/singularitylib/api/runnable/Scheduler.java diff --git a/pom.xml b/pom.xml index d7a648f..63cabe2 100644 --- a/pom.xml +++ b/pom.xml @@ -52,6 +52,7 @@ 23 + 1.21.5-R0.1-SNAPSHOT UTF-8 UTF-8 ${java.version} @@ -148,7 +149,13 @@ io.papermc.paper paper-api - 1.21.8-R0.1-SNAPSHOT + ${paperapi.version} + provided + + + dev.folia + folia-api + ${paperapi.version} provided diff --git a/src/main/java/com/github/pinont/singularitylib/api/runnable/Runner.java b/src/main/java/com/github/pinont/singularitylib/api/runnable/Runner.java new file mode 100644 index 0000000..725c8f0 --- /dev/null +++ b/src/main/java/com/github/pinont/singularitylib/api/runnable/Runner.java @@ -0,0 +1,5 @@ +package com.github.pinont.singularitylib.api.runnable; + +public interface Runner { + void run(); +} diff --git a/src/main/java/com/github/pinont/singularitylib/api/runnable/Scheduler.java b/src/main/java/com/github/pinont/singularitylib/api/runnable/Scheduler.java new file mode 100644 index 0000000..96ccb89 --- /dev/null +++ b/src/main/java/com/github/pinont/singularitylib/api/runnable/Scheduler.java @@ -0,0 +1,126 @@ +package com.github.pinont.singularitylib.api.runnable; + +import com.github.pinont.singularitylib.api.utils.Common; +import com.github.pinont.singularitylib.plugin.CorePlugin; +import io.papermc.paper.threadedregions.scheduler.*; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.Server; +import org.bukkit.World; +import org.bukkit.scheduler.BukkitScheduler; +import org.bukkit.scheduler.BukkitTask; + +import java.util.concurrent.TimeUnit; + +public class Scheduler { + + private final boolean isFolia = CorePlugin.isFolia(); + + private final Server server = Bukkit.getServer(); + + private Runner runner; + private BukkitScheduler bukkitScheduler; + private AsyncScheduler asyncScheduler; + + public ScheduledTask scheduledTask = null; + public BukkitTask bukkitTask = null; + + private GlobalRegionScheduler globalScheduler; + private RegionScheduler regionScheduler; + private EntityScheduler entityScheduler; + + enum RunnerType { + SYNC, + ASYNC, + GLOBAL, + REGION, + ENTITY + } + + public AsyncScheduler getAsyncScheduler() { + return asyncScheduler; + } + + public BukkitScheduler getBukkitScheduler() { + return bukkitScheduler; + } + + public GlobalRegionScheduler getGlobalScheduler() { + return globalScheduler; + } + + public RegionScheduler getRegionScheduler() { + return regionScheduler; + } + + public Object getTask() { + return isFolia ? scheduledTask : bukkitTask; + } + + public void runTaskAsync(Runner runner) { + this.runner = runner; + if (isFolia) { + asyncScheduler = server.getAsyncScheduler(); + scheduledTask = asyncScheduler.runNow(Common.plugin, _ -> runner.run()); + } else { + bukkitScheduler = server.getScheduler(); + bukkitTask = bukkitScheduler.runTaskAsynchronously(Common.plugin, runner::run); + } + } + + public void runTask(Runner runner) { + this.runner = runner; + if (isFolia) { + globalScheduler = server.getGlobalRegionScheduler(); + scheduledTask = globalScheduler.run(Common.plugin, _ -> runner.run()); + } else { + bukkitScheduler = server.getScheduler(); + bukkitTask = bukkitScheduler.runTask(Common.plugin, runner::run); + } + } + + public void runRepeatingTask(Location location, Runner runner, int delayTicks, long periodTicks, TimeUnit timeUnit) { + this.runner = runner; + if (isFolia) { + regionScheduler = server.getRegionScheduler(); + scheduledTask = regionScheduler.runAtFixedRate(Common.plugin, location, _ -> runner.run(), delayTicks, periodTicks); + } else { + bukkitScheduler = server.getScheduler(); + bukkitTask = bukkitScheduler.runTaskTimer(Common.plugin, runner::run, 0L, periodTicks * timeUnit.toMillis(periodTicks)); + } + } + + public void runRepeatingTask(World world, Runner runner, int delayTicks, long periodTicks, TimeUnit timeUnit) { + runRepeatingTask(new Location(world, 0, 0, 0), runner,delayTicks, periodTicks, timeUnit); + } + + public void runRepeatingTaskAsync(Runner runner, int delayTicks, long periodTicks, TimeUnit timeUnit) { + if (isFolia) { + asyncScheduler = server.getAsyncScheduler(); + scheduledTask = asyncScheduler.runAtFixedRate(Common.plugin, _ -> runner.run(), delayTicks, periodTicks, timeUnit); + } else { + bukkitScheduler = server.getScheduler(); + bukkitTask = bukkitScheduler.runTaskTimer(Common.plugin, runner::run, delayTicks, Common.toTicks(periodTicks, timeUnit)); + } + } + + public void cancelTask() { + if (isFolia) { + if (scheduledTask != null) { + scheduledTask.cancel(); + } + } else { + if (bukkitTask != null) { + bukkitTask.cancel(); + } + } + } + + public void cancelAllTasks() { + if (isFolia) { + asyncScheduler.cancelTasks(Common.plugin); + } else { + bukkitScheduler.cancelTasks(Common.plugin); + } + } +} diff --git a/src/main/java/com/github/pinont/singularitylib/api/utils/Common.java b/src/main/java/com/github/pinont/singularitylib/api/utils/Common.java index fd0fd73..1bc03c6 100644 --- a/src/main/java/com/github/pinont/singularitylib/api/utils/Common.java +++ b/src/main/java/com/github/pinont/singularitylib/api/utils/Common.java @@ -15,6 +15,7 @@ import java.util.Arrays; import java.util.Collection; import java.util.List; +import java.util.concurrent.TimeUnit; import static com.github.pinont.singularitylib.plugin.CorePlugin.getInstance; @@ -314,4 +315,14 @@ public static String resetStringColor(String text) { public static String resetStringColor(Component component) { return MiniMessage.miniMessage().serialize(component); } + + public static long toTicks(long amount, TimeUnit unit) { + return switch (unit) { + case SECONDS -> amount * 20; + case MINUTES -> amount * 20 * 60; + case HOURS -> amount * 20 * 60 * 60; + case DAYS -> amount * 20 * 60 * 60 * 24; + default -> amount; + }; + } } \ No newline at end of file diff --git a/src/main/java/com/github/pinont/singularitylib/plugin/CorePlugin.java b/src/main/java/com/github/pinont/singularitylib/plugin/CorePlugin.java index d655e51..f7510a2 100644 --- a/src/main/java/com/github/pinont/singularitylib/plugin/CorePlugin.java +++ b/src/main/java/com/github/pinont/singularitylib/plugin/CorePlugin.java @@ -45,12 +45,17 @@ public CorePlugin() { private static String prefix; private static Long startTime; + private static boolean isFolia; /** * Flag indicating if the plugin is running in test mode. */ public boolean isTest = false; + public static boolean isFolia() { + return isFolia; + } + /** * Gets the time when the plugin started loading. * @@ -94,8 +99,8 @@ public static void sendConsoleMessage(String message) { * @return the API version string */ public static String getAPIVersion() { - String version = new ConfigManager("api-version.yml").getConfig().getString("version"); -// String version = "1.0.0"; + new ConfigManager("api-version.yml").saveConfig(); + String version = new ConfigManager("api-version.yml").getConfig().getString("version") == null ? "1.0.0" : new ConfigManager("api-version.yml").getConfig().getString("version"); return "V-" + version; } @@ -164,6 +169,11 @@ public final void onEnable() { // TODO: Move to Devtool // WorldManager.autoLoadWorlds(); + isFolia = foliaCheck(); + if (isFolia) { + sendConsoleMessage(ChatColor.GREEN + "" + ChatColor.ITALIC + "Folia environment detected, enabling Folia compatibility mode..."); + } + // Initialize API To Plugin. sendConsoleMessage(ChatColor.WHITE + "" + ChatColor.ITALIC + "Hooked " + ChatColor.YELLOW + ChatColor.ITALIC + this.getName() + ChatColor.WHITE + ChatColor.ITALIC + " into " + ChatColor.LIGHT_PURPLE + ChatColor.ITALIC + "SingularityAPI! " + getAPIVersion()); onPluginStart(); @@ -178,6 +188,15 @@ public final void onEnable() { } } + private boolean foliaCheck() { + try { + Class.forName("io.papermc.paper.threadedregions.RegionizedServer"); + return true; + } catch (ClassNotFoundException e) { + return false; + } + } + private void registerAPIListener(Plugin plugin, Listener... listener) { sendConsoleMessage(ChatColor.GREEN + "" + ChatColor.ITALIC + "Initializing API listeners for " + plugin.getName() + "..."); for (Listener l : listener) { From 29e853419bcfaa995864ff4a9e50a616c8a0c098 Mon Sep 17 00:00:00 2001 From: Nont Nonnipat Date: Thu, 23 Oct 2025 14:14:38 +0700 Subject: [PATCH 10/13] feat: update project version to 1.1.0-SNAPSHOT and enhance dependency management with MockBukkit integration --- pom.xml | 48 +++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 45 insertions(+), 3 deletions(-) diff --git a/pom.xml b/pom.xml index 63cabe2..cc82ab0 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ com.github.pinont singularitylib - 1.0.0 + 1.1.0-SNAPSHOT jar SingularityLib @@ -52,7 +52,9 @@ 23 - 1.21.5-R0.1-SNAPSHOT + 1.21.8-R0.1-SNAPSHOT + 4.87.0 + ${paperapi.version} UTF-8 UTF-8 ${java.version} @@ -135,6 +137,40 @@ maven-deploy-plugin 3.1.2 + + + + org.codehaus.gmaven + groovy-maven-plugin + 2.1.1 + + + initialize + + execute + + + + // Extract Paper version from MockBukkit JAR + def mockbukkitJar = project.artifacts.find { + it.artifactId.startsWith('mockbukkit-') + }?.file + + if (mockbukkitJar) { + def jar = new java.util.jar.JarFile(mockbukkitJar) + def manifest = jar.manifest + def paperVersion = manifest.mainAttributes.getValue('Paper-Version') + jar.close() + + if (paperVersion) { + project.properties['paper.version.from.mockbukkit'] = paperVersion + } + } + + + + + @@ -176,7 +212,13 @@ org.mockbukkit.mockbukkit mockbukkit-v1.21 - 4.77.0 + ${mockbukkit.version} + test + + + io.papermc.paper + paper-api + ${paper.version.from.mockbukkit} test From e2c450205067ba53a39c7b4eeefc62234cc52d22 Mon Sep 17 00:00:00 2001 From: Nont Nonnipat Date: Sat, 25 Oct 2025 01:33:13 +0700 Subject: [PATCH 11/13] refactor: remove unnecessary blank line in EntityCreator.java --- .../github/pinont/singularitylib/api/entity/EntityCreator.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/com/github/pinont/singularitylib/api/entity/EntityCreator.java b/src/main/java/com/github/pinont/singularitylib/api/entity/EntityCreator.java index d1c7c74..331fde0 100644 --- a/src/main/java/com/github/pinont/singularitylib/api/entity/EntityCreator.java +++ b/src/main/java/com/github/pinont/singularitylib/api/entity/EntityCreator.java @@ -24,7 +24,6 @@ public class EntityCreator { private List ScoreboardTag; - private boolean isSetFireTicks = false; private int fireTicks; From 165e7288fd6b7c5c174f05b2f9ee744ccc7d02f4 Mon Sep 17 00:00:00 2001 From: PinozenTH Date: Thu, 6 Nov 2025 15:07:07 +0700 Subject: [PATCH 12/13] feat: refactor item creators and interactions to include plugin dependency for improved functionality --- .../api/command/SimpleCommand.java | 16 +- .../api/entity/EntityCreator.java | 192 ++++----- .../api/items/CrossbowCreator.java | 5 +- .../singularitylib/api/items/ItemCreator.java | 83 +--- .../api/items/ItemHeadCreator.java | 5 +- .../api/items/ItemInteraction.java | 94 ++++- .../api/manager/CustomItemManager.java | 373 +++++++++--------- .../api/runnable/Scheduler.java | 35 +- .../pinont/singularitylib/api/ui/Layout.java | 23 +- .../pinont/singularitylib/api/ui/Menu.java | 11 +- .../singularitylib/api/utils/Common.java | 12 +- .../plugin/listener/PlayerListener.java | 15 +- .../api/items/ItemCreatorMetaTest.java | 64 +-- 13 files changed, 462 insertions(+), 466 deletions(-) diff --git a/src/main/java/com/github/pinont/singularitylib/api/command/SimpleCommand.java b/src/main/java/com/github/pinont/singularitylib/api/command/SimpleCommand.java index 47db203..e9f0ebd 100644 --- a/src/main/java/com/github/pinont/singularitylib/api/command/SimpleCommand.java +++ b/src/main/java/com/github/pinont/singularitylib/api/command/SimpleCommand.java @@ -16,6 +16,14 @@ public interface SimpleCommand extends BasicCommand { */ String getName(); +// /** +// * Gets the description of the command. +// * This description is used in help messages and command documentation. +// * +// * @return the command description +// */ +// String getDescription(); + /** * Gets the usage string for this command. * @@ -25,12 +33,4 @@ public interface SimpleCommand extends BasicCommand { default String usage(Boolean bool) { return "/" + getName(); } - - /** - * Gets the description of the command. - * This description is used in help messages and command documentation. - * - * @return the command description - */ - String description(); } diff --git a/src/main/java/com/github/pinont/singularitylib/api/entity/EntityCreator.java b/src/main/java/com/github/pinont/singularitylib/api/entity/EntityCreator.java index 331fde0..083d7af 100644 --- a/src/main/java/com/github/pinont/singularitylib/api/entity/EntityCreator.java +++ b/src/main/java/com/github/pinont/singularitylib/api/entity/EntityCreator.java @@ -7,6 +7,7 @@ import org.bukkit.entity.LivingEntity; import org.bukkit.util.Vector; +import java.util.HashMap; import java.util.List; import java.util.Objects; @@ -20,57 +21,7 @@ public class EntityCreator { private final EntityType entityType; - private Entity passenger = null; - - private List ScoreboardTag; - - private boolean isSetFireTicks = false; - private int fireTicks; - - private boolean isSetGlowing = false; - private boolean glowing; - - private boolean isSetInvulnerable = false; - private boolean invulnerable; - - private boolean isSetSilient = false; - private boolean silent; - - private boolean isSetGravity = false; - private boolean gravity; - - private boolean isSetSilentGravity = false; - private boolean persistent; - - private boolean isSetFreezeTicks = false; - private int freezeTicks; - - private boolean isSetCustomNameVisible = false; - private boolean customNameVisible; - - private boolean isSetProtalCooldown = false; - private int portalCooldown; - - private boolean isSetFallingDistance = false; - private float fallingDistance; - - private boolean isSetRotation = false; - private float[] rotation = null; - - private boolean isSetVector = false; - private Vector vector = null; - - private boolean isSetVisualFire = false; - private boolean visualFire; - - private boolean isSetVisibleByDefault = false; - private boolean visibleByDefault = true; - - private boolean isSetTicksLived = false; - private int ticksLived; - - private boolean isSetMaxHealth = false; - private double maxHealth; + private HashMap properties; /** * Creates a new EntityCreator for the specified entity type. @@ -88,7 +39,7 @@ public EntityCreator(EntityType entityType) { * @return this EntityCreator for method chaining */ public EntityCreator addPassenger(Entity passenger) { - this.passenger = passenger; + properties.put("passenger", passenger); return this; } @@ -99,7 +50,7 @@ public EntityCreator addPassenger(Entity passenger) { * @return this EntityCreator for method chaining */ public EntityCreator addScoreboardTag(String... ScoreboardTag) { - this.ScoreboardTag.addAll(List.of(ScoreboardTag)); + properties.put("scoreboardTag", ScoreboardTag); return this; } @@ -110,8 +61,7 @@ public EntityCreator addScoreboardTag(String... ScoreboardTag) { * @return this EntityCreator for method chaining */ public EntityCreator setMaxHealth(double maxHealth) { - this.isSetMaxHealth = true; - this.maxHealth = maxHealth; + properties.put("maxHealth", maxHealth); return this; } @@ -122,8 +72,7 @@ public EntityCreator setMaxHealth(double maxHealth) { * @return this EntityCreator for method chaining */ public EntityCreator setFireTicks(int ticks) { - this.isSetFireTicks = true; - this.fireTicks = ticks; + properties.put("fireTicks", ticks); return this; } @@ -134,8 +83,7 @@ public EntityCreator setFireTicks(int ticks) { * @return this EntityCreator for method chaining */ public EntityCreator setGlowing(boolean glowing) { - this.isSetGlowing = true; - this.glowing = glowing; + properties.put("glowing", glowing); return this; } @@ -146,8 +94,7 @@ public EntityCreator setGlowing(boolean glowing) { * @return this EntityCreator for method chaining */ public EntityCreator setInvulnerable(boolean invulnerable) { - this.isSetInvulnerable = true; - this.invulnerable = invulnerable; + properties.put("invulnerable", invulnerable); return this; } @@ -158,8 +105,7 @@ public EntityCreator setInvulnerable(boolean invulnerable) { * @return this EntityCreator for method chaining */ public EntityCreator setSilent(boolean silent) { - this.isSetSilient = true; - this.silent = silent; + properties.put("silent", silent); return this; } @@ -170,8 +116,7 @@ public EntityCreator setSilent(boolean silent) { * @return this EntityCreator for method chaining */ public EntityCreator hasGravity(boolean gravity) { - this.isSetGravity = true; - this.gravity = gravity; + properties.put("gravity", gravity); return this; } @@ -182,8 +127,7 @@ public EntityCreator hasGravity(boolean gravity) { * @return this EntityCreator for method chaining */ public EntityCreator setVelocity(Vector vector) { - this.isSetVector = true; - this.vector = vector; + properties.put("vector", vector); return this; } @@ -194,8 +138,7 @@ public EntityCreator setVelocity(Vector vector) { * @return this EntityCreator for method chaining */ public EntityCreator setPersistent(Boolean persistent) { - this.isSetSilentGravity = true; - this.persistent = persistent; + properties.put("persistent", persistent); return this; } @@ -206,8 +149,7 @@ public EntityCreator setPersistent(Boolean persistent) { * @return this EntityCreator for method chaining */ public EntityCreator setFreezeTicks(int ticks) { - this.isSetFreezeTicks = true; - this.freezeTicks = ticks; + properties.put("freezeTicks", ticks); return this; } @@ -218,8 +160,7 @@ public EntityCreator setFreezeTicks(int ticks) { * @return this EntityCreator for method chaining */ public EntityCreator setCustomNameVisible(Boolean visible) { - this.isSetCustomNameVisible = true; - this.customNameVisible = visible; + properties.put("customNameVisible", visible); return this; } @@ -230,8 +171,7 @@ public EntityCreator setCustomNameVisible(Boolean visible) { * @return this EntityCreator for method chaining */ public EntityCreator setPortalCooldown(int ticks) { - this.isSetProtalCooldown = true; - this.portalCooldown = ticks; + properties.put("portalCooldown", ticks); return this; } @@ -242,8 +182,7 @@ public EntityCreator setPortalCooldown(int ticks) { * @return this EntityCreator for method chaining */ public EntityCreator setFallingDistance(float distance) { - this.isSetFallingDistance = true; - this.fallingDistance = distance; + properties.put("fallingDistance", distance); return this; } @@ -255,8 +194,7 @@ public EntityCreator setFallingDistance(float distance) { * @return this EntityCreator for method chaining */ public EntityCreator setRotation(float yaw, float pitch) { - this.isSetRotation = true; - this.rotation = new float[]{yaw, pitch}; + properties.put("rotation", new float[]{yaw, pitch}); return this; } @@ -267,8 +205,7 @@ public EntityCreator setRotation(float yaw, float pitch) { * @return this EntityCreator for method chaining */ public EntityCreator setTicksLived(int ticks) { - this.isSetTicksLived = true; - this.ticksLived = ticks; + properties.put("ticksLived", ticks); return this; } @@ -279,8 +216,7 @@ public EntityCreator setTicksLived(int ticks) { * @return this EntityCreator for method chaining */ public EntityCreator setVisibleByDefault(boolean visible) { - this.isSetVisibleByDefault = true; - this.visibleByDefault = visible; + properties.put("visibleByDefault", visible); return this; } @@ -291,8 +227,7 @@ public EntityCreator setVisibleByDefault(boolean visible) { * @return this EntityCreator for method chaining */ public EntityCreator setVisualFire(boolean fire) { - this.isSetVisualFire = true; - this.visualFire = fire; + properties.put("visualFire", fire); return this; } @@ -305,7 +240,9 @@ public EntityCreator setVisualFire(boolean fire) { public Entity spawn(Location location) { Entity entity = Objects.requireNonNull(location.getWorld()).spawnEntity(location, entityType); sendDebugMessage("Spawned " + entityType + " at " + location); - if (isSetMaxHealth) { + if (properties != null) return entity; + if (properties.containsKey("maxHealth")) { + double maxHealth = (double) properties.get("maxHealth"); if (entity instanceof LivingEntity livingEntity) { livingEntity.setMaxHealth(maxHealth); livingEntity.setHealth(maxHealth); @@ -313,34 +250,75 @@ public Entity spawn(Location location) { sendDebugMessage("Entity " + entityType + " does not support health setting."); } } - if (passenger != null) entity.addPassenger(passenger); - if (ScoreboardTag != null) { - for (String tag : ScoreboardTag) { + if (properties.containsKey("passenger")) { + Entity passenger = (Entity) properties.get("passenger"); + entity.addPassenger(passenger); + } + if (properties.containsKey("scoreboardTag")) { + String[] tags = (String[]) properties.get("scoreboardTag"); + for (String tag : tags) { entity.addScoreboardTag(tag); } } - if (isSetFireTicks) entity.setFireTicks(fireTicks); - if (isSetGlowing) entity.setGlowing(glowing); - if (isSetInvulnerable) entity.setInvulnerable(invulnerable); - if (isSetSilient) entity.setSilent(silent); - if (isSetGravity) entity.setGravity(gravity); - if (isSetSilentGravity) entity.setPersistent(persistent); - if (isSetFreezeTicks) entity.setFreezeTicks(freezeTicks); - if (isSetCustomNameVisible) entity.setCustomNameVisible(customNameVisible); - if (isSetProtalCooldown) entity.setPortalCooldown(portalCooldown); - if (isSetFallingDistance) entity.setFallDistance(fallingDistance); - if (isSetRotation) { - entity.setRotation(rotation[0], rotation[1]); + if (properties.containsKey("fireTicks")) { + int ticks = (int) properties.get("fireTicks"); + entity.setFireTicks(ticks); + } + if (properties.containsKey("glowing")) { + boolean glowing = (boolean) properties.get("glowing"); + entity.setGlowing(glowing); } - if (isSetVector) { + if (properties.containsKey("invulnerable")) { + boolean invulnerable = (boolean) properties.get("invulnerable"); + entity.setInvulnerable(invulnerable); + } + if (properties.containsKey("silent")) { + boolean silent = (boolean) properties.get("silent"); + entity.setSilent(silent); + } + if (properties.containsKey("gravity")) { + boolean gravity = (boolean) properties.get("gravity"); + entity.setGravity(gravity); + } + if (properties.containsKey("vector")) { + Vector vector = (Vector) properties.get("vector"); entity.setVelocity(vector); } - if (isSetVisualFire) entity.setVisualFire(visualFire); - if (isSetVisibleByDefault) { - entity.setVisibleByDefault(visibleByDefault); + if (properties.containsKey("persistent")) { + boolean persistent = (boolean) properties.get("persistent"); + entity.setPersistent(persistent); + } + if (properties.containsKey("freezeTicks")) { + int ticks = (int) properties.get("freezeTicks"); + entity.setFreezeTicks(ticks); + } + if (properties.containsKey("customNameVisible")) { + boolean visible = (boolean) properties.get("customNameVisible"); + entity.setCustomNameVisible(visible); + } + if (properties.containsKey("portalCooldown")) { + int ticks = (int) properties.get("portalCooldown"); + entity.setPortalCooldown(ticks); + } + if (properties.containsKey("fallingDistance")) { + float distance = (float) properties.get("fallingDistance"); + entity.setFallDistance(distance); + } + if (properties.containsKey("rotation")) { + float[] rotation = (float[]) properties.get("rotation"); + entity.setRotation(rotation[0], rotation[1]); + } + if (properties.containsKey("ticksLived")) { + int ticks = (int) properties.get("ticksLived"); + entity.setTicksLived(ticks); + } + if (properties.containsKey("visibleByDefault")) { + boolean visible = (boolean) properties.get("visibleByDefault"); + entity.setVisibleByDefault(visible); } - if (isSetTicksLived) { - entity.setTicksLived(ticksLived); + if (properties.containsKey("visualFire")) { + boolean fire = (boolean) properties.get("visualFire"); + entity.setVisualFire(fire); } return entity; } diff --git a/src/main/java/com/github/pinont/singularitylib/api/items/CrossbowCreator.java b/src/main/java/com/github/pinont/singularitylib/api/items/CrossbowCreator.java index ef0fb72..2e7a0a3 100644 --- a/src/main/java/com/github/pinont/singularitylib/api/items/CrossbowCreator.java +++ b/src/main/java/com/github/pinont/singularitylib/api/items/CrossbowCreator.java @@ -4,6 +4,7 @@ import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.CrossbowMeta; import org.bukkit.inventory.meta.ItemMeta; +import org.bukkit.plugin.Plugin; /** * A specialized ItemCreator for creating crossbow items. @@ -14,8 +15,8 @@ public class CrossbowCreator extends ItemCreator { /** * Creates a new CrossbowCreator with a crossbow ItemStack. */ - public CrossbowCreator() { - super(new ItemStack(Material.CROSSBOW)); + public CrossbowCreator(Plugin plugin) { + super(plugin, new ItemStack(Material.CROSSBOW)); } /** diff --git a/src/main/java/com/github/pinont/singularitylib/api/items/ItemCreator.java b/src/main/java/com/github/pinont/singularitylib/api/items/ItemCreator.java index 2e2c394..9bd99be 100644 --- a/src/main/java/com/github/pinont/singularitylib/api/items/ItemCreator.java +++ b/src/main/java/com/github/pinont/singularitylib/api/items/ItemCreator.java @@ -23,7 +23,6 @@ import java.util.*; -import static com.github.pinont.singularitylib.plugin.CorePlugin.getInstance; import static com.github.pinont.singularitylib.plugin.CorePlugin.sendConsoleMessage; /** @@ -34,16 +33,16 @@ public class ItemCreator { private final Common common = new Common(); - private final ItemStack item; + private ItemStack item; private ItemMeta meta; private short durability = 0; - private final PersistentDataContainer data; + private PersistentDataContainer data; private final ArrayList lore = new ArrayList<>(); private int amount = 1; private Material type; - private final Plugin plugin = getInstance(); + private final Plugin plugin; private static final Set ITEM_INTERACTIONS = Sets.newHashSet(); - private final String name; + private String name; /** * Gets all registered item interactions. @@ -55,7 +54,7 @@ public static Set getInteractions() { } public ItemCreator clone() { - return new ItemCreator(this.create()); + return new ItemCreator(plugin, this.create()); } /** @@ -63,8 +62,8 @@ public ItemCreator clone() { * * @param type the material type for the item */ - public ItemCreator(Material type) { - this(new ItemStack(type)); + public ItemCreator(Plugin plugin, Material type) { + this(plugin, new ItemStack(type)); } /** @@ -73,8 +72,8 @@ public ItemCreator(Material type) { * @param type the material type for the item * @param amount the amount of items in the stack */ - public ItemCreator(Material type, int amount) { - this(new ItemStack(type, amount)); + public ItemCreator(Plugin plugin, Material type, int amount) { + this(plugin, new ItemStack(type, amount)); } /** @@ -82,9 +81,10 @@ public ItemCreator(Material type, int amount) { * * @param item the ItemStack to create from */ - public ItemCreator(@NotNull ItemStack item) { + public ItemCreator(Plugin plugin, @NotNull ItemStack item) { this.item = item; this.meta = item.getItemMeta(); + this.plugin = plugin; this.type = item.getType(); this.amount = item.getAmount(); this.name = item.getItemMeta().getDisplayName().isEmpty() ? Common.normalizeStringName(item.getType().name()) : item.getItemMeta().getDisplayName(); @@ -186,27 +186,6 @@ public ItemCreator setItemMeta(ItemMeta meta) { return this; } - /** - * Gets the interaction associated with the given ItemStack. - * - * @param item the ItemStack to get the interaction for - * @return the ItemInteraction, or null if none found - */ - public static ItemInteraction getInteraction(ItemStack item) { - String id = getItemInteractionName(item); - if (id == null) { - sendConsoleMessage(ChatColor.RED + "Item interaction not found for item: " + item.getType()); - return null; - } - ItemInteraction interaction = ITEM_INTERACTIONS.stream().filter(itemInteraction -> itemInteraction.getName().equals(id)).findFirst().orElse(null); - if (interaction != null) { - return interaction; - } else { - sendConsoleMessage(ChatColor.RED + "Item interaction not found for item: " + item.getType()); - } - return null; - } - /** * Sets the material type of the item. * @@ -504,24 +483,6 @@ public ItemCreator setDurability(int durability) { return this; } - /** - * Gets the persistent data of an item. - * - * @param item the ItemStack to get data from - * @param key the key of the data to get - * @param type the PersistentDataType of the data - * @return the data value, or null if not present - */ - public static Object getItemPersistData(ItemStack item, String key, PersistentDataType type) { - if (isItemHasPersistData(item, key, type)) { - ItemMeta meta = item.getItemMeta(); - if (meta != null) { - return meta.getPersistentDataContainer().get(new NamespacedKey(getInstance(), key), type); - } - } - return null; - } - /** * Sets data in the item's PersistentDataContainer. * @@ -566,16 +527,6 @@ public ItemCreator setDataContainer(String key, Object value, PersisDataType typ return this; } - private static String getItemInteractionName(ItemStack item) { - if (isItemHasPersistData(item, "interaction", PersistentDataType.STRING)) { - ItemMeta meta = item.getItemMeta(); - if (meta != null) { - return Objects.requireNonNull(meta.getPersistentDataContainer().get(new NamespacedKey(getInstance(), "interaction"), PersistentDataType.STRING)); - } - } - return null; - } - /** * Adds an interaction to the item. * @@ -588,17 +539,5 @@ public ItemCreator addInteraction(ItemInteraction itemInteraction) { this.setDataContainer("interaction", itemInteraction.getName(), PersisDataType.STRING); return this; } - - /** - * Checks if the item has persistent data of a specific type. - * - * @param item the ItemStack to check - * @param key the key of the data to check for - * @param type the PersistentDataType of the data - * @return true if the data exists, false otherwise - */ - public static Boolean isItemHasPersistData(ItemStack item, String key, PersistentDataType type) { - return item.getItemMeta().getPersistentDataContainer().has(new NamespacedKey(getInstance(), key), type); - } } diff --git a/src/main/java/com/github/pinont/singularitylib/api/items/ItemHeadCreator.java b/src/main/java/com/github/pinont/singularitylib/api/items/ItemHeadCreator.java index 641e5f5..a96c324 100644 --- a/src/main/java/com/github/pinont/singularitylib/api/items/ItemHeadCreator.java +++ b/src/main/java/com/github/pinont/singularitylib/api/items/ItemHeadCreator.java @@ -3,6 +3,7 @@ import com.github.pinont.singularitylib.api.utils.Common; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.SkullMeta; +import org.bukkit.plugin.Plugin; import org.jetbrains.annotations.NotNull; /** @@ -18,8 +19,8 @@ public class ItemHeadCreator extends ItemCreator { * * @param item the ItemStack to create from (should be a player head) */ - public ItemHeadCreator(@NotNull ItemStack item) { - super(item); + public ItemHeadCreator(Plugin plugin, @NotNull ItemStack item) { + super(plugin, item); skullMeta = (SkullMeta) item.getItemMeta(); } diff --git a/src/main/java/com/github/pinont/singularitylib/api/items/ItemInteraction.java b/src/main/java/com/github/pinont/singularitylib/api/items/ItemInteraction.java index 4243c76..4ea098c 100644 --- a/src/main/java/com/github/pinont/singularitylib/api/items/ItemInteraction.java +++ b/src/main/java/com/github/pinont/singularitylib/api/items/ItemInteraction.java @@ -1,15 +1,32 @@ package com.github.pinont.singularitylib.api.items; +import org.bukkit.ChatColor; +import org.bukkit.NamespacedKey; import org.bukkit.entity.Player; import org.bukkit.event.block.Action; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; +import org.bukkit.persistence.PersistentDataType; +import org.bukkit.plugin.Plugin; +import java.util.Objects; import java.util.Set; +import static com.github.pinont.singularitylib.plugin.CorePlugin.sendConsoleMessage; + /** * Interface for defining custom item interactions. * Items with interactions can respond to player clicks and actions. */ -public interface ItemInteraction { +public abstract class ItemInteraction { + + private String name; + private Set action; + + public ItemInteraction(String name, Set action) { + this.name = name; + this.action = action; + } /** * Gets the number of items to remove when this interaction is executed. @@ -17,7 +34,7 @@ public interface ItemInteraction { * * @return the number of items to remove from the stack */ - default int removeItemAmountOnExecute() { + public int removeItemAmountOnExecute() { return 0; } @@ -26,21 +43,25 @@ default int removeItemAmountOnExecute() { * * @return the interaction name */ - String getName(); + public String getName() { + return name; + } /** * Gets the set of actions that trigger this interaction. * * @return the set of triggering actions */ - Set getAction(); + public Set getAction() { + return action; + } /** * Executes this interaction for the given player. * * @param player the player who triggered the interaction */ - void execute(Player player); + public abstract void execute(Player player); /** * Whether to cancel the original event when this interaction is executed. @@ -48,8 +69,69 @@ default int removeItemAmountOnExecute() { * * @return true to cancel the event, false to allow it to continue */ - default boolean cancelEvent() { + public boolean cancelEvent() { return true; } + /** + * Checks if the item has persistent data of a specific type. + * + * @param item the ItemStack to check + * @param key the key of the data to check for + * @param type the PersistentDataType of the data + * @return true if the data exists, false otherwise + */ + public static Boolean isItemHasPersistData(Plugin plugin, ItemStack item, String key, PersistentDataType type) { + return item.getItemMeta().getPersistentDataContainer().has(new NamespacedKey(plugin, key), type); + } + + private static String getItemInteractionName(Plugin plugin, ItemStack item) { + if (isItemHasPersistData(plugin, item, "interaction", PersistentDataType.STRING)) { + ItemMeta meta = item.getItemMeta(); + if (meta != null) { + return Objects.requireNonNull(meta.getPersistentDataContainer().get(new NamespacedKey(plugin, "interaction"), PersistentDataType.STRING)); + } + } + return null; + } + + /** + * Gets the persistent data of an item. + * + * @param item the ItemStack to get data from + * @param key the key of the data to get + * @param type the PersistentDataType of the data + * @return the data value, or null if not present + */ + public static Object getItemPersistData(Plugin plugin, ItemStack item, String key, PersistentDataType type) { + if (isItemHasPersistData(plugin, item, key, type)) { + ItemMeta meta = item.getItemMeta(); + if (meta != null) { + return meta.getPersistentDataContainer().get(new NamespacedKey(plugin, key), type); + } + } + return null; + } + + /** + * Gets the interaction associated with the given ItemStack. + * + * @param item the ItemStack to get the interaction for + * @return the ItemInteraction, or null if none found + */ + public static ItemInteraction getInteraction(Plugin plugin, ItemStack item) { + String id = getItemInteractionName(plugin, item); + if (id == null) { + sendConsoleMessage(ChatColor.RED + "Item interaction not found for item: " + item.getType()); + return null; + } + ItemInteraction interaction = ItemCreator.getInteractions().stream().filter(itemInteraction -> itemInteraction.getName().equals(id)).findFirst().orElse(null); + if (interaction != null) { + return interaction; + } else { + sendConsoleMessage(ChatColor.RED + "Item interaction not found for item: " + item.getType()); + } + return null; + } + } diff --git a/src/main/java/com/github/pinont/singularitylib/api/manager/CustomItemManager.java b/src/main/java/com/github/pinont/singularitylib/api/manager/CustomItemManager.java index a89f1af..1769efb 100644 --- a/src/main/java/com/github/pinont/singularitylib/api/manager/CustomItemManager.java +++ b/src/main/java/com/github/pinont/singularitylib/api/manager/CustomItemManager.java @@ -11,6 +11,7 @@ import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; +import org.bukkit.plugin.Plugin; import org.jetbrains.annotations.NotNull; import java.util.*; @@ -23,7 +24,7 @@ * This class handles registration of custom items and provides functionality * to give items to players through commands. */ -public class CustomItemManager implements SimpleCommand { +public class CustomItemManager { /** * List of registered custom items managed by this manager. @@ -73,9 +74,6 @@ public List getCustomItems() { public void register(List item) { if (item.isEmpty()) return; sendConsoleMessage("Registering " + item.size() + " custom items"); - if (Common.plugin != null) { - registerAllItems(item, true); - } registerAllItems(item); } @@ -104,9 +102,10 @@ private void registerAllItems(List items) { * @param forDevTool whether to register items with the development tool */ private void registerAllItems(List items, boolean forDevTool) { - if (forDevTool) { - customItemManager = new CItemManager(); - } + // WIP: DevTool integration +// if (forDevTool) { +// customItemManager = new CItemManager(); +// } for (CustomItem customItem : items) { customItems.add(customItem); if (forDevTool) { @@ -120,98 +119,90 @@ private void registerAllItems(List items, boolean forDevTool) { } } - /** - * Gets the name of this command. - * - * @return the command name "give" - */ - @Override - public String getName() { - return "give"; - } - - /** - * Gets the description of this command. - * - * @return a brief description of what this command does - */ - @Override - public String description() { - return "Give item to player"; - } - - /** - * Executes the give command with the provided arguments. - * - *

Command syntax: /give <player> <item> [count]

- * - *

Supported player selectors:

- *
    - *
  • @a - All players
  • - *
  • @r - Random player
  • - *
  • @s - Command sender (self)
  • - *
  • player_name - Specific player by name
  • - *
- * - *

Supported item formats:

- *
    - *
  • minecraft:item_name - Vanilla Minecraft items
  • - *
  • plugin_name:item_name - Custom plugin items
  • - *
- * - * @param commandSourceStack the source of the command execution - * @param strings the command arguments [player, item, count] - */ - @Override - public void execute(CommandSourceStack commandSourceStack, String[] strings) { - if (strings.length < 2) { - commandSourceStack.getSender().sendMessage("Usage: /give [count]"); - return; - } - - String itemName = strings[1]; - int count = strings.length > 2 ? Integer.parseInt(strings[2]) : 1; - - // Find the item - ItemStack item = null; - if (itemName.startsWith("minecraft:")) { - itemName = itemName.replace("minecraft:", ""); - item = new ItemStack(Objects.requireNonNull(Material.getMaterial(itemName.toUpperCase())), count); - } else if (itemName.startsWith(getInstance().getName().toLowerCase() + ":")) { - String finalItemName = itemName.replace(getInstance().getName().toLowerCase() + ":", ""); - item = customItems.stream() - .filter(customItem -> customItem.getName().equalsIgnoreCase(finalItemName)) - .findFirst() - .map(customItem -> customItem.register().setAmount(count).create()) - .orElse(null); - } + // WIP: Move to dev tool - if (item == null) { - commandSourceStack.getSender().sendMessage("Item not found"); - return; - } - - // Give the item to the player - if (strings[0].equalsIgnoreCase("@a")) { - for (Player player : Bukkit.getOnlinePlayers()) { - giveItemToPlayer(player, item); - } - } else if (strings[0].equalsIgnoreCase("@r")) { - List players = new ArrayList<>(Bukkit.getOnlinePlayers()); - Player randomPlayer = players.get(new Random().nextInt(players.size())); - giveItemToPlayer(randomPlayer, item); - } else if (strings[0].equalsIgnoreCase("@s")) { - Player player = (Player) commandSourceStack.getSender(); - giveItemToPlayer(player, item); - } else { - Player player = Bukkit.getPlayer(strings[0]); - if (player == null) { - commandSourceStack.getSender().sendMessage("Player not found"); - return; - } - giveItemToPlayer(player, item); - } - } +// /** +// * Gets the name of this command. +// * +// * @return the command name "give" +// */ +// @Override +// public String getName() { +// return "give"; +// } +// +// /** +// * Executes the give command with the provided arguments. +// * +// *

Command syntax: /give <player> <item> [count]

+// * +// *

Supported player selectors:

+// *
    +// *
  • @a - All players
  • +// *
  • @r - Random player
  • +// *
  • @s - Command sender (self)
  • +// *
  • player_name - Specific player by name
  • +// *
+// * +// *

Supported item formats:

+// *
    +// *
  • minecraft:item_name - Vanilla Minecraft items
  • +// *
  • plugin_name:item_name - Custom plugin items
  • +// *
+// * +// * @param commandSourceStack the source of the command execution +// * @param strings the command arguments [player, item, count] +// */ +// @Override +// public void execute(CommandSourceStack commandSourceStack, String[] strings) { +// if (strings.length < 2) { +// commandSourceStack.getSender().sendMessage("Usage: /give [count]"); +// return; +// } +// +// String itemName = strings[1]; +// int count = strings.length > 2 ? Integer.parseInt(strings[2]) : 1; +// +// // Find the item +// ItemStack item = null; +// if (itemName.startsWith("minecraft:")) { +// itemName = itemName.replace("minecraft:", ""); +// item = new ItemStack(Objects.requireNonNull(Material.getMaterial(itemName.toUpperCase())), count); +// } else if (itemName.startsWith(getInstance().getName().toLowerCase() + ":")) { +// String finalItemName = itemName.replace(getInstance().getName().toLowerCase() + ":", ""); +// item = customItems.stream() +// .filter(customItem -> customItem.getName().equalsIgnoreCase(finalItemName)) +// .findFirst() +// .map(customItem -> customItem.register().setAmount(count).create()) +// .orElse(null); +// } +// +// if (item == null) { +// commandSourceStack.getSender().sendMessage("Item not found"); +// return; +// } +// +// // Give the item to the player +// if (strings[0].equalsIgnoreCase("@a")) { +// for (Player player : Bukkit.getOnlinePlayers()) { +// giveItemToPlayer(player, item); +// } +// } else if (strings[0].equalsIgnoreCase("@r")) { +// List players = new ArrayList<>(Bukkit.getOnlinePlayers()); +// Player randomPlayer = players.get(new Random().nextInt(players.size())); +// giveItemToPlayer(randomPlayer, item); +// } else if (strings[0].equalsIgnoreCase("@s")) { +// Player player = (Player) commandSourceStack.getSender(); +// giveItemToPlayer(player, item); +// } else { +// Player player = Bukkit.getPlayer(strings[0]); +// if (player == null) { +// commandSourceStack.getSender().sendMessage("Player not found"); +// return; +// } +// giveItemToPlayer(player, item); +// } +// } /** * Gives an item to a specific player and sends a confirmation message. @@ -231,97 +222,99 @@ private void giveItemToPlayer(Player player, ItemStack item) { } } - /** - * Provides intelligent tab completion suggestions for the give command. - * - *

This method dynamically generates context-aware suggestions based on the current - * argument position and existing input, enhancing the user experience by providing - * relevant completions for each stage of command construction.

- * - *

Tab Completion Behavior:

- * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - *
Argument PositionSuggestions ProvidedDescription
1 (Player)Online player names + selectorsAll currently connected players, plus @a (all), @s (self), @r (random)
2 (Item)Available items with namespacesMinecraft items (minecraft:) and registered custom items (plugin:)
3 (Count)<count> placeholderVisual hint indicating numeric quantity expected
- * - *

Intelligent Filtering:

- *

For item suggestions (argument 2), the method applies smart filtering when partial - * input is detected, matching against the item name portion after the namespace prefix. - * This allows for efficient item discovery through progressive typing.

- * - *

Performance Considerations:

- *

The method efficiently streams and filters large collections of materials and - * custom items, ensuring responsive tab completion even with extensive item registries.

- * - * @param commandSourceStack the command execution context providing sender information - * @param args the array of command arguments currently being typed by the user - * @return a collection of contextually relevant completion suggestions, never null - * - * @since 1.0.0 - * @deprecated since 1.1.0, scheduled for removal - use new completion system - * - * @see #execute(CommandSourceStack, String[]) for command execution logic - * @see CustomItem#getName() for custom item name retrieval - */ - @Deprecated(since = "1.1.0", forRemoval = true) - @Override - public @NotNull Collection suggest(CommandSourceStack commandSourceStack, String[] args) { - return switch (args.length) { - case 0, 1 -> { - List players = new ArrayList<>(); - players.addAll(Bukkit.getOnlinePlayers().stream().map(Player::getName).toList()); - players.addAll(Arrays.asList("@a", "@s", "@r")); - yield players; - } - case 2 -> { - List items = new ArrayList<>(); - items.addAll(Arrays.stream(Common.getAllItemsMaterials()) - .map(material -> "minecraft:" + material.name().toLowerCase()) - .toList()); - items.addAll(customItems.stream() - .map(item -> getInstance().getName().toLowerCase() + ":" + item.getName()) - .toList()); - if (!args[1].isEmpty()) { - yield items.stream() - .filter(item -> item.split(":")[1].toLowerCase().startsWith(args[1].toLowerCase())) - .toList(); - } - yield items; - } - case 3 -> Collections.singletonList(""); - default -> Collections.emptyList(); - }; - } + // WIP: Move to dev tool - /** - * Determines if a command sender can use this command. - * - *

Currently, only players are allowed to use the give command. - * Console and other command senders are not permitted.

- * - * @param sender the command sender to check permissions for - * @return true if the sender is a player, false otherwise - */ - @Override - public boolean canUse(CommandSender sender) { - return sender instanceof Player; - } +// /** +// * Provides intelligent tab completion suggestions for the give command. +// * +// *

This method dynamically generates context-aware suggestions based on the current +// * argument position and existing input, enhancing the user experience by providing +// * relevant completions for each stage of command construction.

+// * +// *

Tab Completion Behavior:

+// * +// * +// * +// * +// * +// * +// * +// * +// * +// * +// * +// * +// * +// * +// * +// * +// * +// * +// * +// * +// * +// *
Argument PositionSuggestions ProvidedDescription
1 (Player)Online player names + selectorsAll currently connected players, plus @a (all), @s (self), @r (random)
2 (Item)Available items with namespacesMinecraft items (minecraft:) and registered custom items (plugin:)
3 (Count)<count> placeholderVisual hint indicating numeric quantity expected
+// * +// *

Intelligent Filtering:

+// *

For item suggestions (argument 2), the method applies smart filtering when partial +// * input is detected, matching against the item name portion after the namespace prefix. +// * This allows for efficient item discovery through progressive typing.

+// * +// *

Performance Considerations:

+// *

The method efficiently streams and filters large collections of materials and +// * custom items, ensuring responsive tab completion even with extensive item registries.

+// * +// * @param commandSourceStack the command execution context providing sender information +// * @param args the array of command arguments currently being typed by the user +// * @return a collection of contextually relevant completion suggestions, never null +// * +// * @since 1.0.0 +// * @deprecated since 1.1.0, scheduled for removal - use new completion system +// * +// * @see #execute(CommandSourceStack, String[]) for command execution logic +// * @see CustomItem#getName() for custom item name retrieval +// */ +// @Deprecated(since = "1.1.0", forRemoval = true) +// @Override +// public @NotNull Collection suggest(CommandSourceStack commandSourceStack, String[] args) { +// return switch (args.length) { +// case 0, 1 -> { +// List players = new ArrayList<>(); +// players.addAll(Bukkit.getOnlinePlayers().stream().map(Player::getName).toList()); +// players.addAll(Arrays.asList("@a", "@s", "@r")); +// yield players; +// } +// case 2 -> { +// List items = new ArrayList<>(); +// items.addAll(Arrays.stream(Common.getAllItemsMaterials()) +// .map(material -> "minecraft:" + material.name().toLowerCase()) +// .toList()); +// items.addAll(customItems.stream() +// .map(item -> getInstance().getName().toLowerCase() + ":" + item.getName()) +// .toList()); +// if (!args[1].isEmpty()) { +// yield items.stream() +// .filter(item -> item.split(":")[1].toLowerCase().startsWith(args[1].toLowerCase())) +// .toList(); +// } +// yield items; +// } +// case 3 -> Collections.singletonList(""); +// default -> Collections.emptyList(); +// }; +// } +// +// /** +// * Determines if a command sender can use this command. +// * +// *

Currently, only players are allowed to use the give command. +// * Console and other command senders are not permitted.

+// * +// * @param sender the command sender to check permissions for +// * @return true if the sender is a player, false otherwise +// */ +// @Override +// public boolean canUse(CommandSender sender) { +// return sender instanceof Player; +// } } diff --git a/src/main/java/com/github/pinont/singularitylib/api/runnable/Scheduler.java b/src/main/java/com/github/pinont/singularitylib/api/runnable/Scheduler.java index 96ccb89..5ced473 100644 --- a/src/main/java/com/github/pinont/singularitylib/api/runnable/Scheduler.java +++ b/src/main/java/com/github/pinont/singularitylib/api/runnable/Scheduler.java @@ -7,6 +7,7 @@ import org.bukkit.Location; import org.bukkit.Server; import org.bukkit.World; +import org.bukkit.plugin.Plugin; import org.bukkit.scheduler.BukkitScheduler; import org.bukkit.scheduler.BukkitTask; @@ -57,50 +58,50 @@ public Object getTask() { return isFolia ? scheduledTask : bukkitTask; } - public void runTaskAsync(Runner runner) { + public void runTaskAsync(Plugin plugin, Runner runner) { this.runner = runner; if (isFolia) { asyncScheduler = server.getAsyncScheduler(); - scheduledTask = asyncScheduler.runNow(Common.plugin, _ -> runner.run()); + scheduledTask = asyncScheduler.runNow(plugin, _ -> runner.run()); } else { bukkitScheduler = server.getScheduler(); - bukkitTask = bukkitScheduler.runTaskAsynchronously(Common.plugin, runner::run); + bukkitTask = bukkitScheduler.runTaskAsynchronously(plugin, runner::run); } } - public void runTask(Runner runner) { + public void runTask(Plugin plugin, Runner runner) { this.runner = runner; if (isFolia) { globalScheduler = server.getGlobalRegionScheduler(); - scheduledTask = globalScheduler.run(Common.plugin, _ -> runner.run()); + scheduledTask = globalScheduler.run(plugin, _ -> runner.run()); } else { bukkitScheduler = server.getScheduler(); - bukkitTask = bukkitScheduler.runTask(Common.plugin, runner::run); + bukkitTask = bukkitScheduler.runTask(plugin, runner::run); } } - public void runRepeatingTask(Location location, Runner runner, int delayTicks, long periodTicks, TimeUnit timeUnit) { + public void runRepeatingTask(Plugin plugin, Location location, Runner runner, int delayTicks, long periodTicks, TimeUnit timeUnit) { this.runner = runner; if (isFolia) { regionScheduler = server.getRegionScheduler(); - scheduledTask = regionScheduler.runAtFixedRate(Common.plugin, location, _ -> runner.run(), delayTicks, periodTicks); + scheduledTask = regionScheduler.runAtFixedRate(plugin, location, _ -> runner.run(), delayTicks, periodTicks); } else { bukkitScheduler = server.getScheduler(); - bukkitTask = bukkitScheduler.runTaskTimer(Common.plugin, runner::run, 0L, periodTicks * timeUnit.toMillis(periodTicks)); + bukkitTask = bukkitScheduler.runTaskTimer(plugin, runner::run, 0L, periodTicks * timeUnit.toMillis(periodTicks)); } } - public void runRepeatingTask(World world, Runner runner, int delayTicks, long periodTicks, TimeUnit timeUnit) { - runRepeatingTask(new Location(world, 0, 0, 0), runner,delayTicks, periodTicks, timeUnit); + public void runRepeatingTask(Plugin plugin, World world, Runner runner, int delayTicks, long periodTicks, TimeUnit timeUnit) { + new Scheduler().runRepeatingTask(plugin, new Location(world, 0, 0, 0), runner,delayTicks, periodTicks, timeUnit); } - public void runRepeatingTaskAsync(Runner runner, int delayTicks, long periodTicks, TimeUnit timeUnit) { + public void runRepeatingTaskAsync(Plugin plugin, Runner runner, int delayTicks, long periodTicks, TimeUnit timeUnit) { if (isFolia) { asyncScheduler = server.getAsyncScheduler(); - scheduledTask = asyncScheduler.runAtFixedRate(Common.plugin, _ -> runner.run(), delayTicks, periodTicks, timeUnit); + scheduledTask = asyncScheduler.runAtFixedRate(plugin, _ -> runner.run(), delayTicks, periodTicks, timeUnit); } else { bukkitScheduler = server.getScheduler(); - bukkitTask = bukkitScheduler.runTaskTimer(Common.plugin, runner::run, delayTicks, Common.toTicks(periodTicks, timeUnit)); + bukkitTask = bukkitScheduler.runTaskTimer(plugin, runner::run, delayTicks, Common.toTicks(periodTicks, timeUnit)); } } @@ -116,11 +117,11 @@ public void cancelTask() { } } - public void cancelAllTasks() { + public void cancelAllTasks(Plugin plugin) { if (isFolia) { - asyncScheduler.cancelTasks(Common.plugin); + asyncScheduler.cancelTasks(plugin); } else { - bukkitScheduler.cancelTasks(Common.plugin); + bukkitScheduler.cancelTasks(plugin); } } } diff --git a/src/main/java/com/github/pinont/singularitylib/api/ui/Layout.java b/src/main/java/com/github/pinont/singularitylib/api/ui/Layout.java index d65b13a..8311f60 100644 --- a/src/main/java/com/github/pinont/singularitylib/api/ui/Layout.java +++ b/src/main/java/com/github/pinont/singularitylib/api/ui/Layout.java @@ -1,21 +1,30 @@ package com.github.pinont.singularitylib.api.ui; -/** - * Interface for defining layouts in menus. - * A layout maps a character key to a button for menu positioning. - */ -public interface Layout { +public class Layout { + + private final char key; + private final Button button; + public Layout(char c, Button button) { + this.key = c; + this.button = button; + + } + /** * Gets the character key used to position this layout in a menu. * * @return the character key */ - char getKey(); + public char getKey() { + return key; + } /** * Gets the button associated with this layout. * * @return the button for this layout position */ - Button getButton(); + public Button getButton() { + return button; + } } diff --git a/src/main/java/com/github/pinont/singularitylib/api/ui/Menu.java b/src/main/java/com/github/pinont/singularitylib/api/ui/Menu.java index b2bf86b..1d48db9 100644 --- a/src/main/java/com/github/pinont/singularitylib/api/ui/Menu.java +++ b/src/main/java/com/github/pinont/singularitylib/api/ui/Menu.java @@ -8,6 +8,7 @@ import org.bukkit.inventory.Inventory; import org.bukkit.inventory.ItemStack; import org.bukkit.metadata.FixedMetadataValue; +import org.bukkit.plugin.Plugin; import java.util.ArrayList; import java.util.Arrays; @@ -24,6 +25,7 @@ public class Menu { private final String title; private final int size; + private final Plugin plugin; private final ArrayList patternLayout = new ArrayList<>(); private final ArrayList layouts = new ArrayList<>(); private final ArrayList