diff --git a/README.md b/README.md index e4ea120..4eab072 100644 --- a/README.md +++ b/README.md @@ -12,16 +12,16 @@ **ForceBattle** is a multiplayer gamemode where players compete to complete randomized objectives and earn points. The player with the most points after the timer ends wins the battle! -Current supported Minecraft version: 1.21.8 +Currently supports Minecraft version: 1.21.8 **Objective types include:** -- 🔹 Collect an item -- 🔹 Kill a mob -- 🔹 Discover a biome -- 🔹 Complete an advancement -- 🔹 Reach a certain height -- 🔹 Reach a certain coordinate -- 🔹 Discover a certain structure +- Collect an item +- Kill a mob +- Discover a biome +- Complete an advancement +- Reach a certain height +- Reach a certain coordinate +- Discover a certain structure Objective types can be enabled or disabled individually via the plugin's settings menu. @@ -39,23 +39,23 @@ Objective types can be enabled or disabled individually via the plugin's setting ### 📋 Commands -| Command | Description | -|:----------------------------|:-----------------------------------------------------------| -| `/backpack ` | Opens the personal or teammates backpack (can be disabled) | -| `/displayresults` | Show the final leaderboard (player, team) | -| `/exclude ` | Exclude a player from the battle | -| `/help` | Display a list of available commands | -| `/joker ` | Adjust jokers for a player | -| `/language` | Open the language selection menu | -| `/points ` | Modify a player's points | -| `/randomteams ` | Creates random teams with a specific size | -| `/recipe ` | Displays the recipe of an item | -| `/reset [player]` | Reset the battle or a specific player | -| `/result ` | Show detailed results for a player | -| `/settings` | Open the plugin's settings menu | -| `/skip ` | Skip a player's current objective (for admins) | -| `/team` | Manage teams | -| `/timer` | Control the timer (start, stop, set duration) | +| Command | Description | +|:----------------------------|:------------------------------------------------------| +| `/backpack` | Opens the personal or team backpack (can be disabled) | +| `/displayresults` | Show the final leaderboard (player, team) | +| `/exclude ` | Exclude a player from the battle | +| `/help` | Display a list of available commands | +| `/joker ` | Adjust jokers for a player | +| `/language` | Open the language selection menu | +| `/points ` | Modify a player's points | +| `/randomteams ` | Creates random teams with a specific size | +| `/recipe ` | Displays the recipe of an item | +| `/reset [player]` | Reset the battle or a specific player | +| `/result ` | Show detailed results for a player | +| `/settings` | Open the plugin's settings menu | +| `/skip ` | Skip a player's current objective (for admins) | +| `/team` | Manage teams | +| `/timer` | Control the timer (start, stop, set duration) | --- diff --git a/src/main/java/net/fameless/forcebattle/ForceBattle.java b/src/main/java/net/fameless/forcebattle/ForceBattle.java index 8835c96..1ba98b6 100644 --- a/src/main/java/net/fameless/forcebattle/ForceBattle.java +++ b/src/main/java/net/fameless/forcebattle/ForceBattle.java @@ -9,13 +9,12 @@ import net.fameless.forcebattle.command.framework.PermissionManager; import net.fameless.forcebattle.configuration.PluginUpdater; import net.fameless.forcebattle.configuration.SettingsFile; -import net.fameless.forcebattle.game.GameListener; import net.fameless.forcebattle.game.NametagManager; import net.fameless.forcebattle.game.ObjectiveManager; import net.fameless.forcebattle.game.Timer; -import net.fameless.forcebattle.gui.GUIListener; import net.fameless.forcebattle.scoreboard.ScoreboardManager; import net.fameless.forcebattle.util.BukkitUtil; +import net.fameless.forcebattle.util.EventRegistrar; import net.fameless.forcebattle.util.ResourceUtil; import net.kyori.adventure.text.Component; import org.bstats.bukkit.Metrics; @@ -55,8 +54,7 @@ public void onEnable() { NametagManager.runTask(); - Bukkit.getPluginManager().registerEvents(new GameListener(), this); - Bukkit.getPluginManager().registerEvents(new GUIListener(), this); + EventRegistrar.registerAll(this, "net.fameless.forcebattle"); CommandHandler.registerAll(Command.COMMANDS); PermissionManager.registerPermissions(); diff --git a/src/main/java/net/fameless/forcebattle/command/BackpackCommand.java b/src/main/java/net/fameless/forcebattle/command/BackpackCommand.java index 10692d6..092815b 100644 --- a/src/main/java/net/fameless/forcebattle/command/BackpackCommand.java +++ b/src/main/java/net/fameless/forcebattle/command/BackpackCommand.java @@ -5,12 +5,10 @@ import net.fameless.forcebattle.command.framework.Command; import net.fameless.forcebattle.command.framework.CommandCaller; import net.fameless.forcebattle.configuration.SettingsManager; +import net.fameless.forcebattle.game.GameListener; import net.fameless.forcebattle.player.BattlePlayer; -import net.fameless.forcebattle.util.StringUtility; -import net.fameless.forcebattle.util.TabCompletions; import org.jetbrains.annotations.NotNull; -import java.util.ArrayList; import java.util.List; import java.util.Optional; @@ -21,7 +19,7 @@ public BackpackCommand() { "backpack", List.of("bp"), CallerType.PLAYER, - "/backpack ", + "/backpack", "forcebattle.backpack", "Command to open the backpack" ); @@ -33,29 +31,15 @@ public void executeCommand(CommandCaller caller, String[] args) { caller.sendMessage(Caption.of("error.backpacks_disabled")); return; } + if (GameListener.startPhase) return; Optional senderOpt = BattlePlayer.adapt(caller.getName()); - if (args.length > 0 && !args[0].isEmpty()) { - Optional targetOpt = BattlePlayer.adapt(args[0]); - - if (senderOpt.isPresent() && targetOpt.isPresent() && senderOpt.get().isInTeam() && targetOpt.get().isInTeam() && - senderOpt.get().getTeam() == targetOpt.get().getTeam()) { - targetOpt.get().openBackpack(senderOpt.get()); - return; - } - - caller.sendMessage(Caption.of("error.not_same_team")); - } else { - senderOpt.ifPresent(BattlePlayer::openBackpack); - } + senderOpt.ifPresent(BattlePlayer::openBackpack); } @Override public List tabComplete(CommandCaller caller, String @NotNull [] args) { - if (args.length == 1) { - return StringUtility.copyPartialMatches(args[0], TabCompletions.getPlayerNamesTabCompletions(), new ArrayList<>()); - } return List.of(); } } diff --git a/src/main/java/net/fameless/forcebattle/command/RandomTeamsCommand.java b/src/main/java/net/fameless/forcebattle/command/RandomTeamsCommand.java index 947d442..b2686da 100644 --- a/src/main/java/net/fameless/forcebattle/command/RandomTeamsCommand.java +++ b/src/main/java/net/fameless/forcebattle/command/RandomTeamsCommand.java @@ -72,13 +72,6 @@ protected void executeCommand(final CommandCaller caller, final String[] args) { caller.sendMessage(Caption.of("notification.randomteams_successfully_created", TagResolver.resolver("amount", Tag.inserting(Component.text(String.valueOf(amountOfTeams)))))); - - for (Team team : Team.teams) { - List names = new ArrayList<>(); - for (BattlePlayer player : team.getPlayers()) { - names.add(player.getName() + ", "); - } - } } } diff --git a/src/main/java/net/fameless/forcebattle/configuration/SettingsManager.java b/src/main/java/net/fameless/forcebattle/configuration/SettingsManager.java index a7cc84a..2226f68 100644 --- a/src/main/java/net/fameless/forcebattle/configuration/SettingsManager.java +++ b/src/main/java/net/fameless/forcebattle/configuration/SettingsManager.java @@ -94,7 +94,7 @@ public enum Setting { EXCLUDE_ARMOR_TEMPLATES, EXCLUDE_POTTERY_SHERDS, EXCLUDE_ORES, - EXCLUDE_END_ITEMS, + EXCLUDE_END, EXCLUDE_TRIAL_ITEMS, } diff --git a/src/main/java/net/fameless/forcebattle/game/GameListener.java b/src/main/java/net/fameless/forcebattle/game/GameListener.java index b68ccdc..6f88c6a 100644 --- a/src/main/java/net/fameless/forcebattle/game/GameListener.java +++ b/src/main/java/net/fameless/forcebattle/game/GameListener.java @@ -60,7 +60,7 @@ public class GameListener implements Listener { private final List teamSkipCooldown = new ArrayList<>(); private final List swapCooldown = new ArrayList<>(); private boolean sentUpdateMessage = false; - private boolean startPhase = true; + public static boolean startPhase = true; public static boolean spawnCreated = false; public static Location spawn = new Location(Bukkit.getWorld("world"), 0.5, 201, 0.5); @@ -75,9 +75,8 @@ public GameListener() { TaskManager.startAll(); } - //TODO better tablist - //TODO evtl /item => zeigt rezept an => wenn gui system done is - //TODO commands von cords ausführen (for spawn) + //TODO does chain mode work with team objective? + //TODO support only team objective if not already possible @EventHandler public void onPlayerLogin(AsyncPlayerPreLoginEvent event) { @@ -193,6 +192,10 @@ public void onGameStart(TimerStartEvent event) throws IOException { player.getPlayer().teleport(world.getSpawnLocation()); } + + for (Team team : Team.teams) { + team.createBackpackGUIs(); + } } @EventHandler diff --git a/src/main/java/net/fameless/forcebattle/game/ObjectiveManager.java b/src/main/java/net/fameless/forcebattle/game/ObjectiveManager.java index ba91d6b..d7e1b63 100644 --- a/src/main/java/net/fameless/forcebattle/game/ObjectiveManager.java +++ b/src/main/java/net/fameless/forcebattle/game/ObjectiveManager.java @@ -21,7 +21,6 @@ import org.bukkit.entity.Player; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collections; import java.util.HashSet; import java.util.List; @@ -117,25 +116,25 @@ private Objective generateObjective(BattleType battleType, BattlePlayer battlePl private List getAllPossibleObjectives(BattleType battleType, BattlePlayer battlePlayer) { List list = new ArrayList<>(); switch (battleType) { - case FORCE_ITEM -> getAvailableItems().forEach(i -> list.add(i.name())); - case FORCE_MOB -> getAvailableMobs().forEach(m -> list.add(m.name())); + case FORCE_ITEM -> getAvailableItems().forEach(material -> list.add(material.name())); + case FORCE_MOB -> getAvailableMobs().forEach(entityType -> list.add(entityType.name())); case FORCE_BIOME -> { if (SettingsManager.isEnabled(SettingsManager.Setting.SIMPLIFIED_OBJECTIVES)) - getAvailableBiomesSimplified().forEach(b -> list.add(b.getName())); + getAvailableBiomesSimplified().forEach(biomeSimplified -> list.add(biomeSimplified.getName())); else - getAvailableBiomes().forEach(b -> list.add(b.name())); + getAvailableBiomes().forEach(biome -> list.add(biome.name())); } - case FORCE_ADVANCEMENT -> getAvailableAdvancements().forEach(a -> list.add(a.toString())); - case FORCE_HEIGHT -> getAvailableHeights().forEach(h -> list.add(String.valueOf(h))); + case FORCE_ADVANCEMENT -> getAvailableAdvancements().forEach(advancement -> list.add(advancement.toString())); + case FORCE_HEIGHT -> getAvailableHeights().forEach(height -> list.add(String.valueOf(height))); case FORCE_COORDS -> { Location coords = getRandomLocation(battlePlayer); list.add(coords.getX() + "," + coords.getZ()); } case FORCE_STRUCTURE -> { if (SettingsManager.isEnabled(SettingsManager.Setting.SIMPLIFIED_OBJECTIVES)) - getAvailableStructuresSimplified().forEach(s -> list.add(s.getName())); + getAvailableStructuresSimplified().forEach(structureSimplified -> list.add(structureSimplified.getName())); else - getAvailableStructures().forEach(s -> list.add(s.toString())); + getAvailableStructures().forEach(structure -> list.add(structure.toString())); } } return list; @@ -150,7 +149,7 @@ public List getAvailableItems() { boolean excludeArmorTemplates = SettingsManager.isEnabled(SettingsManager.Setting.EXCLUDE_ARMOR_TEMPLATES); boolean excludePotteryShreds = SettingsManager.isEnabled(SettingsManager.Setting.EXCLUDE_POTTERY_SHERDS); boolean excludeOres = SettingsManager.isEnabled(SettingsManager.Setting.EXCLUDE_ORES); - boolean excludeEndItems = SettingsManager.isEnabled(SettingsManager.Setting.EXCLUDE_END_ITEMS); + boolean excludeEndItems = SettingsManager.isEnabled(SettingsManager.Setting.EXCLUDE_END); for (Material material : Material.values()) { if (!material.isItem()) continue; @@ -181,13 +180,14 @@ public List getAvailableItems() { public List getAvailableMobs() { List availableMobs = new ArrayList<>(); + boolean excludeEndMobs = SettingsManager.isEnabled(SettingsManager.Setting.EXCLUDE_END); List mobsToExclude = ForceBattle.get().getConfig().getStringList("exclude.mobs"); for (EntityType entity : EntityType.values()) { - if (mobsToExclude.contains(entity.name())) { - continue; - } + if (mobsToExclude.contains(entity.name())) continue; + if (excludeEndMobs && ENDMOBS.contains(entity)) continue; + availableMobs.add(entity); } return availableMobs; @@ -195,23 +195,32 @@ public List getAvailableMobs() { public List getAvailableBiomes() { List availableBiomes = new ArrayList<>(); + boolean excludeBiomes = SettingsManager.isEnabled(SettingsManager.Setting.EXCLUDE_END); List biomesToExclude = ForceBattle.get().getConfig().getStringList("exclude.biomes"); for (Biome biome : Biome.values()) { - if (biomesToExclude.contains(biome.name())) { - continue; - } + if (biomesToExclude.contains(biome.name())) continue; + if (excludeBiomes && ENDBIOMES.contains(biome)) continue; + availableBiomes.add(biome); } return availableBiomes; } public List getAvailableBiomesSimplified() { - List list = new ArrayList<>(Arrays.asList(BiomeSimplified.values())); + List availableBiomes = new ArrayList<>(); + boolean excludeBiomes = SettingsManager.isEnabled(SettingsManager.Setting.EXCLUDE_END); + List biomesToExclude = ForceBattle.get().getConfig().getStringList("exclude.biomes"); - list.removeIf(b -> biomesToExclude.contains(b.getName().toUpperCase(Locale.ROOT))); - return list; + + for (BiomeSimplified simplified : BiomeSimplified.values()) { + if (biomesToExclude.contains(simplified.getName().toUpperCase(Locale.ROOT))) continue; + if (excludeBiomes && ENDBIOMESSIMPLIFIED.contains(simplified)) continue; + + availableBiomes.add(simplified); + } + return availableBiomes; } public List getAvailableAdvancements() { @@ -220,9 +229,8 @@ public List getAvailableAdvancements() { List advancementsToExclude = ForceBattle.get().getConfig().getStringList("exclude.advancements"); for (FBAdvancement advancement : FBAdvancement.values()) { - if (advancementsToExclude.contains(advancement.name())) { - continue; - } + if (advancementsToExclude.contains(advancement.name())) continue; + availableAdvancements.add(advancement); } return availableAdvancements; @@ -234,9 +242,8 @@ public List getAvailableHeights() { List heightsToExclude = ForceBattle.get().getConfig().getStringList("exclude.heights"); for (int i = -63; i < 321; i++) { - if (heightsToExclude.contains(String.valueOf(i))) { - continue; - } + if (heightsToExclude.contains(String.valueOf(i))) continue; + availableHeights.add(i); } return availableHeights; @@ -263,13 +270,13 @@ public Location getRandomLocation(BattlePlayer battlePlayer) { public List getAvailableStructures() { List availableStructures = new ArrayList<>(); + boolean excludeEndStructures = SettingsManager.isEnabled(SettingsManager.Setting.EXCLUDE_END); List structuresToExclude = ForceBattle.get().getConfig().getStringList("exclude.structures"); for (FBStructure structure : FBStructure.values()) { - if (structuresToExclude.contains(structure.getKey())) { - continue; - } + if (structuresToExclude.contains(structure.getKey())) continue; + if (excludeEndStructures && ENDSTRUCTURES.contains(structure)) continue; availableStructures.add(structure); } @@ -277,10 +284,18 @@ public List getAvailableStructures() { } public List getAvailableStructuresSimplified() { - List list = new ArrayList<>(Arrays.asList(StructureSimplified.values())); + List availableStructures = new ArrayList<>(); + boolean excludeEndStructures = SettingsManager.isEnabled(SettingsManager.Setting.EXCLUDE_END); + List structuresToExclude = ForceBattle.get().getConfig().getStringList("exclude.structures"); - list.removeIf(s -> structuresToExclude.contains(s.name().toUpperCase(Locale.ROOT))); - return list; + + for (StructureSimplified simplified : StructureSimplified.values()) { + if (structuresToExclude.contains(simplified.name().toUpperCase(Locale.ROOT))) continue; + if (excludeEndStructures && ENDSTRUCTURESSIMPLIFIED.contains(simplified)) continue; + + availableStructures.add(simplified); + } + return availableStructures; } public List getChainList() { @@ -333,4 +348,19 @@ public void updateChainList() { Material.ORANGE_SHULKER_BOX, Material.PINK_SHULKER_BOX, Material.PURPLE_SHULKER_BOX, Material.RED_SHULKER_BOX, Material.WHITE_SHULKER_BOX, Material.YELLOW_SHULKER_BOX, Material.SPIRE_ARMOR_TRIM_SMITHING_TEMPLATE ); + private final List ENDMOBS = List.of( + EntityType.ENDER_DRAGON, EntityType.SHULKER, EntityType.SHULKER_BULLET, EntityType.DRAGON_FIREBALL + ); + private final List ENDBIOMES = List.of( + Biome.THE_END, Biome.END_BARRENS, Biome.END_HIGHLANDS, Biome.END_MIDLANDS, Biome.SMALL_END_ISLANDS + ); + private final List ENDBIOMESSIMPLIFIED = List.of( + BiomeSimplified.END + ); + private final List ENDSTRUCTURES = List.of( + FBStructure.END_CITY + ); + private final List ENDSTRUCTURESSIMPLIFIED = List.of( + StructureSimplified.END_CITY + ); } diff --git a/src/main/java/net/fameless/forcebattle/game/Team.java b/src/main/java/net/fameless/forcebattle/game/Team.java index 4aa17a4..e3f45c9 100644 --- a/src/main/java/net/fameless/forcebattle/game/Team.java +++ b/src/main/java/net/fameless/forcebattle/game/Team.java @@ -7,6 +7,7 @@ import net.fameless.forcebattle.event.ObjectiveUpdateEvent; import net.fameless.forcebattle.event.PlayerTeamJoinEvent; import net.fameless.forcebattle.event.PlayerTeamLeaveEvent; +import net.fameless.forcebattle.gui.impl.TeamBackpackGUI; import net.fameless.forcebattle.player.BattlePlayer; import net.fameless.forcebattle.util.StringUtility; import net.kyori.adventure.text.Component; @@ -32,6 +33,10 @@ public class Team { private final List players; private final int ID; private boolean privateTeam = false; + private static final int SLOTS_PER_MEMBER = 45; + private static final int MAX_PAGE_SIZE = 54; + @Getter + private List BACKPACK_INVENTORIES = new ArrayList<>(); @Getter @Setter private Objective objective; @@ -197,6 +202,16 @@ public static int getPlace(Team team) { return -1; } + public void createBackpackGUIs() { + int requiredSlots = getPlayers().size() * SLOTS_PER_MEMBER; + int requiredPages = (int) Math.ceil(requiredSlots / (double) MAX_PAGE_SIZE); + + for (int i = 0; i < requiredPages; i++) { + int pageSize = Math.min(MAX_PAGE_SIZE, requiredSlots - (i * MAX_PAGE_SIZE)); + + BACKPACK_INVENTORIES.add(new TeamBackpackGUI(i, pageSize)); + } + } public void updateObjective(BattlePlayer finisher, boolean finishLast, boolean hasBeenSkipped) { if (finishLast && this.objective != null) { diff --git a/src/main/java/net/fameless/forcebattle/game/data/StructureSimplified.java b/src/main/java/net/fameless/forcebattle/game/data/StructureSimplified.java index 5055979..6de9eef 100644 --- a/src/main/java/net/fameless/forcebattle/game/data/StructureSimplified.java +++ b/src/main/java/net/fameless/forcebattle/game/data/StructureSimplified.java @@ -8,8 +8,7 @@ public enum StructureSimplified { VILLAGE("Village", List.of(FBStructure.VILLAGE_PLAINS, FBStructure.VILLAGE_SAVANNA, FBStructure.VILLAGE_SNOWY, FBStructure.VILLAGE_TAIGA, FBStructure.VILLAGE_DESERT)), PILLAGER_OUTPOST("Pillager Outpost", List.of(FBStructure.PILLAGER_OUTPOST)), - RUINED_PORTAL("Ruined Portal", List.of( - FBStructure.RUINED_PORTAL_MOUNTAIN, FBStructure.RUINED_PORTAL_DESERT, FBStructure.RUINED_PORTAL_JUNGLE, + RUINED_PORTAL("Ruined Portal", List.of(FBStructure.RUINED_PORTAL_MOUNTAIN, FBStructure.RUINED_PORTAL_DESERT, FBStructure.RUINED_PORTAL_JUNGLE, FBStructure.RUINED_PORTAL_OCEAN, FBStructure.RUINED_PORTAL_SWAMP, FBStructure.RUINED_PORTAL_NETHER)), OCEAN_RUIN("Ocean Ruin", List.of(FBStructure.OCEAN_RUIN_COLD, FBStructure.OCEAN_RUIN_WARM)), TRIAL_CHAMBERS("Trial Chambers", List.of(FBStructure.TRIAL_CHAMBERS)), diff --git a/src/main/java/net/fameless/forcebattle/gui/ForceBattleGUI.java b/src/main/java/net/fameless/forcebattle/gui/ForceBattleGUI.java index 721ff52..fb39130 100644 --- a/src/main/java/net/fameless/forcebattle/gui/ForceBattleGUI.java +++ b/src/main/java/net/fameless/forcebattle/gui/ForceBattleGUI.java @@ -53,6 +53,16 @@ public GUIItem get(int slot) { } } + public void clear() { + synchronized (items) { + items.clear(); + } + + if (inventory != null) { + inventory.clear(); + } + } + public int firstEmpty() { for (int i = 0; i < size; i++) { int finalI = i; @@ -121,7 +131,9 @@ public void open(BattlePlayer player) { GUI_MAP.remove(p.getUniqueId()); } - this.inventory = Bukkit.createInventory(this, size, title); + if (this.inventory == null) { + this.inventory = Bukkit.createInventory(this, size, title); + } GUI_MAP.put(p.getUniqueId(), this); try { @@ -164,7 +176,7 @@ public void setTitle(String title) { public abstract void setItems(BattlePlayer player); - public abstract boolean allowHotkeying(); + public abstract boolean allowItemMoving(); public void onOpen(BattlePlayer player) { } diff --git a/src/main/java/net/fameless/forcebattle/gui/GUIListener.java b/src/main/java/net/fameless/forcebattle/gui/GUIListener.java index 525af2b..046d43f 100644 --- a/src/main/java/net/fameless/forcebattle/gui/GUIListener.java +++ b/src/main/java/net/fameless/forcebattle/gui/GUIListener.java @@ -1,7 +1,5 @@ package net.fameless.forcebattle.gui; -import net.fameless.forcebattle.player.BattlePlayer; -import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; import org.bukkit.event.inventory.InventoryClickEvent; @@ -9,26 +7,27 @@ import org.bukkit.event.inventory.InventoryDragEvent; public class GUIListener implements Listener { - @EventHandler public void onClick(InventoryClickEvent event) { if (!(event.getInventory().getHolder() instanceof ForceBattleGUI gui)) return; - event.setCancelled(!gui.allowHotkeying()); - - BattlePlayer player = BattlePlayer.adapt((Player) event.getWhoClicked()); + event.setCancelled(!gui.allowItemMoving()); if (event.getRawSlot() < 0) return; if (event.getRawSlot() >= gui.getSize()) return; - GUIItem item = gui.get(event.getRawSlot()); - if (item == null) return; - item.onClick(event, player); + GUIItem clicked = gui.get(event.getRawSlot()); + if (clicked == null) return; + + if (clicked instanceof GUIClickableItem clickable) { + event.setCancelled(true); + clickable.onClick(event, gui.getPlayer()); + } } @EventHandler public void onDrag(InventoryDragEvent event) { - if (event.getInventory().getHolder() instanceof ForceBattleGUI) { - event.setCancelled(true); + if (event.getInventory().getHolder() instanceof ForceBattleGUI gui) { + event.setCancelled(!gui.allowItemMoving()); } } diff --git a/src/main/java/net/fameless/forcebattle/gui/impl/ConfigSettingsGUI.java b/src/main/java/net/fameless/forcebattle/gui/impl/ConfigSettingsGUI.java index 6bbb042..41d9fb1 100644 --- a/src/main/java/net/fameless/forcebattle/gui/impl/ConfigSettingsGUI.java +++ b/src/main/java/net/fameless/forcebattle/gui/impl/ConfigSettingsGUI.java @@ -37,8 +37,8 @@ public enum ConfigSettingButton { "gui.exclude_pottery_sherds_name", "gui.exclude_pottery_sherds_lore", "notification.exclude_pottery_sherds_changed"), ORES(14, Material.DIAMOND_ORE, SettingsManager.Setting.EXCLUDE_ORES, "gui.exclude_ores_name", "gui.exclude_ores_lore", "notification.exclude_ores_changed"), - END_ITEMS(15, Material.END_STONE, SettingsManager.Setting.EXCLUDE_END_ITEMS, - "gui.exclude_end_items_name", "gui.exclude_end_items_lore", "notification.exclude_end_items_changed"), + END(15, Material.END_STONE, SettingsManager.Setting.EXCLUDE_END, + "gui.exclude_end_name", "gui.exclude_end_lore", "notification.exclude_end_changed"), TRIAL_ITEMS(16, Material.TRIAL_SPAWNER, SettingsManager.Setting.EXCLUDE_TRIAL_ITEMS, "gui.exclude_trial_items_name", "gui.exclude_trial_items_lore", "notification.exclude_trial_items_changed"); @@ -94,7 +94,7 @@ public void handleClick(BattlePlayer whoClicked) { @Override public void setItems(BattlePlayer player) { - fill(ItemStackCreator.createNamedItemStack(Material.GRAY_STAINED_GLASS_PANE, " ")); + fill(ItemStackCreator.fillerItem()); set(GUIClickableItem.getGoBackItem(0, new SettingsGUI())); for (ConfigSettingButton button : ConfigSettingButton.values()) { @@ -113,7 +113,7 @@ public ItemStack getItem(BattlePlayer player) { } @Override - public boolean allowHotkeying() { + public boolean allowItemMoving() { return false; } } diff --git a/src/main/java/net/fameless/forcebattle/gui/impl/CraftingRecipeGUI.java b/src/main/java/net/fameless/forcebattle/gui/impl/CraftingRecipeGUI.java index 6674a37..e572f83 100644 --- a/src/main/java/net/fameless/forcebattle/gui/impl/CraftingRecipeGUI.java +++ b/src/main/java/net/fameless/forcebattle/gui/impl/CraftingRecipeGUI.java @@ -35,7 +35,7 @@ private CraftingRecipeGUI(ItemStack result, int page) { @Override public void setItems(BattlePlayer player) { - fill(ItemStackCreator.createNamedItemStack(Material.GRAY_STAINED_GLASS_PANE, " ")); + fill(ItemStackCreator.fillerItem()); set(new GUIItem(16) { @Override @@ -156,7 +156,7 @@ public ItemStack getItem(BattlePlayer player) { } @Override - public boolean allowHotkeying() { + public boolean allowItemMoving() { return false; } } diff --git a/src/main/java/net/fameless/forcebattle/gui/impl/LanguageGUI.java b/src/main/java/net/fameless/forcebattle/gui/impl/LanguageGUI.java index 0f557d8..65d9e54 100644 --- a/src/main/java/net/fameless/forcebattle/gui/impl/LanguageGUI.java +++ b/src/main/java/net/fameless/forcebattle/gui/impl/LanguageGUI.java @@ -85,7 +85,7 @@ public ItemStack getItem(BattlePlayer p) { } @Override - public boolean allowHotkeying() { + public boolean allowItemMoving() { return false; } } diff --git a/src/main/java/net/fameless/forcebattle/gui/impl/ResultGUI.java b/src/main/java/net/fameless/forcebattle/gui/impl/ResultGUI.java index 2fd4130..fe400a2 100644 --- a/src/main/java/net/fameless/forcebattle/gui/impl/ResultGUI.java +++ b/src/main/java/net/fameless/forcebattle/gui/impl/ResultGUI.java @@ -30,7 +30,6 @@ public class ResultGUI extends ForceBattleGUI { private static final int SPACES_ON_PAGE = 45; - private final int animationDelayTicks = 15; private final ResultType resultType; private final int page; @@ -86,7 +85,7 @@ public void open(BattlePlayer viewer) { } private void startAnimation(BattlePlayer viewer, List objectives) { - fill(ItemStackCreator.createNamedItemStack(Material.GRAY_STAINED_GLASS_PANE, " ")); + fill(ItemStackCreator.fillerItem()); BukkitRunnable task = new BukkitRunnable() { int index = 0; @@ -134,6 +133,7 @@ public ItemStack getItem(BattlePlayer player) { } }; + final int animationDelayTicks = 15; task.runTaskTimer(ForceBattle.get(), 0L, animationDelayTicks); activeAnimations.put(viewer, task); } @@ -146,7 +146,7 @@ public void setItems(BattlePlayer viewer) { List objectives = objectiveList.get(viewer); if (objectives == null) return; - fill(ItemStackCreator.createNamedItemStack(Material.GRAY_STAINED_GLASS_PANE, " ")); + fill(ItemStackCreator.fillerItem()); int totalPages = (int) Math.ceil((double) objectives.size() / SPACES_ON_PAGE); @@ -209,7 +209,7 @@ private void showResultSummary(BattlePlayer viewer) { } @Override - public boolean allowHotkeying() { + public boolean allowItemMoving() { return false; } diff --git a/src/main/java/net/fameless/forcebattle/gui/impl/SettingsGUI.java b/src/main/java/net/fameless/forcebattle/gui/impl/SettingsGUI.java index 87ced9f..eb5bde3 100644 --- a/src/main/java/net/fameless/forcebattle/gui/impl/SettingsGUI.java +++ b/src/main/java/net/fameless/forcebattle/gui/impl/SettingsGUI.java @@ -124,7 +124,7 @@ public void handleClick(BattlePlayer player) { @Override public void setItems(BattlePlayer player) { - fill(ItemStackCreator.createNamedItemStack(Material.GRAY_STAINED_GLASS_PANE, " ")); + fill(ItemStackCreator.fillerItem()); set(GUIClickableItem.getGoForthItem(8, new ConfigSettingsGUI())); for (SettingButton button : SettingButton.values()) { @@ -143,7 +143,7 @@ public ItemStack getItem(BattlePlayer p) { } @Override - public boolean allowHotkeying() { + public boolean allowItemMoving() { return false; } } diff --git a/src/main/java/net/fameless/forcebattle/gui/impl/TeamBackpackGUI.java b/src/main/java/net/fameless/forcebattle/gui/impl/TeamBackpackGUI.java new file mode 100644 index 0000000..83b8e9c --- /dev/null +++ b/src/main/java/net/fameless/forcebattle/gui/impl/TeamBackpackGUI.java @@ -0,0 +1,37 @@ +package net.fameless.forcebattle.gui.impl; + +import net.fameless.forcebattle.game.Team; +import net.fameless.forcebattle.gui.ForceBattleGUI; +import net.fameless.forcebattle.gui.GUIClickableItem; +import net.fameless.forcebattle.player.BattlePlayer; + +public class TeamBackpackGUI extends ForceBattleGUI { + + private final int index; + + public TeamBackpackGUI(int index, int size) { + super("Team Backpack Page: " + (index + 1), size); + this.index = index; + } + + @Override + public void setItems(final BattlePlayer player) { + Team team = player.getTeam(); + int inventoryPages = team.getBACKPACK_INVENTORIES().size(); + + if (index < 0 || index >= inventoryPages) return; + + if (index < inventoryPages - 1) { + set(GUIClickableItem.getGoForthItem(size - 1, team.getBACKPACK_INVENTORIES().get(index + 1))); + } + + if (index > 0) { + set(GUIClickableItem.getGoBackItem(size - 9, team.getBACKPACK_INVENTORIES().get(index - 1))); + } + } + + @Override + public boolean allowItemMoving() { + return true; + } +} diff --git a/src/main/java/net/fameless/forcebattle/player/BattlePlayer.java b/src/main/java/net/fameless/forcebattle/player/BattlePlayer.java index 22b95cf..6a80d71 100644 --- a/src/main/java/net/fameless/forcebattle/player/BattlePlayer.java +++ b/src/main/java/net/fameless/forcebattle/player/BattlePlayer.java @@ -13,7 +13,6 @@ import net.fameless.forcebattle.game.GameListener; import net.fameless.forcebattle.game.Objective; import net.fameless.forcebattle.game.Team; -import net.fameless.forcebattle.util.BackpackInventoryHolder; import net.fameless.forcebattle.util.BukkitUtil; import net.fameless.forcebattle.util.StringUtility; import net.fameless.forcebattle.util.ItemUtils; @@ -66,11 +65,8 @@ public class BattlePlayer implements CommandCaller { public BattlePlayer(@NotNull Player player) { this.uuid = player.getUniqueId(); this.name = player.getName(); - BACKPACK_INVENTORY = Bukkit.createInventory( - new BackpackInventoryHolder(), 27, Caption.getAsLegacy( - "gui.backpack_title", - TagResolver.resolver("player", Tag.inserting(Component.text(player.getName()))) - ) + BACKPACK_INVENTORY = Bukkit.createInventory(null, 27, Caption.getAsLegacy( + "gui.backpack_title", TagResolver.resolver("player", Tag.inserting(Component.text(player.getName())))) ); BATTLE_PLAYERS.add(this); } @@ -183,9 +179,6 @@ public String getName() { } public Audience getAudience() { - if (BukkitUtil.BUKKIT_AUDIENCES == null) { - logger.warn("[ForceBattle] Bukkit audiences not initialized!"); - } if (getPlayer() == null) { return Audience.empty(); } @@ -306,7 +299,12 @@ public void sendActionbar(Component message) { } public void openBackpack() { - openInventory(getBackpack()); + if (isInTeam()) { + Team team = getTeam(); + team.getBACKPACK_INVENTORIES().getFirst().open(this); + } else { + openInventory(getBackpack()); + } } public void openBackpack(BattlePlayer viewer) { @@ -415,7 +413,6 @@ public void teleport(Location location) { getPlayer().teleport(location); } - @SuppressWarnings("unchecked") public Inventory getInventory() { if (getPlayer() == null) { return null; @@ -423,7 +420,6 @@ public Inventory getInventory() { return getPlayer().getInventory(); } - @SuppressWarnings("unchecked") public World getWorld() { if (getPlayer() == null) { return null; @@ -431,7 +427,6 @@ public World getWorld() { return getPlayer().getWorld(); } - @SuppressWarnings("unchecked") public Inventory getBackpack() { return BACKPACK_INVENTORY; } diff --git a/src/main/java/net/fameless/forcebattle/scoreboard/ScoreboardManager.java b/src/main/java/net/fameless/forcebattle/scoreboard/ScoreboardManager.java index 424a370..febf57a 100644 --- a/src/main/java/net/fameless/forcebattle/scoreboard/ScoreboardManager.java +++ b/src/main/java/net/fameless/forcebattle/scoreboard/ScoreboardManager.java @@ -20,6 +20,7 @@ public class ScoreboardManager { private static final Map SCOREBOARDS = new HashMap<>(); private static final Map> LAST_LINES = new HashMap<>(); + private static final int maxStringLength = 30; public static void startUpdater() { Bukkit.getScheduler().runTaskTimer(ForceBattle.get(), ScoreboardManager::updateAll, 20L, 20L); @@ -59,7 +60,8 @@ public static void updateScoreboard(BattlePlayer player) { var selfObjective = player.getObjective(); if (selfObjective != null) { newLines.put(line--, ChatColor.YELLOW + "Your Objective:"); - newLines.put(line--, ChatColor.WHITE + getObjectiveDisplay(selfObjective)); + String objName = getObjectiveDisplay(selfObjective); + newLines.put(line--, ChatColor.WHITE + (objName.length() > maxStringLength ? objName.substring(0, 21) + "..." : objName)); } else { newLines.put(line--, ChatColor.GRAY + "No current objective"); } @@ -72,7 +74,8 @@ public static void updateScoreboard(BattlePlayer player) { var teamObjective = team.getObjective(); if (teamObjective != null && SettingsManager.isEnabled(SettingsManager.Setting.EXTRA_TEAM_OBJECTIVE)) { newLines.put(line--, ChatColor.YELLOW + "Team Objective:"); - newLines.put(line--, ChatColor.WHITE + getObjectiveDisplay(teamObjective)); + String objName = getObjectiveDisplay(teamObjective); + newLines.put(line--, ChatColor.WHITE + (objName.length() > maxStringLength ? objName.substring(0, 21) + "..." : objName)); newLines.put(line--, " "); } @@ -90,8 +93,7 @@ public static void updateScoreboard(BattlePlayer player) { ? getObjectiveDisplay(teammateObjective) : "None"; - newLines.put(line--, ChatColor.WHITE + " " + - (objName.length() > 24 ? objName.substring(0, 21) + "..." : objName)); + newLines.put(line--, ChatColor.WHITE + " " + (objName.length() > maxStringLength ? objName.substring(0, 21) + "..." : objName)); } } diff --git a/src/main/java/net/fameless/forcebattle/util/BackpackInventoryHolder.java b/src/main/java/net/fameless/forcebattle/util/BackpackInventoryHolder.java deleted file mode 100644 index e55f7d2..0000000 --- a/src/main/java/net/fameless/forcebattle/util/BackpackInventoryHolder.java +++ /dev/null @@ -1,14 +0,0 @@ -package net.fameless.forcebattle.util; - -import org.bukkit.inventory.Inventory; -import org.bukkit.inventory.InventoryHolder; -import org.jetbrains.annotations.NotNull; - -public final class BackpackInventoryHolder implements InventoryHolder { - - @Override - public @NotNull Inventory getInventory() { - return null; - } - -} diff --git a/src/main/java/net/fameless/forcebattle/util/EventRegistrar.java b/src/main/java/net/fameless/forcebattle/util/EventRegistrar.java new file mode 100644 index 0000000..ad661b4 --- /dev/null +++ b/src/main/java/net/fameless/forcebattle/util/EventRegistrar.java @@ -0,0 +1,50 @@ +package net.fameless.forcebattle.util; + +import org.bukkit.Bukkit; +import org.bukkit.event.Listener; +import org.bukkit.plugin.java.JavaPlugin; + +import java.io.IOException; +import java.net.URL; +import java.util.Enumeration; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; + +public final class EventRegistrar { + public static void registerAll(JavaPlugin plugin, String basePackage) { + try { + String path = basePackage.replace('.', '/'); + URL resource = plugin.getClass().getClassLoader().getResource(path); + if (resource == null) { + plugin.getLogger().warning("No resource found for package: " + basePackage); + return; + } + + String jarPath = resource.getPath().substring(5, resource.getPath().indexOf("!")); + try (JarFile jar = new JarFile(jarPath)) { + Enumeration entries = jar.entries(); + + while (entries.hasMoreElements()) { + JarEntry entry = entries.nextElement(); + String name = entry.getName(); + + if (name.startsWith(path) && name.endsWith(".class") && !name.contains("$")) { + String className = name.replace('/', '.').substring(0, name.length() - 6); + try { + Class clazz = Class.forName(className); + if (Listener.class.isAssignableFrom(clazz)) { + Listener listener = (Listener) clazz.getDeclaredConstructor().newInstance(); + Bukkit.getPluginManager().registerEvents(listener, plugin); + plugin.getLogger().info("Registered listener: " + className); + } + } catch (Exception ignored) { + } + } + } + } + } catch (IOException e) { + plugin.getLogger().severe("Error while registering listeners: " + e.getMessage()); + e.printStackTrace(); + } + } +} diff --git a/src/main/java/net/fameless/forcebattle/util/ItemStackCreator.java b/src/main/java/net/fameless/forcebattle/util/ItemStackCreator.java index 865d0c7..460f5c7 100644 --- a/src/main/java/net/fameless/forcebattle/util/ItemStackCreator.java +++ b/src/main/java/net/fameless/forcebattle/util/ItemStackCreator.java @@ -34,6 +34,10 @@ public static ItemStack createNamedItemStack(Material material, String name) { return item; } + public static ItemStack fillerItem() { + return createNamedItemStack(Material.GRAY_STAINED_GLASS_PANE, " "); + } + /** * Creates an {@link ItemStack} with a custom name and lore list. * diff --git a/src/main/java/net/fameless/forcebattle/util/ItemUtils.java b/src/main/java/net/fameless/forcebattle/util/ItemUtils.java index dde7caa..10392c3 100644 --- a/src/main/java/net/fameless/forcebattle/util/ItemUtils.java +++ b/src/main/java/net/fameless/forcebattle/util/ItemUtils.java @@ -84,7 +84,6 @@ public static boolean hasData(@NotNull ItemStack stack, NamespacedKey key) { return stack; } - @SuppressWarnings("unchecked") private static void apply(ItemMeta meta, ItemData data) { meta.getPersistentDataContainer().set( data.namespacedKey(), diff --git a/src/main/resources/languages/en_US.json b/src/main/resources/languages/en_US.json index 8bc87be..6c25579 100644 --- a/src/main/resources/languages/en_US.json +++ b/src/main/resources/languages/en_US.json @@ -54,8 +54,8 @@ "gui.exclude_pottery_sherds_lore" : "
Click to toggle excluding Pottery Sherds.

