diff --git a/src/main/java/com/alttd/ctf/Main.java b/src/main/java/com/alttd/ctf/Main.java index 821c51e..ee80962 100644 --- a/src/main/java/com/alttd/ctf/Main.java +++ b/src/main/java/com/alttd/ctf/Main.java @@ -10,6 +10,7 @@ import com.alttd.ctf.events.OnSnowballHit; import com.alttd.ctf.flag.Flag; import com.alttd.ctf.flag.FlagTryCaptureEvent; import com.alttd.ctf.game.GameManager; +import com.alttd.ctf.gui.GUIListener; import com.alttd.ctf.json_config.JacksonConfig; import com.alttd.ctf.json_config.JsonConfigManager; import com.alttd.ctf.team.Team; @@ -69,6 +70,7 @@ public class Main extends JavaPlugin { pluginManager.registerEvents(new FlagTryCaptureEvent(flag), this); pluginManager.registerEvents(new OnPlayerDeath(gameManager), this); pluginManager.registerEvents(new OnPlayerJoin(gameManager, flag), this); + pluginManager.registerEvents(new GUIListener(), this); } private void registerTeams() { diff --git a/src/main/java/com/alttd/ctf/commands/CommandManager.java b/src/main/java/com/alttd/ctf/commands/CommandManager.java index 2bbd093..3bdc1e1 100644 --- a/src/main/java/com/alttd/ctf/commands/CommandManager.java +++ b/src/main/java/com/alttd/ctf/commands/CommandManager.java @@ -1,10 +1,7 @@ package com.alttd.ctf.commands; import com.alttd.ctf.Main; -import com.alttd.ctf.commands.subcommands.ChangeTeam; -import com.alttd.ctf.commands.subcommands.CreateTeam; -import com.alttd.ctf.commands.subcommands.Reload; -import com.alttd.ctf.commands.subcommands.Start; +import com.alttd.ctf.commands.subcommands.*; import com.alttd.ctf.config.Messages; import com.alttd.ctf.flag.Flag; import com.alttd.ctf.game.GameManager; @@ -39,6 +36,7 @@ public class CommandManager implements CommandExecutor, TabExecutor { new ChangeTeam(gameManager), new Start(gameManager, flag), new CreateTeam(main, gameManager), + new SelectClass(gameManager), new Reload(main) ); } diff --git a/src/main/java/com/alttd/ctf/commands/subcommands/SelectClass.java b/src/main/java/com/alttd/ctf/commands/subcommands/SelectClass.java new file mode 100644 index 0000000..aea8c0b --- /dev/null +++ b/src/main/java/com/alttd/ctf/commands/subcommands/SelectClass.java @@ -0,0 +1,70 @@ +package com.alttd.ctf.commands.subcommands; + +import com.alttd.ctf.commands.SubCommand; +import com.alttd.ctf.config.Messages; +import com.alttd.ctf.game.GameManager; +import com.alttd.ctf.game_class.GameClass; +import com.alttd.ctf.game_class.creation.FighterCreator; +import com.alttd.ctf.gui.ClassSelectionGUI; +import com.alttd.ctf.team.TeamPlayer; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Optional; + +public class SelectClass extends SubCommand { + + private final GameManager gameManager; + private final HashMap> gameClasses; + + public SelectClass(GameManager gameManager) { + this.gameManager = gameManager; + this.gameClasses = new HashMap<>(); + gameManager.getTeams().forEach(team -> { + gameClasses.computeIfAbsent(team.getId(), teamId -> new ArrayList<>()).add(FighterCreator.createFighter(team.getColor())); + }); + } + + @Override + public int onCommand(CommandSender commandSender, String[] args) { + if (!(commandSender instanceof Player player)) { + commandSender.sendRichMessage(Messages.GENERIC.PLAYER_ONLY); + return -1; + } + if (gameManager.getGamePhase().isEmpty()) { + commandSender.sendRichMessage("CTF has to be running to select a class."); + return 0; + } + Optional optionalTeamPlayer = gameManager.getTeamPlayer(player.getUniqueId()); + if (optionalTeamPlayer.isEmpty()) { + commandSender.sendRichMessage("You have to be in a CTF team to select a class."); + return 0; + } + TeamPlayer teamPlayer = optionalTeamPlayer.get(); + if (teamPlayer.getTeam().getSpawnLocation().distance(player.getLocation()) > 15) { + commandSender.sendRichMessage("You have to be near your spawn to change classes."); + return 0; + } + new ClassSelectionGUI(gameClasses.get(teamPlayer.getTeam().getId()), teamPlayer) + .open(player); + return 0; + } + + @Override + public String getName() { + return "selectclass"; + } + + @Override + public List getTabComplete(CommandSender commandSender, String[] args) { + return List.of(); + } + + @Override + public String getHelpMessage() { + return Messages.HELP.SELECT_CLASS; + } +} diff --git a/src/main/java/com/alttd/ctf/config/Messages.java b/src/main/java/com/alttd/ctf/config/Messages.java index d5c2783..d596590 100644 --- a/src/main/java/com/alttd/ctf/config/Messages.java +++ b/src/main/java/com/alttd/ctf/config/Messages.java @@ -26,6 +26,7 @@ public class Messages extends AbstractConfig { public static String CHANGE_TEAM = "Change a players team: /ctf changeteam "; public static String CREATE_TEAM = "Create a team: /ctf createteam "; public static String START = "Start a new game: /ctf start "; + public static String SELECT_CLASS = "Open class selection: /ctf selectclass"; @SuppressWarnings("unused") private static void load() { @@ -35,6 +36,7 @@ public class Messages extends AbstractConfig { CHANGE_TEAM = config.getString(prefix, "change-team", CHANGE_TEAM); CREATE_TEAM = config.getString(prefix, "create-team", CREATE_TEAM); START = config.getString(prefix, "start", START); + SELECT_CLASS = config.getString(prefix, "select-class", SELECT_CLASS); } } diff --git a/src/main/java/com/alttd/ctf/game_class/GameClass.java b/src/main/java/com/alttd/ctf/game_class/GameClass.java index 470c3f7..d405129 100644 --- a/src/main/java/com/alttd/ctf/game_class/GameClass.java +++ b/src/main/java/com/alttd/ctf/game_class/GameClass.java @@ -4,6 +4,8 @@ import com.alttd.ctf.team.TeamColor; import com.alttd.ctf.team.TeamPlayer; import lombok.Getter; import lombok.extern.slf4j.Slf4j; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder; import org.bukkit.Bukkit; import org.bukkit.Color; import org.bukkit.Material; @@ -13,6 +15,7 @@ import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ItemMeta; import org.bukkit.inventory.meta.LeatherArmorMeta; +import org.jetbrains.annotations.NotNull; import java.util.List; @@ -21,7 +24,10 @@ public abstract class GameClass { private final List armor; private final List tools; + @Getter private final ItemStack displayItem; + @Getter + private final Component className; private final double health; //Delay in ticks between throws (prevents auto clickers) @Getter @@ -30,7 +36,7 @@ public abstract class GameClass { @Getter private final int damage; - protected GameClass(List armor, List tools, ItemStack displayItem, double health, int throwTickSpeed, int damage) { + protected GameClass(@NotNull List armor, @NotNull List tools, @NotNull ItemStack displayItem, double health, int throwTickSpeed, int damage) { if (armor.size() != 4) { throw new IllegalArgumentException("Armor has to have 4 entries"); } @@ -40,6 +46,11 @@ public abstract class GameClass { this.health = health; this.throwTickSpeed = throwTickSpeed; this.damage = damage; + ItemMeta itemMeta = displayItem.getItemMeta(); + if (itemMeta == null) { + throw new IllegalArgumentException("Display item has no item meta"); + } + this.className = itemMeta.displayName(); } public void apply(TeamPlayer teamPlayer) { @@ -64,6 +75,8 @@ public abstract class GameClass { player.updateInventory(); teamPlayer.setGameClass(this); + player.sendRichMessage("You selected the class", Placeholder.component("class_name", className)); + player.teleportAsync(teamPlayer.getTeam().getSpawnLocation()); } private void setArmor(Player player, int r, int g, int b) { @@ -78,10 +91,6 @@ public abstract class GameClass { }).toArray(ItemStack[]::new)); } - ItemStack getDisplayItem() { - return displayItem; - } - public void setArmor(Player player, TeamPlayer teamPlayer) { TeamColor color = teamPlayer.getTeam().getColor(); setArmor(player, color.r(), color.g(), color.b()); diff --git a/src/main/java/com/alttd/ctf/gui/ClassSelectionGUI.java b/src/main/java/com/alttd/ctf/gui/ClassSelectionGUI.java new file mode 100644 index 0000000..3ad1bd2 --- /dev/null +++ b/src/main/java/com/alttd/ctf/gui/ClassSelectionGUI.java @@ -0,0 +1,29 @@ +package com.alttd.ctf.gui; + +import com.alttd.ctf.game_class.GameClass; +import com.alttd.ctf.team.TeamPlayer; +import net.kyori.adventure.text.minimessage.MiniMessage; +import org.bukkit.event.inventory.InventoryCloseEvent; +import org.bukkit.event.inventory.InventoryType; +import org.jetbrains.annotations.NotNull; + +import java.util.List; + +public class ClassSelectionGUI extends GUIInventory { + + public ClassSelectionGUI(@NotNull List gameClasses, @NotNull TeamPlayer teamPlayer) { + super(InventoryType.CHEST, teamPlayer.getTeam().getName().append(MiniMessage.miniMessage().deserialize(" - class selection"))); + createClassSelection(gameClasses, teamPlayer); + } + + private void createClassSelection(@NotNull List gameClasses, @NotNull TeamPlayer teamPlayer) { + int pos = (9 + (9 - gameClasses.size()) / 2); + for (GameClass gameClass : gameClasses) { + setItem(pos++, gameClass.getDisplayItem(), player -> { + gameClass.apply(teamPlayer); + player.closeInventory(InventoryCloseEvent.Reason.PLUGIN); + }); + } + } + +} diff --git a/src/main/java/com/alttd/ctf/gui/GUI.java b/src/main/java/com/alttd/ctf/gui/GUI.java new file mode 100644 index 0000000..35d88a4 --- /dev/null +++ b/src/main/java/com/alttd/ctf/gui/GUI.java @@ -0,0 +1,19 @@ +package com.alttd.ctf.gui; + +import org.bukkit.entity.Player; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.Merchant; +import org.bukkit.inventory.MerchantInventory; + +import java.util.HashMap; +import java.util.UUID; + +public interface GUI { + HashMap GUIByUUID = new HashMap<>(); + + void open(Player player); + + GUIAction getGuiAction(int slot); + + Inventory getInventory(); +} diff --git a/src/main/java/com/alttd/ctf/gui/GUIAction.java b/src/main/java/com/alttd/ctf/gui/GUIAction.java new file mode 100644 index 0000000..6feb2b1 --- /dev/null +++ b/src/main/java/com/alttd/ctf/gui/GUIAction.java @@ -0,0 +1,7 @@ +package com.alttd.ctf.gui; + +import org.bukkit.entity.Player; + +public interface GUIAction { + void click(Player player); +} \ No newline at end of file diff --git a/src/main/java/com/alttd/ctf/gui/GUIInventory.java b/src/main/java/com/alttd/ctf/gui/GUIInventory.java new file mode 100644 index 0000000..8cbab3a --- /dev/null +++ b/src/main/java/com/alttd/ctf/gui/GUIInventory.java @@ -0,0 +1,46 @@ +package com.alttd.ctf.gui; + +import lombok.Getter; +import net.kyori.adventure.text.Component; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; +import org.bukkit.event.inventory.InventoryType; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.Merchant; +import org.bukkit.inventory.MerchantInventory; + +import java.util.HashMap; + +public abstract class GUIInventory implements GUI { + + @Getter + protected final Inventory inventory; + protected final HashMap guiActions; + + public GUIInventory(InventoryType type, Component name) { + inventory = Bukkit.createInventory(null, type, name); + guiActions = new HashMap<>(); + } + + public void setItem(int slot, ItemStack stack, GUIAction action) { + this.inventory.setItem(slot, stack); + if (action != null) { + guiActions.put(slot, action); + } + } + + public void setItem(int slot, ItemStack stack) { + setItem(slot, stack, null); + } + + public void open(Player player) { + player.openInventory(inventory); + GUIByUUID.put(player.getUniqueId(), this); + } + + public GUIAction getGuiAction(int slot) { + return guiActions.get(slot); + } + +} diff --git a/src/main/java/com/alttd/ctf/gui/GUIListener.java b/src/main/java/com/alttd/ctf/gui/GUIListener.java new file mode 100644 index 0000000..c4db25f --- /dev/null +++ b/src/main/java/com/alttd/ctf/gui/GUIListener.java @@ -0,0 +1,60 @@ +package com.alttd.ctf.gui; + +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.inventory.InventoryClickEvent; +import org.bukkit.event.inventory.InventoryCloseEvent; +import org.bukkit.event.inventory.InventoryType; +import org.bukkit.event.player.PlayerQuitEvent; +import org.bukkit.inventory.Inventory; + +public class GUIListener implements Listener { + + /** + * Handles clicking inside a gui + * @param event gui click event + */ + @EventHandler + public void onClick(InventoryClickEvent event){ + if (!(event.getWhoClicked() instanceof Player player)) { + return; + } + + GUI gui = GUI.GUIByUUID.get(player.getUniqueId()); + if (gui == null) { + return; + } + if (gui.getInventory() != null) { + if (!gui.getInventory().equals(event.getInventory())) { + return; + } + } else { + return; + } + + event.setCancelled(true); + + Inventory clickedInventory = event.getClickedInventory(); + if (clickedInventory == null || clickedInventory.getType().equals(InventoryType.PLAYER)) { + return; + } + + GUIAction action = gui.getGuiAction(event.getSlot()); + + if (action != null) { + action.click(player); + } + } + + @EventHandler + public void onClose(InventoryCloseEvent event) { + GUI.GUIByUUID.remove(event.getPlayer().getUniqueId()); + } + + @EventHandler + public void onQuit(PlayerQuitEvent event){ + GUI.GUIByUUID.remove(event.getPlayer().getUniqueId()); + } + +} diff --git a/version.properties b/version.properties index c164c2f..3cf2d9a 100644 --- a/version.properties +++ b/version.properties @@ -1,3 +1,3 @@ -#Fri Feb 07 22:07:29 CET 2025 -buildNumber=5 +#Fri Feb 07 23:09:43 CET 2025 +buildNumber=8 version=0.1