init commit
This commit is contained in:
@@ -0,0 +1,73 @@
|
||||
package de.winniepat.pierredufaulersack;
|
||||
|
||||
import de.winniepat.pierredufaulersack.commands.*;
|
||||
import de.winniepat.pierredufaulersack.game.*;
|
||||
import de.winniepat.pierredufaulersack.kits.*;
|
||||
import de.winniepat.pierredufaulersack.listeners.*;
|
||||
import org.bukkit.command.PluginCommand;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
|
||||
public final class Pierredufaulersack extends JavaPlugin {
|
||||
|
||||
private KitService kitService;
|
||||
private GameManager gameManager;
|
||||
private SidebarService sidebarService;
|
||||
private LuckPermsService luckPermsService;
|
||||
|
||||
@Override
|
||||
public void onEnable() {
|
||||
saveDefaultConfig();
|
||||
|
||||
this.kitService = new KitService(this);
|
||||
this.luckPermsService = new LuckPermsService(this);
|
||||
this.gameManager = new GameManager(this, kitService, luckPermsService);
|
||||
this.sidebarService = new SidebarService(this, gameManager);
|
||||
|
||||
registerCommands();
|
||||
getServer().getPluginManager().registerEvents(new FriendlyFireListener(gameManager), this);
|
||||
getServer().getPluginManager().registerEvents(new PlayerConnectionListener(gameManager, sidebarService), this);
|
||||
getServer().getPluginManager().registerEvents(new RoundOutcomeListener(gameManager), this);
|
||||
getServer().getPluginManager().registerEvents(new RoundWaterCleanupListener(gameManager), this);
|
||||
getServer().getPluginManager().registerEvents(new PlayerJoinListener(this, gameManager, kitService), this);
|
||||
getServer().getPluginManager().registerEvents(new CobwebDecayListener(this, gameManager), this);
|
||||
getServer().getPluginManager().registerEvents(new PlayerDeathListener(), this);
|
||||
|
||||
sidebarService.start();
|
||||
getLogger().info("Pierredufaulersack enabled.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisable() {
|
||||
if (sidebarService != null) {
|
||||
sidebarService.shutdown();
|
||||
}
|
||||
if (gameManager != null) {
|
||||
gameManager.shutdown();
|
||||
gameManager.stopRound(true);
|
||||
}
|
||||
}
|
||||
|
||||
private void registerCommands() {
|
||||
PluginCommand bossHunt = getCommand("bosshunt");
|
||||
PluginCommand bossKit = getCommand("bosskit");
|
||||
PluginCommand hunterKit = getCommand("hunterkit");
|
||||
|
||||
if (bossHunt != null) {
|
||||
BossHuntCommand bossHuntCommand = new BossHuntCommand(gameManager);
|
||||
bossHunt.setExecutor(bossHuntCommand);
|
||||
bossHunt.setTabCompleter(bossHuntCommand);
|
||||
}
|
||||
|
||||
if (bossKit != null) {
|
||||
KitCommand cmd = new KitCommand(kitService, KitType.BOSS);
|
||||
bossKit.setExecutor(cmd);
|
||||
bossKit.setTabCompleter(cmd);
|
||||
}
|
||||
|
||||
if (hunterKit != null) {
|
||||
KitCommand cmd = new KitCommand(kitService, KitType.HUNTER);
|
||||
hunterKit.setExecutor(cmd);
|
||||
hunterKit.setTabCompleter(cmd);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,167 @@
|
||||
package de.winniepat.pierredufaulersack.commands;
|
||||
|
||||
import de.winniepat.pierredufaulersack.game.GameManager;
|
||||
import de.winniepat.pierredufaulersack.game.GameState;
|
||||
import java.util.*;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.command.*;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
public class BossHuntCommand implements CommandExecutor, TabCompleter {
|
||||
|
||||
private final GameManager gameManager;
|
||||
private static final String PREFIX = "&8[&6BossHunt&8] &r";
|
||||
|
||||
public BossHuntCommand(GameManager gameManager) {
|
||||
this.gameManager = gameManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
|
||||
if (args.length < 1) {
|
||||
send(sender, "&cNutzung: &f/" + label + " <queues|select|join|leave|start|stop|setlobby|setarena|status>");
|
||||
return true;
|
||||
}
|
||||
|
||||
String sub = args[0].toLowerCase();
|
||||
|
||||
switch (sub) {
|
||||
case "queues" -> sendQueues(sender);
|
||||
case "select" -> {
|
||||
if (!(sender instanceof Player player)) {
|
||||
send(sender, "&cNur Spieler können eine Warteschlange auswählen.");
|
||||
return true;
|
||||
}
|
||||
if (args.length < 2) {
|
||||
send(sender, "&cNutzung: &f/" + label + " select <queue>");
|
||||
return true;
|
||||
}
|
||||
gameManager.selectQueue(player, args[1]);
|
||||
}
|
||||
case "join" -> {
|
||||
if (!(sender instanceof Player player)) {
|
||||
send(sender, "&cNur Spieler können einer Warteschlange beitreten.");
|
||||
return true;
|
||||
}
|
||||
gameManager.join(player, args.length >= 2 ? args[1] : null);
|
||||
}
|
||||
case "leave" -> {
|
||||
if (!(sender instanceof Player player)) {
|
||||
send(sender, "&cNur Spieler können die Warteschlange verlassen.");
|
||||
return true;
|
||||
}
|
||||
gameManager.leave(player);
|
||||
}
|
||||
case "setlobby" -> {
|
||||
if (!(sender instanceof Player player)) {
|
||||
send(sender, "&cNur Spieler können die Lobby setzen.");
|
||||
return true;
|
||||
}
|
||||
gameManager.setLobby(player);
|
||||
}
|
||||
case "setarena" -> {
|
||||
if (!(sender instanceof Player player)) {
|
||||
send(sender, "&cNur Spieler können Arenen setzen.");
|
||||
return true;
|
||||
}
|
||||
if (args.length < 2) {
|
||||
send(sender, "&cNutzung: &f/" + label + " setarena <queue>");
|
||||
return true;
|
||||
}
|
||||
gameManager.setArena(player, args[1]);
|
||||
}
|
||||
case "start" -> gameManager.startRound(sender, args.length >= 2 ? args[1] : null);
|
||||
case "stop" -> gameManager.stopRoundByCommand(sender, args.length >= 2 ? args[1] : null);
|
||||
case "status" -> sendStatus(sender, args.length >= 2 ? args[1] : null);
|
||||
default -> send(sender, "&cUnbekannter Unterbefehl.");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> onTabComplete(CommandSender sender, Command command, String alias, String[] args) {
|
||||
if (args.length == 1) {
|
||||
return List.of("queues", "select", "join", "leave", "start", "stop", "setlobby", "setarena", "status").stream()
|
||||
.filter(option -> option.startsWith(args[0].toLowerCase()))
|
||||
.toList();
|
||||
}
|
||||
|
||||
if (args.length == 2) {
|
||||
String sub = args[0].toLowerCase();
|
||||
if (sub.equals("select") || sub.equals("join") || sub.equals("setarena") || sub.equals("start") || sub.equals("status")) {
|
||||
return gameManager.queueIds().stream()
|
||||
.filter(id -> id.toLowerCase().startsWith(args[1].toLowerCase()))
|
||||
.sorted()
|
||||
.toList();
|
||||
}
|
||||
if (sub.equals("stop")) {
|
||||
List<String> options = new ArrayList<>(gameManager.queueIds());
|
||||
options.add("all");
|
||||
return options.stream()
|
||||
.filter(id -> id.toLowerCase().startsWith(args[1].toLowerCase()))
|
||||
.sorted()
|
||||
.toList();
|
||||
}
|
||||
}
|
||||
|
||||
return List.of();
|
||||
}
|
||||
|
||||
private void sendQueues(CommandSender sender) {
|
||||
send(sender, "&fWarteschlangen:");
|
||||
for (String queueId : new TreeSet<>(gameManager.queueIds())) {
|
||||
GameState state = gameManager.getState(queueId);
|
||||
send(sender, "&e- " + queueId + " &7(" + stateText(state) + "&7) &f"
|
||||
+ gameManager.lobbySize(queueId) + "&7/&f" + gameManager.maxPlayers());
|
||||
}
|
||||
}
|
||||
|
||||
private void sendStatus(CommandSender sender, String queueIdArg) {
|
||||
String queueId = queueIdArg;
|
||||
if ((queueId == null || queueId.isBlank()) && sender instanceof Player player) {
|
||||
queueId = gameManager.getSelectedQueue(player.getUniqueId());
|
||||
}
|
||||
if (queueId == null || queueId.isBlank()) {
|
||||
sendQueues(sender);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!gameManager.queueIds().contains(queueId)) {
|
||||
send(sender, "&cUnbekannte Warteschlange. Benutze &f/bosshunt queues&c.");
|
||||
return;
|
||||
}
|
||||
|
||||
GameState state = gameManager.getState(queueId);
|
||||
send(sender, "&fWarteschlange: &e" + queueId);
|
||||
send(sender, "&fStatus: " + stateText(state));
|
||||
send(sender, "&fSpieler: &b" + gameManager.lobbySize(queueId) + "&7/&b" + gameManager.maxPlayers());
|
||||
|
||||
List<String> onlineLobbyPlayers = new ArrayList<>();
|
||||
for (UUID uuid : gameManager.lobbyPlayers(queueId)) {
|
||||
Player player = Bukkit.getPlayer(uuid);
|
||||
if (player != null) {
|
||||
onlineLobbyPlayers.add(player.getName());
|
||||
}
|
||||
}
|
||||
|
||||
if (onlineLobbyPlayers.isEmpty()) {
|
||||
send(sender, "&7Warteschlange ist leer.");
|
||||
} else {
|
||||
send(sender, "&fIn der Warteschlange: &e" + String.join("&7, &e", onlineLobbyPlayers));
|
||||
}
|
||||
}
|
||||
|
||||
private String stateText(GameState state) {
|
||||
return switch (state) {
|
||||
case WAITING -> "&7WAITING";
|
||||
case COUNTDOWN -> "&eCOUNTDOWN";
|
||||
case RUNNING -> "&aRUNNING";
|
||||
};
|
||||
}
|
||||
|
||||
private void send(CommandSender sender, String message) {
|
||||
sender.sendMessage(ChatColor.translateAlternateColorCodes('&', PREFIX + message));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,126 @@
|
||||
package de.winniepat.pierredufaulersack.commands;
|
||||
|
||||
import de.winniepat.pierredufaulersack.kits.*;
|
||||
import java.util.*;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.command.*;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
public class KitCommand implements CommandExecutor, TabCompleter {
|
||||
|
||||
private static final String ADMIN_PERMISSION = "pierredufaulersack.admin";
|
||||
private static final String PREFIX = "&8[&6BossHunt&8] &r";
|
||||
|
||||
private final KitService kitService;
|
||||
private final KitType type;
|
||||
|
||||
public KitCommand(KitService kitService, KitType type) {
|
||||
this.kitService = kitService;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
|
||||
if (!sender.hasPermission(ADMIN_PERMISSION)) {
|
||||
send(sender, "&cKeine Berechtigung.");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (args.length < 1) {
|
||||
send(sender, "&cNutzung: &f/" + label + " <add|set|del|list> [1-3]");
|
||||
return true;
|
||||
}
|
||||
|
||||
String action = args[0].toLowerCase();
|
||||
switch (action) {
|
||||
case "list" -> handleList(sender, label);
|
||||
case "add", "set", "del" -> handleKitMutation(sender, label, action, args);
|
||||
default -> send(sender, "&cUnbekannter Unterbefehl. &7Nutzung: &f/" + label + " <add|set|del|list> [1-3]");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> onTabComplete(CommandSender sender, Command command, String alias, String[] args) {
|
||||
if (args.length == 1) {
|
||||
return List.of("add", "set", "del", "list").stream()
|
||||
.filter(opt -> opt.startsWith(args[0].toLowerCase()))
|
||||
.toList();
|
||||
}
|
||||
|
||||
if (args.length == 2 && !"list".equalsIgnoreCase(args[0])) {
|
||||
List<String> slots = List.of("1", "2", "3");
|
||||
List<String> filtered = new ArrayList<>();
|
||||
for (String slot : slots) {
|
||||
if (slot.startsWith(args[1])) {
|
||||
filtered.add(slot);
|
||||
}
|
||||
}
|
||||
return filtered;
|
||||
}
|
||||
|
||||
return List.of();
|
||||
}
|
||||
|
||||
private void handleList(CommandSender sender, String label) {
|
||||
List<Integer> slots = kitService.listKitSlots(type);
|
||||
if (slots.isEmpty()) {
|
||||
send(sender, "&eKeine Kits für &f/" + label + " &egespeichert.");
|
||||
return;
|
||||
}
|
||||
|
||||
send(sender, "&aVerfügbare Kits fuer &f/" + label + "&a: &e" + slots);
|
||||
}
|
||||
|
||||
private void handleKitMutation(CommandSender sender, String label, String action, String[] args) {
|
||||
if (args.length != 2) {
|
||||
send(sender, "&cNutzung: &f/" + label + " " + action + " <1-3>");
|
||||
return;
|
||||
}
|
||||
|
||||
Integer slot = parseSlot(args[1]);
|
||||
if (slot == null) {
|
||||
send(sender, "&cSlot muss 1, 2 oder 3 sein.");
|
||||
return;
|
||||
}
|
||||
|
||||
if ("del".equals(action)) {
|
||||
boolean deleted = kitService.deleteKit(type, slot);
|
||||
send(sender, deleted ? "&aKit &e" + slot + " &agelöscht." : "&eKit &f" + slot + " &eexistiert nicht.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(sender instanceof Player player)) {
|
||||
send(sender, "&cNur Spieler können Inventar-Kits speichern.");
|
||||
return;
|
||||
}
|
||||
|
||||
if ("add".equals(action)) {
|
||||
boolean added = kitService.addKit(type, slot, player);
|
||||
send(sender, added
|
||||
? "&aKit &e" + slot + " &agespeichert."
|
||||
: "&eKit &f" + slot + " &eexistiert bereits. Nutze &fset &ezum Ueberschreiben.");
|
||||
return;
|
||||
}
|
||||
|
||||
kitService.setKit(type, slot, player);
|
||||
send(sender, "&aKit &e" + slot + " &agesetzt.");
|
||||
}
|
||||
|
||||
private Integer parseSlot(String value) {
|
||||
try {
|
||||
int parsed = Integer.parseInt(value);
|
||||
if (parsed < 1 || parsed > 3) {
|
||||
return null;
|
||||
}
|
||||
return parsed;
|
||||
} catch (NumberFormatException ignored) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private void send(CommandSender sender, String message) {
|
||||
sender.sendMessage(ChatColor.translateAlternateColorCodes('&', PREFIX + message));
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,7 @@
|
||||
package de.winniepat.pierredufaulersack.game;
|
||||
|
||||
public enum GameState {
|
||||
WAITING,
|
||||
COUNTDOWN,
|
||||
RUNNING
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
package de.winniepat.pierredufaulersack.game;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import net.luckperms.api.LuckPerms;
|
||||
import net.luckperms.api.LuckPermsProvider;
|
||||
import net.luckperms.api.node.types.PrefixNode;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
|
||||
public class LuckPermsService {
|
||||
|
||||
private static final String BOSS_PREFIX = "&c[ʙᴏꜱꜱ] &r";
|
||||
private static final String HUNTER_PREFIX = "&9[ʜᴜɴᴛᴇʀ] &r";
|
||||
|
||||
private final JavaPlugin plugin;
|
||||
private final Map<UUID, PrefixNode> appliedPrefixes = new ConcurrentHashMap<>();
|
||||
private LuckPerms luckPerms;
|
||||
|
||||
public LuckPermsService(JavaPlugin plugin) {
|
||||
this.plugin = plugin;
|
||||
initialize();
|
||||
}
|
||||
|
||||
public boolean isAvailable() {
|
||||
return luckPerms != null;
|
||||
}
|
||||
|
||||
public void applyBossPrefix(Player player) {
|
||||
applyPrefix(player.getUniqueId(), BOSS_PREFIX, 100);
|
||||
}
|
||||
|
||||
public void applyHunterPrefix(Player player) {
|
||||
applyPrefix(player.getUniqueId(), HUNTER_PREFIX, 90);
|
||||
}
|
||||
|
||||
public void clearPrefix(Player player) {
|
||||
clearPrefix(player.getUniqueId());
|
||||
}
|
||||
|
||||
public void clearPrefix(UUID playerId) {
|
||||
if (!isAvailable()) {
|
||||
return;
|
||||
}
|
||||
|
||||
PrefixNode previous = appliedPrefixes.remove(playerId);
|
||||
if (previous == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
luckPerms.getUserManager().modifyUser(playerId, user -> user.transientData().remove(previous));
|
||||
}
|
||||
|
||||
public void clearAll() {
|
||||
Set<UUID> tracked = Set.copyOf(appliedPrefixes.keySet());
|
||||
for (UUID playerId : tracked) {
|
||||
clearPrefix(playerId);
|
||||
}
|
||||
}
|
||||
|
||||
private void applyPrefix(UUID playerId, String prefix, int priority) {
|
||||
if (!isAvailable()) {
|
||||
return;
|
||||
}
|
||||
|
||||
PrefixNode next = PrefixNode.builder(prefix, priority).build();
|
||||
PrefixNode previous = appliedPrefixes.put(playerId, next);
|
||||
luckPerms.getUserManager().modifyUser(playerId, user -> {
|
||||
if (previous != null) {
|
||||
user.transientData().remove(previous);
|
||||
}
|
||||
user.transientData().add(next);
|
||||
});
|
||||
}
|
||||
|
||||
private void initialize() {
|
||||
if (Bukkit.getPluginManager().getPlugin("LuckPerms") == null) {
|
||||
plugin.getLogger().info("LuckPerms not found. Prefix integration disabled.");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
luckPerms = LuckPermsProvider.get();
|
||||
plugin.getLogger().info("LuckPerms detected. Prefix integration enabled.");
|
||||
} catch (IllegalStateException ex) {
|
||||
plugin.getLogger().warning("LuckPerms detected but API is not ready. Prefix integration disabled.");
|
||||
luckPerms = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
package de.winniepat.pierredufaulersack.game;
|
||||
|
||||
public enum Role {
|
||||
BOSS,
|
||||
HUNTER
|
||||
}
|
||||
|
||||
@@ -0,0 +1,150 @@
|
||||
package de.winniepat.pierredufaulersack.game;
|
||||
|
||||
import java.util.TreeSet;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
import org.bukkit.scheduler.BukkitTask;
|
||||
import org.bukkit.scoreboard.*;
|
||||
|
||||
public class SidebarService {
|
||||
|
||||
private static final String OBJECTIVE_ID = "bosshunt";
|
||||
private static final String TEAM_BOSS = "0_boss";
|
||||
private static final String TEAM_HUNTER_SAME_QUEUE = "1_hunter_same";
|
||||
private static final String TEAM_HUNTER_OTHER_QUEUE = "1_hunter_other";
|
||||
private static final String TEAM_NORMAL = "2_normal";
|
||||
|
||||
private final JavaPlugin plugin;
|
||||
private final GameManager gameManager;
|
||||
private BukkitTask refreshTask;
|
||||
|
||||
public SidebarService(JavaPlugin plugin, GameManager gameManager) {
|
||||
this.plugin = plugin;
|
||||
this.gameManager = gameManager;
|
||||
}
|
||||
|
||||
public void start() {
|
||||
refreshTask = Bukkit.getScheduler().runTaskTimer(plugin, this::refreshAll, 0L, 20L);
|
||||
}
|
||||
|
||||
public void refreshAll() {
|
||||
for (Player player : Bukkit.getOnlinePlayers()) {
|
||||
showFor(player);
|
||||
}
|
||||
}
|
||||
|
||||
public void showFor(Player player) {
|
||||
ScoreboardManager manager = Bukkit.getScoreboardManager();
|
||||
if (manager == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Scoreboard board = manager.getNewScoreboard();
|
||||
Objective objective = board.registerNewObjective(OBJECTIVE_ID, "dummy", color("&6&lʙᴏꜱꜱʜᴜɴᴛ"));
|
||||
objective.setDisplaySlot(DisplaySlot.SIDEBAR);
|
||||
|
||||
applyTablistOrderingTeams(board, player);
|
||||
|
||||
Role role = gameManager.getRole(player.getUniqueId());
|
||||
if (role != null) {
|
||||
String queueId = gameManager.queueOfPlayer(player.getUniqueId());
|
||||
showRunningSession(objective, player, role, queueId);
|
||||
} else {
|
||||
showLobbyView(objective, player);
|
||||
}
|
||||
|
||||
player.setScoreboard(board);
|
||||
}
|
||||
|
||||
public void clearFor(Player player) {
|
||||
ScoreboardManager manager = Bukkit.getScoreboardManager();
|
||||
if (manager != null) {
|
||||
player.setScoreboard(manager.getMainScoreboard());
|
||||
}
|
||||
}
|
||||
|
||||
public void shutdown() {
|
||||
if (refreshTask != null) {
|
||||
refreshTask.cancel();
|
||||
refreshTask = null;
|
||||
}
|
||||
|
||||
for (Player player : Bukkit.getOnlinePlayers()) {
|
||||
clearFor(player);
|
||||
}
|
||||
}
|
||||
|
||||
private void showRunningSession(Objective objective, Player player, Role role, String queueId) {
|
||||
int line = 9;
|
||||
|
||||
objective.getScore(" ").setScore(line--);
|
||||
objective.getScore(color("&7Status: &aLÄUFT")).setScore(line--);
|
||||
objective.getScore(" ").setScore(line--);
|
||||
objective.getScore(color("&fQueue: &e" + queueId)).setScore(line--);
|
||||
objective.getScore(color("&fRolle: " + roleText(role))).setScore(line--);
|
||||
objective.getScore(color("&fHunter Verbleibend: &b" + gameManager.huntersLeft(player.getUniqueId()))).setScore(line--);
|
||||
objective.getScore(" ").setScore(line--);
|
||||
objective.getScore(color("&eKämpft!")).setScore(line);
|
||||
}
|
||||
|
||||
private void applyTablistOrderingTeams(Scoreboard board, Player viewer) {
|
||||
Team bosses = board.registerNewTeam(TEAM_BOSS);
|
||||
Team huntersSameQueue = board.registerNewTeam(TEAM_HUNTER_SAME_QUEUE);
|
||||
Team huntersOtherQueue = board.registerNewTeam(TEAM_HUNTER_OTHER_QUEUE);
|
||||
Team normals = board.registerNewTeam(TEAM_NORMAL);
|
||||
|
||||
huntersSameQueue.setColor(ChatColor.RED);
|
||||
|
||||
String viewerQueue = gameManager.queueOfPlayer(viewer.getUniqueId());
|
||||
for (Player online : Bukkit.getOnlinePlayers()) {
|
||||
Role onlineRole = gameManager.getRole(online.getUniqueId());
|
||||
if (onlineRole == Role.BOSS) {
|
||||
bosses.addEntry(online.getName());
|
||||
continue;
|
||||
}
|
||||
|
||||
if (onlineRole == Role.HUNTER) {
|
||||
String onlineQueue = gameManager.queueOfPlayer(online.getUniqueId());
|
||||
if (viewerQueue != null && viewerQueue.equals(onlineQueue)) {
|
||||
huntersSameQueue.addEntry(online.getName());
|
||||
} else {
|
||||
huntersOtherQueue.addEntry(online.getName());
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
normals.addEntry(online.getName());
|
||||
}
|
||||
}
|
||||
|
||||
private void showLobbyView(Objective objective, Player player) {
|
||||
int line = 12;
|
||||
|
||||
String selected = gameManager.getSelectedQueue(player.getUniqueId());
|
||||
String currentQueue = gameManager.queueOfPlayer(player.getUniqueId());
|
||||
String selectedText = (selected == null || selected.isBlank()) ? "-" : selected;
|
||||
|
||||
objective.getScore(color("&7Status: &7LOBBY")).setScore(line--);
|
||||
if (currentQueue != null) {
|
||||
objective.getScore(color("&fQueued: &aJa (&e" + currentQueue + "&a)")).setScore(line--);
|
||||
}
|
||||
objective.getScore(" ").setScore(line--);
|
||||
|
||||
for (String queueId : new TreeSet<>(gameManager.queueIds())) {
|
||||
objective.getScore(color("&e" + queueId + ": &f" + gameManager.lobbySize(queueId) + "&7/&f" + gameManager.maxPlayers())).setScore(line--);
|
||||
}
|
||||
}
|
||||
|
||||
private String roleText(Role role) {
|
||||
if (role == Role.BOSS) {
|
||||
return "&6BOSS";
|
||||
}
|
||||
return "&bHUNTER";
|
||||
}
|
||||
|
||||
private String color(String text) {
|
||||
return ChatColor.translateAlternateColorCodes('&', text);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,346 @@
|
||||
package de.winniepat.pierredufaulersack.kits;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
import java.util.function.IntPredicate;
|
||||
import java.util.UUID;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
|
||||
public class KitService {
|
||||
|
||||
private static final int MIN_SLOT = 1;
|
||||
private static final int MAX_SLOT = 3;
|
||||
private static final int KIT_CONTENT_SIZE = 41;
|
||||
|
||||
private final JavaPlugin plugin;
|
||||
|
||||
public KitService(JavaPlugin plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
public boolean addKit(KitType type, int slot, Player player) {
|
||||
validateSlot(slot);
|
||||
String path = path(type, slot);
|
||||
if (plugin.getConfig().contains(path)) {
|
||||
return false;
|
||||
}
|
||||
setKit(type, slot, player);
|
||||
return true;
|
||||
}
|
||||
|
||||
public void setKit(KitType type, int slot, Player player) {
|
||||
setKit(type, slot, player.getInventory().getContents());
|
||||
}
|
||||
|
||||
public void setKit(KitType type, int slot, ItemStack[] contents) {
|
||||
validateSlot(slot);
|
||||
|
||||
ItemStack[] normalizedContents = normalizeContents(contents);
|
||||
List<Map<String, Object>> serialized = new ArrayList<>(normalizedContents.length);
|
||||
for (ItemStack item : normalizedContents) {
|
||||
serialized.add(item == null ? null : item.clone().serialize());
|
||||
}
|
||||
|
||||
plugin.getConfig().set(path(type, slot), serialized);
|
||||
plugin.saveConfig();
|
||||
}
|
||||
|
||||
public boolean deleteKit(KitType type, int slot) {
|
||||
validateSlot(slot);
|
||||
String path = path(type, slot);
|
||||
if (!plugin.getConfig().contains(path)) {
|
||||
return false;
|
||||
}
|
||||
plugin.getConfig().set(path, null);
|
||||
plugin.saveConfig();
|
||||
return true;
|
||||
}
|
||||
|
||||
public List<Integer> listKitSlots(KitType type) {
|
||||
List<Integer> slots = new ArrayList<>();
|
||||
for (int slot = MIN_SLOT; slot <= MAX_SLOT; slot++) {
|
||||
if (hasKit(type, slot)) {
|
||||
slots.add(slot);
|
||||
}
|
||||
}
|
||||
return slots;
|
||||
}
|
||||
|
||||
public boolean hasKit(KitType type, int slot) {
|
||||
validateSlot(slot);
|
||||
return plugin.getConfig().contains(path(type, slot));
|
||||
}
|
||||
|
||||
public Optional<List<ItemStack>> getKit(KitType type, int slot) {
|
||||
validateSlot(slot);
|
||||
|
||||
List<?> raw = plugin.getConfig().getList(path(type, slot));
|
||||
if (raw == null || raw.isEmpty()) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
List<ItemStack> saved = new ArrayList<>(KIT_CONTENT_SIZE);
|
||||
boolean hasItem = false;
|
||||
|
||||
for (int index = 0; index < KIT_CONTENT_SIZE; index++) {
|
||||
Object element = index < raw.size() ? raw.get(index) : null;
|
||||
ItemStack item = deserializeItem(element);
|
||||
if (item != null) {
|
||||
hasItem = true;
|
||||
}
|
||||
saved.add(item);
|
||||
}
|
||||
|
||||
if (!hasItem) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
return Optional.of(cloneInventory(saved));
|
||||
}
|
||||
|
||||
public Optional<List<ItemStack>> getKitForPlayer(UUID playerId, KitType type, int slot) {
|
||||
Optional<List<ItemStack>> maybeBase = getKit(type, slot);
|
||||
if (maybeBase.isEmpty()) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
List<ItemStack> base = maybeBase.get();
|
||||
Optional<int[]> maybeLayout = getPlayerLayout(playerId, type, slot);
|
||||
if (maybeLayout.isEmpty()) {
|
||||
return Optional.of(cloneInventory(base));
|
||||
}
|
||||
|
||||
return Optional.of(applyLayout(base, maybeLayout.get()));
|
||||
}
|
||||
|
||||
public boolean setPlayerLayout(UUID playerId, KitType type, int slot, ItemStack[] arrangedContents) {
|
||||
validateSlot(slot);
|
||||
|
||||
Optional<List<ItemStack>> maybeBase = getKit(type, slot);
|
||||
if (maybeBase.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
List<ItemStack> base = maybeBase.get();
|
||||
ItemStack[] arranged = normalizeContents(arrangedContents);
|
||||
int[] layout = deriveLayout(base, arranged);
|
||||
|
||||
List<Integer> serialized = new ArrayList<>(layout.length);
|
||||
for (int value : layout) {
|
||||
serialized.add(value);
|
||||
}
|
||||
|
||||
plugin.getConfig().set(playerLayoutPath(playerId, type, slot), serialized);
|
||||
plugin.saveConfig();
|
||||
return true;
|
||||
}
|
||||
|
||||
private Optional<int[]> getPlayerLayout(UUID playerId, KitType type, int slot) {
|
||||
String path = playerLayoutPath(playerId, type, slot);
|
||||
List<?> raw = plugin.getConfig().getList(path);
|
||||
if (raw == null || raw.size() != KIT_CONTENT_SIZE) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
int[] layout = new int[KIT_CONTENT_SIZE];
|
||||
for (int i = 0; i < KIT_CONTENT_SIZE; i++) {
|
||||
Object element = raw.get(i);
|
||||
if (!(element instanceof Number number)) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
int value = number.intValue();
|
||||
if (value < 0 || value >= KIT_CONTENT_SIZE) {
|
||||
return Optional.empty();
|
||||
}
|
||||
layout[i] = value;
|
||||
}
|
||||
|
||||
return Optional.of(layout);
|
||||
}
|
||||
|
||||
private static List<ItemStack> applyLayout(List<ItemStack> base, int[] layout) {
|
||||
List<ItemStack> arranged = new ArrayList<>(KIT_CONTENT_SIZE);
|
||||
boolean[] consumed = new boolean[KIT_CONTENT_SIZE];
|
||||
|
||||
for (int target = 0; target < KIT_CONTENT_SIZE; target++) {
|
||||
int source = target < layout.length ? layout[target] : target;
|
||||
if (source < 0 || source >= KIT_CONTENT_SIZE || consumed[source]) {
|
||||
source = firstUnused(consumed, target);
|
||||
}
|
||||
consumed[source] = true;
|
||||
|
||||
ItemStack item = source < base.size() ? base.get(source) : null;
|
||||
arranged.add(item == null ? null : item.clone());
|
||||
}
|
||||
|
||||
return arranged;
|
||||
}
|
||||
|
||||
private static int[] deriveLayout(List<ItemStack> base, ItemStack[] arranged) {
|
||||
int[] layout = new int[KIT_CONTENT_SIZE];
|
||||
boolean[] used = new boolean[KIT_CONTENT_SIZE];
|
||||
|
||||
for (int target = 0; target < KIT_CONTENT_SIZE; target++) {
|
||||
ItemStack desired = arranged[target];
|
||||
int matched = -1;
|
||||
|
||||
for (int source = 0; source < KIT_CONTENT_SIZE; source++) {
|
||||
if (used[source]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ItemStack sourceItem = source < base.size() ? base.get(source) : null;
|
||||
if (isSameStack(sourceItem, desired)) {
|
||||
matched = source;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (matched == -1) {
|
||||
matched = firstUnused(used, target);
|
||||
}
|
||||
|
||||
used[matched] = true;
|
||||
layout[target] = matched;
|
||||
}
|
||||
|
||||
return layout;
|
||||
}
|
||||
|
||||
private static int firstUnused(boolean[] used, int fallback) {
|
||||
if (fallback >= 0 && fallback < used.length && !used[fallback]) {
|
||||
return fallback;
|
||||
}
|
||||
|
||||
for (int i = 0; i < used.length; i++) {
|
||||
if (!used[i]) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private static boolean isSameStack(ItemStack a, ItemStack b) {
|
||||
if (a == null || a.getType().isAir()) {
|
||||
return b == null || b.getType().isAir();
|
||||
}
|
||||
if (b == null || b.getType().isAir()) {
|
||||
return false;
|
||||
}
|
||||
return a.getAmount() == b.getAmount() && a.isSimilar(b);
|
||||
}
|
||||
|
||||
private static ItemStack deserializeItem(Object element) {
|
||||
if (element == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (element instanceof ItemStack itemStack) {
|
||||
return itemStack.clone();
|
||||
}
|
||||
|
||||
if (element instanceof Map<?, ?> map) {
|
||||
Map<String, Object> serialized = new LinkedHashMap<>();
|
||||
for (Map.Entry<?, ?> entry : map.entrySet()) {
|
||||
if (entry.getKey() instanceof String key) {
|
||||
serialized.put(key, entry.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
if (!serialized.isEmpty()) {
|
||||
try {
|
||||
return ItemStack.deserialize(serialized);
|
||||
} catch (IllegalArgumentException ignored) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public OptionalInt rollKitSlot(KitType type, IntPredicate allowedSlot) {
|
||||
List<Integer> slots = new ArrayList<>();
|
||||
List<Integer> weights = new ArrayList<>();
|
||||
int total = 0;
|
||||
|
||||
for (int slot = MIN_SLOT; slot <= MAX_SLOT; slot++) {
|
||||
if (!allowedSlot.test(slot) || !hasKit(type, slot)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int weight = getChance(type, slot);
|
||||
if (weight <= 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
slots.add(slot);
|
||||
weights.add(weight);
|
||||
total += weight;
|
||||
}
|
||||
|
||||
if (total <= 0) {
|
||||
return OptionalInt.empty();
|
||||
}
|
||||
|
||||
int roll = ThreadLocalRandom.current().nextInt(total);
|
||||
int cursor = 0;
|
||||
for (int i = 0; i < slots.size(); i++) {
|
||||
cursor += weights.get(i);
|
||||
if (roll < cursor) {
|
||||
return OptionalInt.of(slots.get(i));
|
||||
}
|
||||
}
|
||||
|
||||
return OptionalInt.empty();
|
||||
}
|
||||
|
||||
public OptionalInt rollKitSlot(KitType type) {
|
||||
return rollKitSlot(type, slot -> true);
|
||||
}
|
||||
|
||||
private int getChance(KitType type, int slot) {
|
||||
String chancePath = "kit-chances." + type.key() + "." + slot;
|
||||
return plugin.getConfig().getInt(chancePath, 0);
|
||||
}
|
||||
|
||||
private static ItemStack[] normalizeContents(ItemStack[] contents) {
|
||||
ItemStack[] normalized = new ItemStack[KIT_CONTENT_SIZE];
|
||||
if (contents == null) {
|
||||
return normalized;
|
||||
}
|
||||
|
||||
int copyLength = Math.min(KIT_CONTENT_SIZE, contents.length);
|
||||
for (int index = 0; index < copyLength; index++) {
|
||||
ItemStack item = contents[index];
|
||||
normalized[index] = item == null ? null : item.clone();
|
||||
}
|
||||
return normalized;
|
||||
}
|
||||
|
||||
private static List<ItemStack> cloneInventory(List<ItemStack> contents) {
|
||||
List<ItemStack> cloned = new ArrayList<>(contents.size());
|
||||
for (ItemStack item : contents) {
|
||||
cloned.add(item == null ? null : item.clone());
|
||||
}
|
||||
return cloned;
|
||||
}
|
||||
|
||||
private static String path(KitType type, int slot) {
|
||||
return "kits." + type.key() + "." + slot;
|
||||
}
|
||||
|
||||
private static String playerLayoutPath(UUID playerId, KitType type, int slot) {
|
||||
return "player-kit-layouts." + playerId + "." + type.key() + "." + slot;
|
||||
}
|
||||
|
||||
private static void validateSlot(int slot) {
|
||||
if (slot < MIN_SLOT || slot > MAX_SLOT) {
|
||||
throw new IllegalArgumentException("Slot must be between 1 and 3");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package de.winniepat.pierredufaulersack.kits;
|
||||
|
||||
public enum KitType {
|
||||
BOSS("boss"),
|
||||
HUNTER("hunter");
|
||||
|
||||
private final String key;
|
||||
|
||||
KitType(String key) {
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
public String key() {
|
||||
return key;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
package de.winniepat.pierredufaulersack.listeners;
|
||||
|
||||
import de.winniepat.pierredufaulersack.game.GameManager;
|
||||
import java.util.UUID;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.block.BlockPlaceEvent;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
|
||||
public class CobwebDecayListener implements Listener {
|
||||
|
||||
private static final long COBWEB_LIFETIME_TICKS = 20L * 10L;
|
||||
|
||||
private final JavaPlugin plugin;
|
||||
private final GameManager gameManager;
|
||||
|
||||
public CobwebDecayListener(JavaPlugin plugin, GameManager gameManager) {
|
||||
this.plugin = plugin;
|
||||
this.gameManager = gameManager;
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
||||
public void onPlace(BlockPlaceEvent event) {
|
||||
if (event.getBlockPlaced().getType() != Material.COBWEB) {
|
||||
return;
|
||||
}
|
||||
|
||||
Player player = event.getPlayer();
|
||||
if (gameManager.getRole(player.getUniqueId()) == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Location location = event.getBlockPlaced().getLocation();
|
||||
UUID worldId = location.getWorld() == null ? null : location.getWorld().getUID();
|
||||
int x = location.getBlockX();
|
||||
int y = location.getBlockY();
|
||||
int z = location.getBlockZ();
|
||||
|
||||
plugin.getServer().getScheduler().runTaskLater(plugin, () -> {
|
||||
if (worldId == null) {
|
||||
return;
|
||||
}
|
||||
World world = plugin.getServer().getWorld(worldId);
|
||||
if (world == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (world.getBlockAt(x, y, z).getType() == Material.COBWEB) {
|
||||
world.getBlockAt(x, y, z).setType(Material.AIR, false);
|
||||
}
|
||||
}, COBWEB_LIFETIME_TICKS);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
package de.winniepat.pierredufaulersack.listeners;
|
||||
|
||||
import de.winniepat.pierredufaulersack.game.GameManager;
|
||||
import org.bukkit.entity.*;
|
||||
import org.bukkit.event.*;
|
||||
import org.bukkit.event.entity.EntityDamageByEntityEvent;
|
||||
|
||||
public class FriendlyFireListener implements Listener {
|
||||
|
||||
private final GameManager gameManager;
|
||||
|
||||
public FriendlyFireListener(GameManager gameManager) {
|
||||
this.gameManager = gameManager;
|
||||
}
|
||||
|
||||
@EventHandler(ignoreCancelled = true)
|
||||
public void onDamage(EntityDamageByEntityEvent event) {
|
||||
if (!gameManager.isRunning()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Player attacker = asPlayerDamager(event.getDamager());
|
||||
if (attacker == null || !(event.getEntity() instanceof Player victim)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (gameManager.areBothHunters(attacker.getUniqueId(), victim.getUniqueId())) {
|
||||
event.setCancelled(true);
|
||||
}
|
||||
}
|
||||
|
||||
private Player asPlayerDamager(Entity entity) {
|
||||
if (entity instanceof Player player) {
|
||||
return player;
|
||||
}
|
||||
|
||||
if (entity instanceof Projectile projectile && projectile.getShooter() instanceof Player shooter) {
|
||||
return shooter;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
package de.winniepat.pierredufaulersack.listeners;
|
||||
|
||||
import de.winniepat.pierredufaulersack.game.*;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.*;
|
||||
import org.bukkit.event.player.*;
|
||||
|
||||
public class PlayerConnectionListener implements Listener {
|
||||
|
||||
private final GameManager gameManager;
|
||||
private final SidebarService sidebarService;
|
||||
|
||||
public PlayerConnectionListener(GameManager gameManager, SidebarService sidebarService) {
|
||||
this.gameManager = gameManager;
|
||||
this.sidebarService = sidebarService;
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onJoin(PlayerJoinEvent event) {
|
||||
sidebarService.showFor(event.getPlayer());
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onQuit(PlayerQuitEvent event) {
|
||||
gameManager.handlePlayerQuit(event.getPlayer());
|
||||
sidebarService.clearFor(event.getPlayer());
|
||||
|
||||
event.setQuitMessage(null);
|
||||
|
||||
for (Player p : Bukkit.getOnlinePlayers()) {
|
||||
p.sendMessage(Component.text("§4- §r" + event.getPlayer().getDisplayName()));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package de.winniepat.pierredufaulersack.listeners;
|
||||
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.entity.PlayerDeathEvent;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
public class PlayerDeathListener implements Listener {
|
||||
|
||||
@EventHandler
|
||||
public void onPlayerDeath(PlayerDeathEvent event) {
|
||||
event.setDeathMessage(null);
|
||||
|
||||
Player victim = event.getEntity();
|
||||
victim.getInventory().clear();
|
||||
victim.getInventory().setArmorContents(new ItemStack[0]);
|
||||
victim.getInventory().setItemInOffHand(new ItemStack(Material.AIR));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,757 @@
|
||||
package de.winniepat.pierredufaulersack.listeners;
|
||||
|
||||
import de.winniepat.pierredufaulersack.Pierredufaulersack;
|
||||
import de.winniepat.pierredufaulersack.game.GameManager;
|
||||
import de.winniepat.pierredufaulersack.kits.KitService;
|
||||
import de.winniepat.pierredufaulersack.kits.KitType;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.NamespacedKey;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
import org.bukkit.configuration.file.FileConfiguration;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.block.Action;
|
||||
import org.bukkit.event.inventory.InventoryClickEvent;
|
||||
import org.bukkit.event.inventory.InventoryCloseEvent;
|
||||
import org.bukkit.event.inventory.InventoryDragEvent;
|
||||
import org.bukkit.event.inventory.ClickType;
|
||||
import org.bukkit.event.inventory.InventoryAction;
|
||||
import org.bukkit.event.player.PlayerInteractEvent;
|
||||
import org.bukkit.event.player.PlayerJoinEvent;
|
||||
import org.bukkit.event.player.PlayerRespawnEvent;
|
||||
import org.bukkit.event.player.PlayerTeleportEvent;
|
||||
import org.bukkit.inventory.EquipmentSlot;
|
||||
import org.bukkit.inventory.Inventory;
|
||||
import org.bukkit.inventory.InventoryHolder;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.meta.ItemMeta;
|
||||
import org.bukkit.persistence.PersistentDataType;
|
||||
import org.bukkit.potion.PotionEffect;
|
||||
|
||||
public class PlayerJoinListener implements Listener {
|
||||
|
||||
private static final String SELECTOR_KEY = "queue_selector";
|
||||
private static final String QUEUE_ITEM_KEY = "queue_item";
|
||||
private static final String LEAVE_ITEM_KEY = "leave_item";
|
||||
private static final String KIT_EDITOR_KEY = "kit_editor";
|
||||
private static final String KIT_TYPE_ITEM_KEY = "kit_editor_type";
|
||||
private static final String KIT_SLOT_ITEM_KEY = "kit_editor_slot";
|
||||
private static final String LEAVE_ACTION = "leave";
|
||||
private static final String QUEUE_MENU_TITLE = "&8Queue Auswahl";
|
||||
private static final String KIT_TYPE_MENU_TITLE = "&8Kit Editor - Rolle";
|
||||
private static final int KIT_STORAGE_SIZE = 36;
|
||||
private static final int KIT_TOTAL_SIZE = 41;
|
||||
private static final int EDITOR_SIZE = 54;
|
||||
private static final int EDITOR_BOOTS_SLOT = 45;
|
||||
private static final int EDITOR_LEGGINGS_SLOT = 46;
|
||||
private static final int EDITOR_CHESTPLATE_SLOT = 47;
|
||||
private static final int EDITOR_HELMET_SLOT = 48;
|
||||
private static final int EDITOR_OFFHAND_SLOT = 50;
|
||||
|
||||
private final Pierredufaulersack plugin;
|
||||
private final GameManager gameManager;
|
||||
private final KitService kitService;
|
||||
private final NamespacedKey selectorItemKey;
|
||||
private final NamespacedKey queueItemKey;
|
||||
private final NamespacedKey leaveItemKey;
|
||||
private final NamespacedKey kitEditorItemKey;
|
||||
private final NamespacedKey kitTypeItemKey;
|
||||
private final NamespacedKey kitSlotItemKey;
|
||||
|
||||
public PlayerJoinListener(Pierredufaulersack plugin, GameManager gameManager, KitService kitService) {
|
||||
this.plugin = plugin;
|
||||
this.gameManager = gameManager;
|
||||
this.kitService = kitService;
|
||||
this.selectorItemKey = new NamespacedKey(plugin, SELECTOR_KEY);
|
||||
this.queueItemKey = new NamespacedKey(plugin, QUEUE_ITEM_KEY);
|
||||
this.leaveItemKey = new NamespacedKey(plugin, LEAVE_ITEM_KEY);
|
||||
this.kitEditorItemKey = new NamespacedKey(plugin, KIT_EDITOR_KEY);
|
||||
this.kitTypeItemKey = new NamespacedKey(plugin, KIT_TYPE_ITEM_KEY);
|
||||
this.kitSlotItemKey = new NamespacedKey(plugin, KIT_SLOT_ITEM_KEY);
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onPlayerJoin(PlayerJoinEvent event) {
|
||||
Player player = event.getPlayer();
|
||||
|
||||
gameManager.handlePlayerQuit(player);
|
||||
|
||||
event.setJoinMessage(null);
|
||||
|
||||
for (Player p : Bukkit.getOnlinePlayers()) {
|
||||
p.sendMessage(Component.text("§a+ §r" + player.getDisplayName()));
|
||||
}
|
||||
|
||||
Location lobby = loadLocation("locations.lobby");
|
||||
if (lobby != null) {
|
||||
player.teleport(lobby);
|
||||
}
|
||||
|
||||
player.getInventory().clear();
|
||||
player.getInventory().setArmorContents(new ItemStack[4]);
|
||||
player.getInventory().setItemInOffHand(null);
|
||||
for (PotionEffect effect : player.getActivePotionEffects()) {
|
||||
player.removePotionEffect(effect.getType());
|
||||
}
|
||||
|
||||
Bukkit.getScheduler().runTask(plugin, () -> giveLobbyItems(player));
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onRespawn(PlayerRespawnEvent event) {
|
||||
Player player = event.getPlayer();
|
||||
Bukkit.getScheduler().runTask(plugin, () -> {
|
||||
if (gameManager.getRole(player.getUniqueId()) != null) {
|
||||
return;
|
||||
}
|
||||
if (isLobbyLocation(player.getLocation()) || isLobbyLocation(event.getRespawnLocation())) {
|
||||
giveLobbyItems(player);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
||||
public void onTeleport(PlayerTeleportEvent event) {
|
||||
if (isLobbyLocation(event.getTo())) {
|
||||
Bukkit.getScheduler().runTask(plugin, () -> giveLobbyItems(event.getPlayer()));
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onSelectorUse(PlayerInteractEvent event) {
|
||||
if (event.getHand() != EquipmentSlot.HAND) {
|
||||
return;
|
||||
}
|
||||
|
||||
Action action = event.getAction();
|
||||
if (action != Action.RIGHT_CLICK_AIR && action != Action.RIGHT_CLICK_BLOCK) {
|
||||
return;
|
||||
}
|
||||
|
||||
ItemStack used = event.getItem();
|
||||
if (used == null) {
|
||||
used = event.getPlayer().getInventory().getItemInMainHand();
|
||||
}
|
||||
|
||||
Player player = event.getPlayer();
|
||||
if (gameManager.getRole(player.getUniqueId()) != null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isQueueSelector(used)) {
|
||||
event.setCancelled(true);
|
||||
Bukkit.getScheduler().runTask(plugin, () -> openQueueSelectorMenu(player));
|
||||
return;
|
||||
}
|
||||
|
||||
if (isKitEditorOpener(used)) {
|
||||
event.setCancelled(true);
|
||||
Bukkit.getScheduler().runTask(plugin, () -> openKitTypeMenu(player));
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(ignoreCancelled = true)
|
||||
public void onInventoryClick(InventoryClickEvent event) {
|
||||
Inventory topInventory = event.getView().getTopInventory();
|
||||
|
||||
if (isQueueMenu(topInventory)) {
|
||||
event.setCancelled(true);
|
||||
if (event.getClickedInventory() == null || event.getClickedInventory() != topInventory) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(event.getWhoClicked() instanceof Player player)) {
|
||||
return;
|
||||
}
|
||||
|
||||
ItemStack clicked = event.getCurrentItem();
|
||||
if (clicked == null || !clicked.hasItemMeta()) {
|
||||
return;
|
||||
}
|
||||
|
||||
ItemMeta meta = clicked.getItemMeta();
|
||||
if (meta == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
String queueId = meta.getPersistentDataContainer().get(queueItemKey, PersistentDataType.STRING);
|
||||
String leaveAction = meta.getPersistentDataContainer().get(leaveItemKey, PersistentDataType.STRING);
|
||||
|
||||
if (LEAVE_ACTION.equals(leaveAction)) {
|
||||
gameManager.leave(player);
|
||||
gameManager.clearSelectedQueue(player);
|
||||
giveLobbyItems(player);
|
||||
player.closeInventory();
|
||||
return;
|
||||
}
|
||||
|
||||
if (queueId == null || queueId.isBlank()) {
|
||||
return;
|
||||
}
|
||||
|
||||
gameManager.selectQueue(player, queueId);
|
||||
gameManager.join(player, queueId);
|
||||
giveLobbyItems(player);
|
||||
player.closeInventory();
|
||||
return;
|
||||
}
|
||||
|
||||
if (isKitTypeMenu(topInventory)) {
|
||||
event.setCancelled(true);
|
||||
if (event.getClickedInventory() == null || event.getClickedInventory() != topInventory) {
|
||||
return;
|
||||
}
|
||||
if (!(event.getWhoClicked() instanceof Player player)) {
|
||||
return;
|
||||
}
|
||||
|
||||
ItemStack clicked = event.getCurrentItem();
|
||||
if (clicked == null || !clicked.hasItemMeta()) {
|
||||
return;
|
||||
}
|
||||
ItemMeta meta = clicked.getItemMeta();
|
||||
if (meta == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
String rawType = meta.getPersistentDataContainer().get(kitTypeItemKey, PersistentDataType.STRING);
|
||||
KitType type = parseKitType(rawType);
|
||||
if (type == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
openKitSlotMenu(player, type);
|
||||
return;
|
||||
}
|
||||
|
||||
if (topInventory != null && topInventory.getHolder() instanceof KitSlotMenuHolder slotHolder) {
|
||||
event.setCancelled(true);
|
||||
if (event.getClickedInventory() == null || event.getClickedInventory() != topInventory) {
|
||||
return;
|
||||
}
|
||||
if (!(event.getWhoClicked() instanceof Player player)) {
|
||||
return;
|
||||
}
|
||||
|
||||
ItemStack clicked = event.getCurrentItem();
|
||||
if (clicked == null || !clicked.hasItemMeta()) {
|
||||
return;
|
||||
}
|
||||
ItemMeta meta = clicked.getItemMeta();
|
||||
if (meta == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Integer slot = meta.getPersistentDataContainer().get(kitSlotItemKey, PersistentDataType.INTEGER);
|
||||
if (slot == null || slot < 1 || slot > 3) {
|
||||
return;
|
||||
}
|
||||
|
||||
openKitEditor(player, slotHolder.type(), slot);
|
||||
return;
|
||||
}
|
||||
|
||||
if (topInventory.getHolder() instanceof KitEditorMenuHolder) {
|
||||
if (event.getClickedInventory() == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.getClickedInventory() != topInventory) {
|
||||
event.setCancelled(true);
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.isShiftClick()
|
||||
|| event.getAction() == InventoryAction.MOVE_TO_OTHER_INVENTORY
|
||||
|| event.getAction() == InventoryAction.DROP_ALL_SLOT
|
||||
|| event.getAction() == InventoryAction.DROP_ONE_SLOT
|
||||
|| event.getAction() == InventoryAction.DROP_ALL_CURSOR
|
||||
|| event.getAction() == InventoryAction.DROP_ONE_CURSOR
|
||||
|| event.getClick() == ClickType.NUMBER_KEY
|
||||
|| event.getClick() == ClickType.SWAP_OFFHAND
|
||||
|| event.getClick() == ClickType.DOUBLE_CLICK
|
||||
|| event.getClick() == ClickType.DROP
|
||||
|| event.getClick() == ClickType.CONTROL_DROP) {
|
||||
event.setCancelled(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(ignoreCancelled = true)
|
||||
public void onInventoryDrag(InventoryDragEvent event) {
|
||||
Inventory topInventory = event.getView().getTopInventory();
|
||||
if (isQueueMenu(topInventory)
|
||||
|| isKitTypeMenu(topInventory)
|
||||
|| topInventory.getHolder() instanceof KitSlotMenuHolder) {
|
||||
event.setCancelled(true);
|
||||
return;
|
||||
}
|
||||
|
||||
if (topInventory.getHolder() instanceof KitEditorMenuHolder) {
|
||||
int topSize = topInventory.getSize();
|
||||
for (int rawSlot : event.getRawSlots()) {
|
||||
if (rawSlot >= topSize) {
|
||||
event.setCancelled(true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onKitEditorClose(InventoryCloseEvent event) {
|
||||
Inventory inventory = event.getInventory();
|
||||
if (!(inventory.getHolder() instanceof KitEditorMenuHolder editorHolder)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.getPlayer() instanceof Player player) {
|
||||
ItemStack cursor = player.getItemOnCursor();
|
||||
if (hasItem(cursor)) {
|
||||
ItemStack leftover = placeIntoEditableSlots(inventory, cursor.clone());
|
||||
if (hasItem(leftover)) {
|
||||
player.getWorld().dropItemNaturally(player.getLocation(), leftover);
|
||||
}
|
||||
player.setItemOnCursor(null);
|
||||
}
|
||||
|
||||
boolean saved = kitService.setPlayerLayout(
|
||||
player.getUniqueId(),
|
||||
editorHolder.type(),
|
||||
editorHolder.slot(),
|
||||
extractKitFromEditor(inventory));
|
||||
|
||||
if (!saved) {
|
||||
player.sendMessage(color("&8[&6BossHunt&8] &cKein Basis-Kit vorhanden. Layout nicht gespeichert."));
|
||||
return;
|
||||
}
|
||||
|
||||
player.sendMessage(color("&8[&6BossHunt&8] &aKit &e" + editorHolder.slot() + " &afür &e"
|
||||
+ typeDisplayName(editorHolder.type()) + " &aAnordnung gespeichert."));
|
||||
return;
|
||||
}
|
||||
|
||||
// Non-player close is rare, but keep layout persistence consistent.
|
||||
kitService.setPlayerLayout(
|
||||
event.getPlayer().getUniqueId(),
|
||||
editorHolder.type(),
|
||||
editorHolder.slot(),
|
||||
extractKitFromEditor(inventory));
|
||||
}
|
||||
|
||||
private void giveLobbyItems(Player player) {
|
||||
if (gameManager.getRole(player.getUniqueId()) != null) {
|
||||
return;
|
||||
}
|
||||
|
||||
ItemStack selector = new ItemStack(Material.COMPASS);
|
||||
ItemMeta selectorMeta = selector.getItemMeta();
|
||||
if (selectorMeta != null) {
|
||||
String selected = gameManager.getSelectedQueue(player.getUniqueId());
|
||||
String selectedText = selected == null || selected.isBlank() ? "None" : selected;
|
||||
selectorMeta.setDisplayName(color("&6Queue Auswahl"));
|
||||
selectorMeta.setLore(List.of(
|
||||
color("&7Gerade: &e" + selectedText),
|
||||
color("&7Clicke um das Menü zu öffnen")));
|
||||
selectorMeta.getPersistentDataContainer().set(selectorItemKey, PersistentDataType.BYTE, (byte) 1);
|
||||
selector.setItemMeta(selectorMeta);
|
||||
}
|
||||
|
||||
ItemStack kitEditor = new ItemStack(Material.CHEST);
|
||||
ItemMeta editorMeta = kitEditor.getItemMeta();
|
||||
if (editorMeta != null) {
|
||||
editorMeta.setDisplayName(color("&dKit Editor"));
|
||||
editorMeta.setLore(List.of(
|
||||
color("&7Clicke um Boss/Hunter Kits"),
|
||||
color("&7für Slot 1-3 zu bearbeiten")));
|
||||
editorMeta.getPersistentDataContainer().set(kitEditorItemKey, PersistentDataType.BYTE, (byte) 1);
|
||||
kitEditor.setItemMeta(editorMeta);
|
||||
}
|
||||
|
||||
player.getInventory().setItem(4, selector);
|
||||
player.getInventory().setItem(6, kitEditor);
|
||||
}
|
||||
|
||||
private boolean isQueueSelector(ItemStack item) {
|
||||
if (item == null || item.getType() != Material.COMPASS || !item.hasItemMeta()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ItemMeta meta = item.getItemMeta();
|
||||
if (meta == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Byte marker = meta.getPersistentDataContainer().get(selectorItemKey, PersistentDataType.BYTE);
|
||||
if (marker != null && marker == (byte) 1) {
|
||||
return true;
|
||||
}
|
||||
|
||||
String displayName = meta.getDisplayName();
|
||||
return displayName != null && displayName.equals(color("&6Queue Selector"));
|
||||
}
|
||||
|
||||
private boolean isKitEditorOpener(ItemStack item) {
|
||||
if (item == null || item.getType() != Material.CHEST || !item.hasItemMeta()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ItemMeta meta = item.getItemMeta();
|
||||
if (meta == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Byte marker = meta.getPersistentDataContainer().get(kitEditorItemKey, PersistentDataType.BYTE);
|
||||
return marker != null && marker == (byte) 1;
|
||||
}
|
||||
|
||||
private boolean isLobbyLocation(Location location) {
|
||||
Location lobby = loadLocation("locations.lobby");
|
||||
if (location == null || lobby == null) {
|
||||
return false;
|
||||
}
|
||||
if (location.getWorld() == null || lobby.getWorld() == null) {
|
||||
return false;
|
||||
}
|
||||
if (!location.getWorld().getUID().equals(lobby.getWorld().getUID())) {
|
||||
return false;
|
||||
}
|
||||
return location.distanceSquared(lobby) <= 4.0;
|
||||
}
|
||||
|
||||
private void openQueueSelectorMenu(Player player) {
|
||||
List<String> queueIds = new ArrayList<>(gameManager.queueIds());
|
||||
if (queueIds.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
Collections.sort(queueIds);
|
||||
|
||||
int requiredSlots = queueIds.size() + 1;
|
||||
int size = 9;
|
||||
while (size < requiredSlots) {
|
||||
size += 9;
|
||||
}
|
||||
|
||||
Inventory menu = Bukkit.createInventory(new QueueMenuHolder(), size, color(QUEUE_MENU_TITLE));
|
||||
String selectedQueue = gameManager.getSelectedQueue(player.getUniqueId());
|
||||
|
||||
int slot = 0;
|
||||
for (String queueId : queueIds) {
|
||||
if (slot == 8) {
|
||||
slot++;
|
||||
}
|
||||
if (slot >= size) {
|
||||
break;
|
||||
}
|
||||
boolean selected = queueId.equals(selectedQueue);
|
||||
menu.setItem(slot, createQueueMenuItem(queueId, selected));
|
||||
slot++;
|
||||
}
|
||||
|
||||
if (size > 8) {
|
||||
menu.setItem(8, createLeaveMenuItem());
|
||||
}
|
||||
|
||||
player.openInventory(menu);
|
||||
}
|
||||
|
||||
private void openKitTypeMenu(Player player) {
|
||||
Inventory menu = Bukkit.createInventory(new KitTypeMenuHolder(), 9, color(KIT_TYPE_MENU_TITLE));
|
||||
menu.setItem(3, createKitTypeMenuItem(KitType.BOSS));
|
||||
menu.setItem(5, createKitTypeMenuItem(KitType.HUNTER));
|
||||
player.openInventory(menu);
|
||||
}
|
||||
|
||||
private void openKitSlotMenu(Player player, KitType type) {
|
||||
Inventory menu = Bukkit.createInventory(new KitSlotMenuHolder(type), 9,
|
||||
color("&8Kit Editor - " + typeDisplayName(type)));
|
||||
menu.setItem(2, createKitSlotMenuItem(type, 1));
|
||||
menu.setItem(4, createKitSlotMenuItem(type, 2));
|
||||
menu.setItem(6, createKitSlotMenuItem(type, 3));
|
||||
player.openInventory(menu);
|
||||
}
|
||||
|
||||
private void openKitEditor(Player player, KitType type, int slot) {
|
||||
Inventory editor = Bukkit.createInventory(new KitEditorMenuHolder(type, slot), EDITOR_SIZE,
|
||||
color("&8Edit " + typeDisplayName(type) + " Kit " + slot));
|
||||
|
||||
kitService.getKitForPlayer(player.getUniqueId(), type, slot)
|
||||
.ifPresent(kit -> editor.setContents(buildEditorContents(kit)));
|
||||
|
||||
player.openInventory(editor);
|
||||
player.sendMessage(color("&8[&6BossHunt&8] &7Bearbeite das Kit und schließe das Inventar zum Speichern."));
|
||||
player.sendMessage(color("&8[&6BossHunt&8] &7Armor: Slots 46-49, Offhand: Slot 51."));
|
||||
}
|
||||
|
||||
private ItemStack createQueueMenuItem(String queueId, boolean selected) {
|
||||
Material material = selected ? Material.LIME_WOOL : Material.GRAY_WOOL;
|
||||
ItemStack item = new ItemStack(material);
|
||||
ItemMeta meta = item.getItemMeta();
|
||||
if (meta == null) {
|
||||
return item;
|
||||
}
|
||||
|
||||
meta.setDisplayName(color((selected ? "&a" : "&e") + queueId));
|
||||
meta.setLore(List.of(
|
||||
color("&7Spieler: &f" + gameManager.lobbySize(queueId) + "&7/&f" + gameManager.maxPlayers()),
|
||||
color("&7Status: &f" + gameManager.getState(queueId).name()),
|
||||
color(selected ? "&aGerade ausgewählt" : "&eClicke zum auswählen")));
|
||||
meta.getPersistentDataContainer().set(queueItemKey, PersistentDataType.STRING, queueId);
|
||||
|
||||
item.setItemMeta(meta);
|
||||
return item;
|
||||
}
|
||||
|
||||
private ItemStack createLeaveMenuItem() {
|
||||
ItemStack item = new ItemStack(Material.BARRIER);
|
||||
ItemMeta meta = item.getItemMeta();
|
||||
if (meta == null) {
|
||||
return item;
|
||||
}
|
||||
|
||||
meta.setDisplayName(color("&cLeave Queue/Lobby"));
|
||||
meta.setLore(List.of(
|
||||
color("&7Click um die queue zu verlassen")));
|
||||
meta.getPersistentDataContainer().set(leaveItemKey, PersistentDataType.STRING, LEAVE_ACTION);
|
||||
|
||||
item.setItemMeta(meta);
|
||||
return item;
|
||||
}
|
||||
|
||||
private ItemStack createKitTypeMenuItem(KitType type) {
|
||||
Material material = type == KitType.BOSS ? Material.NETHERITE_CHESTPLATE : Material.IRON_CHESTPLATE;
|
||||
ItemStack item = new ItemStack(material);
|
||||
ItemMeta meta = item.getItemMeta();
|
||||
if (meta == null) {
|
||||
return item;
|
||||
}
|
||||
|
||||
String display = typeDisplayName(type);
|
||||
meta.setDisplayName(color("&e" + display));
|
||||
meta.setLore(List.of(color("&7Clicke um " + display + " Kits zu bearbeiten")));
|
||||
meta.getPersistentDataContainer().set(kitTypeItemKey, PersistentDataType.STRING, type.key());
|
||||
item.setItemMeta(meta);
|
||||
return item;
|
||||
}
|
||||
|
||||
private ItemStack createKitSlotMenuItem(KitType type, int slot) {
|
||||
boolean hasKit = kitService.hasKit(type, slot);
|
||||
ItemStack item = new ItemStack(hasKit ? Material.LIME_SHULKER_BOX : Material.GRAY_SHULKER_BOX);
|
||||
ItemMeta meta = item.getItemMeta();
|
||||
if (meta == null) {
|
||||
return item;
|
||||
}
|
||||
|
||||
meta.setDisplayName(color("&eKit " + slot));
|
||||
meta.setLore(List.of(
|
||||
color(hasKit ? "&aBereits gespeichert" : "&7Noch leer"),
|
||||
color("&7Clicke zum Bearbeiten")));
|
||||
meta.getPersistentDataContainer().set(kitSlotItemKey, PersistentDataType.INTEGER, slot);
|
||||
|
||||
item.setItemMeta(meta);
|
||||
return item;
|
||||
}
|
||||
|
||||
private KitType parseKitType(String raw) {
|
||||
if (raw == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
for (KitType type : KitType.values()) {
|
||||
if (type.key().equalsIgnoreCase(raw)) {
|
||||
return type;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private String typeDisplayName(KitType type) {
|
||||
return type == KitType.BOSS ? "Boss" : "Hunter";
|
||||
}
|
||||
|
||||
private ItemStack[] buildEditorContents(List<ItemStack> kit) {
|
||||
ItemStack[] editor = new ItemStack[EDITOR_SIZE];
|
||||
for (int i = 0; i < Math.min(KIT_STORAGE_SIZE, kit.size()); i++) {
|
||||
ItemStack item = kit.get(i);
|
||||
editor[i] = item == null ? null : item.clone();
|
||||
}
|
||||
|
||||
editor[EDITOR_BOOTS_SLOT] = cloneAt(kit, 36);
|
||||
editor[EDITOR_LEGGINGS_SLOT] = cloneAt(kit, 37);
|
||||
editor[EDITOR_CHESTPLATE_SLOT] = cloneAt(kit, 38);
|
||||
editor[EDITOR_HELMET_SLOT] = cloneAt(kit, 39);
|
||||
editor[EDITOR_OFFHAND_SLOT] = cloneAt(kit, 40);
|
||||
return editor;
|
||||
}
|
||||
|
||||
private ItemStack[] extractKitFromEditor(Inventory inventory) {
|
||||
ItemStack[] editorContents = inventory.getContents();
|
||||
ItemStack[] kit = new ItemStack[KIT_TOTAL_SIZE];
|
||||
for (int i = 0; i < KIT_STORAGE_SIZE; i++) {
|
||||
ItemStack item = editorContents[i];
|
||||
kit[i] = item == null ? null : item.clone();
|
||||
}
|
||||
|
||||
kit[36] = cloneAt(editorContents, EDITOR_BOOTS_SLOT);
|
||||
kit[37] = cloneAt(editorContents, EDITOR_LEGGINGS_SLOT);
|
||||
kit[38] = cloneAt(editorContents, EDITOR_CHESTPLATE_SLOT);
|
||||
kit[39] = cloneAt(editorContents, EDITOR_HELMET_SLOT);
|
||||
kit[40] = cloneAt(editorContents, EDITOR_OFFHAND_SLOT);
|
||||
return kit;
|
||||
}
|
||||
|
||||
private ItemStack cloneAt(List<ItemStack> items, int index) {
|
||||
if (index < 0 || index >= items.size()) {
|
||||
return null;
|
||||
}
|
||||
ItemStack item = items.get(index);
|
||||
return item == null ? null : item.clone();
|
||||
}
|
||||
|
||||
private ItemStack cloneAt(ItemStack[] items, int index) {
|
||||
if (index < 0 || index >= items.length) {
|
||||
return null;
|
||||
}
|
||||
ItemStack item = items[index];
|
||||
return item == null ? null : item.clone();
|
||||
}
|
||||
|
||||
private boolean hasItem(ItemStack item) {
|
||||
return item != null && item.getType() != Material.AIR;
|
||||
}
|
||||
|
||||
private ItemStack placeIntoEditableSlots(Inventory inventory, ItemStack stack) {
|
||||
ItemStack remaining = stack;
|
||||
|
||||
for (int slot = 0; slot < KIT_STORAGE_SIZE; slot++) {
|
||||
if (remaining == null || remaining.getType() == Material.AIR) {
|
||||
return null;
|
||||
}
|
||||
|
||||
ItemStack existing = inventory.getItem(slot);
|
||||
if (existing == null || existing.getType() == Material.AIR) {
|
||||
inventory.setItem(slot, remaining);
|
||||
return null;
|
||||
}
|
||||
|
||||
if (existing.isSimilar(remaining) && existing.getAmount() < existing.getMaxStackSize()) {
|
||||
int free = existing.getMaxStackSize() - existing.getAmount();
|
||||
int move = Math.min(free, remaining.getAmount());
|
||||
existing.setAmount(existing.getAmount() + move);
|
||||
remaining.setAmount(remaining.getAmount() - move);
|
||||
}
|
||||
}
|
||||
|
||||
return remaining;
|
||||
}
|
||||
|
||||
private boolean isQueueMenu(Inventory inventory) {
|
||||
if (inventory == null) {
|
||||
return false;
|
||||
}
|
||||
return inventory.getHolder() instanceof QueueMenuHolder;
|
||||
}
|
||||
|
||||
private boolean isKitTypeMenu(Inventory inventory) {
|
||||
if (inventory == null) {
|
||||
return false;
|
||||
}
|
||||
return inventory.getHolder() instanceof KitTypeMenuHolder;
|
||||
}
|
||||
|
||||
private static final class QueueMenuHolder implements InventoryHolder {
|
||||
@Override
|
||||
public Inventory getInventory() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static final class KitTypeMenuHolder implements InventoryHolder {
|
||||
@Override
|
||||
public Inventory getInventory() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static final class KitSlotMenuHolder implements InventoryHolder {
|
||||
private final KitType type;
|
||||
|
||||
private KitSlotMenuHolder(KitType type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
private KitType type() {
|
||||
return type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Inventory getInventory() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static final class KitEditorMenuHolder implements InventoryHolder {
|
||||
private final KitType type;
|
||||
private final int slot;
|
||||
|
||||
private KitEditorMenuHolder(KitType type, int slot) {
|
||||
this.type = type;
|
||||
this.slot = slot;
|
||||
}
|
||||
|
||||
private KitType type() {
|
||||
return type;
|
||||
}
|
||||
|
||||
private int slot() {
|
||||
return slot;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Inventory getInventory() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private String color(String text) {
|
||||
return ChatColor.translateAlternateColorCodes('&', text);
|
||||
}
|
||||
|
||||
private Location loadLocation(String path) {
|
||||
FileConfiguration config = plugin.getConfig();
|
||||
ConfigurationSection section = config.getConfigurationSection(path);
|
||||
if (section == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String worldName = section.getString("world");
|
||||
if (worldName == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
World world = Bukkit.getWorld(worldName);
|
||||
if (world == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new Location(
|
||||
world,
|
||||
section.getDouble("x"),
|
||||
section.getDouble("y"),
|
||||
section.getDouble("z"),
|
||||
(float) section.getDouble("yaw"),
|
||||
(float) section.getDouble("pitch"));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package de.winniepat.pierredufaulersack.listeners;
|
||||
|
||||
import de.winniepat.pierredufaulersack.game.GameManager;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.*;
|
||||
import org.bukkit.event.entity.PlayerDeathEvent;
|
||||
import org.bukkit.event.player.PlayerRespawnEvent;
|
||||
|
||||
public class RoundOutcomeListener implements Listener {
|
||||
|
||||
private final GameManager gameManager;
|
||||
|
||||
public RoundOutcomeListener(GameManager gameManager) {
|
||||
this.gameManager = gameManager;
|
||||
}
|
||||
|
||||
@EventHandler(ignoreCancelled = true)
|
||||
public void onDeath(PlayerDeathEvent event) {
|
||||
|
||||
Player victim = event.getEntity();
|
||||
Player killer = victim.getKiller();
|
||||
if (killer == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
gameManager.handleKill(killer, victim);
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onRespawn(PlayerRespawnEvent event) {
|
||||
Location lobby = gameManager.consumePendingLobbyRespawn(event.getPlayer().getUniqueId());
|
||||
if (lobby != null) {
|
||||
event.setRespawnLocation(lobby);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
package de.winniepat.pierredufaulersack.listeners;
|
||||
|
||||
import de.winniepat.pierredufaulersack.game.GameManager;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.player.PlayerBucketEmptyEvent;
|
||||
|
||||
public class RoundWaterCleanupListener implements Listener {
|
||||
|
||||
private final GameManager gameManager;
|
||||
|
||||
public RoundWaterCleanupListener(GameManager gameManager) {
|
||||
this.gameManager = gameManager;
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
||||
public void onWaterBucketEmpty(PlayerBucketEmptyEvent event) {
|
||||
if (event.getBucket() != Material.WATER_BUCKET) {
|
||||
return;
|
||||
}
|
||||
|
||||
Player player = event.getPlayer();
|
||||
if (gameManager.getRole(player.getUniqueId()) == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Block placedAt = event.getBlockClicked().getRelative(event.getBlockFace());
|
||||
gameManager.trackRoundWaterPlacement(player, placedAt.getLocation());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
max-players: 5
|
||||
max-concurrent-games: 3
|
||||
hunter-kit-max-duplicates: 2
|
||||
|
||||
countdown:
|
||||
seconds: 10
|
||||
full-seconds: 10
|
||||
not-full-seconds: 20
|
||||
min-players: 2
|
||||
announce-every-second: true
|
||||
|
||||
sounds:
|
||||
countdown:
|
||||
sound: BLOCK_NOTE_BLOCK_HAT
|
||||
volume: 1.0
|
||||
pitch: 1.4
|
||||
countdown-final:
|
||||
sound: BLOCK_NOTE_BLOCK_PLING
|
||||
volume: 1.0
|
||||
pitch: 1.8
|
||||
start:
|
||||
sound: ENTITY_PLAYER_LEVELUP
|
||||
volume: 1.0
|
||||
pitch: 1.0
|
||||
stop:
|
||||
sound: ENTITY_ITEM_BREAK
|
||||
volume: 1.0
|
||||
pitch: 1.0
|
||||
killed:
|
||||
sound: ENTITY_PLAYER_HURT
|
||||
volume: 1.0
|
||||
pitch: 1.0
|
||||
hunter-win:
|
||||
sound: ENTITY_PLAYER_LEVELUP
|
||||
volume: 1.0
|
||||
pitch: 1.2
|
||||
boss-lose:
|
||||
sound: ENTITY_VILLAGER_NO
|
||||
volume: 1.0
|
||||
pitch: 1.0
|
||||
boss-win:
|
||||
sound: ENTITY_ENDER_DRAGON_GROWL
|
||||
volume: 1.0
|
||||
pitch: 1.0
|
||||
|
||||
kit-chances:
|
||||
boss:
|
||||
1: 40
|
||||
2: 40
|
||||
3: 20
|
||||
hunter:
|
||||
1: 40
|
||||
2: 40
|
||||
3: 20
|
||||
|
||||
locations:
|
||||
lobby: {}
|
||||
|
||||
arenas:
|
||||
game1: {}
|
||||
game2: {}
|
||||
game3: {}
|
||||
|
||||
kits:
|
||||
boss: {}
|
||||
hunter: {}
|
||||
@@ -0,0 +1,26 @@
|
||||
name: Pierredufaulersack
|
||||
version: '${version}'
|
||||
main: de.winniepat.pierredufaulersack.Pierredufaulersack
|
||||
api-version: '1.21'
|
||||
authors: [ WinniePatGG ]
|
||||
website: https://winniepat.de
|
||||
description: Plugin für Boss Hunt Minigame by WinniePatGG
|
||||
depend: [ LuckPerms ]
|
||||
|
||||
commands:
|
||||
bosshunt:
|
||||
description: Hauptbefehl für Boss Hunt
|
||||
usage: /bosshunt <queues|select|join|leave|start|stop|setlobby|setarena|status>
|
||||
bosskit:
|
||||
description: Verwalte Boss Kits
|
||||
usage: /bosskit <add|set|del|list> [1-3]
|
||||
permission: pierredufaulersack.admin
|
||||
hunterkit:
|
||||
description: Verwalte Hunter Kits
|
||||
usage: /hunterkit <add|set|del|list> [1-3]
|
||||
permission: pierredufaulersack.admin
|
||||
|
||||
permissions:
|
||||
pierredufaulersack.admin:
|
||||
description: Admin Rechte für Boss Hunt
|
||||
default: op
|
||||
Reference in New Issue
Block a user