add categories and arena cleaner

This commit is contained in:
okx-code
2024-10-31 00:18:15 +00:00
parent 883b59565a
commit 2868627366
12 changed files with 198 additions and 13 deletions

View File

@@ -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);
}

View File

@@ -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<LoadedArena, Long> 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<Map.Entry<LoadedArena, Long>> iterator = emptyArenas.entrySet().iterator();
while (iterator.hasNext()) {
Map.Entry<LoadedArena, Long> 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);
}
}
}

View File

@@ -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;

View File

@@ -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) {

View File

@@ -6,6 +6,7 @@ import org.bukkit.Material;
public record Arena(
String name,
String displayName,
String category,
Location spawn,
Material icon
) {

View File

@@ -11,4 +11,6 @@ public interface ArenaDao {
boolean deleteArena(String arenaName);
boolean setDisplayName(String arenaName, String displayName);
boolean setCategory(String arenaName, String category);
}

View File

@@ -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;
}
}
}

View File

@@ -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<Arena> arenas = arenaDao.getArenas();
Bukkit.getScheduler().runTask(plugin, () -> open(player, arenas));
});
}
private void open(Player player, List<Arena> arenas) {
if (arenas.isEmpty()) {
player.sendMessage(Component.text("No available arenas", NamedTextColor.RED));
return;
}
List<Arena> uncategorised = new ArrayList<>();
SequencedMap<String, List<Arena>> 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<String, List<Arena>> 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<Arena> 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));
}
};
}
}

View File

@@ -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();

View File

@@ -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<Arena> arenas = arenaDao.getArenas();
Bukkit.getScheduler().runTask(plugin, () -> open(player, arenas));
});
}
private void open(Player player, List<Arena> arenas) {
public void open(Player player, List<Arena> 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);
}
}

View File

@@ -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;

View File

@@ -21,6 +21,7 @@ commands:
/<command> create <name> <icon> (administrators only)
/<command> delete <name> (administrators only)
/<command> displayname <name> <display name> (administrators only)
/<command> category <name> <category> (administrators only)
spawn: {}
setspawn:
permission: kitpvp.admin