From 57b21c2e1f821541bc9d724c01a569e66d5766fc Mon Sep 17 00:00:00 2001 From: Shiewk Date: Fri, 26 Jul 2024 18:36:57 +0200 Subject: [PATCH 01/11] Fix EnderchestSee bug --- .../java/de/shiewk/smoderation/event/EnderchestSeeEvents.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/de/shiewk/smoderation/event/EnderchestSeeEvents.java b/src/main/java/de/shiewk/smoderation/event/EnderchestSeeEvents.java index 7962e0e..974b759 100644 --- a/src/main/java/de/shiewk/smoderation/event/EnderchestSeeEvents.java +++ b/src/main/java/de/shiewk/smoderation/event/EnderchestSeeEvents.java @@ -15,7 +15,7 @@ public class EnderchestSeeEvents implements Listener { final Inventory clicked = event.getView().getTopInventory(); if (!(clicked instanceof PlayerInventory)){ final InventoryHolder holder = clicked.getHolder(); - if (holder instanceof HumanEntity humanHolder){ + if (holder instanceof HumanEntity humanHolder && humanHolder.getEnderChest().equals(clicked)){ if (!event.getWhoClicked().hasPermission("smod.enderchestsee.modify")){ event.setCancelled(true); } From 0db57042af997a5a089280b5b7fe73f9581d48c1 Mon Sep 17 00:00:00 2001 From: Shiewk Date: Fri, 26 Jul 2024 18:38:42 +0200 Subject: [PATCH 02/11] Fix vanish bug --- .../smoderation/listener/VanishListener.java | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/src/main/java/de/shiewk/smoderation/listener/VanishListener.java b/src/main/java/de/shiewk/smoderation/listener/VanishListener.java index bd8a44a..09c2884 100644 --- a/src/main/java/de/shiewk/smoderation/listener/VanishListener.java +++ b/src/main/java/de/shiewk/smoderation/listener/VanishListener.java @@ -1,6 +1,7 @@ package de.shiewk.smoderation.listener; import de.shiewk.smoderation.SModeration; +import org.bukkit.Bukkit; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; @@ -21,14 +22,16 @@ public class VanishListener implements Listener { } } - @EventHandler(priority = EventPriority.HIGHEST) public void onPlayerJoin(PlayerJoinEvent event){ - final Player player = event.getPlayer(); - if (player.hasPermission("smod.vanish.see")){ - for (Player vanishedPlayer : SModeration.getVanishedPlayers()) { - // to show visible vanished players - player.showEntity(SModeration.PLUGIN, vanishedPlayer); + @EventHandler(priority = EventPriority.MONITOR) public void onPlayerJoin(PlayerJoinEvent event){ + Bukkit.getScheduler().scheduleSyncDelayedTask(SModeration.PLUGIN, () -> { + final Player player = event.getPlayer(); + if (player.hasPermission("smod.vanish.see")){ + for (Player vanishedPlayer : SModeration.getVanishedPlayers()) { + // to show visible vanished players + player.showEntity(SModeration.PLUGIN, vanishedPlayer); + } } - } + }); } } From 4392456b151f5c49a0f93fe90154c7df3d3169e8 Mon Sep 17 00:00:00 2001 From: Shiewk Date: Fri, 26 Jul 2024 18:39:14 +0200 Subject: [PATCH 03/11] Add missing docs, update to 1.2.1 --- docs/permissions.md | 2 ++ gradle.properties | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/permissions.md b/docs/permissions.md index 7e41db0..e17de60 100644 --- a/docs/permissions.md +++ b/docs/permissions.md @@ -15,5 +15,7 @@ - **smod.invsee.preventmodify**: When giving this permission to a player, prevents their inventory from being modified. - **smod.enderchestsee**: Allows the player to view other players ender chests. - **smod.enderchestsee.modify**: Allows the player to view and modify other players ender chests. +- **smod.vanish**: Allows the player to enter and leave vanish mode. +- **smod.vanish.see**: Allows the player to see vanished players All of these permissions are granted by default if the player is a server operator. diff --git a/gradle.properties b/gradle.properties index 4338220..da901d3 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1 +1 @@ -pluginVersion = 1.2.0 \ No newline at end of file +pluginVersion = 1.2.1 \ No newline at end of file From 755b758b2f88d418d924bb87a77bd88bc7d35951 Mon Sep 17 00:00:00 2001 From: Shiewk Date: Sun, 28 Jul 2024 15:29:41 +0200 Subject: [PATCH 04/11] Move vanish-related methods to VanishCommand.java --- .../de/shiewk/smoderation/SModeration.java | 52 +----------------- .../smoderation/command/VanishCommand.java | 55 ++++++++++++++++++- .../smoderation/listener/VanishListener.java | 9 +-- 3 files changed, 61 insertions(+), 55 deletions(-) diff --git a/src/main/java/de/shiewk/smoderation/SModeration.java b/src/main/java/de/shiewk/smoderation/SModeration.java index f89470b..b0caeb0 100644 --- a/src/main/java/de/shiewk/smoderation/SModeration.java +++ b/src/main/java/de/shiewk/smoderation/SModeration.java @@ -7,13 +7,11 @@ import de.shiewk.smoderation.event.InvSeeEvents; import de.shiewk.smoderation.listener.PunishmentListener; import de.shiewk.smoderation.listener.VanishListener; import de.shiewk.smoderation.storage.PunishmentContainer; -import it.unimi.dsi.fastutil.objects.ObjectArrayList; import net.kyori.adventure.text.TextComponent; import net.kyori.adventure.text.format.NamedTextColor; import net.kyori.adventure.text.format.TextColor; import net.kyori.adventure.text.logger.slf4j.ComponentLogger; import org.bukkit.Bukkit; -import org.bukkit.command.CommandSender; import org.bukkit.command.PluginCommand; import org.bukkit.command.TabExecutor; import org.bukkit.entity.Player; @@ -21,6 +19,8 @@ import org.bukkit.plugin.java.JavaPlugin; import java.io.File; +import static de.shiewk.smoderation.command.VanishCommand.isVanished; +import static de.shiewk.smoderation.command.VanishCommand.toggleVanish; import static net.kyori.adventure.text.Component.text; import static org.bukkit.Bukkit.getPluginManager; @@ -86,52 +86,4 @@ public final class SModeration extends JavaPlugin { } } } - - private static final ObjectArrayList vanishedPlayers = new ObjectArrayList<>(); - - public static void toggleVanish(Player player){ - final boolean newStatus = !isVanished(player); - if (newStatus){ - vanishedPlayers.add(player); - for (CommandSender sender : container.collectBroadcastTargets()) { - sender.sendMessage(CHAT_PREFIX.append( - player.displayName() - .colorIfAbsent(SECONDARY_COLOR) - ).append( - text() - .content(" vanished.") - .color(PRIMARY_COLOR) - )); - } - player.sendMessage(CHAT_PREFIX.append(text("You are now vanished.").color(PRIMARY_COLOR))); - player.setVisibleByDefault(false); - for (Player onlinePlayer : Bukkit.getOnlinePlayers()) { - if (onlinePlayer.hasPermission("smod.vanish.see")){ - onlinePlayer.showEntity(PLUGIN, player); - } - } - } else { - vanishedPlayers.remove(player); - for (CommandSender sender : container.collectBroadcastTargets()) { - sender.sendMessage(CHAT_PREFIX.append( - player.displayName() - .colorIfAbsent(SECONDARY_COLOR) - ).append( - text() - .content(" re-appeared.") - .color(PRIMARY_COLOR) - )); - } - player.sendMessage(CHAT_PREFIX.append(text("You are no longer vanished.").color(PRIMARY_COLOR))); - player.setVisibleByDefault(true); - } - } - - public static boolean isVanished(Player player){ - return vanishedPlayers.contains(player); - } - - public static ObjectArrayList getVanishedPlayers() { - return vanishedPlayers.clone(); - } } diff --git a/src/main/java/de/shiewk/smoderation/command/VanishCommand.java b/src/main/java/de/shiewk/smoderation/command/VanishCommand.java index b8dc5c7..3d954ed 100644 --- a/src/main/java/de/shiewk/smoderation/command/VanishCommand.java +++ b/src/main/java/de/shiewk/smoderation/command/VanishCommand.java @@ -2,6 +2,8 @@ package de.shiewk.smoderation.command; import de.shiewk.smoderation.SModeration; import de.shiewk.smoderation.util.PlayerUtil; +import it.unimi.dsi.fastutil.objects.ObjectArrayList; +import org.bukkit.Bukkit; import org.bukkit.command.Command; import org.bukkit.command.CommandSender; import org.bukkit.command.TabExecutor; @@ -11,6 +13,9 @@ import org.jetbrains.annotations.Nullable; import java.util.List; +import static de.shiewk.smoderation.SModeration.*; +import static net.kyori.adventure.text.Component.text; + public class VanishCommand implements TabExecutor { @Override @@ -22,7 +27,7 @@ public class VanishCommand implements TabExecutor { player = (Player) sender; } if (player != null){ - SModeration.toggleVanish(player); + toggleVanish(player); return true; } else { return false; @@ -36,4 +41,52 @@ public class VanishCommand implements TabExecutor { } return List.of(); } + + private static final ObjectArrayList vanishedPlayers = new ObjectArrayList<>(); + + public static void toggleVanish(Player player){ + final boolean newStatus = !isVanished(player); + if (newStatus){ + vanishedPlayers.add(player); + for (CommandSender sender : SModeration.container.collectBroadcastTargets()) { + sender.sendMessage(CHAT_PREFIX.append( + player.displayName() + .colorIfAbsent(SECONDARY_COLOR) + ).append( + text() + .content(" vanished.") + .color(PRIMARY_COLOR) + )); + } + player.sendMessage(CHAT_PREFIX.append(text("You are now vanished.").color(PRIMARY_COLOR))); + player.setVisibleByDefault(false); + for (Player onlinePlayer : Bukkit.getOnlinePlayers()) { + if (onlinePlayer.hasPermission("smod.vanish.see")){ + onlinePlayer.showEntity(PLUGIN, player); + } + } + } else { + vanishedPlayers.remove(player); + for (CommandSender sender : container.collectBroadcastTargets()) { + sender.sendMessage(CHAT_PREFIX.append( + player.displayName() + .colorIfAbsent(SECONDARY_COLOR) + ).append( + text() + .content(" re-appeared.") + .color(PRIMARY_COLOR) + )); + } + player.sendMessage(CHAT_PREFIX.append(text("You are no longer vanished.").color(PRIMARY_COLOR))); + player.setVisibleByDefault(true); + } + } + + public static boolean isVanished(Player player){ + return vanishedPlayers.contains(player); + } + + public static ObjectArrayList getVanishedPlayers() { + return vanishedPlayers.clone(); + } } diff --git a/src/main/java/de/shiewk/smoderation/listener/VanishListener.java b/src/main/java/de/shiewk/smoderation/listener/VanishListener.java index 09c2884..bd7fd6b 100644 --- a/src/main/java/de/shiewk/smoderation/listener/VanishListener.java +++ b/src/main/java/de/shiewk/smoderation/listener/VanishListener.java @@ -1,6 +1,7 @@ package de.shiewk.smoderation.listener; import de.shiewk.smoderation.SModeration; +import de.shiewk.smoderation.command.VanishCommand; import org.bukkit.Bukkit; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; @@ -13,10 +14,10 @@ public class VanishListener implements Listener { @EventHandler public void onPlayerQuit(PlayerQuitEvent event){ final Player player = event.getPlayer(); - if (SModeration.isVanished(player)){ - SModeration.toggleVanish(player); + if (VanishCommand.isVanished(player)){ + VanishCommand.toggleVanish(player); } - for (Player vanishedPlayer : SModeration.getVanishedPlayers()) { + for (Player vanishedPlayer : VanishCommand.getVanishedPlayers()) { // to clean up visibility status player.hideEntity(SModeration.PLUGIN, vanishedPlayer); } @@ -26,7 +27,7 @@ public class VanishListener implements Listener { Bukkit.getScheduler().scheduleSyncDelayedTask(SModeration.PLUGIN, () -> { final Player player = event.getPlayer(); if (player.hasPermission("smod.vanish.see")){ - for (Player vanishedPlayer : SModeration.getVanishedPlayers()) { + for (Player vanishedPlayer : VanishCommand.getVanishedPlayers()) { // to show visible vanished players player.showEntity(SModeration.PLUGIN, vanishedPlayer); } From 56aef4a2c9e6644ce9da525ad17689050454e871 Mon Sep 17 00:00:00 2001 From: Shiewk Date: Sun, 28 Jul 2024 16:10:22 +0200 Subject: [PATCH 05/11] Added /vanish list command and list vanished players on join --- .../smoderation/command/VanishCommand.java | 59 ++++++++++++++++--- .../smoderation/listener/VanishListener.java | 4 +- .../shiewk/smoderation/util/PlayerUtil.java | 5 ++ src/main/resources/plugin.yml | 2 +- 4 files changed, 59 insertions(+), 11 deletions(-) diff --git a/src/main/java/de/shiewk/smoderation/command/VanishCommand.java b/src/main/java/de/shiewk/smoderation/command/VanishCommand.java index 3d954ed..ec53f08 100644 --- a/src/main/java/de/shiewk/smoderation/command/VanishCommand.java +++ b/src/main/java/de/shiewk/smoderation/command/VanishCommand.java @@ -3,6 +3,9 @@ package de.shiewk.smoderation.command; import de.shiewk.smoderation.SModeration; import de.shiewk.smoderation.util.PlayerUtil; import it.unimi.dsi.fastutil.objects.ObjectArrayList; +import it.unimi.dsi.fastutil.objects.ObjectListIterator; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; import org.bukkit.Bukkit; import org.bukkit.command.Command; import org.bukkit.command.CommandSender; @@ -20,14 +23,25 @@ public class VanishCommand implements TabExecutor { @Override public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) { - Player player = null; - if (args.length > 0){ - player = PlayerUtil.findOnlinePlayer(args[0]); - } else if (sender instanceof Player){ - player = (Player) sender; - } - if (player != null){ - toggleVanish(player); + if (args.length == 0 || args[0].equalsIgnoreCase("toggle")){ + Player player = null; + if (args.length > 1){ + player = PlayerUtil.findOnlinePlayer(args[1]); + } else if (sender instanceof Player){ + player = (Player) sender; + } + if (player != null){ + toggleVanish(player); + return true; + } else { + return false; + } + } else if (args[0].equalsIgnoreCase("list")) { + if (sender.hasPermission("smod.vanish.see")){ + listVanishedPlayersTo(sender); + } else { + sender.sendMessage(text().color(NamedTextColor.RED).content("You do not have permission to list all vanished players.")); + } return true; } else { return false; @@ -37,7 +51,10 @@ public class VanishCommand implements TabExecutor { @Override public @Nullable List onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) { if (args.length < 2){ - return PlayerUtil.listPlayerNames(); + return List.of("list", "toggle"); + } + if (args.length < 3 && args[0].equalsIgnoreCase("toggle")){ + return PlayerUtil.listPlayerNames(args[1]); } return List.of(); } @@ -89,4 +106,28 @@ public class VanishCommand implements TabExecutor { public static ObjectArrayList getVanishedPlayers() { return vanishedPlayers.clone(); } + + public static void listVanishedPlayersTo(CommandSender receiver){ + if (vanishedPlayers.isEmpty()){ + receiver.sendMessage(CHAT_PREFIX.append( + text().content("No players are currently vanished.").color(PRIMARY_COLOR) + )); + } else { + Component vanishList = CHAT_PREFIX.append( + text().content("The following players are currently vanished: ").color(PRIMARY_COLOR) + ); + for (ObjectListIterator iterator = vanishedPlayers.iterator(); iterator.hasNext(); ) { + Player vanishedPlayer = iterator.next(); + vanishList = vanishList.append( + vanishedPlayer.displayName().colorIfAbsent(SECONDARY_COLOR) + ); + if (iterator.hasNext()){ + vanishList = vanishList.append( + text().content(", ").color(PRIMARY_COLOR) + ); + } + } + receiver.sendMessage(vanishList); + } + } } diff --git a/src/main/java/de/shiewk/smoderation/listener/VanishListener.java b/src/main/java/de/shiewk/smoderation/listener/VanishListener.java index bd7fd6b..a1bf84e 100644 --- a/src/main/java/de/shiewk/smoderation/listener/VanishListener.java +++ b/src/main/java/de/shiewk/smoderation/listener/VanishListener.java @@ -25,12 +25,14 @@ public class VanishListener implements Listener { @EventHandler(priority = EventPriority.MONITOR) public void onPlayerJoin(PlayerJoinEvent event){ Bukkit.getScheduler().scheduleSyncDelayedTask(SModeration.PLUGIN, () -> { - final Player player = event.getPlayer(); + final Player player = event.getPlayer().getPlayer(); + assert player != null; if (player.hasPermission("smod.vanish.see")){ for (Player vanishedPlayer : VanishCommand.getVanishedPlayers()) { // to show visible vanished players player.showEntity(SModeration.PLUGIN, vanishedPlayer); } + VanishCommand.listVanishedPlayersTo(player); } }); } diff --git a/src/main/java/de/shiewk/smoderation/util/PlayerUtil.java b/src/main/java/de/shiewk/smoderation/util/PlayerUtil.java index 10d59a6..afc6fc5 100644 --- a/src/main/java/de/shiewk/smoderation/util/PlayerUtil.java +++ b/src/main/java/de/shiewk/smoderation/util/PlayerUtil.java @@ -6,6 +6,7 @@ import org.bukkit.Bukkit; import org.bukkit.OfflinePlayer; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; +import org.bukkit.util.StringUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -71,4 +72,8 @@ public abstract class PlayerUtil { } return List.copyOf(names); } + + public static List listPlayerNames(String search) { + return StringUtil.copyPartialMatches(search, listPlayerNames(), new ArrayList<>()); + } } diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index a25ac28..becbadc 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -72,7 +72,7 @@ commands: permission: smod.enderchestsee description: Views the ender chest of another player. vanish: - usage: "§cUsage: /vanish " + usage: "§cUsage: /vanish list or /vanish toggle " aliases: - smvanish permission: smod.vanish From ab037716c469b7db9b0dda3f6e0b2263704f600d Mon Sep 17 00:00:00 2001 From: Shiewk Date: Mon, 29 Jul 2024 13:22:00 +0200 Subject: [PATCH 06/11] Add search option in SMod menu with chat input --- .../de/shiewk/smoderation/SModeration.java | 2 + .../shiewk/smoderation/input/ChatInput.java | 70 +++++++++++++++ .../smoderation/input/ChatInputListener.java | 32 +++++++ .../smoderation/inventory/SModMenu.java | 85 ++++++++++++++----- .../smoderation/punishments/Punishment.java | 19 +++++ 5 files changed, 189 insertions(+), 19 deletions(-) create mode 100644 src/main/java/de/shiewk/smoderation/input/ChatInput.java create mode 100644 src/main/java/de/shiewk/smoderation/input/ChatInputListener.java diff --git a/src/main/java/de/shiewk/smoderation/SModeration.java b/src/main/java/de/shiewk/smoderation/SModeration.java index b0caeb0..f30a550 100644 --- a/src/main/java/de/shiewk/smoderation/SModeration.java +++ b/src/main/java/de/shiewk/smoderation/SModeration.java @@ -4,6 +4,7 @@ import de.shiewk.smoderation.command.*; import de.shiewk.smoderation.event.CustomInventoryEvents; import de.shiewk.smoderation.event.EnderchestSeeEvents; import de.shiewk.smoderation.event.InvSeeEvents; +import de.shiewk.smoderation.input.ChatInputListener; import de.shiewk.smoderation.listener.PunishmentListener; import de.shiewk.smoderation.listener.VanishListener; import de.shiewk.smoderation.storage.PunishmentContainer; @@ -51,6 +52,7 @@ public final class SModeration extends JavaPlugin { getPluginManager().registerEvents(new InvSeeEvents(), this); getPluginManager().registerEvents(new EnderchestSeeEvents(), this); getPluginManager().registerEvents(new VanishListener(), this); + getPluginManager().registerEvents(new ChatInputListener(), this); registerCommand("mute", new MuteCommand()); registerCommand("ban", new BanCommand()); diff --git a/src/main/java/de/shiewk/smoderation/input/ChatInput.java b/src/main/java/de/shiewk/smoderation/input/ChatInput.java new file mode 100644 index 0000000..036bd6a --- /dev/null +++ b/src/main/java/de/shiewk/smoderation/input/ChatInput.java @@ -0,0 +1,70 @@ +package de.shiewk.smoderation.input; + +import net.kyori.adventure.text.Component; +import net.kyori.adventure.title.Title; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; + +import java.time.Duration; +import java.util.Objects; +import java.util.concurrent.ConcurrentHashMap; +import java.util.function.Consumer; + +import static de.shiewk.smoderation.SModeration.CHAT_PREFIX; +import static net.kyori.adventure.text.Component.text; +import static net.kyori.adventure.text.format.NamedTextColor.GRAY; + +public class ChatInput { + private final Player player; + private final Component prompt; + private final Consumer action; + private int remainingTicks; + + private ChatInput(@NotNull Player player, @NotNull Component prompt, @NotNull Consumer action, int remainingSeconds){ + Objects.requireNonNull(action); + Objects.requireNonNull(prompt); + Objects.requireNonNull(player); + this.player = player; + this.prompt = prompt; + this.action = action; + this.remainingTicks = remainingSeconds * 20; + } + + static void tickAll() { + runningInputs.values().forEach(ChatInput::tick); + } + + void tick(){ + remainingTicks--; + if (remainingTicks <= 0){ + runningInputs.remove(player); + return; + } + if (remainingTicks % 20 == 0){ + player.showTitle(Title.title( + text().content(getRemainingTicks() / 20 + " seconds").color(GRAY).build(), + getPrompt(), + Title.Times.times(Duration.ZERO, Duration.ofSeconds(2), Duration.ZERO) + )); + } + } + + final static ConcurrentHashMap runningInputs = new ConcurrentHashMap<>(); + + public static void prompt(Player player, Consumer consumer, Component prompt, int timeSeconds){ + runningInputs.put(player, new ChatInput(player, prompt, consumer, timeSeconds)); + player.sendMessage(CHAT_PREFIX.append(prompt)); + } + + public Component getPrompt() { + return prompt; + } + + public Consumer getAction() { + return action; + } + + public int getRemainingTicks() { + return remainingTicks; + } +} diff --git a/src/main/java/de/shiewk/smoderation/input/ChatInputListener.java b/src/main/java/de/shiewk/smoderation/input/ChatInputListener.java new file mode 100644 index 0000000..5d48a60 --- /dev/null +++ b/src/main/java/de/shiewk/smoderation/input/ChatInputListener.java @@ -0,0 +1,32 @@ +package de.shiewk.smoderation.input; + +import com.destroystokyo.paper.event.server.ServerTickStartEvent; +import io.papermc.paper.event.player.AsyncChatEvent; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerQuitEvent; + +import static de.shiewk.smoderation.input.ChatInput.runningInputs; + +public class ChatInputListener implements Listener { + + + @EventHandler + public void onAsyncChat(AsyncChatEvent event){ + final ChatInput input = runningInputs.remove(event.getPlayer()); + if (input != null){ + event.setCancelled(true); + input.getAction().accept(event.message()); + } + } + + @EventHandler public void onPlayerQuit(PlayerQuitEvent event){ + runningInputs.remove(event.getPlayer()); + } + + @EventHandler(priority = EventPriority.MONITOR) public void onServerTickStart(ServerTickStartEvent event){ + ChatInput.tickAll(); + } + +} diff --git a/src/main/java/de/shiewk/smoderation/inventory/SModMenu.java b/src/main/java/de/shiewk/smoderation/inventory/SModMenu.java index 52aee58..de7b74f 100644 --- a/src/main/java/de/shiewk/smoderation/inventory/SModMenu.java +++ b/src/main/java/de/shiewk/smoderation/inventory/SModMenu.java @@ -1,11 +1,13 @@ package de.shiewk.smoderation.inventory; +import de.shiewk.smoderation.input.ChatInput; import de.shiewk.smoderation.punishments.Punishment; import de.shiewk.smoderation.punishments.PunishmentType; import de.shiewk.smoderation.storage.PunishmentContainer; import de.shiewk.smoderation.util.PlayerUtil; import de.shiewk.smoderation.util.TimeUtil; import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.TextComponent; import net.kyori.adventure.text.format.NamedTextColor; import net.kyori.adventure.text.format.TextDecoration; import org.bukkit.Bukkit; @@ -15,6 +17,7 @@ import org.bukkit.Sound; import org.bukkit.entity.Player; import org.bukkit.event.inventory.InventoryClickEvent; import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.ItemFlag; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ItemMeta; import org.bukkit.inventory.meta.SkullMeta; @@ -28,6 +31,7 @@ import java.util.List; import java.util.function.Predicate; import static de.shiewk.smoderation.SModeration.*; +import static net.kyori.adventure.text.Component.text; public class SModMenu extends PageableCustomInventory { @@ -70,13 +74,15 @@ public class SModMenu extends PageableCustomInventory { private List punishments; private ItemStack sortStack = null; private ItemStack filterStack = null; + private ItemStack searchStack = null; private int sort = 0; private int filter = 0; + private String searchQuery = null; public SModMenu(Player player, PunishmentContainer container) { this.player = player; this.container = container; - this.inventory = Bukkit.createInventory(this, 54, Component.text("SMod Menu")); + this.inventory = Bukkit.createInventory(this, 54, text("SMod Menu")); reload(); } @@ -89,7 +95,18 @@ public class SModMenu extends PageableCustomInventory { } private void reload(){ - this.punishments = container.copy().stream().filter(getFilter().filter).sorted(getSort().comparator).toList(); + this.punishments = container.copy().stream().filter(getFilter().filter).filter(p -> p.matchesSearchQuery(searchQuery)).sorted(getSort().comparator).toList(); + } + + public void promptSearchQuery(){ + Bukkit.getScheduler().scheduleSyncDelayedTask(PLUGIN, player::closeInventory); + ChatInput.prompt(player, component -> { + if (component instanceof TextComponent text){ + this.searchQuery = text.content(); + // chat event is async + Bukkit.getScheduler().scheduleSyncDelayedTask(PLUGIN, this::open); + } + }, text("Enter your search query in chat").color(SECONDARY_COLOR), 30); } @Override @@ -144,16 +161,16 @@ public class SModMenu extends PageableCustomInventory { final Filter filter = getFilter(); final ItemStack stack = new ItemStack(Filter.ICON); stack.editMeta(meta -> { - meta.displayName(applyFormatting(Component.text("Filter: " + filter.name).color(SECONDARY_COLOR))); + meta.displayName(applyFormatting(text("Filter: " + filter.name).color(PRIMARY_COLOR))); ArrayList lore = new ArrayList<>(); lore.add(Component.empty()); for (Filter value : Filter.values()) { final boolean selected = filter == value; - Component filterText = applyFormatting(Component.text((selected ? "\u00BB " : "") + value.name).color(selected ? PRIMARY_COLOR : INACTIVE_COLOR)); + Component filterText = applyFormatting(text((selected ? "\u00BB " : "") + value.name).color(selected ? SECONDARY_COLOR : INACTIVE_COLOR)); lore.add(filterText); } lore.add(Component.empty()); - lore.add(applyFormatting(Component.text("\u00BB Click to switch filter").color(NamedTextColor.GOLD))); + lore.add(applyFormatting(text("\u00BB Click to switch filter").color(NamedTextColor.GOLD))); meta.lore(lore); }); filterStack = stack; @@ -164,35 +181,54 @@ public class SModMenu extends PageableCustomInventory { final Sort sort = getSort(); final ItemStack stack = new ItemStack(Sort.ICON); stack.editMeta(meta -> { - meta.displayName(applyFormatting(Component.text("Sort by: " + sort.name).color(PRIMARY_COLOR))); + meta.displayName(applyFormatting(text("Sort by: " + sort.name).color(PRIMARY_COLOR))); ArrayList lore = new ArrayList<>(); lore.add(Component.empty()); for (Sort value : Sort.values()) { final boolean selected = sort == value; - Component sortText = applyFormatting(Component.text((selected ? "\u00BB " : "") + value.name).color(selected ? SECONDARY_COLOR : INACTIVE_COLOR)); + Component sortText = applyFormatting(text((selected ? "\u00BB " : "") + value.name).color(selected ? SECONDARY_COLOR : INACTIVE_COLOR)); lore.add(sortText); } lore.add(Component.empty()); - lore.add(applyFormatting(Component.text("\u00BB Click to switch sorting option").color(NamedTextColor.GOLD))); + lore.add(applyFormatting(text("\u00BB Click to switch sorting option").color(NamedTextColor.GOLD))); meta.lore(lore); }); sortStack = stack; return stack; } + private ItemStack createSearchItem(){ + final ItemStack stack = new ItemStack(Material.FLOWER_BANNER_PATTERN); + stack.editMeta(meta -> { + meta.addItemFlags(ItemFlag.HIDE_ITEM_SPECIFICS); + meta.displayName(applyFormatting(text("Search").color(PRIMARY_COLOR))); + final ArrayList lore = new ArrayList<>(List.of( + Component.empty(), + applyFormatting(text("Current search query: %s".formatted(searchQuery == null ? "None" : "\"" + searchQuery + "\"")).color(SECONDARY_COLOR)), + Component.empty(), + applyFormatting(text("\u00BB Click to enter new search query").color(NamedTextColor.GOLD)) + )); + if (searchQuery != null){ + lore.add(applyFormatting(text("\u00BB Right click to remove search query").color(NamedTextColor.GOLD))); + } + meta.lore(lore); + }); + return searchStack = stack; + } + private ItemStack createPunishmentItem(Punishment punishment){ ItemStack stack = new ItemStack(Material.PLAYER_HEAD); stack.editMeta(meta -> { if (meta instanceof SkullMeta skullMeta){ skullMeta.setOwningPlayer(Bukkit.getOfflinePlayer(punishment.to)); } - meta.displayName(applyFormatting(Component.text(punishment.type.name).color(NamedTextColor.RED).decorate(TextDecoration.BOLD))); + meta.displayName(applyFormatting(text(punishment.type.name).color(NamedTextColor.RED).decorate(TextDecoration.BOLD))); ArrayList lore = new ArrayList<>(); - lore.add(applyFormatting(Component.text("Player: ").color(SECONDARY_COLOR).append(Component.text(PlayerUtil.offlinePlayerName(punishment.to)).color(PRIMARY_COLOR)))); - lore.add(applyFormatting(Component.text("Punished by: ").color(SECONDARY_COLOR).append(Component.text(PlayerUtil.offlinePlayerName(punishment.by)).color(PRIMARY_COLOR)))); - lore.add(applyFormatting(Component.text("Timestamp: ").color(SECONDARY_COLOR).append(Component.text(TimeUtil.calendarTimestamp(punishment.time)).color(PRIMARY_COLOR)))); + lore.add(applyFormatting(text("Player: ").color(SECONDARY_COLOR).append(text(PlayerUtil.offlinePlayerName(punishment.to)).color(PRIMARY_COLOR)))); + lore.add(applyFormatting(text("Punished by: ").color(SECONDARY_COLOR).append(text(PlayerUtil.offlinePlayerName(punishment.by)).color(PRIMARY_COLOR)))); + lore.add(applyFormatting(text("Timestamp: ").color(SECONDARY_COLOR).append(text(TimeUtil.calendarTimestamp(punishment.time)).color(PRIMARY_COLOR)))); if (punishment.type != PunishmentType.KICK){ - lore.add(applyFormatting(Component.text("Duration: ").color(SECONDARY_COLOR).append(Component.text(TimeUtil.formatTimeLong(punishment.until - punishment.time)).color(PRIMARY_COLOR)))); + lore.add(applyFormatting(text("Duration: ").color(SECONDARY_COLOR).append(text(TimeUtil.formatTimeLong(punishment.until - punishment.time)).color(PRIMARY_COLOR)))); long remainingTime = punishment.until - System.currentTimeMillis(); final String expires; if (remainingTime > 0){ @@ -201,15 +237,15 @@ public class SModMenu extends PageableCustomInventory { remainingTime *= -1; expires = TimeUtil.formatTimeLong(remainingTime) + " ago"; } - lore.add(applyFormatting(Component.text("Expires: ").color(SECONDARY_COLOR).append(Component.text(expires).color(PRIMARY_COLOR)))); + lore.add(applyFormatting(text("Expires: ").color(SECONDARY_COLOR).append(text(expires).color(PRIMARY_COLOR)))); } - lore.add(applyFormatting(Component.text("Reason: ").color(SECONDARY_COLOR).append(Component.text(punishment.reason).color(PRIMARY_COLOR)))); + lore.add(applyFormatting(text("Reason: ").color(SECONDARY_COLOR).append(text(punishment.reason).color(PRIMARY_COLOR)))); if (punishment.wasUndone()){ - lore.add(applyFormatting(Component.text("Undone by: ").color(NamedTextColor.RED).append(Component.text(PlayerUtil.offlinePlayerName(punishment.undoneBy())).color(NamedTextColor.GOLD)))); + lore.add(applyFormatting(text("Undone by: ").color(NamedTextColor.RED).append(text(PlayerUtil.offlinePlayerName(punishment.undoneBy())).color(NamedTextColor.GOLD)))); } else if (punishment.isActive()) { if ((punishment.type == PunishmentType.BAN && player.hasPermission("smod.unban")) || (punishment.type == PunishmentType.MUTE && player.hasPermission("smod.unmute"))){ lore.add(Component.empty()); - lore.add(applyFormatting(Component.text("\u00BB Click to undo punishment").color(NamedTextColor.GOLD))); + lore.add(applyFormatting(text("\u00BB Click to undo punishment").color(NamedTextColor.GOLD))); } } meta.lore(lore); @@ -224,8 +260,9 @@ public class SModMenu extends PageableCustomInventory { } inventory.setItem(45, createPreviousPageStack()); inventory.setItem(53, createNextPageStack()); - inventory.setItem(50, createFilterItem()); - inventory.setItem(48, createSortItem()); + inventory.setItem(51, createFilterItem()); + inventory.setItem(49, createSortItem()); + inventory.setItem(47, createSearchItem()); for (int i = 0; i < 45; i++) { int ci = i + (getPage() * 45); @@ -252,6 +289,16 @@ public class SModMenu extends PageableCustomInventory { cycleFilter(event.isRightClick()); } else if (stack.equals(sortStack)){ cycleSort(event.isRightClick()); + } else if (stack.equals(searchStack)){ + if (event.isRightClick() && searchQuery != null){ + player.playSound(player, Sound.UI_BUTTON_CLICK, 1f, 0.8f); + searchQuery = null; + reload(); + refresh(); + } else { + player.playSound(player, Sound.UI_BUTTON_CLICK, 1f, 2f); + promptSearchQuery(); + } } final ItemMeta itemMeta = stack.getItemMeta(); if (itemMeta != null) { diff --git a/src/main/java/de/shiewk/smoderation/punishments/Punishment.java b/src/main/java/de/shiewk/smoderation/punishments/Punishment.java index 3f89896..8b086d7 100644 --- a/src/main/java/de/shiewk/smoderation/punishments/Punishment.java +++ b/src/main/java/de/shiewk/smoderation/punishments/Punishment.java @@ -239,4 +239,23 @@ public class Punishment { default -> throw new IllegalStateException("Unknown punishment type " + type); } } + + public boolean matchesSearchQuery(String searchQuery) { + if (searchQuery == null) return true; + searchQuery = searchQuery.toLowerCase(); + return reason.toLowerCase().contains(searchQuery) + || by.toString().equalsIgnoreCase(searchQuery) + || to.toString().equalsIgnoreCase(searchQuery) + || getPlayerName().toLowerCase().contains(searchQuery) + || getModeratorName().toLowerCase().contains(searchQuery); + + } + + private String getPlayerName() { + return PlayerUtil.offlinePlayerName(to); + } + + private String getModeratorName() { + return PlayerUtil.offlinePlayerName(by); + } } From b40e543f9ecaec2aaeb5cc131b955f5f23440df9 Mon Sep 17 00:00:00 2001 From: Shiewk Date: Mon, 29 Jul 2024 15:10:47 +0200 Subject: [PATCH 07/11] Fixed a bug where players could not put any items in their ender chests --- .../java/de/shiewk/smoderation/event/EnderchestSeeEvents.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/de/shiewk/smoderation/event/EnderchestSeeEvents.java b/src/main/java/de/shiewk/smoderation/event/EnderchestSeeEvents.java index 974b759..8e86474 100644 --- a/src/main/java/de/shiewk/smoderation/event/EnderchestSeeEvents.java +++ b/src/main/java/de/shiewk/smoderation/event/EnderchestSeeEvents.java @@ -15,7 +15,7 @@ public class EnderchestSeeEvents implements Listener { final Inventory clicked = event.getView().getTopInventory(); if (!(clicked instanceof PlayerInventory)){ final InventoryHolder holder = clicked.getHolder(); - if (holder instanceof HumanEntity humanHolder && humanHolder.getEnderChest().equals(clicked)){ + if (holder instanceof HumanEntity humanHolder && humanHolder.getEnderChest().equals(clicked) && !humanHolder.equals(event.getWhoClicked())){ if (!event.getWhoClicked().hasPermission("smod.enderchestsee.modify")){ event.setCancelled(true); } From 7902bb9a4698757e15e3d9f3c26201af99c33204 Mon Sep 17 00:00:00 2001 From: Shiewk Date: Mon, 29 Jul 2024 15:12:23 +0200 Subject: [PATCH 08/11] Refactor listeners --- src/main/java/de/shiewk/smoderation/SModeration.java | 12 ++++-------- .../CustomInventoryListener.java} | 4 ++-- .../EnderchestSeeListener.java} | 4 ++-- .../InvSeeListener.java} | 4 ++-- 4 files changed, 10 insertions(+), 14 deletions(-) rename src/main/java/de/shiewk/smoderation/{event/CustomInventoryEvents.java => listener/CustomInventoryListener.java} (85%) rename src/main/java/de/shiewk/smoderation/{event/EnderchestSeeEvents.java => listener/EnderchestSeeListener.java} (90%) rename src/main/java/de/shiewk/smoderation/{event/InvSeeEvents.java => listener/InvSeeListener.java} (91%) diff --git a/src/main/java/de/shiewk/smoderation/SModeration.java b/src/main/java/de/shiewk/smoderation/SModeration.java index f30a550..6bbdb7a 100644 --- a/src/main/java/de/shiewk/smoderation/SModeration.java +++ b/src/main/java/de/shiewk/smoderation/SModeration.java @@ -1,12 +1,8 @@ package de.shiewk.smoderation; import de.shiewk.smoderation.command.*; -import de.shiewk.smoderation.event.CustomInventoryEvents; -import de.shiewk.smoderation.event.EnderchestSeeEvents; -import de.shiewk.smoderation.event.InvSeeEvents; import de.shiewk.smoderation.input.ChatInputListener; -import de.shiewk.smoderation.listener.PunishmentListener; -import de.shiewk.smoderation.listener.VanishListener; +import de.shiewk.smoderation.listener.*; import de.shiewk.smoderation.storage.PunishmentContainer; import net.kyori.adventure.text.TextComponent; import net.kyori.adventure.text.format.NamedTextColor; @@ -48,9 +44,9 @@ public final class SModeration extends JavaPlugin { @Override public void onEnable() { getPluginManager().registerEvents(new PunishmentListener(), this); - getPluginManager().registerEvents(new CustomInventoryEvents(), this); - getPluginManager().registerEvents(new InvSeeEvents(), this); - getPluginManager().registerEvents(new EnderchestSeeEvents(), this); + getPluginManager().registerEvents(new CustomInventoryListener(), this); + getPluginManager().registerEvents(new InvSeeListener(), this); + getPluginManager().registerEvents(new EnderchestSeeListener(), this); getPluginManager().registerEvents(new VanishListener(), this); getPluginManager().registerEvents(new ChatInputListener(), this); diff --git a/src/main/java/de/shiewk/smoderation/event/CustomInventoryEvents.java b/src/main/java/de/shiewk/smoderation/listener/CustomInventoryListener.java similarity index 85% rename from src/main/java/de/shiewk/smoderation/event/CustomInventoryEvents.java rename to src/main/java/de/shiewk/smoderation/listener/CustomInventoryListener.java index 3cf21ec..26dcb88 100644 --- a/src/main/java/de/shiewk/smoderation/event/CustomInventoryEvents.java +++ b/src/main/java/de/shiewk/smoderation/listener/CustomInventoryListener.java @@ -1,4 +1,4 @@ -package de.shiewk.smoderation.event; +package de.shiewk.smoderation.listener; import de.shiewk.smoderation.inventory.CustomInventory; import org.bukkit.event.EventHandler; @@ -6,7 +6,7 @@ import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; import org.bukkit.event.inventory.InventoryClickEvent; -public class CustomInventoryEvents implements Listener { +public class CustomInventoryListener implements Listener { @EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true) public void onInventoryClick(InventoryClickEvent event){ if (event.getInventory().getHolder() instanceof CustomInventory customInventory){ diff --git a/src/main/java/de/shiewk/smoderation/event/EnderchestSeeEvents.java b/src/main/java/de/shiewk/smoderation/listener/EnderchestSeeListener.java similarity index 90% rename from src/main/java/de/shiewk/smoderation/event/EnderchestSeeEvents.java rename to src/main/java/de/shiewk/smoderation/listener/EnderchestSeeListener.java index 8e86474..787f96b 100644 --- a/src/main/java/de/shiewk/smoderation/event/EnderchestSeeEvents.java +++ b/src/main/java/de/shiewk/smoderation/listener/EnderchestSeeListener.java @@ -1,4 +1,4 @@ -package de.shiewk.smoderation.event; +package de.shiewk.smoderation.listener; import org.bukkit.entity.HumanEntity; import org.bukkit.event.EventHandler; @@ -8,7 +8,7 @@ import org.bukkit.inventory.Inventory; import org.bukkit.inventory.InventoryHolder; import org.bukkit.inventory.PlayerInventory; -public class EnderchestSeeEvents implements Listener { +public class EnderchestSeeListener implements Listener { @EventHandler public void onInventoryClick(InventoryClickEvent event){ diff --git a/src/main/java/de/shiewk/smoderation/event/InvSeeEvents.java b/src/main/java/de/shiewk/smoderation/listener/InvSeeListener.java similarity index 91% rename from src/main/java/de/shiewk/smoderation/event/InvSeeEvents.java rename to src/main/java/de/shiewk/smoderation/listener/InvSeeListener.java index cd26f06..0a9d7b9 100644 --- a/src/main/java/de/shiewk/smoderation/event/InvSeeEvents.java +++ b/src/main/java/de/shiewk/smoderation/listener/InvSeeListener.java @@ -1,4 +1,4 @@ -package de.shiewk.smoderation.event; +package de.shiewk.smoderation.listener; import org.bukkit.entity.HumanEntity; import org.bukkit.event.EventHandler; @@ -9,7 +9,7 @@ import org.bukkit.inventory.PlayerInventory; import java.util.Objects; -public class InvSeeEvents implements Listener { +public class InvSeeListener implements Listener { @EventHandler public void onInventoryClick(InventoryClickEvent event){ From ce8a8a44cdd9d57747d4b05bcc2ebe5f64e53575 Mon Sep 17 00:00:00 2001 From: Shiewk Date: Mon, 29 Jul 2024 16:27:42 +0200 Subject: [PATCH 09/11] Added Invsee for equipment --- .../smoderation/command/InvseeCommand.java | 26 +++++++- .../AutoUpdatingCustomInventory.java | 3 + .../inventory/InvSeeEquipmentInventory.java | 66 +++++++++++++++++++ .../listener/CustomInventoryListener.java | 20 ++++++ 4 files changed, 112 insertions(+), 3 deletions(-) create mode 100644 src/main/java/de/shiewk/smoderation/inventory/AutoUpdatingCustomInventory.java create mode 100644 src/main/java/de/shiewk/smoderation/inventory/InvSeeEquipmentInventory.java diff --git a/src/main/java/de/shiewk/smoderation/command/InvseeCommand.java b/src/main/java/de/shiewk/smoderation/command/InvseeCommand.java index 65cec0a..c929d8f 100644 --- a/src/main/java/de/shiewk/smoderation/command/InvseeCommand.java +++ b/src/main/java/de/shiewk/smoderation/command/InvseeCommand.java @@ -1,5 +1,6 @@ package de.shiewk.smoderation.command; +import de.shiewk.smoderation.inventory.InvSeeEquipmentInventory; import de.shiewk.smoderation.util.PlayerUtil; import net.kyori.adventure.text.Component; import org.bukkit.Bukkit; @@ -19,16 +20,30 @@ import static de.shiewk.smoderation.SModeration.*; public class InvseeCommand implements TabExecutor { + private enum InvseeType { + INVENTORY, + EQUIPMENT + } + @Override public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) { if (args.length < 1) { return false; } + final InvseeType type; + if (args.length > 1){ + switch (args[1].toLowerCase()){ + case "armor", "equipment" -> type = InvseeType.EQUIPMENT; + default -> type = InvseeType.INVENTORY; + } + } else { + type = InvseeType.INVENTORY; + } if (sender instanceof HumanEntity human){ final Player player = PlayerUtil.findOnlinePlayer(args[0]); if (player != null) { - if (human.getUniqueId().equals(player.getUniqueId())){ + if (human.getUniqueId().equals(player.getUniqueId()) && type != InvseeType.EQUIPMENT){ human.sendMessage(Component.text("You can't open your own inventory.").color(FAIL_COLOR)); } else { human.sendMessage(CHAT_PREFIX.append( @@ -36,7 +51,10 @@ public class InvseeCommand implements TabExecutor { .append(Component.text(player.getName()).color(SECONDARY_COLOR)) .append(Component.text(".")) )); - human.openInventory(player.getInventory()); + switch (type){ + case INVENTORY -> human.openInventory(player.getInventory()); + case EQUIPMENT -> new InvSeeEquipmentInventory(human, player).open(); + } } } else { human.sendMessage(Component.text("This player is not online.").color(FAIL_COLOR)); @@ -49,8 +67,10 @@ public class InvseeCommand implements TabExecutor { @Override public @Nullable List onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) { - if (args.length > 1){ + if (args.length > 2){ return List.of(); + } else if (args.length > 1){ + return List.of("armor", "equipment", "inventory"); } List available = new ArrayList<>(); for (Player onlinePlayer : Bukkit.getOnlinePlayers()) { diff --git a/src/main/java/de/shiewk/smoderation/inventory/AutoUpdatingCustomInventory.java b/src/main/java/de/shiewk/smoderation/inventory/AutoUpdatingCustomInventory.java new file mode 100644 index 0000000..e055a3c --- /dev/null +++ b/src/main/java/de/shiewk/smoderation/inventory/AutoUpdatingCustomInventory.java @@ -0,0 +1,3 @@ +package de.shiewk.smoderation.inventory; + +public interface AutoUpdatingCustomInventory extends CustomInventory { } diff --git a/src/main/java/de/shiewk/smoderation/inventory/InvSeeEquipmentInventory.java b/src/main/java/de/shiewk/smoderation/inventory/InvSeeEquipmentInventory.java new file mode 100644 index 0000000..f208b39 --- /dev/null +++ b/src/main/java/de/shiewk/smoderation/inventory/InvSeeEquipmentInventory.java @@ -0,0 +1,66 @@ +package de.shiewk.smoderation.inventory; + +import de.shiewk.smoderation.SModeration; +import org.bukkit.Bukkit; +import org.bukkit.entity.HumanEntity; +import org.bukkit.event.inventory.InventoryClickEvent; +import org.bukkit.event.inventory.InventoryType; +import org.bukkit.inventory.EntityEquipment; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.NotNull; + +import static net.kyori.adventure.text.Component.text; + +public class InvSeeEquipmentInventory implements AutoUpdatingCustomInventory { + private final HumanEntity viewer; + private final HumanEntity subject; + private final Inventory inventory = Bukkit.createInventory(this, InventoryType.HOPPER, text("Player equipment")); + private boolean changing = false; + + public InvSeeEquipmentInventory(HumanEntity viewer, HumanEntity subject) { + this.viewer = viewer; + this.subject = subject; + } + + + @Override + public void refresh() { + if (!changing){ + final EntityEquipment equipment = subject.getEquipment(); + inventory.setItem(0, equipment.getHelmet()); + inventory.setItem(1, equipment.getChestplate()); + inventory.setItem(2, equipment.getLeggings()); + inventory.setItem(3, equipment.getBoots()); + inventory.setItem(4, equipment.getItemInOffHand()); + } + } + + @Override + public void open() { + refresh(); + viewer.openInventory(getInventory()); + } + + @Override + public void click(ItemStack stack, InventoryClickEvent event) { + if (viewer.hasPermission("smod.invsee.modify") && !subject.hasPermission("smod.invsee.preventmodify")){ + event.setCancelled(false); + changing = true; + Bukkit.getScheduler().scheduleSyncDelayedTask(SModeration.PLUGIN, () -> { + changing = false; + final EntityEquipment equipment = subject.getEquipment(); + equipment.setHelmet(inventory.getItem(0)); + equipment.setChestplate(inventory.getItem(1)); + equipment.setLeggings(inventory.getItem(2)); + equipment.setBoots(inventory.getItem(3)); + equipment.setItemInOffHand(inventory.getItem(4)); + }); + } + } + + @Override + public @NotNull Inventory getInventory() { + return inventory; + } +} diff --git a/src/main/java/de/shiewk/smoderation/listener/CustomInventoryListener.java b/src/main/java/de/shiewk/smoderation/listener/CustomInventoryListener.java index 26dcb88..148a857 100644 --- a/src/main/java/de/shiewk/smoderation/listener/CustomInventoryListener.java +++ b/src/main/java/de/shiewk/smoderation/listener/CustomInventoryListener.java @@ -1,17 +1,37 @@ package de.shiewk.smoderation.listener; +import com.destroystokyo.paper.event.server.ServerTickEndEvent; +import de.shiewk.smoderation.inventory.AutoUpdatingCustomInventory; import de.shiewk.smoderation.inventory.CustomInventory; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; import org.bukkit.event.inventory.InventoryClickEvent; +import org.bukkit.event.inventory.InventoryDragEvent; public class CustomInventoryListener implements Listener { @EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true) public void onInventoryClick(InventoryClickEvent event){ if (event.getInventory().getHolder() instanceof CustomInventory customInventory){ + event.setCancelled(true); customInventory.click(event.getCurrentItem(), event); + } + } + @EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true) + public void onInventoryDrag(InventoryDragEvent event){ + if (event.getInventory().getHolder() instanceof CustomInventory){ event.setCancelled(true); } } + + @EventHandler(priority = EventPriority.LOWEST) + public void onServerTickEnd(ServerTickEndEvent event){ + for (Player onlinePlayer : Bukkit.getOnlinePlayers()) { + if (onlinePlayer.getOpenInventory().getTopInventory().getHolder() instanceof AutoUpdatingCustomInventory ci) { + ci.refresh(); + } + } + } } From d7560d5ef382971a730c916609a6c745b3e1aadd Mon Sep 17 00:00:00 2001 From: Shiewk Date: Mon, 29 Jul 2024 17:07:45 +0200 Subject: [PATCH 10/11] Add ability to filter by type in SMod menu --- .../smoderation/inventory/SModMenu.java | 58 ++++++++++++++++++- 1 file changed, 55 insertions(+), 3 deletions(-) diff --git a/src/main/java/de/shiewk/smoderation/inventory/SModMenu.java b/src/main/java/de/shiewk/smoderation/inventory/SModMenu.java index de7b74f..c2bb440 100644 --- a/src/main/java/de/shiewk/smoderation/inventory/SModMenu.java +++ b/src/main/java/de/shiewk/smoderation/inventory/SModMenu.java @@ -28,6 +28,7 @@ import org.jetbrains.annotations.NotNull; import java.util.ArrayList; import java.util.Comparator; import java.util.List; +import java.util.function.Consumer; import java.util.function.Predicate; import static de.shiewk.smoderation.SModeration.*; @@ -75,8 +76,10 @@ public class SModMenu extends PageableCustomInventory { private ItemStack sortStack = null; private ItemStack filterStack = null; private ItemStack searchStack = null; + private ItemStack typeStack = null; private int sort = 0; private int filter = 0; + private int type = -1; private String searchQuery = null; public SModMenu(Player player, PunishmentContainer container) { @@ -94,8 +97,12 @@ public class SModMenu extends PageableCustomInventory { return Filter.values()[filter]; } + public PunishmentType getType(){ + return type == -1 ? null : PunishmentType.values()[type]; + } + private void reload(){ - this.punishments = container.copy().stream().filter(getFilter().filter).filter(p -> p.matchesSearchQuery(searchQuery)).sorted(getSort().comparator).toList(); + this.punishments = container.copy().stream().filter(getFilter().filter).filter(p -> getType() == null || p.type == getType()).filter(p -> p.matchesSearchQuery(searchQuery)).sorted(getSort().comparator).toList(); } public void promptSearchQuery(){ @@ -152,6 +159,25 @@ public class SModMenu extends PageableCustomInventory { refresh(); } + public void cycleType(boolean backwards){ + player.playSound(player, Sound.UI_BUTTON_CLICK, 1f, backwards ? 0.8f : 2f); + if (backwards){ + if (type <= -1){ + type = PunishmentType.values().length-1; + } else { + type--; + } + } else { + if (type >= PunishmentType.values().length-1){ + type = -1; + } else { + type++; + } + } + reload(); + refresh(); + } + @Override public void switchPage() { player.playSound(player, Sound.BLOCK_STONE_HIT, 0.75f, 1f); @@ -177,6 +203,29 @@ public class SModMenu extends PageableCustomInventory { return stack; } + private ItemStack createTypeItem(){ + final PunishmentType type = getType(); + final ItemStack stack = new ItemStack(Material.CHEST); + stack.editMeta(meta -> { + meta.displayName(applyFormatting(text("Type: " + (type == null ? "All" : type.name)).color(PRIMARY_COLOR))); + ArrayList lore = new ArrayList<>(); + lore.add(Component.empty()); + final Consumer addToLore = value -> { + final boolean selected = type == value; + Component typeText = applyFormatting(text((selected ? "\u00BB " : "") + (value == null ? "All" : value.name)).color(selected ? SECONDARY_COLOR : INACTIVE_COLOR)); + lore.add(typeText); + }; + addToLore.accept(null); + for (PunishmentType value : PunishmentType.values()) { + addToLore.accept(value); + } + lore.add(Component.empty()); + lore.add(applyFormatting(text("\u00BB Click to switch type").color(NamedTextColor.GOLD))); + meta.lore(lore); + }); + return typeStack = stack; + } + private ItemStack createSortItem(){ final Sort sort = getSort(); final ItemStack stack = new ItemStack(Sort.ICON); @@ -260,9 +309,10 @@ public class SModMenu extends PageableCustomInventory { } inventory.setItem(45, createPreviousPageStack()); inventory.setItem(53, createNextPageStack()); - inventory.setItem(51, createFilterItem()); - inventory.setItem(49, createSortItem()); inventory.setItem(47, createSearchItem()); + inventory.setItem(48, createTypeItem()); + inventory.setItem(50, createFilterItem()); + inventory.setItem(51, createSortItem()); for (int i = 0; i < 45; i++) { int ci = i + (getPage() * 45); @@ -299,6 +349,8 @@ public class SModMenu extends PageableCustomInventory { player.playSound(player, Sound.UI_BUTTON_CLICK, 1f, 2f); promptSearchQuery(); } + } else if (stack.equals(typeStack)) { + cycleType(event.isRightClick()); } final ItemMeta itemMeta = stack.getItemMeta(); if (itemMeta != null) { From 5c5eee0bca45d167288b695ef112054205782cd1 Mon Sep 17 00:00:00 2001 From: Shiewk Date: Mon, 29 Jul 2024 17:33:56 +0200 Subject: [PATCH 11/11] Update to version 1.3.0 --- README.md | 1 + docs/commands.md | 66 +++++++++++---------------------------------- docs/permissions.md | 38 +++++++++++++------------- gradle.properties | 2 +- 4 files changed, 37 insertions(+), 70 deletions(-) diff --git a/README.md b/README.md index c50cd7f..ecd553e 100644 --- a/README.md +++ b/README.md @@ -25,6 +25,7 @@ The most important ones are: - /smod - /unmute & /unban - /invsee & /enderchestsee +- /vanish ## Permissions This plugin uses Bukkit permissions for commands and other actions. diff --git a/docs/commands.md b/docs/commands.md index a7eb9cd..7685173 100644 --- a/docs/commands.md +++ b/docs/commands.md @@ -1,53 +1,17 @@ # SModeration commands -### /smod -The /smod command just opens the SMod menu. It takes no arguments. -### /mute -The /mute command is used to mute players. - -It requires 2 arguments: -- Player name -- Duration - -If you want to, you can also add a **reason**. - -For example, if you want to mute a player for breaking server rules, just use **/mute playername 1h 30min Breaking server rules.** - -The player will be muted for 1 hour and 30 minutes with the reason "Breaking server rules.". - -Muted players can still join the server, but can't use the chat. -### /ban -The /ban command works the same as the /mute command, with one important difference: - -Banned players **can't even join** the server until the ban expires. -### /kick -The /kick command is a bit different. It does not require a duration because kicks are instant. Instead, you can use the command like this: **/kick playername reason** -### /modlogs -The /modlogs command can be used when the /smod menu is unavailable. It displays information about a player in chat instead of a menu. - -Example: **/modlogs playername** shows you a message in chat that tells you whether the player is muted or banned. -### /unmute & /unban -The /unmute and /unban commands only take one argument, the player name. - -The specified player will then be unmuted or unbanned. -### /invsee -The /invsee command can be used to view the inventory of another player. - -It takes one argument: the player name. -The player has to be online. -### /enderchestsee -The /enderchestsee command can, similarly to /invsee, be used to view the ender chest of another player. - -It takes one argument: the player name. -The player has to be online. - -### /vanish -The /vanish command is used to toggle vanish mode. - -In vanish mode, other players (who don't have the necessary permissions) can't see that you're online. - -To toggle vanish mode for yourself, use **/vanish**. - -To toggle vanish mode for someone else, use **/vanish **. - -Vanish status is not saved, so you re-appear when you leave the server. \ No newline at end of file +| Command | Description | Permission | +|----------------------------------------|------------------------------------------------------------------------------|---------------------| +| /smod | Opens the SMod menu. | smod.menu | +| /mute \ \ \ | Mutes a player so that they can't type in chat for the specified duration. | smod.mute | +| /ban \ \ \ | Bans a player so that they can't join the server for the specified duration. | smod.ban | +| /kick \ \ | Kicks a player from the server. | smod.kick | +| /modlogs | Lists a player's active punishments in chat. | smod.logs | +| /unmute | Clears a player's mute status. | smod.unmute | +| /unban | Clears a player's ban status. | smod.unban | +| /invsee \ inventory | Views another player's inventory. | smod.invsee | +| /invsee \ equipment | Views another player's equipment (armor and offhand). | smod.invsee | +| /enderchestsee | Views another player's ender chest. | smod.enderchestsee | +| /vanish | Toggles vanish mode so that other players can't see you're online. | smod.vanish | +| /vanish toggle \ | Toggles vanish mode for another player. | smod.vanish | +| /vanish list | Lists all vanished players. | smod.vanish.see | diff --git a/docs/permissions.md b/docs/permissions.md index e17de60..0572df5 100644 --- a/docs/permissions.md +++ b/docs/permissions.md @@ -1,21 +1,23 @@ # SModeration permissions -- **smod.mute**: Allows the player to mute other players. -- **smod.preventmute**: Prevents the player from being muted (if they are online). -- **smod.ban**: Allows the player to ban and kick other players. -- **smod.preventban**: Prevents the player from being banned (if they are online). -- **smod.kick**: Allows the player to kick other players. -- **smod.preventkick**: Prevents the player from being kicked (if they are online). -- **smod.menu**: Allows the player to use the SModeration menu. -- **smod.notifications**: Allows the player to be notified when a punishment is issued. -- **smod.unmute**: Allows the player to unmute other players. -- **smod.unban**: Allows the player to unban other players. -- **smod.logs**: Allows the player to view mod logs. -- **smod.invsee**: Allows the player to view other players inventories. -- **smod.invsee.modify**: Allows the player to view and modify other players inventories. -- **smod.invsee.preventmodify**: When giving this permission to a player, prevents their inventory from being modified. -- **smod.enderchestsee**: Allows the player to view other players ender chests. -- **smod.enderchestsee.modify**: Allows the player to view and modify other players ender chests. -- **smod.vanish**: Allows the player to enter and leave vanish mode. -- **smod.vanish.see**: Allows the player to see vanished players +| Permission | Description | +|---------------------------|------------------------------------------------------------------| +| smod.mute | Allows the player to mute other players. | +| smod.preventmute | Prevents the player from being muted (if they are online). | +| smod.ban | Allows the player to ban and kick other players. | +| smod.preventban | Prevents the player from being banned (if they are online). | +| smod.kick | Allows the player to kick other players. | +| smod.preventkick | Prevents the player from being kicked (if they are online). | +| smod.menu | Allows the player to use the SModeration menu. | +| smod.notifications | Allows the player to be notified when a punishment is issued. | +| smod.unmute | Allows the player to unmute other players. | +| smod.unban | Allows the player to unban other players. | +| smod.logs | Allows the player to view mod logs. | +| smod.invsee | Allows the player to view other players inventories. | +| smod.invsee.modify | Allows the player to view and modify other players inventories. | +| smod.invsee.preventmodify | Prevents the player's inventory from being modified. | +| smod.enderchestsee | Allows the player to view other players ender chests. | +| smod.enderchestsee.modify | Allows the player to view and modify other players ender chests. | +| smod.vanish | Allows the player to enter and leave vanish mode. | +| smod.vanish.see | Allows the player to see vanished players | All of these permissions are granted by default if the player is a server operator. diff --git a/gradle.properties b/gradle.properties index da901d3..52a421b 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1 +1 @@ -pluginVersion = 1.2.1 \ No newline at end of file +pluginVersion = 1.3.0 \ No newline at end of file