From 28686273662c260dea4cb6ceb3fa2cf7f6694ff5 Mon Sep 17 00:00:00 2001 From: okx-code Date: Thu, 31 Oct 2024 00:18:15 +0000 Subject: [PATCH] add categories and arena cleaner --- .../java/net/civmc/kitpvp/KitPvpPlugin.java | 2 + .../net/civmc/kitpvp/arena/ArenaCleaner.java | 53 ++++++++++++ .../net/civmc/kitpvp/arena/ArenaCommand.java | 23 ++++- .../net/civmc/kitpvp/arena/ArenaManager.java | 6 +- .../net/civmc/kitpvp/arena/data/Arena.java | 1 + .../net/civmc/kitpvp/arena/data/ArenaDao.java | 2 + .../civmc/kitpvp/arena/data/SqlArenaDao.java | 19 +++++ .../arena/gui/ArenaCategorySelectionGui.java | 84 +++++++++++++++++++ .../net/civmc/kitpvp/arena/gui/ArenaGui.java | 3 +- .../kitpvp/arena/gui/ArenaSelectionGui.java | 15 ++-- .../civmc/kitpvp/spawn/SetSpawnCommand.java | 2 +- .../src/main/resources/plugin.yml | 1 + 12 files changed, 198 insertions(+), 13 deletions(-) create mode 100644 plugins/kitpvp-paper/src/main/java/net/civmc/kitpvp/arena/ArenaCleaner.java create mode 100644 plugins/kitpvp-paper/src/main/java/net/civmc/kitpvp/arena/gui/ArenaCategorySelectionGui.java diff --git a/plugins/kitpvp-paper/src/main/java/net/civmc/kitpvp/KitPvpPlugin.java b/plugins/kitpvp-paper/src/main/java/net/civmc/kitpvp/KitPvpPlugin.java index b61e35e3d..c15c171d9 100644 --- a/plugins/kitpvp-paper/src/main/java/net/civmc/kitpvp/KitPvpPlugin.java +++ b/plugins/kitpvp-paper/src/main/java/net/civmc/kitpvp/KitPvpPlugin.java @@ -2,6 +2,7 @@ package net.civmc.kitpvp; import java.sql.SQLException; import net.civmc.kitpvp.anvil.AnvilGui; +import net.civmc.kitpvp.arena.ArenaCleaner; import net.civmc.kitpvp.arena.ArenaCommand; import net.civmc.kitpvp.arena.ArenaManager; import net.civmc.kitpvp.arena.MysqlLoader; @@ -55,6 +56,7 @@ public class KitPvpPlugin extends ACivMod { ArenaManager manager = new ArenaManager(this, spawnProvider, new MysqlLoader(source)); getCommand("arena").setExecutor(new ArenaCommand(this, new SqlArenaDao(source), manager)); getServer().getPluginManager().registerEvents(new RespawnListener(manager), this); + Bukkit.getScheduler().runTaskTimer(this, new ArenaCleaner(manager), 20, 20); } catch (SQLException e) { throw new RuntimeException(e); } diff --git a/plugins/kitpvp-paper/src/main/java/net/civmc/kitpvp/arena/ArenaCleaner.java b/plugins/kitpvp-paper/src/main/java/net/civmc/kitpvp/arena/ArenaCleaner.java new file mode 100644 index 000000000..7a9255ff3 --- /dev/null +++ b/plugins/kitpvp-paper/src/main/java/net/civmc/kitpvp/arena/ArenaCleaner.java @@ -0,0 +1,53 @@ +package net.civmc.kitpvp.arena; + +import net.civmc.kitpvp.KitPvpPlugin; +import org.bukkit.Bukkit; +import org.bukkit.World; +import org.bukkit.plugin.java.JavaPlugin; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.concurrent.TimeUnit; +import java.util.logging.Level; + +public class ArenaCleaner implements Runnable { + private static final long EMPTY_ARENA_DURATION = TimeUnit.SECONDS.toMillis(20); + + private final Map emptyArenas = new HashMap<>(); + private final ArenaManager arenaManager; + + public ArenaCleaner(ArenaManager arenaManager) { + this.arenaManager = arenaManager; + } + + @Override + public void run() { + try { + for (LoadedArena loadedArena : this.arenaManager.getArenas()) { + String arenaName = this.arenaManager.getArenaName(loadedArena.arena().name(), loadedArena.owner()); + World world = Bukkit.getWorld(arenaName); + if (world == null) { + continue; + } + + if (world.getPlayerCount() == 0) { + emptyArenas.putIfAbsent(loadedArena, System.currentTimeMillis()); + } else { + emptyArenas.remove(loadedArena); + } + } + Iterator> iterator = emptyArenas.entrySet().iterator(); + while (iterator.hasNext()) { + Map.Entry entry = iterator.next(); + if (entry.getValue() + EMPTY_ARENA_DURATION < System.currentTimeMillis()) { + if (this.arenaManager.getArenas().contains(entry.getKey())) { + this.arenaManager.deleteArena(entry.getKey().owner()); + } + iterator.remove(); + } + } + } catch (RuntimeException ex) { + JavaPlugin.getPlugin(KitPvpPlugin.class).getLogger().log(Level.WARNING, "Cleaning arenas", ex); + } + } +} diff --git a/plugins/kitpvp-paper/src/main/java/net/civmc/kitpvp/arena/ArenaCommand.java b/plugins/kitpvp-paper/src/main/java/net/civmc/kitpvp/arena/ArenaCommand.java index 3578bdf6e..c722fa3a9 100644 --- a/plugins/kitpvp-paper/src/main/java/net/civmc/kitpvp/arena/ArenaCommand.java +++ b/plugins/kitpvp-paper/src/main/java/net/civmc/kitpvp/arena/ArenaCommand.java @@ -78,7 +78,7 @@ public class ArenaCommand implements CommandExecutor { throw new RuntimeException(e); } - boolean success = dao.newArena(new Arena(arenaName, null, player.getLocation(), icon)); + boolean success = dao.newArena(new Arena(arenaName, null, null, player.getLocation(), icon)); if (success) { player.sendMessage(Component.text("Created arena", NamedTextColor.GREEN)); } else { @@ -127,6 +127,27 @@ public class ArenaCommand implements CommandExecutor { } }); return true; + } else if (args.length > 0 && args[0].equalsIgnoreCase("category")) { + if (args.length < 3) { + return false; + } + if (!player.hasPermission("kitpvp.admin")) { + player.sendMessage(Component.text("No permission", NamedTextColor.RED)); + return true; + } + + String arenaName = args[1]; + String category = String.join(" ", Arrays.copyOfRange(args, 2, args.length)); + + Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> { + boolean success = dao.setCategory(arenaName, category); + if (success) { + player.sendMessage(Component.text("Set category of arena", NamedTextColor.GREEN)); + } else { + player.sendMessage(Component.text("Could not set category of arena. Does it exist?", NamedTextColor.RED)); + } + }); + return true; } else if (args.length == 0) { new ArenaGui(dao, manager).open(player); return true; diff --git a/plugins/kitpvp-paper/src/main/java/net/civmc/kitpvp/arena/ArenaManager.java b/plugins/kitpvp-paper/src/main/java/net/civmc/kitpvp/arena/ArenaManager.java index 51a011e4b..cedb8d3ac 100644 --- a/plugins/kitpvp-paper/src/main/java/net/civmc/kitpvp/arena/ArenaManager.java +++ b/plugins/kitpvp-paper/src/main/java/net/civmc/kitpvp/arena/ArenaManager.java @@ -61,7 +61,11 @@ public class ArenaManager { } public void deleteArena(PlayerProfile owner) { - Arena arena = arenas.remove(owner.getId()).arena(); + LoadedArena removedArena = arenas.remove(owner.getId()); + if (removedArena == null) { + return; + } + Arena arena = removedArena.arena(); String worldName = getArenaName(arena.name(), owner); World world = Bukkit.getWorld(worldName); if (world != null) { diff --git a/plugins/kitpvp-paper/src/main/java/net/civmc/kitpvp/arena/data/Arena.java b/plugins/kitpvp-paper/src/main/java/net/civmc/kitpvp/arena/data/Arena.java index fe98a18cf..4a645b384 100644 --- a/plugins/kitpvp-paper/src/main/java/net/civmc/kitpvp/arena/data/Arena.java +++ b/plugins/kitpvp-paper/src/main/java/net/civmc/kitpvp/arena/data/Arena.java @@ -6,6 +6,7 @@ import org.bukkit.Material; public record Arena( String name, String displayName, + String category, Location spawn, Material icon ) { diff --git a/plugins/kitpvp-paper/src/main/java/net/civmc/kitpvp/arena/data/ArenaDao.java b/plugins/kitpvp-paper/src/main/java/net/civmc/kitpvp/arena/data/ArenaDao.java index ae8cf5812..efbbbfa84 100644 --- a/plugins/kitpvp-paper/src/main/java/net/civmc/kitpvp/arena/data/ArenaDao.java +++ b/plugins/kitpvp-paper/src/main/java/net/civmc/kitpvp/arena/data/ArenaDao.java @@ -11,4 +11,6 @@ public interface ArenaDao { boolean deleteArena(String arenaName); boolean setDisplayName(String arenaName, String displayName); + + boolean setCategory(String arenaName, String category); } diff --git a/plugins/kitpvp-paper/src/main/java/net/civmc/kitpvp/arena/data/SqlArenaDao.java b/plugins/kitpvp-paper/src/main/java/net/civmc/kitpvp/arena/data/SqlArenaDao.java index b92f663f9..a032c0e47 100644 --- a/plugins/kitpvp-paper/src/main/java/net/civmc/kitpvp/arena/data/SqlArenaDao.java +++ b/plugins/kitpvp-paper/src/main/java/net/civmc/kitpvp/arena/data/SqlArenaDao.java @@ -36,6 +36,10 @@ public class SqlArenaDao implements ArenaDao { """ ALTER TABLE arenas ADD COLUMN IF NOT EXISTS display_name VARCHAR(64) """); + source.registerMigration(6, false, + """ + ALTER TABLE arenas ADD COLUMN IF NOT EXISTS category VARCHAR(64) + """); } @Override @@ -47,6 +51,7 @@ public class SqlArenaDao implements ArenaDao { arenas.add(new Arena( resultSet.getString("name"), resultSet.getString("display_name"), + resultSet.getString("category"), new Location(null, resultSet.getDouble("spawn_x"), resultSet.getDouble("spawn_y"), resultSet.getDouble("spawn_z"), resultSet.getFloat("spawn_yaw"), 0), Material.valueOf(resultSet.getString("icon")) )); @@ -102,4 +107,18 @@ public class SqlArenaDao implements ArenaDao { return false; } } + + @Override + public boolean setCategory(String arenaName, String category) { + try (Connection connection = source.getConnection()) { + PreparedStatement statement = connection.prepareStatement("UPDATE arenas SET category = ? WHERE name = ?"); + statement.setString(1, "null".equalsIgnoreCase(category) ? null : category); + statement.setString(2, arenaName); + + return statement.executeUpdate() == 1; + } catch (SQLException ex) { + JavaPlugin.getPlugin(KitPvpPlugin.class).getLogger().log(Level.WARNING, "Error setting display name of arena", ex); + return false; + } + } } diff --git a/plugins/kitpvp-paper/src/main/java/net/civmc/kitpvp/arena/gui/ArenaCategorySelectionGui.java b/plugins/kitpvp-paper/src/main/java/net/civmc/kitpvp/arena/gui/ArenaCategorySelectionGui.java new file mode 100644 index 000000000..1cb82df6c --- /dev/null +++ b/plugins/kitpvp-paper/src/main/java/net/civmc/kitpvp/arena/gui/ArenaCategorySelectionGui.java @@ -0,0 +1,84 @@ +package net.civmc.kitpvp.arena.gui; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.SequencedMap; +import java.util.TreeMap; +import net.civmc.kitpvp.KitPvpPlugin; +import net.civmc.kitpvp.arena.ArenaManager; +import net.civmc.kitpvp.arena.data.Arena; +import net.civmc.kitpvp.arena.data.ArenaDao; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import org.bukkit.Bukkit; +import org.bukkit.Material; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; +import org.bukkit.plugin.java.JavaPlugin; +import org.jetbrains.annotations.NotNull; +import vg.civcraft.mc.civmodcore.inventory.gui.Clickable; +import vg.civcraft.mc.civmodcore.inventory.gui.ClickableInventory; + +public class ArenaCategorySelectionGui { + + private final JavaPlugin plugin = JavaPlugin.getPlugin(KitPvpPlugin.class); + private final ArenaDao arenaDao; + private final ArenaManager manager; + + public ArenaCategorySelectionGui(ArenaDao arenaDao, ArenaManager manager) { + this.arenaDao = arenaDao; + this.manager = manager; + } + + public void open(Player player) { + Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> { + List arenas = arenaDao.getArenas(); + Bukkit.getScheduler().runTask(plugin, () -> open(player, arenas)); + }); + } + + private void open(Player player, List arenas) { + if (arenas.isEmpty()) { + player.sendMessage(Component.text("No available arenas", NamedTextColor.RED)); + return; + } + + List uncategorised = new ArrayList<>(); + SequencedMap> arenasByCategory = new TreeMap<>(); + for (Arena arena : arenas) { + if (arena.category() == null) { + uncategorised.add(arena); + } else { + arenasByCategory.computeIfAbsent(arena.category(), k -> new ArrayList<>()).add(arena); + } + } + + int cats = arenasByCategory.size() + (uncategorised.isEmpty() ? 0 : 1); + ClickableInventory inventory = new ClickableInventory(Math.ceilDiv(cats, 9) * 9, "Arena categories"); + + int slot = 0; + for (Map.Entry> entry : arenasByCategory.entrySet()) { + inventory.setSlot(toClickable(entry.getKey(), NamedTextColor.WHITE, entry.getValue()), slot++); + } + if (!uncategorised.isEmpty()) { + inventory.setSlot(toClickable("Uncategorised", NamedTextColor.GRAY, uncategorised), slot); + } + inventory.showInventory(player, false); + } + + private Clickable toClickable(String category, NamedTextColor colour, List arenas) { + ItemStack item = new ItemStack(Material.ARROW); + ItemMeta meta = item.getItemMeta(); + meta.itemName(Component.text(category, colour)); + item.setItemMeta(meta); + return new Clickable(item) { + @Override + protected void clicked(@NotNull Player clicker) { + ArenaSelectionGui gui = new ArenaSelectionGui(arenaDao, ArenaCategorySelectionGui.this, manager); + Bukkit.getScheduler().runTask(plugin, () -> gui.open(clicker, arenas)); + } + }; + } +} diff --git a/plugins/kitpvp-paper/src/main/java/net/civmc/kitpvp/arena/gui/ArenaGui.java b/plugins/kitpvp-paper/src/main/java/net/civmc/kitpvp/arena/gui/ArenaGui.java index f63639d35..1e277d889 100644 --- a/plugins/kitpvp-paper/src/main/java/net/civmc/kitpvp/arena/gui/ArenaGui.java +++ b/plugins/kitpvp-paper/src/main/java/net/civmc/kitpvp/arena/gui/ArenaGui.java @@ -82,6 +82,7 @@ public class ArenaGui { protected void onShiftRightClick(@NotNull Player clicker) { if (!hasAccess) { super.onShiftRightClick(clicker); + return; } new ConfirmDeletionGui(manager, loadedArena.owner(), clicker); @@ -103,7 +104,7 @@ public class ArenaGui { return; } - new ArenaSelectionGui(dao, manager).open(clicker); + new ArenaCategorySelectionGui(dao, manager).open(clicker); } }, 0); view.showScreen(); diff --git a/plugins/kitpvp-paper/src/main/java/net/civmc/kitpvp/arena/gui/ArenaSelectionGui.java b/plugins/kitpvp-paper/src/main/java/net/civmc/kitpvp/arena/gui/ArenaSelectionGui.java index 6f9ec1193..3bd762e0d 100644 --- a/plugins/kitpvp-paper/src/main/java/net/civmc/kitpvp/arena/gui/ArenaSelectionGui.java +++ b/plugins/kitpvp-paper/src/main/java/net/civmc/kitpvp/arena/gui/ArenaSelectionGui.java @@ -21,20 +21,15 @@ public class ArenaSelectionGui { private final JavaPlugin plugin = JavaPlugin.getPlugin(KitPvpPlugin.class); private final ArenaDao arenaDao; private final ArenaManager manager; + private final ArenaCategorySelectionGui parent; - public ArenaSelectionGui(ArenaDao arenaDao, ArenaManager manager) { + public ArenaSelectionGui(ArenaDao arenaDao, ArenaCategorySelectionGui parent, ArenaManager manager) { this.arenaDao = arenaDao; + this.parent = parent; this.manager = manager; } - public void open(Player player) { - Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> { - List arenas = arenaDao.getArenas(); - Bukkit.getScheduler().runTask(plugin, () -> open(player, arenas)); - }); - } - - private void open(Player player, List arenas) { + public void open(Player player, List arenas) { if (arenas.size() > 54) { throw new IllegalArgumentException("too many arenas"); } else if (arenas.isEmpty()) { @@ -51,11 +46,13 @@ public class ArenaSelectionGui { inventory.setSlot(new Clickable(item) { @Override protected void clicked(@NotNull Player clicker) { + inventory.setOnClose(null); clicker.closeInventory(); Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> manager.createArena(clicker, arena)); } }, slot++); } + inventory.setOnClose(() -> parent.open(player)); inventory.showInventory(player, false); } } diff --git a/plugins/kitpvp-paper/src/main/java/net/civmc/kitpvp/spawn/SetSpawnCommand.java b/plugins/kitpvp-paper/src/main/java/net/civmc/kitpvp/spawn/SetSpawnCommand.java index 71b94cef9..4c7b9d037 100644 --- a/plugins/kitpvp-paper/src/main/java/net/civmc/kitpvp/spawn/SetSpawnCommand.java +++ b/plugins/kitpvp-paper/src/main/java/net/civmc/kitpvp/spawn/SetSpawnCommand.java @@ -35,7 +35,7 @@ public class SetSpawnCommand implements CommandExecutor { if (spawnProvider.setSpawn(location)) { player.sendMessage(Component.text("Set spawn", NamedTextColor.GREEN)); } else { - player.sendMessage(Component.text("Could not set spawn", NamedTextColor.GREEN)); + player.sendMessage(Component.text("Could not set spawn", NamedTextColor.RED)); } }); return true; diff --git a/plugins/kitpvp-paper/src/main/resources/plugin.yml b/plugins/kitpvp-paper/src/main/resources/plugin.yml index 98e936822..64dbfba72 100644 --- a/plugins/kitpvp-paper/src/main/resources/plugin.yml +++ b/plugins/kitpvp-paper/src/main/resources/plugin.yml @@ -21,6 +21,7 @@ commands: / create (administrators only) / delete (administrators only) / displayname (administrators only) + / category (administrators only) spawn: {} setspawn: permission: kitpvp.admin