1
mirror of https://github.com/Shiewk/SModeration.git synced 2026-04-29 06:34:17 +02:00

36 Commits

Author SHA1 Message Date
Shiewk 041c541356 (1.8.2) Fix translating system for 1.21.4 2025-12-05 17:12:08 +01:00
Shiewk dcb52e3e6d Fix hostile entities targeting vanished players 2025-12-05 16:51:23 +01:00
Shiewk 53df1a908a Fix timestamp display in SMod menu 2025-12-05 16:26:43 +01:00
Shiewk 3317e2fffd (1.8.1) Fix ban message not being translated (#13) 2025-09-19 18:59:02 +02:00
Shiewk 4b52f74fc5 (1.8.0) Allow disabling plugin features from the config (#10) 2025-09-19 18:09:52 +02:00
Shiewk 4ef2700d6b (1.7.1) Fix Folia inventory ticking error (#11) 2025-09-19 14:38:35 +02:00
Shiewk 7826c4e75a Make the mute command require a positive duration 2025-08-24 11:38:21 +02:00
Shiewk c4953d2acb (1.7.0) Add a config option that prevents players from running certain commands when they are muted 2025-08-22 11:19:04 +02:00
Shiewk 7e3139126c Config rework 2025-08-22 11:00:28 +02:00
Shiewk 2be16da939 Internationalization support 2025-07-30 13:37:30 +02:00
Shiewk a17086b059 /offlinetp command 2025-07-27 15:10:25 +02:00
Shiewk 039b40bd53 (1.6.0) Switch to Paper plugin & support Folia 2025-07-09 12:59:43 +02:00
Shiewk a69c7cb426 Clear player title after chat input 2025-07-09 11:48:00 +02:00
Shiewk 8a147eb7cf Use AsyncPlayerPreLoginEvent instead of PlayerLoginEvent
because of its deprecation in Paper 1.21.6, this event disabled re-configuration APIs when a listener is registered for it; we don't want that to happen
2025-07-09 11:44:23 +02:00
Shiewk ecdd688a79 Fix SMod menu opening in newer versions 2025-07-09 11:08:29 +02:00
Shiewk 26166b5a73 Use API version 1.21.3, fix invsee 2025-07-09 10:28:54 +02:00
Shiewk 27a1fd8244 1.5.0 2025-05-02 18:01:43 +02:00
Shiewk 66c113bad2 Save vanish state for next join 2025-05-02 17:55:10 +02:00
Shiewk d863622168 Add a config option to require a reason 2025-05-02 16:30:14 +02:00
Shiewk 361f66f645 Upgrade Paper to 1.21, use Brigadier command system 2025-05-01 19:55:55 +02:00
Shiewk fbaaa6ec89 Not using the constant value
how did I not notice
2025-05-01 11:43:15 +02:00
Shiewk 955ab8791a Allow registering skin texture provider for player heads 2025-05-01 11:25:49 +02:00
Shiewk 8128628b12 Fix pagination in SMod menu 2025-05-01 10:56:20 +02:00
Shiewk 02570993a7 Move SModeration for Paper to root project 2025-05-01 10:46:00 +02:00
Shiewk 0d095c40f0 Removed unnecessary log message, 1.4.2 2025-04-11 16:30:48 +02:00
Shiewk 8df1029d42 Add a VanishToggleEvent 2025-04-02 18:29:20 +02:00
Shiewk 2f66c6f12c move SModeration for Paper to subproject 2024-12-19 15:59:20 +01:00
Shiewk 1f9758f3d0 Use main branch for development from now on (#5) 2024-12-16 14:48:39 +01:00
Shiewk c7502fd661 add missing whitespace 2024-12-06 19:41:06 +01:00
Shiewk 1a9cf76a93 1.4.1 2024-08-25 11:12:39 +02:00
Shiewk b3ec076cae Fix chat input title delay 2024-08-25 10:59:29 +02:00
Shiewk 3cb3314f4c Allow opening own ender chest 2024-08-22 15:28:25 +02:00
Shiewk fb785fb53a Improve styling 2024-08-22 13:57:31 +02:00
Shiewk e44f6489af Update main branch to 1.4.0 (#4)
- Fixed a bug where unknown players would crash the SMod menu
- SocialSpy command and permissions
- Hide death messages from vanished players
2024-08-21 18:43:41 +02:00
Shiewk 7e90939b84 Update main branch to version 1.3.0 (#3)
- Fixed EnderchestSee bug
- Fixed vanish bug
- Moved vanish-related methods to VanishCommand.java
- Added /vanish list command and list vanished players on join
- Added search option in SMod menu with chat input
- Refactored listeners
- Added Invsee for equipment
- Added ability to filter by type in SMod menu
- Updated docs and README to version 1.3.0
2024-07-29 17:41:04 +02:00
Shiewk 4266b7ebb6 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
2024-07-23 18:36:40 +02:00
75 changed files with 2824 additions and 2145 deletions
+1 -1
View File
@@ -14,7 +14,7 @@ SModeration provides a nice user interface that can be used instead of chat comm
![SMod Menu Sort](https://github.com/Shiewk/SModeration/assets/152653291/23e3862d-0915-47bd-9c47-6d8d10f8ab69) ![SMod Menu Sort](https://github.com/Shiewk/SModeration/assets/152653291/23e3862d-0915-47bd-9c47-6d8d10f8ab69)
It has helpful functions like filtering and sorting options. It has helpful functions like filtering, searching and sorting options.
## Commands ## Commands
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). 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).
+33 -14
View File
@@ -1,5 +1,6 @@
plugins { plugins {
id 'java' id 'java'
id("xyz.jpenilla.run-paper") version "2.3.1"
} }
group = 'de.shiewk' group = 'de.shiewk'
@@ -11,17 +12,44 @@ repositories {
name = "papermc-repo" name = "papermc-repo"
url = "https://repo.papermc.io/repository/maven-public/" url = "https://repo.papermc.io/repository/maven-public/"
} }
maven { }
name = "sonatype"
url = "https://oss.sonatype.org/content/groups/public/" processResources {
def props = [version: version]
inputs.properties props
filteringCharset 'UTF-8'
filesMatching('paper-plugin.yml') {
expand props
}
}
runPaper {
folia {
registerTask()
}
}
runServer {
minecraftVersion("1.21.10")
downloadPlugins {
// for testing from other client versions
modrinth("ViaVersion", "5.5.1")
modrinth("ViaBackwards", "5.5.1")
} }
} }
dependencies { dependencies {
compileOnly "io.papermc.paper:paper-api:1.20.4-R0.1-SNAPSHOT" //compileOnly "io.papermc.paper:paper-api:1.21.4-R0.1-SNAPSHOT"
compileOnly 'dev.folia:folia-api:1.21.4-R0.1-SNAPSHOT'
} }
def targetJavaVersion = 17 jar {
archiveBaseName.set('SModeration-Paper')
archiveVersion.set(pluginVersion)
}
def targetJavaVersion = 21
java { java {
def javaVersion = JavaVersion.toVersion(targetJavaVersion) def javaVersion = JavaVersion.toVersion(targetJavaVersion)
sourceCompatibility = javaVersion sourceCompatibility = javaVersion
@@ -38,12 +66,3 @@ tasks.withType(JavaCompile).configureEach {
options.release.set(targetJavaVersion) options.release.set(targetJavaVersion)
} }
} }
processResources {
def props = [version: version]
inputs.properties props
filteringCharset 'UTF-8'
filesMatching('plugin.yml') {
expand props
}
}
+1 -1
View File
@@ -13,6 +13,6 @@
| /invsee \<player> equipment | Views another player's equipment (armor and offhand). | smod.invsee | | /invsee \<player> equipment | Views another player's equipment (armor and offhand). | smod.invsee |
| /enderchestsee <player> | Views another player's ender chest. | smod.enderchestsee | | /enderchestsee <player> | 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 | Toggles vanish mode so that other players can't see you're online. | smod.vanish |
| /vanish toggle \<player> | Toggles vanish mode for another player. | smod.vanish | | /vanish toggle \<players> | Toggles vanish mode for other players. | smod.vanish |
| /vanish list | Lists all vanished players. | smod.vanish.see | | /vanish list | Lists all vanished players. | smod.vanish.see |
| /socialspy | Enables SocialSpy mode where you can see other player's private messages. | smod.socialspy | | /socialspy | Enables SocialSpy mode where you can see other player's private messages. | smod.socialspy |
+15
View File
@@ -0,0 +1,15 @@
# SModeration config
| Key | What it does |
|--------------------------|------------------------------------------------------------------------------------------------------------------------|
| socialspy-commands | The commands that `/socialspy` will listen to. |
| force-reason | Whether a reason is required for every punishment. |
| muted-forbidden-commands | Commands that players are not allowed to run while they are muted. |
| features | Controls which plugin features are enabled. |
| features.punishments | Whether the plugin provides punishing features (kick, ban, mute) |
| features.smodmenu | If punishments are enabled, controls whether the SMod Menu can be opened. Has no effect when punishments are disabled. |
| features.invsee | Whether the plugin provides invsee feature |
| features.enderchestsee | Whether the plugin provides enderchestsee feature |
| features.offlinetp | Whether the plugin provides the offlinetp feature |
| features.socialspy | Whether the plugin provides the SocialSpy feature |
| features.vanish | Whether the plugin provides the vanish feature |
+1 -1
View File
@@ -1 +1 @@
pluginVersion = 1.4.0 pluginVersion = 1.8.2
+1 -1
View File
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip distributionUrl=https\://services.gradle.org/distributions/gradle-8.11-bin.zip
networkTimeout=10000 networkTimeout=10000
validateDistributionUrl=true validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
@@ -1,92 +0,0 @@
package de.shiewk.smoderation;
import de.shiewk.smoderation.command.*;
import de.shiewk.smoderation.config.SModerationConfig;
import de.shiewk.smoderation.input.ChatInputListener;
import de.shiewk.smoderation.listener.*;
import de.shiewk.smoderation.storage.PunishmentContainer;
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.PluginCommand;
import org.bukkit.command.TabExecutor;
import org.bukkit.entity.Player;
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;
public final class SModeration extends JavaPlugin {
public static final PunishmentContainer container = new PunishmentContainer();
public static ComponentLogger LOGGER = null;
public static SModeration PLUGIN = null;
public static SModerationConfig CONFIG = null;
public static File SAVE_FILE = null;
public static final TextColor PRIMARY_COLOR = TextColor.color(212, 0, 255);
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 = text("SM \u00BB ").color(PRIMARY_COLOR);
@Override
public void onLoad() {
LOGGER = getComponentLogger();
PLUGIN = this;
CONFIG = new SModerationConfig(this.getConfig(), this);
SAVE_FILE = new File(this.getDataFolder().getAbsolutePath() + "/container.gz");
}
@Override
public void onEnable() {
getPluginManager().registerEvents(new PunishmentListener(), 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);
getPluginManager().registerEvents(new SocialSpyListener(), this);
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());
registerCommand("socialspy", new SocialSpyCommand());
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);
}
}
}
}
@@ -1,124 +0,0 @@
package de.shiewk.smoderation.command;
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.*;
import org.bukkit.entity.Player;
import org.bukkit.util.StringUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
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){
return false;
} else {
UUID senderUUID;
if (sender instanceof ConsoleCommandSender){
senderUUID = PlayerUtil.UUID_CONSOLE;
} 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));
return true;
} else {
sender.sendMessage(Component.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 ban 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));
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++) {
String arg = args[i];
long parsedDuration = TimeUtil.parseDurationMillisSafely(arg);
if (parsedDuration == -1){
p = i;
break;
} else {
duration += parsedDuration;
}
if (i == args.length - 1){ p = args.length; }
}
if (duration == 0){
sender.sendMessage(Component.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));
return false;
}
StringBuilder reason = new StringBuilder();
for (int i = p; i < args.length; i++) {
if (!reason.isEmpty()){
reason.append(" ");
}
reason.append(args[i]);
}
final Punishment punishment = Punishment.ban(System.currentTimeMillis(), System.currentTimeMillis() + duration, senderUUID, uuid, reason.isEmpty() ? Punishment.DEFAULT_REASON : reason.toString());
Punishment.issue(punishment, SModeration.container);
return true;
}
}
@Override
public @Nullable List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
if (args.length < 2){
String toComplete = args.length > 0 ? args[0] : "";
ArrayList<String> names = new ArrayList<>();
for (Player onlinePlayer : Bukkit.getOnlinePlayers()) {
names.add(onlinePlayer.getName());
}
ArrayList<String> completions = new ArrayList<>();
StringUtil.copyPartialMatches(toComplete, names, completions);
return completions;
} else {
for (int i = 1; i < args.length; i++) {
if (TimeUtil.parseDurationMillisSafely(args[i]) == -1){
try {
Long.parseLong(args[i]);
} catch (NumberFormatException ignored){
if (i != 1){
return List.of();
}
}
}
}
return List.of(
"100ms",
"15s", // some sample completions for duration
"30min", // you can input your own ones as well
"6h",
"1d",
"2w",
"3mo",
"1y"
);
}
}
}
@@ -1,63 +0,0 @@
package de.shiewk.smoderation.command;
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.CommandSender;
import org.bukkit.command.TabExecutor;
import org.bukkit.entity.HumanEntity;
import org.bukkit.entity.Player;
import org.bukkit.util.StringUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.List;
import static de.shiewk.smoderation.SModeration.*;
public class EnderchestSeeCommand implements TabExecutor {
@Override
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
if (args.length < 1) {
return false;
}
if (sender instanceof HumanEntity human){
final Player player = PlayerUtil.findOnlinePlayer(args[0]);
if (player != null) {
if (human.getUniqueId().equals(player.getUniqueId())){
human.sendMessage(Component.text("You can't open your own ender chest.").color(FAIL_COLOR));
} else {
human.sendMessage(CHAT_PREFIX.append(
Component.text("Opening ender chest of ").color(PRIMARY_COLOR)
.append(Component.text(player.getName()).color(SECONDARY_COLOR))
.append(Component.text("."))
));
human.openInventory(player.getEnderChest());
}
} else {
human.sendMessage(Component.text("This player is not online.").color(FAIL_COLOR));
}
} else {
sender.sendMessage(Component.text("Only an entity that can open inventories can execute this command!").color(FAIL_COLOR));
}
return true;
}
@Override
public @Nullable List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
if (args.length > 1){
return List.of();
}
List<String> available = new ArrayList<>();
for (Player onlinePlayer : Bukkit.getOnlinePlayers()) {
available.add(onlinePlayer.getName());
}
List<String> completions = new ArrayList<>();
StringUtil.copyPartialMatches(args.length > 0 ? args[0] : "", available, completions);
return completions;
}
}
@@ -1,83 +0,0 @@
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;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.command.TabExecutor;
import org.bukkit.entity.HumanEntity;
import org.bukkit.entity.Player;
import org.bukkit.util.StringUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.List;
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()) && type != InvseeType.EQUIPMENT){
human.sendMessage(Component.text("You can't open your own inventory.").color(FAIL_COLOR));
} else {
human.sendMessage(CHAT_PREFIX.append(
Component.text("Opening inventory of ").color(PRIMARY_COLOR)
.append(Component.text(player.getName()).color(SECONDARY_COLOR))
.append(Component.text("."))
));
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));
}
} else {
sender.sendMessage(Component.text("Only an entity that can open inventories can execute this command!").color(FAIL_COLOR));
}
return true;
}
@Override
public @Nullable List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
if (args.length > 2){
return List.of();
} else if (args.length > 1){
return List.of("armor", "equipment", "inventory");
}
List<String> available = new ArrayList<>();
for (Player onlinePlayer : Bukkit.getOnlinePlayers()) {
available.add(onlinePlayer.getName());
}
List<String> completions = new ArrayList<>();
StringUtil.copyPartialMatches(args.length > 0 ? args[0] : "", available, completions);
return completions;
}
}
@@ -1,81 +0,0 @@
package de.shiewk.smoderation.command;
import de.shiewk.smoderation.SModeration;
import de.shiewk.smoderation.punishments.Punishment;
import de.shiewk.smoderation.util.PlayerUtil;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;
import org.bukkit.Bukkit;
import org.bukkit.command.*;
import org.bukkit.entity.Player;
import org.bukkit.util.StringUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
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){
return false;
} else {
UUID senderUUID;
if (sender instanceof ConsoleCommandSender){
senderUUID = PlayerUtil.UUID_CONSOLE;
} 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));
return true;
} else {
sender.sendMessage(Component.text("Your command sender type is unknown (%s).".formatted(sender.getClass().getName())).color(NamedTextColor.RED));
return true;
}
String playerName = args[0];
Player player = Bukkit.getPlayer(playerName);
if (player == null) {
sender.sendMessage(Component.text("This player is not online.").color(NamedTextColor.RED));
return true;
}
UUID uuid = player.getUniqueId();
if (senderUUID.equals(uuid)) {
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()){
reason.append(" ");
}
reason.append(args[i]);
}
final Punishment punishment = Punishment.kick(System.currentTimeMillis(), senderUUID, uuid, reason.isEmpty() ? Punishment.DEFAULT_REASON : reason.toString());
Punishment.issue(punishment, SModeration.container);
return true;
}
}
@Override
public @Nullable List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
if (args.length < 2){
String toComplete = args.length > 0 ? args[0] : "";
ArrayList<String> names = new ArrayList<>();
for (Player onlinePlayer : Bukkit.getOnlinePlayers()) {
names.add(onlinePlayer.getName());
}
ArrayList<String> completions = new ArrayList<>();
StringUtil.copyPartialMatches(toComplete, names, completions);
return completions;
}
return List.of();
}
}
@@ -1,79 +0,0 @@
package de.shiewk.smoderation.command;
import de.shiewk.smoderation.SModeration;
import de.shiewk.smoderation.punishments.Punishment;
import de.shiewk.smoderation.punishments.PunishmentType;
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.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.command.TabExecutor;
import org.bukkit.entity.Player;
import org.bukkit.util.StringUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import static de.shiewk.smoderation.SModeration.*;
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){
return false;
} else {
String playername = args[0];
String name;
UUID uuid;
try {
uuid = UUID.fromString(playername);
} catch (IllegalArgumentException ignored){
uuid = PlayerUtil.offlinePlayerUUIDByName(playername);
}
if (uuid == null){
sender.sendMessage(Component.text("This player was not found. Try running /%s with an UUID instead.".formatted(label)).color(NamedTextColor.RED));
return true;
}
name = PlayerUtil.offlinePlayerName(uuid);
sender.sendMessage(CHAT_PREFIX.append(Component.text("Player ").color(PRIMARY_COLOR)
.append(Component.text(name).color(SECONDARY_COLOR))
.append(Component.text(" (%s)".formatted(uuid)).color(INACTIVE_COLOR))));
UUID finalUuid = uuid;
final List<Punishment> punishments = SModeration.container.findAll(p -> p.to.equals(finalUuid) && p.isActive());
for (Punishment punishment : punishments) {
sender.sendMessage(Component.text("- is currently ").color(PRIMARY_COLOR)
.append(Component.text(punishment.type == PunishmentType.BAN ? "banned" : "muted").color(SECONDARY_COLOR))
.append(Component.text(" until ").color(PRIMARY_COLOR))
.append(Component.text(TimeUtil.calendarTimestamp(punishment.until)).color(SECONDARY_COLOR))
.append(Component.text(" (in %s)".formatted(TimeUtil.formatTimeLong(punishment.until - System.currentTimeMillis()))).color(INACTIVE_COLOR))
.append(Component.text(". Reason: ").color(PRIMARY_COLOR))
.append(Component.text(punishment.reason).color(SECONDARY_COLOR)));
}
if (punishments.isEmpty()){
sender.sendMessage(Component.text("- has no punishments.").color(PRIMARY_COLOR));
}
return true;
}
}
@Override
public @Nullable List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
if (args.length > 1){
return List.of();
}
String search = args.length > 0 ? args[0] : "";
List<String> playernames = new ArrayList<>();
for (Player onlinePlayer : Bukkit.getOnlinePlayers()) {
playernames.add(onlinePlayer.getName());
}
List<String> completions = new ArrayList<>();
StringUtil.copyPartialMatches(search, playernames, completions);
return completions;
}
}
@@ -1,123 +0,0 @@
package de.shiewk.smoderation.command;
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.format.NamedTextColor;
import org.bukkit.Bukkit;
import org.bukkit.command.*;
import org.bukkit.entity.Player;
import org.bukkit.util.StringUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
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){
return false;
} else {
UUID senderUUID;
if (sender instanceof ConsoleCommandSender){
senderUUID = PlayerUtil.UUID_CONSOLE;
} else if (sender instanceof Player pl){
senderUUID = pl.getUniqueId();
} else if (sender instanceof BlockCommandSender){
sender.sendMessage(text("Blocks can't execute this command.").color(NamedTextColor.RED));
return true;
} else {
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(text("You can't mute yourself.").color(NamedTextColor.RED));
return true;
}
if (uuid == null) {
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;
int p = 1;
for (int i = 1 /* start with index 1 to avoid player name */; i < args.length; i++) {
String arg = args[i];
long parsedDuration = TimeUtil.parseDurationMillisSafely(arg);
if (parsedDuration == -1){
p = i;
break;
} else {
duration += parsedDuration;
}
if (i == args.length - 1){ p = args.length; }
}
if (duration == 0){
sender.sendMessage(text("Please provide a valid duration.").color(NamedTextColor.RED));
return false;
}
if (duration < 0){
sender.sendMessage(text("Please provide a duration that's longer than 0ms.").color(NamedTextColor.RED));
return false;
}
StringBuilder reason = new StringBuilder();
for (int i = p; i < args.length; i++) {
if (!reason.isEmpty()){
reason.append(" ");
}
reason.append(args[i]);
}
final Punishment punishment = Punishment.mute(System.currentTimeMillis(), System.currentTimeMillis() + duration, senderUUID, uuid, reason.isEmpty() ? Punishment.DEFAULT_REASON : reason.toString());
Punishment.issue(punishment, SModeration.container);
return true;
}
}
@Override
public @Nullable List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
if (args.length < 2){
String toComplete = args.length > 0 ? args[0] : "";
ArrayList<String> names = new ArrayList<>();
for (Player onlinePlayer : Bukkit.getOnlinePlayers()) {
names.add(onlinePlayer.getName());
}
ArrayList<String> completions = new ArrayList<>();
StringUtil.copyPartialMatches(toComplete, names, completions);
return completions;
} else {
for (int i = 1; i < args.length; i++) {
if (TimeUtil.parseDurationMillisSafely(args[i]) == -1){
try {
Long.parseLong(args[i]);
} catch (NumberFormatException ignored){
if (i != 1){
return List.of();
}
}
}
}
return List.of(
"100ms",
"15s", // some sample completions for duration
"30min", // you can input your own ones as well
"6h",
"1d",
"2w",
"3mo",
"1y"
);
}
}
}
@@ -1,27 +0,0 @@
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.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 SModCommand implements TabExecutor {
@Override
public boolean onCommand(@NotNull CommandSender commandSender, @NotNull Command command, @NotNull String s, @NotNull String[] strings) {
if (commandSender instanceof Player player){
new SModMenu(player, SModeration.container).open();
}
return true;
}
@Override
public @Nullable List<String> onTabComplete(@NotNull CommandSender commandSender, @NotNull Command command, @NotNull String s, @NotNull String[] strings) {
return List.of();
}
}
@@ -1,32 +0,0 @@
package de.shiewk.smoderation.command;
import de.shiewk.smoderation.listener.SocialSpyListener;
import net.kyori.adventure.text.format.NamedTextColor;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.command.TabExecutor;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
import static de.shiewk.smoderation.SModeration.CHAT_PREFIX;
import static net.kyori.adventure.text.Component.text;
public class SocialSpyCommand implements TabExecutor {
@Override
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
final boolean enabled = SocialSpyListener.toggle(sender);
sender.sendMessage(CHAT_PREFIX.append(text("SocialSpy ").append(
enabled ?
text("enabled").color(NamedTextColor.GREEN) :
text("disabled").color(NamedTextColor.RED)
).append(text("."))));
return true;
}
@Override
public @Nullable List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
return List.of();
}
}
@@ -1,64 +0,0 @@
package de.shiewk.smoderation.command;
import de.shiewk.smoderation.SModeration;
import de.shiewk.smoderation.punishments.Punishment;
import de.shiewk.smoderation.punishments.PunishmentType;
import de.shiewk.smoderation.util.PlayerUtil;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;
import org.bukkit.command.*;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
import java.util.UUID;
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){
return false;
} else {
UUID senderUUID;
if (sender instanceof ConsoleCommandSender){
senderUUID = PlayerUtil.UUID_CONSOLE;
} 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));
return true;
} else {
sender.sendMessage(Component.text("Your command sender type is unknown (%s).".formatted(sender.getClass().getName())).color(NamedTextColor.RED));
return true;
}
String nameArg = args[0];
UUID uuid;
try {
uuid = UUID.fromString(nameArg);
} catch (IllegalArgumentException ignored){
uuid = PlayerUtil.offlinePlayerUUIDByName(nameArg);
}
if (uuid == null){
sender.sendMessage(Component.text("This player was not found. Try running /%s with an UUID instead.".formatted(label)).color(NamedTextColor.RED));
return true;
}
UUID finalUuid = uuid;
final Punishment punishment = SModeration.container.find(p -> p.to.equals(finalUuid) && p.isActive() && p.type == PunishmentType.BAN);
if (punishment != null) {
punishment.undo(senderUUID);
punishment.broadcastUndo(SModeration.container);
} else {
sender.sendMessage(Component.text("This player is not banned.").color(NamedTextColor.RED));
}
return true;
}
}
@Override
public @Nullable List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
return List.of();
}
}
@@ -1,64 +0,0 @@
package de.shiewk.smoderation.command;
import de.shiewk.smoderation.SModeration;
import de.shiewk.smoderation.punishments.Punishment;
import de.shiewk.smoderation.punishments.PunishmentType;
import de.shiewk.smoderation.util.PlayerUtil;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;
import org.bukkit.command.*;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
import java.util.UUID;
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){
return false;
} else {
UUID senderUUID;
if (sender instanceof ConsoleCommandSender){
senderUUID = PlayerUtil.UUID_CONSOLE;
} 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));
return true;
} else {
sender.sendMessage(Component.text("Your command sender type is unknown (%s).".formatted(sender.getClass().getName())).color(NamedTextColor.RED));
return true;
}
String nameArg = args[0];
UUID uuid;
try {
uuid = UUID.fromString(nameArg);
} catch (IllegalArgumentException ignored){
uuid = PlayerUtil.offlinePlayerUUIDByName(nameArg);
}
if (uuid == null){
sender.sendMessage(Component.text("This player was not found. Try running /%s with an UUID instead.".formatted(label)).color(NamedTextColor.RED));
return true;
}
UUID finalUuid = uuid;
final Punishment punishment = SModeration.container.find(p -> p.to.equals(finalUuid) && p.isActive() && p.type == PunishmentType.MUTE);
if (punishment != null) {
punishment.undo(senderUUID);
punishment.broadcastUndo(SModeration.container);
} else {
sender.sendMessage(Component.text("This player is not muted.").color(NamedTextColor.RED));
}
return true;
}
}
@Override
public @Nullable List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
return List.of();
}
}
()){
@@ -1,133 +0,0 @@
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;
import org.bukkit.command.TabExecutor;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
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
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
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;
}
}
@Override
public @Nullable List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
if (args.length < 2){
return List.of("list", "toggle");
}
if (args.length < 3 && args[0].equalsIgnoreCase("toggle")){
return PlayerUtil.listPlayerNames(args[1]);
}
return List.of();
}
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 : 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);
}
}
@Override
public @NotNull ArgumentType<String> getNativeType() {
return StringArgumentType.word();
}
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<Player> 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);
}
}
}
@@ -1,30 +0,0 @@
package de.shiewk.smoderation.config;
import de.shiewk.smoderation.SModeration;
import org.bukkit.configuration.file.FileConfiguration;
import java.util.List;
public class SModerationConfig {
private final FileConfiguration config;
private final SModeration plugin;
public SModerationConfig(FileConfiguration config, SModeration plugin) {
this.config = config;
this.plugin = plugin;
}
public List<String> getSocialSpyCommands(List<String> default_){
final String path = "socialspy-commands";
if (!config.contains(path)){
config.set(path, default_);
plugin.saveConfig();
}
return config.getStringList(path);
}
public FileConfiguration getConfig() {
return config;
}
}
@@ -1,393 +0,0 @@
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;
import org.bukkit.Material;
import org.bukkit.NamespacedKey;
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;
import org.bukkit.persistence.PersistentDataContainer;
import org.bukkit.persistence.PersistentDataType;
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.*;
import static net.kyori.adventure.text.Component.text;
public class SModMenu extends PageableCustomInventory {
public enum Filter {
ACTIVE("Active punishments", Punishment::isActive),
OLD("Old punishments", p -> !p.isActive()),
ALL("All punishments", p -> true);
public static final Material ICON = Material.HOPPER;
public final String name;
public final Predicate<Punishment> filter;
Filter(String name, Predicate<Punishment> filter) {
this.name = name;
this.filter = filter;
}
}
public enum Sort {
EXPIRY("Expiry", Comparator.comparingLong(p -> p.until)),
TIME("Date", Comparator.comparingLong(p -> p.time)),
PLAYER_NAME("Player name", (p1, p2) -> String.CASE_INSENSITIVE_ORDER.compare(PlayerUtil.offlinePlayerName(p1.to), PlayerUtil.offlinePlayerName(p2.to))),
MODERATOR_NAME("Moderator name", (p1, p2) -> String.CASE_INSENSITIVE_ORDER.compare(PlayerUtil.offlinePlayerName(p1.by), PlayerUtil.offlinePlayerName(p2.by)));
public static final Material ICON = Material.COMPARATOR;
public final String name;
public final Comparator<Punishment> comparator;
Sort(String name, Comparator<Punishment> comparator) {
this.name = name;
this.comparator = comparator;
}
}
private static final NamespacedKey PUNISHMENT_STORE_KEY = new NamespacedKey("smod", "punishmentid");
private final Inventory inventory;
private final Player player;
private final PunishmentContainer container;
private List<Punishment> punishments;
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) {
this.player = player;
this.container = container;
this.inventory = Bukkit.createInventory(this, 54, text("SMod Menu"));
reload();
}
public Sort getSort(){
return Sort.values()[sort];
}
public Filter getFilter(){
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 -> getType() == null || p.type == getType())
.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
public int lastPage() {
return Math.max((punishments.size() - 1) / 45, 0);
}
public void cycleFilter(boolean backwards){
player.playSound(player, Sound.UI_BUTTON_CLICK, 1f, backwards ? 0.8f : 2f);
if (backwards){
if (filter <= 0){
filter = Filter.values().length-1;
} else {
filter--;
}
} else {
if (filter >= Filter.values().length-1){
filter = 0;
} else {
filter++;
}
}
reload();
refresh();
}
public void cycleSort(boolean backwards){
player.playSound(player, Sound.UI_BUTTON_CLICK, 1f, backwards ? 0.8f : 2f);
if (backwards){
if (sort <= 0){
sort = Sort.values().length-1;
} else {
sort--;
}
} else {
if (sort >= Sort.values().length-1){
sort = 0;
} else {
sort++;
}
}
reload();
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);
}
private ItemStack createFilterItem(){
final Filter filter = getFilter();
final ItemStack stack = new ItemStack(Filter.ICON);
stack.editMeta(meta -> {
meta.displayName(applyFormatting(text("Filter: " + filter.name).color(PRIMARY_COLOR)));
ArrayList<Component> lore = new ArrayList<>();
lore.add(Component.empty());
for (Filter value : Filter.values()) {
final boolean selected = filter == value;
Component filterText = applyFormatting(text((selected ? "\u00BB " : "") + value.name).color(selected ? SECONDARY_COLOR : INACTIVE_COLOR));
lore.add(filterText);
}
lore.add(Component.empty());
lore.add(applyFormatting(text("\u00BB Click to switch filter").color(NamedTextColor.GOLD)));
meta.lore(lore);
});
filterStack = stack;
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<Component> lore = new ArrayList<>();
lore.add(Component.empty());
final Consumer<PunishmentType> 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);
stack.editMeta(meta -> {
meta.displayName(applyFormatting(text("Sort by: " + sort.name).color(PRIMARY_COLOR)));
ArrayList<Component> lore = new ArrayList<>();
lore.add(Component.empty());
for (Sort value : Sort.values()) {
final boolean selected = sort == value;
Component sortText = applyFormatting(text((selected ? "\u00BB " : "") + value.name).color(selected ? SECONDARY_COLOR : INACTIVE_COLOR));
lore.add(sortText);
}
lore.add(Component.empty());
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<Component> 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){
try {
skullMeta.setOwningPlayer(Bukkit.getOfflinePlayer(punishment.to));
} catch (NullPointerException e) {
LOGGER.warn("Player {} has a punishment but was never on this server!", punishment.to);
};
}
meta.displayName(applyFormatting(text(punishment.type.name).color(NamedTextColor.RED).decorate(TextDecoration.BOLD)));
ArrayList<Component> lore = new ArrayList<>();
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(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){
expires = "in " + TimeUtil.formatTimeLong(remainingTime);
} else {
remainingTime *= -1;
expires = TimeUtil.formatTimeLong(remainingTime) + " ago";
}
lore.add(applyFormatting(text("Expires: ").color(SECONDARY_COLOR).append(text(expires).color(PRIMARY_COLOR))));
}
lore.add(applyFormatting(text("Reason: ").color(SECONDARY_COLOR).append(text(punishment.reason).color(PRIMARY_COLOR))));
if (punishment.wasUndone()){
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(text("\u00BB Click to undo punishment").color(NamedTextColor.GOLD)));
}
}
meta.lore(lore);
});
return stack;
}
@Override
public void refresh() {
for (int i = 45; i < 54; i++) {
inventory.setItem(i, createEmptyStack());
}
inventory.setItem(45, createPreviousPageStack());
inventory.setItem(53, createNextPageStack());
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);
if (punishments.size() > ci){
final Punishment punishment = punishments.get(ci);
final ItemStack item = createPunishmentItem(punishment);
if (punishment.isActive()){
if ((punishment.type == PunishmentType.BAN && player.hasPermission("smod.unban")) || (punishment.type == PunishmentType.MUTE && player.hasPermission("smod.unmute"))) {
item.editMeta(meta -> meta.getPersistentDataContainer().set(PUNISHMENT_STORE_KEY, PersistentDataType.LONG, punishment.time));
}
}
inventory.setItem(i, item);
} else {
inventory.setItem(i, new ItemStack(Material.AIR));
}
}
}
@Override
public void click(ItemStack stack, InventoryClickEvent event) {
super.click(stack, event);
if (stack != null) {
if (stack.equals(filterStack)){
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();
}
} else if (stack.equals(typeStack)) {
cycleType(event.isRightClick());
}
final ItemMeta itemMeta = stack.getItemMeta();
if (itemMeta != null) {
final PersistentDataContainer persistentDataContainer = itemMeta.getPersistentDataContainer();
final Long timestamp = persistentDataContainer.get(PUNISHMENT_STORE_KEY, PersistentDataType.LONG);
if (timestamp != null) {
final Punishment punishment = container.findByTimestamp(timestamp);
if (punishment != null) {
new ConfirmationInventory(player, "Do you want to undo this punishment?", () -> {
punishment.undo(player.getUniqueId());
punishment.broadcastUndo(container);
player.playSound(player, Sound.BLOCK_NOTE_BLOCK_PLING, 1f, 2f);
this.open();
}, this::open, false).open();
}
}
}
}
}
@Override
public void open() {
reload();
refresh();
player.openInventory(this.inventory);
}
@Override
public @NotNull Inventory getInventory() {
return inventory;
}
}
@@ -1,70 +0,0 @@
package de.shiewk.smoderation.listener;
import de.shiewk.smoderation.SModeration;
import de.shiewk.smoderation.event.PunishmentIssueEvent;
import de.shiewk.smoderation.punishments.Punishment;
import de.shiewk.smoderation.punishments.PunishmentType;
import de.shiewk.smoderation.storage.PunishmentContainer;
import io.papermc.paper.event.player.AsyncChatEvent;
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.player.PlayerLoginEvent;
import org.bukkit.event.world.WorldSaveEvent;
import static de.shiewk.smoderation.SModeration.CHAT_PREFIX;
public class PunishmentListener implements Listener {
@EventHandler(priority = EventPriority.LOW)
public void onPlayerLogin(PlayerLoginEvent event){
Punishment punishment = SModeration.container.find(p ->
p.type == PunishmentType.BAN
&& p.to.equals(event.getPlayer().getUniqueId())
&& p.isActive());
if (punishment != null){
event.disallow(PlayerLoginEvent.Result.KICK_BANNED, CHAT_PREFIX.append(punishment.playerMessage()));
}
}
@EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
public void onPlayerChat(AsyncChatEvent event){
final Player player = event.getPlayer();
final Punishment punishment = SModeration.container.find(p ->
p.type == PunishmentType.MUTE
&& p.
Shiewk faa2eb0a43 1.4.0 2024-08-21 18:40:56 +02:00
Shiewk 8c00347ef2 Hide death messages from vanished players 2024-08-21 18:40:06 +02:00
Shiewk 8de4382ec4 SocialSpy command and permissions 2024-08-21 18:32:01 +02:00
Shiewk 7e90939b84 Update main branch to version 1.3.0 (#3)
- Fixed EnderchestSee bug
- Fixed vanish bug
- Moved vanish-related methods to VanishCommand.java
- Added /vanish list command and list vanished players on join
- Added search option in SMod menu with chat input
- Refactored listeners
- Added Invsee for equipment
- Added ability to filter by type in SMod menu
- Updated docs and README to version 1.3.0
2024-07-29 17:41:04 +02:00
Shiewk 4266b7ebb6 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
2024-07-23 18:36:40 +02:00
+33 -14
View File
@@ -1,5 +1,6 @@
plugins { plugins {
id 'java' id 'java'
id("xyz.jpenilla.run-paper") version "2.3.1"
} }
group = 'de.shiewk' group = 'de.shiewk'
@@ -11,17 +12,44 @@ repositories {
name = "papermc-repo" group = 'de.shiewk' group = 'de.shiewk'
@@ -11,17 +12,44 @@ repositories {
name = "papermc-repo" name = "papermc-repo"
url = "https://repo.papermc.io/repository/maven-public/" url = "https://repo.papermc.io/repository/maven-public/"
} }
maven { }
name = "sonatype"
url = "https://oss.sonatype.org/content/groups/public/"
import org.bukkit.event.player.PlayerQuitEvent;
import static de.shiewk.smoderation.SModeration.SECONDARY_COLOR;
import static net.kyori.adventure.text.Component.text;
public class VanishListener implements Listener {
@EventHandler public void onPlayerQuit(PlayerQuitEvent event){
final Player player = event.getPlayer();
if (VanishCommand.isVanished(player)){
VanishCommand.toggleVanish(player);
}
for (Player vanishedPlayer : VanishCommand.getVanishedPlayers()) {
// to clean up visibility status
player.hideEntity(SModeration.PLUGIN, vanishedPlayer);
}
}
@EventHandler(priority = EventPriority.MONITOR) public void onPlayerJoin(PlayerJoinEvent event){
Bukkit.getScheduler().scheduleSyncDelayedTask(SModeration.PLUGIN, () -> {
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);
}
});
}
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
public void onPlayerDeath(PlayerDeathEvent event){
final Component message = event.deathMessage();
if (VanishCommand.isVanished(event.getPlayer()) && message != null){
event.deathMessage(null);
for (Player onlinePlayer : Bukkit.getOnlinePlayers()) {
if (onlinePlayer.hasPermission("smod.vanish.see")){
onlinePlayer.sendMessage(text("[VANISH] ").color(SECONDARY_COLOR).append(message));
}
}
}
}
}
@@ -0,0 +1,197 @@
package de.shiewk.smoderation.paper;
import com.google.gson.Gson;
import de.shiewk.smoderation.paper.command.*;
import de.shiewk.smoderation.paper.input.ChatInput;
import de.shiewk.smoderation.paper.input.ChatInputListener;
import de.shiewk.smoderation.paper.listener.*;
import de.shiewk.smoderation.paper.storage.PunishmentContainer;
import de.shiewk.smoderation.paper.translation.TranslatorManager;
import de.shiewk.smoderation.paper.util.SchedulerUtil;
import io.papermc.paper.command.brigadier.Commands;
import io.papermc.paper.plugin.lifecycle.event.types.LifecycleEvents;
import net.kyori.adventure.key.Key;
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 net.kyori.adventure.text.minimessage.MiniMessage;
import net.kyori.adventure.text.minimessage.tag.Tag;
import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver;
import org.bukkit.Bukkit;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.entity.Player;
import org.bukkit.event.Listener;
import org.bukkit.plugin.java.JavaPlugin;
import java.io.File;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Locale;
import static de.shiewk.smoderation.paper.command.VanishCommand.isVanished;
import static de.shiewk.smoderation.paper.command.VanishCommand.toggleVanish;
import static net.kyori.adventure.text.Component.text;
import static org.bukkit.Bukkit.getPluginManager;
public final class SModerationPaper extends JavaPlugin {
public static final Gson gson = new Gson();
public static final PunishmentContainer container = new PunishmentContainer }
public boolean isFeatureEnabled(String feature){
return getConfig().getBoolean("features."+feature, true);
}
@Override
public void onEnable() {
LOGGER.info("Folia: {}", SchedulerUtil. Comparing a7c487decd..823093be35 - SModeration - Shy Git