From ad02113a8150e5188edb5054d5985231e11160b3 Mon Sep 17 00:00:00 2001 From: benrobson Date: Thu, 10 Apr 2025 23:33:23 +1000 Subject: [PATCH 1/5] Refactor to use YML and remove SQL. Base implementation needs additional fixes. --- pom.xml | 6 + .../PlayerHeadHunt/HeadChatController.java | 12 +- .../modularsoft/PlayerHeadHunt/HeadQuery.java | 253 +++++------------- .../PlayerHeadHunt/HeadWorldController.java | 42 +-- .../PlayerHeadHunt/PlayerHeadHuntMain.java | 50 +--- .../PlayerHeadHunt/PluginConfig.java | 12 - .../PlayerHeadHunt/commands/clearheads.java | 15 +- .../PlayerHeadHunt/commands/countheads.java | 21 +- .../PlayerHeadHunt/commands/leaderboard.java | 9 +- .../PlayerHeadHunt/events/HeadFindEvent.java | 48 ++-- .../events/HeadHunterOnJoin.java | 16 +- .../helpers/YamlFileManager.java | 78 ++++++ src/main/resources/config.yml | 6 - 13 files changed, 258 insertions(+), 310 deletions(-) create mode 100644 src/main/java/org/modularsoft/PlayerHeadHunt/helpers/YamlFileManager.java diff --git a/pom.xml b/pom.xml index be2b865..4e970b9 100644 --- a/pom.xml +++ b/pom.xml @@ -100,6 +100,12 @@ 1.18.30 provided + + + org.yaml + snakeyaml + 2.0 + diff --git a/src/main/java/org/modularsoft/PlayerHeadHunt/HeadChatController.java b/src/main/java/org/modularsoft/PlayerHeadHunt/HeadChatController.java index a545a0f..52dfbdc 100644 --- a/src/main/java/org/modularsoft/PlayerHeadHunt/HeadChatController.java +++ b/src/main/java/org/modularsoft/PlayerHeadHunt/HeadChatController.java @@ -9,13 +9,13 @@ import java.util.List; -import static org.modularsoft.PlayerHeadHunt.HeadQuery.foundHeadsAlreadyCount; - public class HeadChatController { private final PlayerHeadHuntMain plugin; + private final HeadQuery headQuery; - public HeadChatController(PlayerHeadHuntMain plugin) { + public HeadChatController(PlayerHeadHuntMain plugin, HeadQuery headQuery) { this.plugin = plugin; + this.headQuery = headQuery; } public void headFoundResponse(Player player, boolean hasAlreadyBeenFound, int headCount, int x, int y, int z) { @@ -28,7 +28,7 @@ public void headFoundResponse(Player player, boolean hasAlreadyBeenFound, int he player.playSound(player.getLocation(), plugin.config().getHeadFoundSound(), 1, 1); } - int otherPlayerFoundHead = foundHeadsAlreadyCount(plugin, x, y, z) - 1; + int otherPlayerFoundHead = headQuery.foundHeadsAlreadyCount(x, y, z) - 1; String otherPlayersHaveFoundSuffix; if (otherPlayerFoundHead == 0) { @@ -100,9 +100,9 @@ public void newPlayerJoinsTheHunt(Player player) { } public void playersOwnHeadCountResponse(Player player) { - // Players wants to see their own head count + // Use the instance of HeadQuery to call the method player.sendMessage(plugin.config().getLangHeadCount() - .replace("%FOUNDHEADS%", "" + HeadQuery.foundHeadsCount(plugin, player)) + .replace("%FOUNDHEADS%", "" + headQuery.foundHeadsCount(player)) .replace("%NUMBEROFHEADS%", "" + plugin.config().getTotalHeads())); } diff --git a/src/main/java/org/modularsoft/PlayerHeadHunt/HeadQuery.java b/src/main/java/org/modularsoft/PlayerHeadHunt/HeadQuery.java index af057aa..959d74e 100644 --- a/src/main/java/org/modularsoft/PlayerHeadHunt/HeadQuery.java +++ b/src/main/java/org/modularsoft/PlayerHeadHunt/HeadQuery.java @@ -2,217 +2,102 @@ import lombok.Getter; import org.bukkit.entity.Player; +import org.modularsoft.PlayerHeadHunt.helpers.YamlFileManager; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; import java.util.ArrayList; import java.util.List; +import java.util.Map; public class HeadQuery { - public record HeadHunter(@Getter String name, @Getter int headsCollected) { } - - /** - * @param plugin The PlayerHeadHunt main plugin - * @param player The player to check - * @return Returns the number of heads found by the player - */ - public static int foundHeadsCount(PlayerHeadHuntMain plugin, Player player) { - String playerUUID = "" + player.getUniqueId(); - - try { - // Check how many heads the player has collected. - PreparedStatement foundHeadsCount = plugin.getConnection().prepareStatement( - "SELECT headsCollected AS 'heads' FROM playerdata WHERE uuid=?"); - foundHeadsCount.setString(1, playerUUID); - ResultSet results = foundHeadsCount.executeQuery(); + private final YamlFileManager yamlFileManager; - if (results.next()) return results.getInt("heads"); - } catch (SQLException e) { - e.printStackTrace(); - player.sendMessage(plugin.config().getLangDatabaseConnectionError()); - } - return 0; + public HeadQuery(YamlFileManager yamlFileManager) { + this.yamlFileManager = yamlFileManager; } - /** - * @param plugin The PlayerHeadHunt main plugin - * @param xCord The x int to check - * @param yCord The y int to check - * @param zCord The z int to check - * @return Returns the number of other players who have found this head already - */ - public static int foundHeadsAlreadyCount(PlayerHeadHuntMain plugin, int xCord, int yCord, int zCord) { - try { - // Check how many heads the player has collected. - PreparedStatement foundHeadsCount = plugin.getConnection().prepareStatement( - "SELECT COUNT(*) AS total_heads FROM heads WHERE headcordx=? AND headcordy=? AND headcordz=?;"); - foundHeadsCount.setInt(1, xCord); - foundHeadsCount.setInt(2, yCord); - foundHeadsCount.setInt(3, zCord); - ResultSet results = foundHeadsCount.executeQuery(); + public record HeadHunter(@Getter String name, @Getter int headsCollected) { } - if (results.next()) return results.getInt("total_heads"); - } catch (SQLException e) { - e.printStackTrace(); - } - return 0; + public int foundHeadsCount(Player player) { + String playerUUID = player.getUniqueId().toString(); + Map data = yamlFileManager.getData(); + Map playerData = (Map) data.get(playerUUID); + return playerData != null ? (int) playerData.getOrDefault("headsCollected", 0) : 0; } - /** - * Clears the number of heads found by the player to 0 - * @param plugin The PlayerHeadHunt main plugin - * @param player The player to reset - * @return Returns true if the clear was successful. - */ - public static boolean clearHeads(PlayerHeadHuntMain plugin, Player player) { - String playerUUID = "" + player.getUniqueId(); - - // - // Database Query - // Check how many heads the player has collected. - // - try { - PreparedStatement clearHeadsStatement = plugin.getConnection().prepareStatement( - "DELETE FROM heads WHERE playerid=(SELECT id FROM playerdata WHERE uuid=?)"); - clearHeadsStatement.setString(1, playerUUID); - clearHeadsStatement.executeUpdate(); - - PreparedStatement resetHeadCountStatement = plugin.getConnection().prepareStatement( - "UPDATE playerdata SET headsCollected = 0 WHERE uuid = ?"); - resetHeadCountStatement.setString(1, playerUUID); - resetHeadCountStatement.executeUpdate(); - return true; - } catch (SQLException e) { - e.printStackTrace(); - player.sendMessage(plugin.config().getLangDatabaseConnectionError()); - } - - return false; + public int foundHeadsAlreadyCount(int xCord, int yCord, int zCord) { + Map data = yamlFileManager.getData(); + List> heads = (List>) data.get("heads"); + return (int) heads.stream() + .filter(head -> head.get("x").equals(xCord) && head.get("y").equals(yCord) && head.get("z").equals(zCord)) + .count(); } - /** - * Checks if the player has found a head in the specified position before - * @param plugin The PlayerHeadHunt main plugin - * @param player The player who found the head - * @param x X position of the head - * @param y Y position of the head - * @param z Z position of the head - * @return True if the head has already been found - */ - public static boolean hasAlreadyCollectedHead(PlayerHeadHuntMain plugin, Player player, int x, int y, int z) { + public boolean clearHeads(Player player) { String playerUUID = player.getUniqueId().toString(); - - try { - // Check if the player has already found that Player Head before. - PreparedStatement hasAlreadyFoundHeadStatement = plugin.getConnection().prepareStatement( - "SELECT e.* FROM heads e JOIN playerdata p ON e.playerid = p.id WHERE p.uuid = ? AND headcordx=? AND headcordy=? AND headcordz=?"); - hasAlreadyFoundHeadStatement.setString(1, playerUUID); - hasAlreadyFoundHeadStatement.setString(2, "" + x); - hasAlreadyFoundHeadStatement.setString(3, "" + y); - hasAlreadyFoundHeadStatement.setString(4, "" + z); - ResultSet results = hasAlreadyFoundHeadStatement.executeQuery(); - - // Return's true if we already found the head. - return results.next(); - } catch (SQLException e) { - e.printStackTrace(); - player.sendMessage(plugin.config().getLangDatabaseConnectionError()); - } - return false; + Map data = yamlFileManager.getData(); + data.remove(playerUUID); + yamlFileManager.save(); + return true; } - /** - * Ties the location of the head (x, y, z) to the player so that we know in - * the future that this head has been found - * @param plugin The PlayerHeadHunt main plugin - * @param player The player who found the head - * @param x X position of the head - * @param y Y position of the head - * @param z Z position of the head - */ - public static void insertCollectedHead(PlayerHeadHuntMain plugin, Player player, int x, int y, int z) { + public boolean hasAlreadyCollectedHead(Player player, int x, int y, int z) { String playerUUID = player.getUniqueId().toString(); + Map data = yamlFileManager.getData(); + + // Safely retrieve the "heads" list + List> heads = (List>) data.get("heads"); + if (heads == null) { + // Initialize the "heads" list if it is null + heads = new ArrayList<>(); + data.put("heads", heads); + yamlFileManager.save(); + } - try { - // Insert Player Head - PreparedStatement insertCollectedHeadStatement = plugin.getConnection().prepareStatement( - "INSERT INTO heads (playerid, headcordx, headcordy, headcordz) " + - "VALUES ((SELECT id FROM playerdata WHERE uuid=?), ?, ?, ?)"); - insertCollectedHeadStatement.setString(1, playerUUID); - insertCollectedHeadStatement.setString(2, String.valueOf(x)); - insertCollectedHeadStatement.setString(3, String.valueOf(y)); - insertCollectedHeadStatement.setString(4, String.valueOf(z)); - insertCollectedHeadStatement.executeUpdate(); + // Check if the player has already collected the head + return heads.stream() + .anyMatch(head -> head.get("playerUUID").equals(playerUUID) && + head.get("x").equals(x) && + head.get("y").equals(y) && + head.get("z").equals(z)); + } - PreparedStatement updatePlayersHeadsCollectedStatement = plugin.getConnection().prepareStatement( - "UPDATE playerdata SET headsCollected = headsCollected + 1 WHERE uuid = ?"); - updatePlayersHeadsCollectedStatement.setString(1, "" + player.getUniqueId()); - updatePlayersHeadsCollectedStatement.executeUpdate(); - } catch (SQLException e) { - e.printStackTrace(); - player.sendMessage(plugin.config().getLangDatabaseConnectionError()); + public void insertCollectedHead(Player player, int x, int y, int z) { + String playerUUID = player.getUniqueId().toString(); + Map data = yamlFileManager.getData(); + List> heads = (List>) data.get("heads"); + heads.add(Map.of("playerUUID", playerUUID, "x", x, "y", y, "z", z)); + Map playerData = (Map) data.get(playerUUID); + if (playerData == null) { + playerData = Map.of("headsCollected", 1); + data.put(playerUUID, playerData); + } else { + playerData.put("headsCollected", (int) playerData.get("headsCollected") + 1); } + yamlFileManager.save(); } - /** - * @param plugin The PlayerHeadHunt main plugin - * @param player The player who joined - * @return Returns true if the player specified was indeed a new player. - */ - public static boolean addNewHunter(PlayerHeadHuntMain plugin, Player player) { + public boolean addNewHunter(Player player) { String playerUUID = player.getUniqueId().toString(); String username = player.getName(); - - try { - // Check if a player has been added into the database already. - PreparedStatement findstatement = plugin.getConnection().prepareStatement( - "SELECT * FROM playerdata WHERE uuid=?"); - findstatement.setString(1, playerUUID); - ResultSet results = findstatement.executeQuery(); - - // The player already exists - if (results.next()) - return false; - - PreparedStatement insertstatement = plugin.getConnection().prepareStatement( - "INSERT INTO playerdata (uuid, username) VALUES (?, ?)"); - insertstatement.setString(1, playerUUID); - insertstatement.setString(2, username); - insertstatement.executeUpdate(); - return true; - } catch (SQLException e) { - e.printStackTrace(); - player.sendMessage(plugin.config().getLangDatabaseConnectionError()); + Map data = yamlFileManager.getData(); + if (data.containsKey(playerUUID)) { + return false; } - return false; + data.put(playerUUID, Map.of("username", username, "headsCollected", 0)); + yamlFileManager.save(); + return true; } - /** - * @param plugin The PlayerHeadHunt main plugin - * @param player The player who issued the command - * @return Returns a list of the Best Hunters. idx 0 is the best player and so on... - */ - public static List getBestHunters(PlayerHeadHuntMain plugin, Player player, int topHunters) { + public List getBestHunters(int topHunters) { + Map data = yamlFileManager.getData(); List bestHunters = new ArrayList<>(); - - try { - // Check if a player has been added into the database already. - PreparedStatement getHeadHuntersStatement = plugin.getConnection().prepareStatement( - "SELECT username, headsCollected, id FROM playerdata ORDER BY headsCollected DESC LIMIT ?"); - getHeadHuntersStatement.setInt(1, topHunters); - ResultSet results = getHeadHuntersStatement.executeQuery(); - - // The player already exists - while (results.next()) { - String name = results.getString("username"); - int headsCollected = results.getInt("headsCollected"); - bestHunters.add(new HeadHunter(name, headsCollected)); + data.forEach((key, value) -> { + if (value instanceof Map) { + Map playerData = (Map) value; + bestHunters.add(new HeadHunter((String) playerData.get("username"), (int) playerData.get("headsCollected"))); } - } catch (SQLException e) { - e.printStackTrace(); - player.sendMessage(plugin.config().getLangDatabaseConnectionError()); - } - return bestHunters; + }); + bestHunters.sort((a, b) -> Integer.compare(b.headsCollected(), a.headsCollected())); + return bestHunters.subList(0, Math.min(topHunters, bestHunters.size())); } -} +} \ No newline at end of file diff --git a/src/main/java/org/modularsoft/PlayerHeadHunt/HeadWorldController.java b/src/main/java/org/modularsoft/PlayerHeadHunt/HeadWorldController.java index ac130bd..9e6d7bb 100644 --- a/src/main/java/org/modularsoft/PlayerHeadHunt/HeadWorldController.java +++ b/src/main/java/org/modularsoft/PlayerHeadHunt/HeadWorldController.java @@ -21,28 +21,20 @@ import org.bukkit.block.data.BlockData; import org.bukkit.entity.Player; import org.bukkit.scheduler.BukkitRunnable; +import org.modularsoft.PlayerHeadHunt.helpers.YamlFileManager; -import java.util.Objects; -import java.util.Random; -import java.util.UUID; +import java.io.File; +import java.util.*; -/** - * This class controls any functionality that requires access to the world. - */ public class HeadWorldController { private final PlayerHeadHuntMain plugin; + private final YamlFileManager yamlFileManager; public HeadWorldController(PlayerHeadHuntMain plugin) { this.plugin = plugin; + this.yamlFileManager = new YamlFileManager(new File(plugin.getDataFolder(), "player-data.yml")); } - /** - * Using the lower region and upper region areas in the config file, count the - * number of heads in the region (technically it counts the number of player heads) - * and update the "totalHeads" field in the config to reflect the answer. - * - * Note: Heads that have disappeared temporarily will not show up in this count. - */ public void countHeadsInRegion() { String headBlock = plugin.config().getHeadBlock().toLowerCase(); BlockVector3 upperRegion = plugin.config().getUpperRegion(); @@ -53,17 +45,28 @@ public void countHeadsInRegion() { Mask mask = new BlockTypeMask(world, BlockTypes.get(headBlock)); try (EditSession editSession = WorldEdit.getInstance().newEditSession(world)) { - int countedblocks = editSession.countBlocks(selection, mask); - plugin.getServer().getConsoleSender().sendMessage("There are " + countedblocks + " total heads in the region"); + int countedBlocks = editSession.countBlocks(selection, mask); + plugin.getServer().getConsoleSender().sendMessage("There are " + countedBlocks + " total heads in the region"); - // Put total amount into config file. - plugin.config().setTotalHeads(countedblocks); + // Update the HEAD.HEADTOTAL in the plugin config + plugin.config().setTotalHeads(countedBlocks); plugin.config().save(); } } public void playerCollectedHead(Player player, Block block, int x, int y, int z) { - HeadQuery.insertCollectedHead(plugin, player, x, y, z); + Map data = yamlFileManager.getData(); + List> collectedHeads = (List>) data.get("collectedHeads"); + + // Initialize the list if it is null + if (collectedHeads == null) { + collectedHeads = new ArrayList<>(); + data.put("collectedHeads", collectedHeads); + } + + collectedHeads.add(Map.of("player", player.getUniqueId().toString(), "x", x, "y", y, "z", z)); + yamlFileManager.save(); + Material blockType = block.getType(); BlockData blockData = block.getBlockData(); @@ -77,7 +80,6 @@ public void run() { replaceHeadBlock(blockType, blockData, x, y, z); } }.runTaskLater(plugin, headRespawnTimer); - } private void breakBlock(int x, int y, int z) { @@ -105,4 +107,4 @@ private String getRandomHead() { int skins = plugin.config().getHeadSkins().size(); return plugin.config().getHeadSkins().get(random.nextInt(0, skins)); } -} +} \ No newline at end of file diff --git a/src/main/java/org/modularsoft/PlayerHeadHunt/PlayerHeadHuntMain.java b/src/main/java/org/modularsoft/PlayerHeadHunt/PlayerHeadHuntMain.java index b95faf7..bf2827d 100644 --- a/src/main/java/org/modularsoft/PlayerHeadHunt/PlayerHeadHuntMain.java +++ b/src/main/java/org/modularsoft/PlayerHeadHunt/PlayerHeadHuntMain.java @@ -12,7 +12,9 @@ import org.bukkit.command.ConsoleCommandSender; import org.bukkit.plugin.PluginManager; import org.bukkit.plugin.java.JavaPlugin; +import org.modularsoft.PlayerHeadHunt.helpers.YamlFileManager; +import java.io.File; import java.sql.Connection; import java.sql.SQLException; import java.util.Objects; @@ -29,33 +31,32 @@ public PluginConfig config() { @Override public void onEnable() { // Generate configuration file - // plugin.saveDefaultConfig(); + saveDefaultConfig(); config = new PluginConfig(this); console = getServer().getConsoleSender(); - HeadChatController headChatController = new HeadChatController(this); + YamlFileManager yamlFileManager = new YamlFileManager(new File(getDataFolder(), "player-data.yml")); + HeadQuery headQuery = new HeadQuery(yamlFileManager); + HeadChatController headChatController = new HeadChatController(this, headQuery); HeadWorldController headWorldController = new HeadWorldController(this); HeadHatController headHatController = new HeadHatController(this); HeadScoreboardController headScoreboardController = new HeadScoreboardController(this); - // Connect to the database - establishConnection(); - // Do an initial calculation of the number of heads. This can be // manually recalculated with the relevant command. headWorldController.countHeadsInRegion(); // Plugin Event Register PluginManager pluginmanager = getServer().getPluginManager(); - pluginmanager.registerEvents(new HeadFindEvent(this, headWorldController, headChatController, headHatController, headScoreboardController), this); - pluginmanager.registerEvents(new HeadHunterOnJoin(this, headChatController, headScoreboardController), this); + pluginmanager.registerEvents(new HeadFindEvent(this, headWorldController, headChatController, headHatController, headScoreboardController, headQuery), this); + pluginmanager.registerEvents(new HeadHunterOnJoin(this, headChatController, headScoreboardController, headQuery), this); pluginmanager.registerEvents(new HeadHatOnHead(), this); // Command Registry Objects.requireNonNull(getCommand("heads")).setExecutor(new heads(this, headChatController)); - Objects.requireNonNull(getCommand("clearheads")).setExecutor(new clearheads(this, headChatController, headHatController, headScoreboardController)); - Objects.requireNonNull(getCommand("countheads")).setExecutor(new countheads(this, headWorldController, headScoreboardController)); - Objects.requireNonNull(getCommand("leaderboard")).setExecutor(new leaderboard(this, headChatController)); + Objects.requireNonNull(getCommand("clearheads")).setExecutor(new clearheads(this, headChatController, headHatController, headScoreboardController, headQuery)); + Objects.requireNonNull(getCommand("countheads")).setExecutor(new countheads(this, headWorldController, headScoreboardController, headQuery)); + Objects.requireNonNull(getCommand("heads")).setExecutor(new heads(this, headChatController)); // Plugin Load Message console.sendMessage(ChatColor.GREEN + getDescription().getName() + " is now enabled."); @@ -69,33 +70,4 @@ public void onDisable() { // Plugin Shutdown Message console.sendMessage(ChatColor.RED + getDescription().getName() + " is now disabled."); } - - public void establishConnection() { - try { - Class.forName("com.mysql.jdbc.Driver"); - MysqlDataSource dataSource = new MysqlDataSource(); - dataSource.setServerName(config.getDatabaseHost()); - dataSource.setPort(config.getDatabasePort()); - dataSource.setDatabaseName(config.getDatabaseName()); - dataSource.setUser(config.getDatabaseUsername()); - dataSource.setPassword(config.getDatabasePassword()); - connection = dataSource.getConnection(); - } catch (SQLException | ClassNotFoundException e) { - getLogger().info(config.getLangDatabaseConnectionError()); - e.printStackTrace(); - } - } - - public Connection getConnection() { - if (connection != null) { - try { - connection.close(); - } catch (SQLException e) { - getLogger().info(config.getLangDatabaseConnectionError()); - e.printStackTrace(); - } - } - establishConnection(); - return connection; - } } diff --git a/src/main/java/org/modularsoft/PlayerHeadHunt/PluginConfig.java b/src/main/java/org/modularsoft/PlayerHeadHunt/PluginConfig.java index c9d3816..2ed8059 100644 --- a/src/main/java/org/modularsoft/PlayerHeadHunt/PluginConfig.java +++ b/src/main/java/org/modularsoft/PlayerHeadHunt/PluginConfig.java @@ -14,12 +14,6 @@ public class PluginConfig { private final PlayerHeadHuntMain plugin; private final FileConfiguration config; - @Getter private final String databaseHost; - @Getter private final int databasePort; - @Getter private final String databaseName; - @Getter private final String databaseUsername; - @Getter private final String databasePassword; - @Getter private final boolean milestoneHatFeatureEnabled; @Getter private final boolean milestoneMessageFeatureEnabled; @@ -61,12 +55,6 @@ public PluginConfig(PlayerHeadHuntMain plugin) { this.plugin = plugin; this.config = plugin.getConfig(); - databaseHost = config.getString("DATABASE.HOST"); - databasePort = config.getInt("DATABASE.PORT"); - databaseName = config.getString("DATABASE.DATABASE"); - databaseUsername = config.getString("DATABASE.USERNAME"); - databasePassword = config.getString("DATABASE.PASSWORD"); - milestoneHatFeatureEnabled = config.getBoolean("FEATURE.MILESTONEHAT"); milestoneMessageFeatureEnabled = config.getBoolean("FEATURE.MILESTONEMESSAGE"); diff --git a/src/main/java/org/modularsoft/PlayerHeadHunt/commands/clearheads.java b/src/main/java/org/modularsoft/PlayerHeadHunt/commands/clearheads.java index 1770cbf..9bc1592 100644 --- a/src/main/java/org/modularsoft/PlayerHeadHunt/commands/clearheads.java +++ b/src/main/java/org/modularsoft/PlayerHeadHunt/commands/clearheads.java @@ -12,13 +12,18 @@ public class clearheads implements CommandExecutor { private final HeadChatController headChatController; private final HeadHatController headHatController; private final HeadScoreboardController scoreboardController; + private final HeadQuery headQuery; - public clearheads(PlayerHeadHuntMain plugin, HeadChatController headChatController, - HeadHatController headHatController, HeadScoreboardController scoreboardController) { + public clearheads(PlayerHeadHuntMain plugin, + HeadChatController headChatController, + HeadHatController headHatController, + HeadScoreboardController scoreboardController, + HeadQuery headQuery) { this.plugin = plugin; this.headChatController = headChatController; this.headHatController = headHatController; this.scoreboardController = scoreboardController; + this.headQuery = headQuery; } @Override @@ -33,12 +38,12 @@ public boolean onCommand(@NotNull CommandSender sender, @NotNull Command cmd, @N return true; } - if (!HeadQuery.clearHeads(plugin, player)) + if (!headQuery.clearHeads(player)) // Use the HeadQuery instance to call clearHeads return true; headChatController.playerClearedTheirHeadsResponse(player); headHatController.clearHelmet(player); - scoreboardController.reloadScoreboard(player, HeadQuery.foundHeadsCount(plugin, player)); + scoreboardController.reloadScoreboard(player, headQuery.foundHeadsCount(player)); // Use headQuery for foundHeadsCount return true; } -} +} \ No newline at end of file diff --git a/src/main/java/org/modularsoft/PlayerHeadHunt/commands/countheads.java b/src/main/java/org/modularsoft/PlayerHeadHunt/commands/countheads.java index 1bb92c9..b2890f3 100644 --- a/src/main/java/org/modularsoft/PlayerHeadHunt/commands/countheads.java +++ b/src/main/java/org/modularsoft/PlayerHeadHunt/commands/countheads.java @@ -15,11 +15,16 @@ public class countheads implements CommandExecutor { private final PlayerHeadHuntMain plugin; private final HeadWorldController headWorldController; private final HeadScoreboardController headScoreboardController; + private final HeadQuery headQuery; - public countheads(PlayerHeadHuntMain plugin, HeadWorldController headWorldController, HeadScoreboardController headScoreboardController) { + public countheads(PlayerHeadHuntMain plugin, + HeadWorldController headWorldController, + HeadScoreboardController headScoreboardController, + HeadQuery headQuery) { this.plugin = plugin; this.headWorldController = headWorldController; this.headScoreboardController = headScoreboardController; + this.headQuery = headQuery; } @Override @@ -34,14 +39,22 @@ public boolean onCommand(@NotNull CommandSender sender, @NotNull Command cmd, @N return true; } + // Count heads in the region headWorldController.countHeadsInRegion(); + + // Update HEAD.HEADTOTAL in the configuration + int totalHeads = plugin.config().getTotalHeads(); + plugin.getConfig().set("HEAD.HEADTOTAL", totalHeads); + plugin.saveConfig(); // Save the updated configuration to disk + + // Notify the sender BlockVector3 upper = plugin.config().getUpperRegion(); BlockVector3 lower = plugin.config().getLowerRegion(); - sender.sendMessage("There are " + plugin.config().getTotalHeads() + - " total heads in " + lower + ", " + upper + "."); + sender.sendMessage("There are " + totalHeads + " total heads in " + lower + ", " + upper + "."); + // Update the scoreboard for all online players for (Player otherPlayer : plugin.getServer().getOnlinePlayers()) { - int headsFound = HeadQuery.foundHeadsCount(plugin, otherPlayer); + int headsFound = headQuery.foundHeadsCount(otherPlayer); headScoreboardController.reloadScoreboard(otherPlayer, headsFound); } return true; diff --git a/src/main/java/org/modularsoft/PlayerHeadHunt/commands/leaderboard.java b/src/main/java/org/modularsoft/PlayerHeadHunt/commands/leaderboard.java index c8a582c..8b12021 100644 --- a/src/main/java/org/modularsoft/PlayerHeadHunt/commands/leaderboard.java +++ b/src/main/java/org/modularsoft/PlayerHeadHunt/commands/leaderboard.java @@ -14,10 +14,12 @@ public class leaderboard implements CommandExecutor { private final PlayerHeadHuntMain plugin; private final HeadChatController headChatController; + private final HeadQuery headQuery; // Add HeadQuery instance - public leaderboard(PlayerHeadHuntMain plugin, HeadChatController headChatController) { + public leaderboard(PlayerHeadHuntMain plugin, HeadChatController headChatController, HeadQuery headQuery) { this.plugin = plugin; this.headChatController = headChatController; + this.headQuery = headQuery; // Initialize HeadQuery } @Override @@ -27,8 +29,9 @@ public boolean onCommand(@NotNull CommandSender sender, @NotNull Command cmd, @N return true; } - List bestHunters = HeadQuery.getBestHunters(plugin, player, 5); + // Use the HeadQuery instance to call getBestHunters + List bestHunters = headQuery.getBestHunters(5); headChatController.showLeaderBoardResponse(player, bestHunters); return true; } -} +} \ No newline at end of file diff --git a/src/main/java/org/modularsoft/PlayerHeadHunt/events/HeadFindEvent.java b/src/main/java/org/modularsoft/PlayerHeadHunt/events/HeadFindEvent.java index 65e47fc..13272be 100644 --- a/src/main/java/org/modularsoft/PlayerHeadHunt/events/HeadFindEvent.java +++ b/src/main/java/org/modularsoft/PlayerHeadHunt/events/HeadFindEvent.java @@ -1,14 +1,13 @@ package org.modularsoft.PlayerHeadHunt.events; +import org.bukkit.Material; import org.modularsoft.PlayerHeadHunt.*; import org.modularsoft.PlayerHeadHunt.helpers.HeadMileStone; import org.bukkit.block.Block; 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.PlayerInteractEvent; -import org.bukkit.inventory.EquipmentSlot; import java.util.Map; @@ -20,14 +19,17 @@ public class HeadFindEvent implements Listener { private final HeadScoreboardController headScoreboardController; private final Map milestones; + private final HeadQuery headQuery; + public HeadFindEvent(PlayerHeadHuntMain plugin, HeadWorldController headWorldController, HeadChatController headChatController, HeadHatController headHatController, - HeadScoreboardController headScoreboardController) { + HeadScoreboardController headScoreboardController, HeadQuery headQuery) { this.plugin = plugin; this.headWorldController = headWorldController; this.headChatController = headChatController; this.headHatController = headHatController; this.headScoreboardController = headScoreboardController; + this.headQuery = headQuery; this.milestones = plugin.config().getHeadMilestones(); } @@ -40,17 +42,18 @@ public void onHeadFind(PlayerInteractEvent event) { Player player = event.getPlayer(); Block block = event.getClickedBlock(); - int x = block.getX(); // Can't be null. Would have been found by isFindHeadEvent + int x = block.getX(); int y = block.getY(); int z = block.getZ(); - if (HeadQuery.hasAlreadyCollectedHead(plugin, player, x, y, z)) { + + if (headQuery.hasAlreadyCollectedHead(player, x, y, z)) { headChatController.headFoundResponse(player, true, 0, x, y, z); return; } headWorldController.playerCollectedHead(player, block, x, y, z); - int foundHeads = HeadQuery.foundHeadsCount(plugin, player); + int foundHeads = headQuery.foundHeadsCount(player); headScoreboardController.reloadScoreboard(player, foundHeads); if (foundHeads == 1) { @@ -58,8 +61,6 @@ public void onHeadFind(PlayerInteractEvent event) { return; } - // Trigger any milestones if they are relevant. We'll use the milestone text if it's available - // otherwise we'll draw the default text to the screen. if (milestones.containsKey(foundHeads)) { milestones.get(foundHeads).trigger(headChatController, headHatController, player, event); } else { @@ -68,26 +69,23 @@ public void onHeadFind(PlayerInteractEvent event) { } private boolean isFindHeadEvent(PlayerInteractEvent event) { - if (event == null) - return false; - - Block block = event.getClickedBlock(); - if (block == null) + // Check if the event involves a block and if the block is a specific type (e.g., a head block) + if (event.getClickedBlock() == null) { return false; + } - EquipmentSlot equipSlot = event.getHand(); - if (equipSlot == null) - return false; + String headBlockConfig = plugin.getConfig().getString("HEAD.HEADBLOCK"); + if (headBlockConfig == null) { + return false; // Configuration is missing or invalid + } - // This stops the event from firing twice, since the event fires for each hand. - if (equipSlot.equals(EquipmentSlot.OFF_HAND) || - event.getAction().equals(Action.LEFT_CLICK_BLOCK) || - event.getAction().equals(Action.LEFT_CLICK_AIR) || - event.getAction().equals(Action.RIGHT_CLICK_AIR)) - return false; + Material headBlockMaterial; + try { + headBlockMaterial = Material.valueOf(headBlockConfig.toUpperCase()); + } catch (IllegalArgumentException e) { + return false; // Invalid material in the configuration + } - // Only continue if we clicked on a head - String blockType = "" + block.getType(); - return plugin.config().getHeadBlock().equals(blockType); + return event.getClickedBlock().getType() == headBlockMaterial; } } \ No newline at end of file diff --git a/src/main/java/org/modularsoft/PlayerHeadHunt/events/HeadHunterOnJoin.java b/src/main/java/org/modularsoft/PlayerHeadHunt/events/HeadHunterOnJoin.java index a534385..074ecf7 100644 --- a/src/main/java/org/modularsoft/PlayerHeadHunt/events/HeadHunterOnJoin.java +++ b/src/main/java/org/modularsoft/PlayerHeadHunt/events/HeadHunterOnJoin.java @@ -13,12 +13,16 @@ public class HeadHunterOnJoin implements Listener { private final PlayerHeadHuntMain plugin; private final HeadChatController headChatController; private final HeadScoreboardController headScoreboardController; + private final HeadQuery headQuery; // Add HeadQuery instance - public HeadHunterOnJoin(PlayerHeadHuntMain plugin, HeadChatController headChatController, - HeadScoreboardController headScoreboardController) { + public HeadHunterOnJoin(PlayerHeadHuntMain plugin, + HeadChatController headChatController, + HeadScoreboardController headScoreboardController, + HeadQuery headQuery) { this.plugin = plugin; this.headChatController = headChatController; this.headScoreboardController = headScoreboardController; + this.headQuery = headQuery; // Initialize HeadQuery } @EventHandler @@ -26,14 +30,14 @@ public void onHeadHunterJoin(PlayerJoinEvent event) { Player player = event.getPlayer(); String username = player.getName(); - // Give the new player a scoreboard - headScoreboardController.reloadScoreboard(player, HeadQuery.foundHeadsCount(plugin, player)); + // Use the instance of HeadQuery to call the method + headScoreboardController.reloadScoreboard(player, headQuery.foundHeadsCount(player)); - if (HeadQuery.addNewHunter(plugin, player)) { + if (headQuery.addNewHunter(player)) { // New player joined plugin.getServer().getConsoleSender().sendMessage(username + " is a new player, creating a player profile."); plugin.getServer().getConsoleSender().sendMessage("Added a new hunter, " + username + "."); headChatController.newPlayerJoinsTheHunt(player); } } -} +} \ No newline at end of file diff --git a/src/main/java/org/modularsoft/PlayerHeadHunt/helpers/YamlFileManager.java b/src/main/java/org/modularsoft/PlayerHeadHunt/helpers/YamlFileManager.java new file mode 100644 index 0000000..d608253 --- /dev/null +++ b/src/main/java/org/modularsoft/PlayerHeadHunt/helpers/YamlFileManager.java @@ -0,0 +1,78 @@ +package org.modularsoft.PlayerHeadHunt.helpers; + +import lombok.Getter; +import lombok.Setter; +import org.yaml.snakeyaml.DumperOptions; +import org.yaml.snakeyaml.LoaderOptions; +import org.yaml.snakeyaml.Yaml; +import org.yaml.snakeyaml.constructor.SafeConstructor; +import org.yaml.snakeyaml.representer.Representer; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileWriter; +import java.io.IOException; +import java.util.Map; + +public class YamlFileManager { + private final File file; + private final Yaml yaml; + + @Getter + @Setter + private Map data; + + public YamlFileManager(File file) { + this.file = file; + + // Configure YAML dump options + DumperOptions dumperOptions = new DumperOptions(); + dumperOptions.setIndent(2); + dumperOptions.setPrettyFlow(true); + dumperOptions.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK); + + // Configure YAML representer + Representer representer = new Representer(dumperOptions); + representer.getPropertyUtils().setSkipMissingProperties(true); + + // Configure YAML loader options + LoaderOptions loaderOptions = new LoaderOptions(); + + // Initialize YAML parser + this.yaml = new Yaml(new SafeConstructor(loaderOptions), representer, dumperOptions); + + // Load the YAML file contents + load(); + } + + @SuppressWarnings("unchecked") + public void load() { + try { + if (!file.exists()) { + file.getParentFile().mkdirs(); + file.createNewFile(); + try (FileWriter writer = new FileWriter(file)) { + writer.write("{}"); + } + } + + try (FileInputStream inputStream = new FileInputStream(file)) { + data = yaml.load(inputStream); + if (data == null) { + data = new java.util.LinkedHashMap<>(); + } + } + } catch (IOException e) { + e.printStackTrace(); + data = new java.util.LinkedHashMap<>(); + } + } + + public void save() { + try (FileWriter writer = new FileWriter(file)) { + yaml.dump(data, writer); + } catch (IOException e) { + e.printStackTrace(); + } + } +} \ No newline at end of file diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 563f7e8..b963488 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -1,9 +1,3 @@ -DATABASE: - HOST: "127.0.0.1" - PORT: 3306 - DATABASE: "PlayerHeadHunt" - USERNAME: "root" - PASSWORD: "root" REGION: UPPERREGION: X: -54 From 2c6aa3845ceee0d6e7449d9ac2b7509f35a52154 Mon Sep 17 00:00:00 2001 From: benrobson Date: Fri, 11 Apr 2025 23:22:33 +1000 Subject: [PATCH 2/5] Complete refactor with some tests, still WIP --- .../PlayerHeadHunt/HeadChatController.java | 13 ++- .../modularsoft/PlayerHeadHunt/HeadQuery.java | 107 ++++++++++++++---- .../PlayerHeadHunt/HeadWorldController.java | 27 +++-- .../PlayerHeadHunt/PlayerHeadHuntMain.java | 9 +- .../PlayerHeadHunt/events/HeadFindEvent.java | 19 ++-- 5 files changed, 129 insertions(+), 46 deletions(-) diff --git a/src/main/java/org/modularsoft/PlayerHeadHunt/HeadChatController.java b/src/main/java/org/modularsoft/PlayerHeadHunt/HeadChatController.java index 52dfbdc..d1320e1 100644 --- a/src/main/java/org/modularsoft/PlayerHeadHunt/HeadChatController.java +++ b/src/main/java/org/modularsoft/PlayerHeadHunt/HeadChatController.java @@ -28,7 +28,8 @@ public void headFoundResponse(Player player, boolean hasAlreadyBeenFound, int he player.playSound(player.getLocation(), plugin.config().getHeadFoundSound(), 1, 1); } - int otherPlayerFoundHead = headQuery.foundHeadsAlreadyCount(x, y, z) - 1; + // Get the number of other players who have found this head + int otherPlayerFoundHead = Math.max(0, headQuery.foundHeadsAlreadyCount(x, y, z) - 1); String otherPlayersHaveFoundSuffix; if (otherPlayerFoundHead == 0) { @@ -39,18 +40,18 @@ public void headFoundResponse(Player player, boolean hasAlreadyBeenFound, int he } } else if (otherPlayerFoundHead == 1) { otherPlayersHaveFoundSuffix = plugin.config().getLangHeadNotFirstFinderSingle() - .replace("%OTHERPLAYERSFOUNDHEAD%", "" + otherPlayerFoundHead); + .replace("%OTHERPLAYERSFOUNDHEAD%", String.valueOf(otherPlayerFoundHead)); } else { otherPlayersHaveFoundSuffix = plugin.config().getLangHeadNotFirstFinderMultiple() - .replace("%OTHERPLAYERSFOUNDHEAD%", "" + otherPlayerFoundHead); + .replace("%OTHERPLAYERSFOUNDHEAD%", String.valueOf(otherPlayerFoundHead)); } + // Replace placeholders in the message String message = baseMessage - .replace("%FOUNDHEADS%", "" + headCount) - .replace("%NUMBEROFHEADS%", "" + plugin.config().getTotalHeads()) + .replace("%FOUNDHEADS%", String.valueOf(headCount)) + .replace("%NUMBEROFHEADS%", String.valueOf(plugin.config().getTotalHeads())) .replace("%ALREADYFOUNDHEADS%", otherPlayersHaveFoundSuffix); - // Play sound for a Player Head that is found. player.sendMessage(message); } diff --git a/src/main/java/org/modularsoft/PlayerHeadHunt/HeadQuery.java b/src/main/java/org/modularsoft/PlayerHeadHunt/HeadQuery.java index 959d74e..3860bb1 100644 --- a/src/main/java/org/modularsoft/PlayerHeadHunt/HeadQuery.java +++ b/src/main/java/org/modularsoft/PlayerHeadHunt/HeadQuery.java @@ -5,6 +5,7 @@ import org.modularsoft.PlayerHeadHunt.helpers.YamlFileManager; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; import java.util.Map; @@ -21,14 +22,38 @@ public int foundHeadsCount(Player player) { String playerUUID = player.getUniqueId().toString(); Map data = yamlFileManager.getData(); Map playerData = (Map) data.get(playerUUID); - return playerData != null ? (int) playerData.getOrDefault("headsCollected", 0) : 0; + + if (playerData == null) { + return 0; // No data for the player, so no heads collected + } + + List> headsCollected = (List>) playerData.get("headsCollected"); + if (headsCollected == null) { + return 0; // No heads collected yet + } + + return headsCollected.size(); // Return the count of collected heads } public int foundHeadsAlreadyCount(int xCord, int yCord, int zCord) { Map data = yamlFileManager.getData(); - List> heads = (List>) data.get("heads"); + Object headsObject = data.get("heads"); + + // Ensure the "heads" object is a list + if (!(headsObject instanceof List)) { + return 0; // Return 0 if the data is not a list + } + + List heads = (List) headsObject; + + // Filter and count matching heads return (int) heads.stream() - .filter(head -> head.get("x").equals(xCord) && head.get("y").equals(yCord) && head.get("z").equals(zCord)) + .filter(head -> head instanceof Map) + .map(head -> (Map) head) + .filter(head -> + head.get("x") instanceof Integer && head.get("y") instanceof Integer && head.get("z") instanceof Integer && + head.get("x").equals(xCord) && head.get("y").equals(yCord) && head.get("z").equals(zCord) + ) .count(); } @@ -43,36 +68,51 @@ public boolean clearHeads(Player player) { public boolean hasAlreadyCollectedHead(Player player, int x, int y, int z) { String playerUUID = player.getUniqueId().toString(); Map data = yamlFileManager.getData(); + Map playerData = (Map) data.get(playerUUID); + + if (playerData == null) { + return false; // Player has no data, so they haven't collected any heads + } - // Safely retrieve the "heads" list - List> heads = (List>) data.get("heads"); - if (heads == null) { - // Initialize the "heads" list if it is null - heads = new ArrayList<>(); - data.put("heads", heads); - yamlFileManager.save(); + List> headsCollected = (List>) playerData.get("headsCollected"); + if (headsCollected == null) { + return false; // No heads collected yet } - // Check if the player has already collected the head - return heads.stream() - .anyMatch(head -> head.get("playerUUID").equals(playerUUID) && - head.get("x").equals(x) && - head.get("y").equals(y) && - head.get("z").equals(z)); + // Check if the head coordinates already exist in the list + return headsCollected.stream().anyMatch(head -> + head.get("x") == x && head.get("y") == y && head.get("z") == z); } public void insertCollectedHead(Player player, int x, int y, int z) { String playerUUID = player.getUniqueId().toString(); Map data = yamlFileManager.getData(); - List> heads = (List>) data.get("heads"); - heads.add(Map.of("playerUUID", playerUUID, "x", x, "y", y, "z", z)); Map playerData = (Map) data.get(playerUUID); + if (playerData == null) { - playerData = Map.of("headsCollected", 1); + playerData = new HashMap<>(); + playerData.put("headsCollected", new ArrayList>()); + playerData.put("headsCollectedCount", 0); data.put(playerUUID, playerData); - } else { - playerData.put("headsCollected", (int) playerData.get("headsCollected") + 1); } + + List> headsCollected = (List>) playerData.get("headsCollected"); + if (headsCollected == null) { + headsCollected = new ArrayList<>(); + playerData.put("headsCollected", headsCollected); + } + + // Add the new head coordinates to the list + Map newHead = new HashMap<>(); + newHead.put("x", x); + newHead.put("y", y); + newHead.put("z", z); + headsCollected.add(newHead); + + // Increment the count of collected heads + int currentCount = (int) playerData.getOrDefault("headsCollectedCount", 0); + playerData.put("headsCollectedCount", currentCount + 1); + yamlFileManager.save(); } @@ -80,10 +120,18 @@ public boolean addNewHunter(Player player) { String playerUUID = player.getUniqueId().toString(); String username = player.getName(); Map data = yamlFileManager.getData(); + if (data.containsKey(playerUUID)) { return false; } - data.put(playerUUID, Map.of("username", username, "headsCollected", 0)); + + // Use a mutable map to store player data + Map newPlayerData = new HashMap<>(); + newPlayerData.put("username", username); + newPlayerData.put("headsCollected", new ArrayList>()); // Initialize an empty list for collected heads + newPlayerData.put("headsCollectedCount", 0); // Optional: Track the count separately for efficiency + data.put(playerUUID, newPlayerData); + yamlFileManager.save(); return true; } @@ -91,13 +139,26 @@ public boolean addNewHunter(Player player) { public List getBestHunters(int topHunters) { Map data = yamlFileManager.getData(); List bestHunters = new ArrayList<>(); + data.forEach((key, value) -> { if (value instanceof Map) { Map playerData = (Map) value; - bestHunters.add(new HeadHunter((String) playerData.get("username"), (int) playerData.get("headsCollected"))); + + String username = (String) playerData.get("username"); + Object headsCollectedObj = playerData.get("headsCollected"); + + // Validate that headsCollected is a list + if (username != null && headsCollectedObj instanceof List) { + int headsCollectedCount = ((List) headsCollectedObj).size(); + bestHunters.add(new HeadHunter(username, headsCollectedCount)); + } } }); + + // Sort hunters by the number of heads collected in descending order bestHunters.sort((a, b) -> Integer.compare(b.headsCollected(), a.headsCollected())); + + // Return the top hunters return bestHunters.subList(0, Math.min(topHunters, bestHunters.size())); } } \ No newline at end of file diff --git a/src/main/java/org/modularsoft/PlayerHeadHunt/HeadWorldController.java b/src/main/java/org/modularsoft/PlayerHeadHunt/HeadWorldController.java index 9e6d7bb..2f66aca 100644 --- a/src/main/java/org/modularsoft/PlayerHeadHunt/HeadWorldController.java +++ b/src/main/java/org/modularsoft/PlayerHeadHunt/HeadWorldController.java @@ -55,22 +55,35 @@ public void countHeadsInRegion() { } public void playerCollectedHead(Player player, Block block, int x, int y, int z) { + String playerUUID = player.getUniqueId().toString(); Map data = yamlFileManager.getData(); - List> collectedHeads = (List>) data.get("collectedHeads"); + Map playerData = (Map) data.get(playerUUID); - // Initialize the list if it is null - if (collectedHeads == null) { - collectedHeads = new ArrayList<>(); - data.put("collectedHeads", collectedHeads); + if (playerData == null) { + playerData = new HashMap<>(); + playerData.put("collected", new ArrayList>()); + data.put(playerUUID, playerData); } - collectedHeads.add(Map.of("player", player.getUniqueId().toString(), "x", x, "y", y, "z", z)); + List> collectedHeads = (List>) playerData.get("collected"); + + boolean alreadyCollected = collectedHeads.stream().anyMatch(head -> + head.get("x") == x && head.get("y") == y && head.get("z") == z); + + if (alreadyCollected) { + player.sendMessage(plugin.config().getLangHeadAlreadyFound()); + return; + } + + collectedHeads.add(Map.of("x", x, "y", y, "z", z)); yamlFileManager.save(); + // Increment the player's head count + plugin.getHeadQuery().insertCollectedHead(player, x, y, z); + Material blockType = block.getType(); BlockData blockData = block.getBlockData(); - // Break and set the block to be replaced later int headRespawnTimer = plugin.config().getHeadRespawnTimer(); breakBlock(x, y, z); diff --git a/src/main/java/org/modularsoft/PlayerHeadHunt/PlayerHeadHuntMain.java b/src/main/java/org/modularsoft/PlayerHeadHunt/PlayerHeadHuntMain.java index bf2827d..53e8041 100644 --- a/src/main/java/org/modularsoft/PlayerHeadHunt/PlayerHeadHuntMain.java +++ b/src/main/java/org/modularsoft/PlayerHeadHunt/PlayerHeadHuntMain.java @@ -1,5 +1,6 @@ package org.modularsoft.PlayerHeadHunt; +import lombok.Getter; import org.modularsoft.PlayerHeadHunt.commands.clearheads; import org.modularsoft.PlayerHeadHunt.commands.heads; import org.modularsoft.PlayerHeadHunt.commands.countheads; @@ -21,13 +22,15 @@ public class PlayerHeadHuntMain extends JavaPlugin { private PluginConfig config; - private Connection connection; private ConsoleCommandSender console; public PluginConfig config() { return config; } + @Getter + private HeadQuery headQuery; + @Override public void onEnable() { // Generate configuration file @@ -36,7 +39,8 @@ public void onEnable() { console = getServer().getConsoleSender(); YamlFileManager yamlFileManager = new YamlFileManager(new File(getDataFolder(), "player-data.yml")); - HeadQuery headQuery = new HeadQuery(yamlFileManager); + headQuery = new HeadQuery(yamlFileManager); + HeadChatController headChatController = new HeadChatController(this, headQuery); HeadWorldController headWorldController = new HeadWorldController(this); HeadHatController headHatController = new HeadHatController(this); @@ -57,6 +61,7 @@ public void onEnable() { Objects.requireNonNull(getCommand("clearheads")).setExecutor(new clearheads(this, headChatController, headHatController, headScoreboardController, headQuery)); Objects.requireNonNull(getCommand("countheads")).setExecutor(new countheads(this, headWorldController, headScoreboardController, headQuery)); Objects.requireNonNull(getCommand("heads")).setExecutor(new heads(this, headChatController)); + Objects.requireNonNull(getCommand("leaderboard")).setExecutor(new leaderboard(this, headChatController, headQuery)); // Register leaderboard command // Plugin Load Message console.sendMessage(ChatColor.GREEN + getDescription().getName() + " is now enabled."); diff --git a/src/main/java/org/modularsoft/PlayerHeadHunt/events/HeadFindEvent.java b/src/main/java/org/modularsoft/PlayerHeadHunt/events/HeadFindEvent.java index 13272be..7b8a793 100644 --- a/src/main/java/org/modularsoft/PlayerHeadHunt/events/HeadFindEvent.java +++ b/src/main/java/org/modularsoft/PlayerHeadHunt/events/HeadFindEvent.java @@ -35,8 +35,9 @@ public HeadFindEvent(PlayerHeadHuntMain plugin, HeadWorldController headWorldCon @EventHandler public void onHeadFind(PlayerInteractEvent event) { - if (!isFindHeadEvent(event)) + if (!isFindHeadEvent(event)) { return; + } event.setCancelled(true); @@ -46,21 +47,23 @@ public void onHeadFind(PlayerInteractEvent event) { int y = block.getY(); int z = block.getZ(); + // Check if the head has already been collected if (headQuery.hasAlreadyCollectedHead(player, x, y, z)) { - headChatController.headFoundResponse(player, true, 0, x, y, z); - return; + // Send the "head already found" message and stop further processing + headChatController.headFoundResponse(player, true, headQuery.foundHeadsCount(player), x, y, z); + return; // Ensure no further processing occurs } + // Process head collection headWorldController.playerCollectedHead(player, block, x, y, z); + // Retrieve the updated count of heads found int foundHeads = headQuery.foundHeadsCount(player); - headScoreboardController.reloadScoreboard(player, foundHeads); - if (foundHeads == 1) { - headChatController.headMilestoneReachedEvent(player, false, foundHeads); - return; - } + // Update the scoreboard with the new count + headScoreboardController.reloadScoreboard(player, foundHeads); + // Handle milestones or send a success message if (milestones.containsKey(foundHeads)) { milestones.get(foundHeads).trigger(headChatController, headHatController, player, event); } else { From 10d264151154dbdbf236d8dd0c88f1ea10394f93 Mon Sep 17 00:00:00 2001 From: benrobson Date: Sat, 12 Apr 2025 07:14:48 +1000 Subject: [PATCH 3/5] Re,ove mysql and merge clearheads and count heads and fix lb. --- pom.xml | 7 -- .../modularsoft/PlayerHeadHunt/HeadQuery.java | 16 ++++- .../PlayerHeadHunt/HeadWorldController.java | 8 ++- .../PlayerHeadHunt/PlayerHeadHuntMain.java | 12 +--- .../PlayerHeadHunt/commands/clearheads.java | 49 ------------- .../PlayerHeadHunt/commands/countheads.java | 62 ----------------- .../commands/debugheadhunt.java | 68 +++++++++++++++++++ src/main/resources/plugin.yml | 14 ++-- 8 files changed, 96 insertions(+), 140 deletions(-) delete mode 100644 src/main/java/org/modularsoft/PlayerHeadHunt/commands/clearheads.java delete mode 100644 src/main/java/org/modularsoft/PlayerHeadHunt/commands/countheads.java create mode 100644 src/main/java/org/modularsoft/PlayerHeadHunt/commands/debugheadhunt.java diff --git a/pom.xml b/pom.xml index 4e970b9..f834f6d 100644 --- a/pom.xml +++ b/pom.xml @@ -60,13 +60,6 @@ - - - mysql - mysql-connector-java - 8.0.33 - - com.sk89q.worldedit diff --git a/src/main/java/org/modularsoft/PlayerHeadHunt/HeadQuery.java b/src/main/java/org/modularsoft/PlayerHeadHunt/HeadQuery.java index 3860bb1..56b1c0f 100644 --- a/src/main/java/org/modularsoft/PlayerHeadHunt/HeadQuery.java +++ b/src/main/java/org/modularsoft/PlayerHeadHunt/HeadQuery.java @@ -60,7 +60,21 @@ public int foundHeadsAlreadyCount(int xCord, int yCord, int zCord) { public boolean clearHeads(Player player) { String playerUUID = player.getUniqueId().toString(); Map data = yamlFileManager.getData(); - data.remove(playerUUID); + Map playerData = (Map) data.get(playerUUID); + + if (playerData == null) { + return false; // No data for the player + } + + // Clear the contents of the headsCollected list + List> headsCollected = (List>) playerData.get("headsCollected"); + if (headsCollected != null) { + headsCollected.clear(); + } + + // Reset the headsCollectedCount to 0 + playerData.put("headsCollectedCount", 0); + yamlFileManager.save(); return true; } diff --git a/src/main/java/org/modularsoft/PlayerHeadHunt/HeadWorldController.java b/src/main/java/org/modularsoft/PlayerHeadHunt/HeadWorldController.java index 2f66aca..4afbb0e 100644 --- a/src/main/java/org/modularsoft/PlayerHeadHunt/HeadWorldController.java +++ b/src/main/java/org/modularsoft/PlayerHeadHunt/HeadWorldController.java @@ -61,11 +61,15 @@ public void playerCollectedHead(Player player, Block block, int x, int y, int z) if (playerData == null) { playerData = new HashMap<>(); - playerData.put("collected", new ArrayList>()); + playerData.put("headsCollected", new ArrayList>()); data.put(playerUUID, playerData); } - List> collectedHeads = (List>) playerData.get("collected"); + List> collectedHeads = (List>) playerData.get("headsCollected"); + if (collectedHeads == null) { + collectedHeads = new ArrayList<>(); + playerData.put("headsCollected", collectedHeads); + } boolean alreadyCollected = collectedHeads.stream().anyMatch(head -> head.get("x") == x && head.get("y") == y && head.get("z") == z); diff --git a/src/main/java/org/modularsoft/PlayerHeadHunt/PlayerHeadHuntMain.java b/src/main/java/org/modularsoft/PlayerHeadHunt/PlayerHeadHuntMain.java index 53e8041..450403c 100644 --- a/src/main/java/org/modularsoft/PlayerHeadHunt/PlayerHeadHuntMain.java +++ b/src/main/java/org/modularsoft/PlayerHeadHunt/PlayerHeadHuntMain.java @@ -1,14 +1,10 @@ package org.modularsoft.PlayerHeadHunt; import lombok.Getter; -import org.modularsoft.PlayerHeadHunt.commands.clearheads; -import org.modularsoft.PlayerHeadHunt.commands.heads; -import org.modularsoft.PlayerHeadHunt.commands.countheads; -import org.modularsoft.PlayerHeadHunt.commands.leaderboard; +import org.modularsoft.PlayerHeadHunt.commands.*; import org.modularsoft.PlayerHeadHunt.events.HeadFindEvent; import org.modularsoft.PlayerHeadHunt.events.HeadHatOnHead; import org.modularsoft.PlayerHeadHunt.events.HeadHunterOnJoin; -import com.mysql.cj.jdbc.MysqlDataSource; import org.bukkit.ChatColor; import org.bukkit.command.ConsoleCommandSender; import org.bukkit.plugin.PluginManager; @@ -16,8 +12,6 @@ import org.modularsoft.PlayerHeadHunt.helpers.YamlFileManager; import java.io.File; -import java.sql.Connection; -import java.sql.SQLException; import java.util.Objects; public class PlayerHeadHuntMain extends JavaPlugin { @@ -58,10 +52,8 @@ public void onEnable() { // Command Registry Objects.requireNonNull(getCommand("heads")).setExecutor(new heads(this, headChatController)); - Objects.requireNonNull(getCommand("clearheads")).setExecutor(new clearheads(this, headChatController, headHatController, headScoreboardController, headQuery)); - Objects.requireNonNull(getCommand("countheads")).setExecutor(new countheads(this, headWorldController, headScoreboardController, headQuery)); - Objects.requireNonNull(getCommand("heads")).setExecutor(new heads(this, headChatController)); Objects.requireNonNull(getCommand("leaderboard")).setExecutor(new leaderboard(this, headChatController, headQuery)); // Register leaderboard command + Objects.requireNonNull(getCommand("debugheadhunt")).setExecutor(new debugheadhunt(this, headChatController, headHatController, headScoreboardController, headWorldController, headQuery)); // Plugin Load Message console.sendMessage(ChatColor.GREEN + getDescription().getName() + " is now enabled."); diff --git a/src/main/java/org/modularsoft/PlayerHeadHunt/commands/clearheads.java b/src/main/java/org/modularsoft/PlayerHeadHunt/commands/clearheads.java deleted file mode 100644 index 9bc1592..0000000 --- a/src/main/java/org/modularsoft/PlayerHeadHunt/commands/clearheads.java +++ /dev/null @@ -1,49 +0,0 @@ -package org.modularsoft.PlayerHeadHunt.commands; - -import org.modularsoft.PlayerHeadHunt.*; -import org.bukkit.command.Command; -import org.bukkit.command.CommandExecutor; -import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; -import org.jetbrains.annotations.NotNull; - -public class clearheads implements CommandExecutor { - private final PlayerHeadHuntMain plugin; - private final HeadChatController headChatController; - private final HeadHatController headHatController; - private final HeadScoreboardController scoreboardController; - private final HeadQuery headQuery; - - public clearheads(PlayerHeadHuntMain plugin, - HeadChatController headChatController, - HeadHatController headHatController, - HeadScoreboardController scoreboardController, - HeadQuery headQuery) { - this.plugin = plugin; - this.headChatController = headChatController; - this.headHatController = headHatController; - this.scoreboardController = scoreboardController; - this.headQuery = headQuery; - } - - @Override - public boolean onCommand(@NotNull CommandSender sender, @NotNull Command cmd, @NotNull String s, String[] args) { - if (!(sender instanceof Player player)) { - sender.sendMessage(plugin.config().getLangNotAPlayer()); - return true; - } - - if (!sender.hasPermission("playerheadhunt.clearhead") || !sender.isOp()) { - sender.sendMessage(plugin.config().getLangInsufficientPermissions()); - return true; - } - - if (!headQuery.clearHeads(player)) // Use the HeadQuery instance to call clearHeads - return true; - - headChatController.playerClearedTheirHeadsResponse(player); - headHatController.clearHelmet(player); - scoreboardController.reloadScoreboard(player, headQuery.foundHeadsCount(player)); // Use headQuery for foundHeadsCount - return true; - } -} \ No newline at end of file diff --git a/src/main/java/org/modularsoft/PlayerHeadHunt/commands/countheads.java b/src/main/java/org/modularsoft/PlayerHeadHunt/commands/countheads.java deleted file mode 100644 index b2890f3..0000000 --- a/src/main/java/org/modularsoft/PlayerHeadHunt/commands/countheads.java +++ /dev/null @@ -1,62 +0,0 @@ -package org.modularsoft.PlayerHeadHunt.commands; - -import org.modularsoft.PlayerHeadHunt.PlayerHeadHuntMain; -import org.modularsoft.PlayerHeadHunt.HeadWorldController; -import org.modularsoft.PlayerHeadHunt.HeadQuery; -import org.modularsoft.PlayerHeadHunt.HeadScoreboardController; -import com.sk89q.worldedit.math.BlockVector3; -import org.bukkit.command.Command; -import org.bukkit.command.CommandExecutor; -import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; -import org.jetbrains.annotations.NotNull; - -public class countheads implements CommandExecutor { - private final PlayerHeadHuntMain plugin; - private final HeadWorldController headWorldController; - private final HeadScoreboardController headScoreboardController; - private final HeadQuery headQuery; - - public countheads(PlayerHeadHuntMain plugin, - HeadWorldController headWorldController, - HeadScoreboardController headScoreboardController, - HeadQuery headQuery) { - this.plugin = plugin; - this.headWorldController = headWorldController; - this.headScoreboardController = headScoreboardController; - this.headQuery = headQuery; - } - - @Override - public boolean onCommand(@NotNull CommandSender sender, @NotNull Command cmd, @NotNull String s, String[] args) { - if (!(sender instanceof Player)) { - sender.sendMessage(plugin.config().getLangNotAPlayer()); - return true; - } - - if (!sender.hasPermission("playerheadhunt.clearhead") || !sender.isOp()) { - sender.sendMessage(plugin.config().getLangInsufficientPermissions()); - return true; - } - - // Count heads in the region - headWorldController.countHeadsInRegion(); - - // Update HEAD.HEADTOTAL in the configuration - int totalHeads = plugin.config().getTotalHeads(); - plugin.getConfig().set("HEAD.HEADTOTAL", totalHeads); - plugin.saveConfig(); // Save the updated configuration to disk - - // Notify the sender - BlockVector3 upper = plugin.config().getUpperRegion(); - BlockVector3 lower = plugin.config().getLowerRegion(); - sender.sendMessage("There are " + totalHeads + " total heads in " + lower + ", " + upper + "."); - - // Update the scoreboard for all online players - for (Player otherPlayer : plugin.getServer().getOnlinePlayers()) { - int headsFound = headQuery.foundHeadsCount(otherPlayer); - headScoreboardController.reloadScoreboard(otherPlayer, headsFound); - } - return true; - } -} diff --git a/src/main/java/org/modularsoft/PlayerHeadHunt/commands/debugheadhunt.java b/src/main/java/org/modularsoft/PlayerHeadHunt/commands/debugheadhunt.java new file mode 100644 index 0000000..dc41ab0 --- /dev/null +++ b/src/main/java/org/modularsoft/PlayerHeadHunt/commands/debugheadhunt.java @@ -0,0 +1,68 @@ +package org.modularsoft.PlayerHeadHunt.commands; + +import org.bukkit.command.Command; +import org.bukkit.command.CommandExecutor; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; +import org.modularsoft.PlayerHeadHunt.*; + +public class debugheadhunt implements CommandExecutor { + private final PlayerHeadHuntMain plugin; + private final HeadChatController headChatController; + private final HeadHatController headHatController; + private final HeadScoreboardController scoreboardController; + private final HeadWorldController headWorldController; + private final HeadQuery headQuery; + + public debugheadhunt(PlayerHeadHuntMain plugin, + HeadChatController headChatController, + HeadHatController headHatController, + HeadScoreboardController scoreboardController, + HeadWorldController headWorldController, + HeadQuery headQuery) { + this.plugin = plugin; + this.headChatController = headChatController; + this.headHatController = headHatController; + this.scoreboardController = scoreboardController; + this.headWorldController = headWorldController; + this.headQuery = headQuery; + } + + @Override + public boolean onCommand(@NotNull CommandSender sender, @NotNull Command cmd, @NotNull String label, String[] args) { + if (!(sender instanceof Player player)) { + sender.sendMessage(plugin.config().getLangNotAPlayer()); + return true; + } + + if (!sender.hasPermission("playerheadhunt.debug") || !sender.isOp()) { + sender.sendMessage(plugin.config().getLangInsufficientPermissions()); + return true; + } + + if (args.length == 0) { + sender.sendMessage("Usage: /debugheadhunt "); + return true; + } + + switch (args[0].toLowerCase()) { + case "clearheads" -> { + if (!headQuery.clearHeads(player)) { + sender.sendMessage("No heads to clear."); + return true; + } + headChatController.playerClearedTheirHeadsResponse(player); + headHatController.clearHelmet(player); + scoreboardController.reloadScoreboard(player, headQuery.foundHeadsCount(player)); + sender.sendMessage("Heads cleared successfully."); + } + case "countheads" -> { + headWorldController.countHeadsInRegion(); + sender.sendMessage("Heads counted successfully."); + } + default -> sender.sendMessage("Invalid subcommand. Use: clearheads or countheads."); + } + return true; + } +} \ No newline at end of file diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index 1ae75b5..d9482f5 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -11,15 +11,11 @@ commands: description: Grab the amount of heads you have. usage: /heads aliases: [eggs, presents] - clearheads: - description: Clear all heads from yourself. - usage: /clearheads - aliases: [cleareggs, clearpresents] - countheads: - description: Recalculates the number of heads in the world. - usage: /countheads - aliases: [counteggs, countpresents] leaderboard: description: Show the 5 best heads hunters on the Server. usage: /leaderboard - aliases: [lb] \ No newline at end of file + aliases: [lb] + debugheadhunt: + description: Debug command for developers. + usage: /debugheadhunt + aliases: [ dhh ] \ No newline at end of file From 2e580991c0f4a0436096ca3a22d965d9c6ed98d3 Mon Sep 17 00:00:00 2001 From: benrobson Date: Sat, 12 Apr 2025 20:05:11 +1000 Subject: [PATCH 4/5] Base implementation head compass. --- .../PlayerHeadHunt/HeadWorldController.java | 37 +++++++++++++++- .../PlayerHeadHunt/PlayerHeadHuntMain.java | 2 +- .../events/HeadHunterOnJoin.java | 3 ++ .../helpers/HeadLocatorTask.java | 43 +++++++++++++++++++ .../PlayerHeadHunt/items/HeadLocator.java | 19 ++++++++ 5 files changed, 102 insertions(+), 2 deletions(-) create mode 100644 src/main/java/org/modularsoft/PlayerHeadHunt/helpers/HeadLocatorTask.java create mode 100644 src/main/java/org/modularsoft/PlayerHeadHunt/items/HeadLocator.java diff --git a/src/main/java/org/modularsoft/PlayerHeadHunt/HeadWorldController.java b/src/main/java/org/modularsoft/PlayerHeadHunt/HeadWorldController.java index 4afbb0e..fcac96f 100644 --- a/src/main/java/org/modularsoft/PlayerHeadHunt/HeadWorldController.java +++ b/src/main/java/org/modularsoft/PlayerHeadHunt/HeadWorldController.java @@ -29,10 +29,12 @@ public class HeadWorldController { private final PlayerHeadHuntMain plugin; private final YamlFileManager yamlFileManager; + private final HeadQuery headQuery; - public HeadWorldController(PlayerHeadHuntMain plugin) { + public HeadWorldController(PlayerHeadHuntMain plugin, HeadQuery headQuery) { this.plugin = plugin; this.yamlFileManager = new YamlFileManager(new File(plugin.getDataFolder(), "player-data.yml")); + this.headQuery = headQuery; } public void countHeadsInRegion() { @@ -124,4 +126,37 @@ private String getRandomHead() { int skins = plugin.config().getHeadSkins().size(); return plugin.config().getHeadSkins().get(random.nextInt(0, skins)); } + + public Location findNearestUnclaimedHead(Player player) { + Location playerLocation = player.getLocation(); + Map data = yamlFileManager.getData(); + Object headsObject = data.get("heads"); + + if (!(headsObject instanceof List heads)) { + return null; // No heads available + } + + Location nearestHead = null; + double nearestDistance = Double.MAX_VALUE; + + for (Object headObj : heads) { + if (headObj instanceof Map head) { + int x = (int) head.get("x"); + int y = (int) head.get("y"); + int z = (int) head.get("z"); + + if (!headQuery.hasAlreadyCollectedHead(player, x, y, z)) { + Location headLocation = new Location(player.getWorld(), x, y, z); + double distance = playerLocation.distance(headLocation); + + if (distance < nearestDistance) { + nearestDistance = distance; + nearestHead = headLocation; + } + } + } + } + + return nearestHead; + } } \ No newline at end of file diff --git a/src/main/java/org/modularsoft/PlayerHeadHunt/PlayerHeadHuntMain.java b/src/main/java/org/modularsoft/PlayerHeadHunt/PlayerHeadHuntMain.java index 450403c..1baff6d 100644 --- a/src/main/java/org/modularsoft/PlayerHeadHunt/PlayerHeadHuntMain.java +++ b/src/main/java/org/modularsoft/PlayerHeadHunt/PlayerHeadHuntMain.java @@ -36,7 +36,7 @@ public void onEnable() { headQuery = new HeadQuery(yamlFileManager); HeadChatController headChatController = new HeadChatController(this, headQuery); - HeadWorldController headWorldController = new HeadWorldController(this); + HeadWorldController headWorldController = new HeadWorldController(this, headQuery); HeadHatController headHatController = new HeadHatController(this); HeadScoreboardController headScoreboardController = new HeadScoreboardController(this); diff --git a/src/main/java/org/modularsoft/PlayerHeadHunt/events/HeadHunterOnJoin.java b/src/main/java/org/modularsoft/PlayerHeadHunt/events/HeadHunterOnJoin.java index 074ecf7..52db1cc 100644 --- a/src/main/java/org/modularsoft/PlayerHeadHunt/events/HeadHunterOnJoin.java +++ b/src/main/java/org/modularsoft/PlayerHeadHunt/events/HeadHunterOnJoin.java @@ -39,5 +39,8 @@ public void onHeadHunterJoin(PlayerJoinEvent event) { plugin.getServer().getConsoleSender().sendMessage("Added a new hunter, " + username + "."); headChatController.newPlayerJoinsTheHunt(player); } + + // Give the player a Head Locator compass + player.getInventory().addItem(org.modularsoft.PlayerHeadHunt.items.HeadLocator.createHeadLocator()); } } \ No newline at end of file diff --git a/src/main/java/org/modularsoft/PlayerHeadHunt/helpers/HeadLocatorTask.java b/src/main/java/org/modularsoft/PlayerHeadHunt/helpers/HeadLocatorTask.java new file mode 100644 index 0000000..1141772 --- /dev/null +++ b/src/main/java/org/modularsoft/PlayerHeadHunt/helpers/HeadLocatorTask.java @@ -0,0 +1,43 @@ +package org.modularsoft.PlayerHeadHunt.helpers; + +import net.md_5.bungee.api.ChatMessageType; +import net.md_5.bungee.api.chat.TextComponent; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; +import org.bukkit.plugin.java.JavaPlugin; +import org.modularsoft.PlayerHeadHunt.HeadWorldController; +import org.modularsoft.PlayerHeadHunt.items.HeadLocator; + +public class HeadLocatorTask { + private final JavaPlugin plugin; + private final HeadLocator headLocator; + private final HeadWorldController headWorldController; + + public HeadLocatorTask(JavaPlugin plugin, HeadLocator headLocator, HeadWorldController headWorldController) { + this.plugin = plugin; + this.headLocator = headLocator; + this.headWorldController = headWorldController; + } + + public void startTask(Player player) { + Bukkit.getScheduler().runTaskTimer(plugin, () -> { + // Check if the player is holding the Head Locator item + ItemStack itemInHand = player.getInventory().getItemInMainHand(); + if (itemInHand.isSimilar(HeadLocator.createHeadLocator())) { + Location nearestHead = headWorldController.findNearestUnclaimedHead(player); + if (nearestHead != null) { + double distance = player.getLocation().distance(nearestHead); + if (distance > 10) { + player.spigot().sendMessage(ChatMessageType.ACTION_BAR, new TextComponent("§aNearest unclaimed head is " + (int) distance + " meters away.")); + } else { + player.spigot().sendMessage(ChatMessageType.ACTION_BAR, new TextComponent("§aYou are very close to an unclaimed head!")); + } + } else { + player.spigot().sendMessage(ChatMessageType.ACTION_BAR, new TextComponent("§cNo unclaimed heads found.")); + } + } + }, 0L, 1200L); // Runs every 60 seconds (1200 ticks) + } +} \ No newline at end of file diff --git a/src/main/java/org/modularsoft/PlayerHeadHunt/items/HeadLocator.java b/src/main/java/org/modularsoft/PlayerHeadHunt/items/HeadLocator.java new file mode 100644 index 0000000..cb5995b --- /dev/null +++ b/src/main/java/org/modularsoft/PlayerHeadHunt/items/HeadLocator.java @@ -0,0 +1,19 @@ +package org.modularsoft.PlayerHeadHunt.items; + +import org.bukkit.Material; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; +import java.util.List; + +public class HeadLocator { + public static ItemStack createHeadLocator() { + ItemStack headLocator = new ItemStack(Material.COMPASS); + ItemMeta meta = headLocator.getItemMeta(); + if (meta != null) { + meta.setDisplayName("§6Head Locator"); + meta.setLore(List.of("§7Tracks the nearest unclaimed head.")); + headLocator.setItemMeta(meta); + } + return headLocator; + } +} \ No newline at end of file From 96fc791d2a973e78ebd97aaced1161e95aebfde4 Mon Sep 17 00:00:00 2001 From: benrobson Date: Sun, 13 Apr 2025 00:41:10 +1000 Subject: [PATCH 5/5] Refactor to recovery compass and add sounds and actionbar messages. --- .../HeadScoreboardController.java | 7 +++++ .../PlayerHeadHunt/HeadWorldController.java | 9 ++++++ .../PlayerHeadHunt/PlayerHeadHuntMain.java | 3 +- .../commands/debugheadhunt.java | 4 ++- .../events/HeadHunterOnJoin.java | 29 ++++++++++++++----- .../helpers/HeadLocatorTask.java | 13 ++++++++- .../PlayerHeadHunt/items/HeadLocator.java | 2 +- 7 files changed, 55 insertions(+), 12 deletions(-) diff --git a/src/main/java/org/modularsoft/PlayerHeadHunt/HeadScoreboardController.java b/src/main/java/org/modularsoft/PlayerHeadHunt/HeadScoreboardController.java index 9b6e3fa..9ba3d2f 100644 --- a/src/main/java/org/modularsoft/PlayerHeadHunt/HeadScoreboardController.java +++ b/src/main/java/org/modularsoft/PlayerHeadHunt/HeadScoreboardController.java @@ -33,4 +33,11 @@ public void reloadScoreboard(Player player, int headsFound) { player.setScoreboard(board); } + + public void updateLeaderboard(int totalHeads) { + for (Player player : Bukkit.getOnlinePlayers()) { + int headsFound = plugin.getHeadQuery().foundHeadsCount(player); // Get the player's collected heads + reloadScoreboard(player, headsFound); // Reload the scoreboard with the updated total + } + } } diff --git a/src/main/java/org/modularsoft/PlayerHeadHunt/HeadWorldController.java b/src/main/java/org/modularsoft/PlayerHeadHunt/HeadWorldController.java index fcac96f..11f1a1c 100644 --- a/src/main/java/org/modularsoft/PlayerHeadHunt/HeadWorldController.java +++ b/src/main/java/org/modularsoft/PlayerHeadHunt/HeadWorldController.java @@ -133,6 +133,7 @@ public Location findNearestUnclaimedHead(Player player) { Object headsObject = data.get("heads"); if (!(headsObject instanceof List heads)) { + plugin.getServer().getConsoleSender().sendMessage("§cNo heads data found in the YAML file."); return null; // No heads available } @@ -149,14 +150,22 @@ public Location findNearestUnclaimedHead(Player player) { Location headLocation = new Location(player.getWorld(), x, y, z); double distance = playerLocation.distance(headLocation); + plugin.getServer().getConsoleSender().sendMessage("§aFound unclaimed head at: " + x + ", " + y + ", " + z + " (Distance: " + distance + ")"); + if (distance < nearestDistance) { nearestDistance = distance; nearestHead = headLocation; } + } else { + plugin.getServer().getConsoleSender().sendMessage("§eHead at " + x + ", " + y + ", " + z + " already collected by the player."); } } } + if (nearestHead == null) { + plugin.getServer().getConsoleSender().sendMessage("§cNo unclaimed heads found for the player."); + } + return nearestHead; } } \ No newline at end of file diff --git a/src/main/java/org/modularsoft/PlayerHeadHunt/PlayerHeadHuntMain.java b/src/main/java/org/modularsoft/PlayerHeadHunt/PlayerHeadHuntMain.java index 1baff6d..f8e9afd 100644 --- a/src/main/java/org/modularsoft/PlayerHeadHunt/PlayerHeadHuntMain.java +++ b/src/main/java/org/modularsoft/PlayerHeadHunt/PlayerHeadHuntMain.java @@ -17,6 +17,7 @@ public class PlayerHeadHuntMain extends JavaPlugin { private PluginConfig config; private ConsoleCommandSender console; + private HeadWorldController headWorldController; public PluginConfig config() { return config; @@ -47,7 +48,7 @@ public void onEnable() { // Plugin Event Register PluginManager pluginmanager = getServer().getPluginManager(); pluginmanager.registerEvents(new HeadFindEvent(this, headWorldController, headChatController, headHatController, headScoreboardController, headQuery), this); - pluginmanager.registerEvents(new HeadHunterOnJoin(this, headChatController, headScoreboardController, headQuery), this); + pluginmanager.registerEvents(new HeadHunterOnJoin(this, headChatController, headScoreboardController, headQuery, headWorldController), this); pluginmanager.registerEvents(new HeadHatOnHead(), this); // Command Registry diff --git a/src/main/java/org/modularsoft/PlayerHeadHunt/commands/debugheadhunt.java b/src/main/java/org/modularsoft/PlayerHeadHunt/commands/debugheadhunt.java index dc41ab0..c6e0714 100644 --- a/src/main/java/org/modularsoft/PlayerHeadHunt/commands/debugheadhunt.java +++ b/src/main/java/org/modularsoft/PlayerHeadHunt/commands/debugheadhunt.java @@ -59,7 +59,9 @@ public boolean onCommand(@NotNull CommandSender sender, @NotNull Command cmd, @N } case "countheads" -> { headWorldController.countHeadsInRegion(); - sender.sendMessage("Heads counted successfully."); + int totalHeads = plugin.config().getTotalHeads(); // Retrieve the updated total head count + scoreboardController.updateLeaderboard(totalHeads); // Update the leaderboard with the new total + sender.sendMessage("Heads counted and leaderboard updated successfully."); } default -> sender.sendMessage("Invalid subcommand. Use: clearheads or countheads."); } diff --git a/src/main/java/org/modularsoft/PlayerHeadHunt/events/HeadHunterOnJoin.java b/src/main/java/org/modularsoft/PlayerHeadHunt/events/HeadHunterOnJoin.java index 52db1cc..ae1f25e 100644 --- a/src/main/java/org/modularsoft/PlayerHeadHunt/events/HeadHunterOnJoin.java +++ b/src/main/java/org/modularsoft/PlayerHeadHunt/events/HeadHunterOnJoin.java @@ -1,9 +1,6 @@ package org.modularsoft.PlayerHeadHunt.events; -import org.modularsoft.PlayerHeadHunt.PlayerHeadHuntMain; -import org.modularsoft.PlayerHeadHunt.HeadChatController; -import org.modularsoft.PlayerHeadHunt.HeadQuery; -import org.modularsoft.PlayerHeadHunt.HeadScoreboardController; +import org.modularsoft.PlayerHeadHunt.*; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; @@ -13,16 +10,19 @@ public class HeadHunterOnJoin implements Listener { private final PlayerHeadHuntMain plugin; private final HeadChatController headChatController; private final HeadScoreboardController headScoreboardController; - private final HeadQuery headQuery; // Add HeadQuery instance + private final HeadQuery headQuery; + private final HeadWorldController headWorldController; // Add this field public HeadHunterOnJoin(PlayerHeadHuntMain plugin, HeadChatController headChatController, HeadScoreboardController headScoreboardController, - HeadQuery headQuery) { + HeadQuery headQuery, + HeadWorldController headWorldController) { this.plugin = plugin; this.headChatController = headChatController; this.headScoreboardController = headScoreboardController; - this.headQuery = headQuery; // Initialize HeadQuery + this.headQuery = headQuery; + this.headWorldController = headWorldController; // Initialize it here } @EventHandler @@ -40,7 +40,20 @@ public void onHeadHunterJoin(PlayerJoinEvent event) { headChatController.newPlayerJoinsTheHunt(player); } - // Give the player a Head Locator compass + // Remove all existing Head Locator items from the player's inventory + player.getInventory().forEach(item -> { + if (item != null && + item.hasItemMeta() && + item.getItemMeta().hasDisplayName() && + item.getItemMeta().getDisplayName().equals("§6Head Locator")) { + player.getInventory().remove(item); + } + }); + + // Add a new Head Locator compass player.getInventory().addItem(org.modularsoft.PlayerHeadHunt.items.HeadLocator.createHeadLocator()); + + // Start the HeadLocatorTask for the player + new org.modularsoft.PlayerHeadHunt.helpers.HeadLocatorTask(plugin, new org.modularsoft.PlayerHeadHunt.items.HeadLocator(), headWorldController).startTask(player); } } \ No newline at end of file diff --git a/src/main/java/org/modularsoft/PlayerHeadHunt/helpers/HeadLocatorTask.java b/src/main/java/org/modularsoft/PlayerHeadHunt/helpers/HeadLocatorTask.java index 1141772..975d9e7 100644 --- a/src/main/java/org/modularsoft/PlayerHeadHunt/helpers/HeadLocatorTask.java +++ b/src/main/java/org/modularsoft/PlayerHeadHunt/helpers/HeadLocatorTask.java @@ -23,20 +23,31 @@ public HeadLocatorTask(JavaPlugin plugin, HeadLocator headLocator, HeadWorldCont public void startTask(Player player) { Bukkit.getScheduler().runTaskTimer(plugin, () -> { + // Check if the player is online + if (!player.isOnline()) { + return; // Stop if the player is offline + } + // Check if the player is holding the Head Locator item ItemStack itemInHand = player.getInventory().getItemInMainHand(); - if (itemInHand.isSimilar(HeadLocator.createHeadLocator())) { + if (itemInHand.hasItemMeta() && itemInHand.getItemMeta().hasDisplayName() && + itemInHand.getItemMeta().getDisplayName().equals("§6Head Locator")) { + Location nearestHead = headWorldController.findNearestUnclaimedHead(player); if (nearestHead != null) { double distance = player.getLocation().distance(nearestHead); if (distance > 10) { player.spigot().sendMessage(ChatMessageType.ACTION_BAR, new TextComponent("§aNearest unclaimed head is " + (int) distance + " meters away.")); + player.playSound(player.getLocation(), "minecraft:block.note_block.pling", 1.0f, 1.0f); // Play a sound for far distance } else { player.spigot().sendMessage(ChatMessageType.ACTION_BAR, new TextComponent("§aYou are very close to an unclaimed head!")); + player.playSound(player.getLocation(), "minecraft:block.note_block.bell", 1.0f, 1.5f); // Play a sound for close distance } } else { player.spigot().sendMessage(ChatMessageType.ACTION_BAR, new TextComponent("§cNo unclaimed heads found.")); } + } else { + player.spigot().sendMessage(ChatMessageType.ACTION_BAR, new TextComponent("§cHold the Head Locator to track heads.")); } }, 0L, 1200L); // Runs every 60 seconds (1200 ticks) } diff --git a/src/main/java/org/modularsoft/PlayerHeadHunt/items/HeadLocator.java b/src/main/java/org/modularsoft/PlayerHeadHunt/items/HeadLocator.java index cb5995b..823cd8e 100644 --- a/src/main/java/org/modularsoft/PlayerHeadHunt/items/HeadLocator.java +++ b/src/main/java/org/modularsoft/PlayerHeadHunt/items/HeadLocator.java @@ -7,7 +7,7 @@ public class HeadLocator { public static ItemStack createHeadLocator() { - ItemStack headLocator = new ItemStack(Material.COMPASS); + ItemStack headLocator = new ItemStack(Material.RECOVERY_COMPASS); // Use Recovery Compass ItemMeta meta = headLocator.getItemMeta(); if (meta != null) { meta.setDisplayName("§6Head Locator");