1
mirror of https://github.com/Shiewk/SModeration.git synced 2026-04-28 05:54:16 +02:00

Update main branch to version 1.2.0

- Improved command registration
- Add permissions for mute/kick/ban immunity
- Add vanish command and permissions
- Update to version 1.2.0
This commit is contained in:
Shy
2024-07-23 18:36:40 +02:00
committed by GitHub
19 changed files with 258 additions and 128 deletions
+9 -56
View File
@@ -17,62 +17,15 @@ SModeration provides a nice user interface that can be used instead of chat comm
It has helpful functions like filtering and sorting options.
## 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.
This plugin has many commands, for a complete list of commands and their usage, please see [the commands list](https://github.com/Shiewk/SModeration/blob/main/docs/commands.md).
The most important ones are:
- /mute
- /ban
- /kick
- /smod
- /unmute & /unban
- /invsee & /enderchestsee
## Permissions
This plugin uses Bukkit permissions for commands and other actions.
- **smod.mute**: Allows the player to mute other players.
- **smod.ban**: Allows the player to ban and kick other players.
- **smod.kick**: Allows the player to kick other players.
- **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.
All of these permissions are granted by default if the player is a server operator.
For a list of permissions, please see [the permissions file](https://github.com/Shiewk/SModeration/blob/main/docs/permissions.md).
+1 -1
View File
@@ -3,7 +3,7 @@ plugins {
}
group = 'de.shiewk'
version = '1.1.1'
version = pluginVersion
repositories {
mavenCentral()
+11
View File
@@ -40,3 +40,14 @@ The /enderchestsee command can, similarly to /invsee, be used to view the ender
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 <playername>**.
Vanish status is not saved, so you re-appear when you leave the server.
+3
View File
@@ -1,7 +1,10 @@
# 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.
+1
View File
@@ -0,0 +1 @@
pluginVersion = 1.2.0
@@ -5,17 +5,23 @@ import de.shiewk.smoderation.event.CustomInventoryEvents;
import de.shiewk.smoderation.event.EnderchestSeeEvents;
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 net.kyori.adventure.text.Component;
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;
import org.bukkit.plugin.java.JavaPlugin;
import java.io.File;
import static net.kyori.adventure.text.Component.text;
import static org.bukkit.Bukkit.getPluginManager;
public final class SModeration extends JavaPlugin {
@@ -29,7 +35,7 @@ public final class SModeration extends JavaPlugin {
public static final TextColor SECONDARY_COLOR = TextColor.color(52, 143, 255);
public static final TextColor INACTIVE_COLOR = NamedTextColor.GRAY;
public static final TextColor FAIL_COLOR = NamedTextColor.RED;
public static final TextComponent CHAT_PREFIX = Component.text("SM \u00BB ").color(PRIMARY_COLOR);
public static final TextComponent CHAT_PREFIX = text("SM \u00BB ").color(PRIMARY_COLOR);
@Override
public void onLoad() {
@@ -44,57 +50,88 @@ public final class SModeration extends JavaPlugin {
getPluginManager().registerEvents(new CustomInventoryEvents(), this);
getPluginManager().registerEvents(new InvSeeEvents(), this);
getPluginManager().registerEvents(new EnderchestSeeEvents(), this);
getPluginManager().registerEvents(new VanishListener(), this);
final PluginCommand mute = getCommand("mute");
assert mute != null;
mute.setExecutor(new MuteCommand());
mute.setTabCompleter(new MuteCommand());
final PluginCommand ban = getCommand("ban");
assert ban != null;
ban.setExecutor(new BanCommand());
ban.setTabCompleter(new BanCommand());
final PluginCommand kick = getCommand("kick");
assert kick != null;
kick.setExecutor(new KickCommand());
kick.setTabCompleter(new KickCommand());
final PluginCommand smod = getCommand("smod");
assert smod != null;
smod.setExecutor(new SModCommand());
smod.setTabCompleter(new SModCommand());
final PluginCommand logs = getCommand("modlogs");
assert logs != null;
logs.setExecutor(new ModLogsCommand());
logs.setTabCompleter(new ModLogsCommand());
final PluginCommand unmute = getCommand("unmute");
assert unmute != null;
unmute.setExecutor(new UnmuteCommand());
unmute.setTabCompleter(new UnmuteCommand());
final PluginCommand unban = getCommand("unban");
assert unban != null;
unban.setExecutor(new UnbanCommand());
unban.setTabCompleter(new UnbanCommand());
final PluginCommand invsee = getCommand("invsee");
assert invsee != null;
invsee.setExecutor(new InvseeCommand());
invsee.setTabCompleter(new InvseeCommand());
final PluginCommand ecsee = getCommand("enderchestsee");
assert ecsee != null;
ecsee.setExecutor(new EnderchestSeeCommand());
ecsee.setTabCompleter(new EnderchestSeeCommand());
registerCommand("mute", new MuteCommand());
registerCommand("ban", new BanCommand());
registerCommand("kick", new KickCommand());
registerCommand("smod", new SModCommand());
registerCommand("modlogs", new ModLogsCommand());
registerCommand("unmute", new UnmuteCommand());
registerCommand("unban", new UnbanCommand());
registerCommand("invsee", new InvseeCommand());
registerCommand("enderchestsee", new EnderchestSeeCommand());
registerCommand("vanish", new VanishCommand());
container.load(SAVE_FILE);
}
private void registerCommand(String label, TabExecutor executor){
final PluginCommand command = getCommand(label);
if (command != null) {
command.setExecutor(executor);
command.setTabCompleter(executor);
} else {
LOGGER.warn("Command %s failed to register: This command does not exist".formatted(label));
}
}
@Override
public void onDisable() {
SModeration.container.save(SModeration.SAVE_FILE);
for (Player player : Bukkit.getOnlinePlayers()) {
// in case players are still vanished when the server shuts down
if (isVanished(player)){
toggleVanish(player);
}
}
}
private static final ObjectArrayList<Player> 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<Player> getVanishedPlayers() {
return vanishedPlayers.clone();
}
}
@@ -17,7 +17,9 @@ import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
public class BanCommand implements CommandExecutor, TabCompleter {
import static net.kyori.adventure.text.Component.text;
public class BanCommand implements TabExecutor {
@Override
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
if (args.length < 2){
@@ -45,6 +47,11 @@ public class BanCommand implements CommandExecutor, TabCompleter {
sender.sendMessage(Component.text("This player is either offline or was never on this server.").color(NamedTextColor.RED));
return true;
}
final Player toPlayer = Bukkit.getPlayer(uuid);
if (toPlayer != null && toPlayer.hasPermission("smod.preventban")){
sender.sendMessage(text().content("This player can't be banned.").color(NamedTextColor.RED));
return true;
}
long duration = 0;
int p = 1;
for (int i = 1 /* start with index 1 to avoid player name */; i < args.length; i++) {
@@ -4,9 +4,8 @@ import de.shiewk.smoderation.util.PlayerUtil;
import net.kyori.adventure.text.Component;
import org.bukkit.Bukkit;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.command.TabCompleter;
import org.bukkit.command.TabExecutor;
import org.bukkit.entity.HumanEntity;
import org.bukkit.entity.Player;
import org.bukkit.util.StringUtil;
@@ -18,7 +17,7 @@ import java.util.List;
import static de.shiewk.smoderation.SModeration.*;
public class EnderchestSeeCommand implements CommandExecutor, TabCompleter {
public class EnderchestSeeCommand implements TabExecutor {
@Override
@@ -4,9 +4,8 @@ import de.shiewk.smoderation.util.PlayerUtil;
import net.kyori.adventure.text.Component;
import org.bukkit.Bukkit;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.command.TabCompleter;
import org.bukkit.command.TabExecutor;
import org.bukkit.entity.HumanEntity;
import org.bukkit.entity.Player;
import org.bukkit.util.StringUtil;
@@ -18,7 +17,7 @@ import java.util.List;
import static de.shiewk.smoderation.SModeration.*;
public class InvseeCommand implements CommandExecutor, TabCompleter {
public class InvseeCommand implements TabExecutor {
@Override
@@ -16,7 +16,9 @@ import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
public class KickCommand implements CommandExecutor, TabCompleter {
import static net.kyori.adventure.text.Component.text;
public class KickCommand implements TabExecutor {
@Override
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
if (args.length < 1){
@@ -45,6 +47,10 @@ public class KickCommand implements CommandExecutor, TabCompleter {
sender.sendMessage(Component.text("You can't kick yourself.").color(NamedTextColor.RED));
return true;
}
if (player.hasPermission("smod.preventkick")){
sender.sendMessage(text().content("This player can't be kicked.").color(NamedTextColor.RED));
return true;
}
StringBuilder reason = new StringBuilder();
for (int i = 1; i < args.length; i++) {
if (!reason.isEmpty()){
@@ -9,9 +9,8 @@ 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.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.command.TabCompleter;
import org.bukkit.command.TabExecutor;
import org.bukkit.entity.Player;
import org.bukkit.util.StringUtil;
import org.jetbrains.annotations.NotNull;
@@ -23,7 +22,7 @@ import java.util.UUID;
import static de.shiewk.smoderation.SModeration.*;
public class ModLogsCommand implements CommandExecutor, TabCompleter {
public class ModLogsCommand implements TabExecutor {
@Override
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
if (args.length < 1){
@@ -4,7 +4,6 @@ import de.shiewk.smoderation.SModeration;
import de.shiewk.smoderation.punishments.Punishment;
import de.shiewk.smoderation.util.PlayerUtil;
import de.shiewk.smoderation.util.TimeUtil;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;
import org.bukkit.Bukkit;
import org.bukkit.command.*;
@@ -17,7 +16,9 @@ import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
public class MuteCommand implements CommandExecutor, TabCompleter {
import static net.kyori.adventure.text.Component.text;
public class MuteCommand implements TabExecutor {
@Override
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
if (args.length < 2){
@@ -29,20 +30,25 @@ public class MuteCommand implements CommandExecutor, TabCompleter {
} else if (sender instanceof Player pl){
senderUUID = pl.getUniqueId();
} else if (sender instanceof BlockCommandSender){
sender.sendMessage(Component.text("Blocks can't execute this command.").color(NamedTextColor.RED));
sender.sendMessage(text("Blocks can't execute this command.").color(NamedTextColor.RED));
return true;
} else {
sender.sendMessage(Component.text("Your command sender type is unknown (%s).".formatted(sender.getClass().getName())).color(NamedTextColor.RED));
sender.sendMessage(text("Your command sender type is unknown (%s).".formatted(sender.getClass().getName())).color(NamedTextColor.RED));
return true;
}
String playerName = args[0];
UUID uuid = PlayerUtil.offlinePlayerUUIDByName(playerName);
if (senderUUID.equals(uuid)) {
sender.sendMessage(Component.text("You can't mute yourself.").color(NamedTextColor.RED));
sender.sendMessage(text("You can't mute yourself.").color(NamedTextColor.RED));
return true;
}
if (uuid == null) {
sender.sendMessage(Component.text("This player is either offline or was never on this server.").color(NamedTextColor.RED));
sender.sendMessage(text("This player is either offline or was never on this server.").color(NamedTextColor.RED));
return true;
}
final Player toPlayer = Bukkit.getPlayer(uuid);
if (toPlayer != null && toPlayer.hasPermission("smod.preventmute")){
sender.sendMessage(text().content("This player can't be muted.").color(NamedTextColor.RED));
return true;
}
long duration = 0;
@@ -59,11 +65,11 @@ public class MuteCommand implements CommandExecutor, TabCompleter {
if (i == args.length - 1){ p = args.length; }
}
if (duration == 0){
sender.sendMessage(Component.text("Please provide a valid duration.").color(NamedTextColor.RED));
sender.sendMessage(text("Please provide a valid duration.").color(NamedTextColor.RED));
return false;
}
if (duration < 0){
sender.sendMessage(Component.text("Please provide a duration that's longer than 0ms.").color(NamedTextColor.RED));
sender.sendMessage(text("Please provide a duration that's longer than 0ms.").color(NamedTextColor.RED));
return false;
}
StringBuilder reason = new StringBuilder();
@@ -3,16 +3,15 @@ package de.shiewk.smoderation.command;
import de.shiewk.smoderation.SModeration;
import de.shiewk.smoderation.inventory.SModMenu;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.command.TabCompleter;
import org.bukkit.command.TabExecutor;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
public class SModCommand implements CommandExecutor, TabCompleter {
public class SModCommand implements TabExecutor {
@Override
public boolean onCommand(@NotNull CommandSender commandSender, @NotNull Command command, @NotNull String s, @NotNull String[] strings) {
if (commandSender instanceof Player player){
@@ -14,7 +14,7 @@ import org.jetbrains.annotations.Nullable;
import java.util.List;
import java.util.UUID;
public class UnbanCommand implements CommandExecutor, TabCompleter {
public class UnbanCommand implements TabExecutor {
@Override
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
if (args.length < 1){
@@ -14,7 +14,7 @@ import org.jetbrains.annotations.Nullable;
import java.util.List;
import java.util.UUID;
public class UnmuteCommand implements CommandExecutor, TabCompleter {
public class UnmuteCommand implements TabExecutor {
@Override
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
if (args.length < 1){
@@ -0,0 +1,39 @@
package de.shiewk.smoderation.command;
import de.shiewk.smoderation.SModeration;
import de.shiewk.smoderation.util.PlayerUtil;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.command.TabExecutor;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
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){
SModeration.toggleVanish(player);
return true;
} else {
return false;
}
}
@Override
public @Nullable List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
if (args.length < 2){
return PlayerUtil.listPlayerNames();
}
return List.of();
}
}
@@ -0,0 +1,34 @@
package de.shiewk.smoderation.listener;
import de.shiewk.smoderation.SModeration;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.event.player.PlayerQuitEvent;
public class VanishListener implements Listener {
@EventHandler public void onPlayerQuit(PlayerQuitEvent event){
final Player player = event.getPlayer();
if (SModeration.isVanished(player)){
SModeration.toggleVanish(player);
}
for (Player vanishedPlayer : SModeration.getVanishedPlayers()) {
// to clean up visibility status
player.hideEntity(SModeration.PLUGIN, vanishedPlayer);
}
}
@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);
}
}
}
}
@@ -9,7 +9,10 @@ import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.function.Predicate;
public abstract class PlayerUtil {
private PlayerUtil(){}
@@ -55,4 +58,17 @@ public abstract class PlayerUtil {
return null;
}
public static List<String> listPlayerNames(){
return listPlayerNames(pl -> true);
}
public static List<String> listPlayerNames(final Predicate<Player> predicate) {
final ArrayList<String> names = new ArrayList<>();
for (Player onlinePlayer : Bukkit.getOnlinePlayers()) {
if (predicate.test(onlinePlayer)){
names.add(onlinePlayer.getName());
}
}
return List.copyOf(names);
}
}
+22 -1
View File
@@ -71,6 +71,12 @@ commands:
- ecs
permission: smod.enderchestsee
description: Views the ender chest of another player.
vanish:
usage: "§cUsage: /vanish <player>"
aliases:
- smvanish
permission: smod.vanish
description: Toggles vanish mode which prevents other players from seeing you're online
permissions:
smod.mute:
default: op
@@ -116,4 +122,19 @@ permissions:
default: op
description: Allows the player to view and modify other players ender chests.
children:
- smod.enderchestsee
- smod.enderchestsee
smod.preventmute:
default: op
description: Prevents the player from being muted (if online)
smod.preventkick:
default: op
description: Prevents the player from being muted (if online)
smod.preventban:
default: op
description: Prevents the player from being muted (if online)
smod.vanish:
default: op
description: Allows the player to use /vanish
smod.vanish.see:
default: op
description: Allows the player to see vanished players