Current Status: ", "gui.exclude_ores_name" : "Exclude Ores", "gui.exclude_ores_lore" : "
Click to toggle excluding Ores.

Current Status: ", - "gui.exclude_end_items_name" : "Exclude End Items", - "gui.exclude_end_items_lore" : "
Click to toggle excluding End Items.

Current Status: ", + "gui.exclude_end_name" : "Exclude End Objectives", + "gui.exclude_end_lore" : "
Click to toggle excluding End Objectives.

Current Status: ", "gui.exclude_trial_items_name" : "Exclude Trial Items", "gui.exclude_trial_items_lore" : "
Click to toggle excluding Trial Items.

Current Status: ", "notification.objective_finished" : "You finished .", @@ -83,7 +83,7 @@ "notification.exclude_armor_templates_changed" : "Exclude Armor Templates has been set to !", "notification.exclude_pottery_sherds_changed" : "Exclude Pottery Sherds has been set to !", "notification.exclude_ores_changed" : "Exclude Ores has been set to !", - "notification.exclude_end_items_changed" : "Exclude End Items has been set to !", + "notification.exclude_end_changed" : "Exclude End Items has been set to !", "notification.exclude_trial_items_changed" : "Exclude Trial Items has been set to !", "notification.team_registered" : "New team has been created. Team ID: ", "notification.team_join_request" : " has requested to join your team. /team accept|reject.",