9 Commits
Author SHA1 Message Date
auto 3b2aa84164 Add player muted logging and abstract embed building
The update introduces a log entry indicating when a player has been muted due to voting. The embed creation for this process has been isolated and extracted into a separate function. This contributes to better code modularity and organization.
2024-04-13 16:52:56 +02:00
auto 0fb497c2f1 Merge branch 'main' into vote_mute 2024-04-13 16:15:56 +02:00
auto 192fca3a89 Fix chat log message deletion query
Corrected the SQL query in the `deleteOldMessages` method within `ChatLogQueries.java`. Originally, it was incorrectly deleting newer messages rather than older ones due to an incorrect comparison symbol. It has now been adjusted to properly delete older messages based on the provided duration.
2024-04-07 19:16:32 +02:00
auto d6135f2456 Add mute vote results sent to Discord and staff presence check
Enhanced the vote-to-mute feature by adding a function that sends the mute vote results to a general channel on Discord. A 'staff presence' check has also been added which prevents the mute vote from being initiated if a staff member is online, instead, it prompts users to directly contact a staff member for help.
2024-04-07 18:29:46 +02:00
auto c057c69653 Enable optional logging in ChatLogHandler
Modified the ChatLogHandler to support optional logging by introducing a new argument in the getInstance() method. This argument sets the logging state during instantiation. This facilitates better flexibility when using the ChatLogHandler across different sections of the code base as logging requirements may differ.
2024-04-07 18:11:19 +02:00
auto c25767e473 Add VoteToMuteHelper and enhance ActiveVoteToMute
Implemented a new module titled VoteToMuteHelper to enhance the voting system and augment the user experience. This module enhances the system by providing relevant player suggestions and setting up the mute player. Made updates to the ActiveVoteToMute module to handle potential voters and mute the player if the vote is passed. VoteToMute module is also updated to include the total eligible players. The code is made robust by adding appropriate error checks.
2024-04-07 18:07:20 +02:00
auto 37aa9fdf4c Replace Object2ObjectOpenHashMap with HashMap
The usage of Object2ObjectOpenHashMap in storing chat logs and the chat log handler was switched to HashMap. This was done to ensure the plugin can be run on proxy as velocity does not include this library
2024-04-07 16:32:33 +02:00
auto ed2ba74772 Add start of VoteToMute functionality in chat system
Implemented VoteToMute system enabling initiated voting for muting a player in chat. This includes creating new classes "ActiveVoteToMute", "VoteToMute", and "VoteToMuteStarter". The "VoteToMute" class handles the voting command logic, it allows players to vote on whether to mute other players. The code also adds a call to register this new command in the main VelocityChat class.
2024-04-06 19:39:36 +02:00
auto 44d6e994cc Implement chat log handler with database support
The code changes introduce the ability to log chat messages. A new ChatLogHandler class has been added that manages the queue of chat log messages, both storing them in memory and writing them to a database. New columns have been added to the database and the interactivity with the database is handled using prepared statements to improve security and performance. The chat messages are deleted from the database after a certain period, which can be configured.
2024-04-06 17:25:15 +02:00
25 changed files with 179 additions and 275 deletions
Vendored
-20
View File
@@ -1,20 +0,0 @@
pipeline {
agent any
stages {
stage('Gradle') {
steps {
sh './gradlew build'
}
}
stage('Archive') {
steps {
archiveArtifacts artifacts: 'build/libs/', followSymlinks: false
}
}
stage('discord') {
steps {
discordSend description: "Build: ${BUILD_NUMBER}", showChangeset: true, result: currentBuild.currentResult, title: currentBuild.fullProjectName, webhookURL: env.discordwebhook
}
}
}
}
+2 -3
View File
@@ -3,10 +3,9 @@ plugins {
} }
dependencies { dependencies {
// compileOnly("com.alttd:Galaxy-API:1.21-R0.1-SNAPSHOT") { compileOnly("com.alttd:Galaxy-API:1.19.2-R0.1-SNAPSHOT") {
// exclude("net.kyori") // exclude("net.kyori")
// } }
compileOnly("io.papermc.paper:paper-api:1.21-R0.1-SNAPSHOT")
compileOnly("org.spongepowered:configurate-yaml:4.1.2") // Configurate compileOnly("org.spongepowered:configurate-yaml:4.1.2") // Configurate
compileOnly("net.luckperms:api:5.3") // Luckperms compileOnly("net.luckperms:api:5.3") // Luckperms
} }
@@ -32,7 +32,7 @@ public final class Config {
public static File CONFIGPATH; public static File CONFIGPATH;
public static void init() { public static void init() {
CONFIGPATH = new File(File.separator + "mnt" + File.separator + "configs" + File.separator + "ChatPlugin"); CONFIGPATH = new File(System.getProperty("user.home") + File.separator + "share" + File.separator + "configs" + File.separator + "ChatPlugin");
CONFIG_FILE = new File(CONFIGPATH, "config.yml"); CONFIG_FILE = new File(CONFIGPATH, "config.yml");
configLoader = YamlConfigurationLoader.builder() configLoader = YamlConfigurationLoader.builder()
.file(CONFIG_FILE) .file(CONFIG_FILE)
@@ -28,10 +28,8 @@ public class ChatLogHandler {
private final HashMap<UUID, List<ChatLog>> chatLogs = new HashMap<>(); private final HashMap<UUID, List<ChatLog>> chatLogs = new HashMap<>();
public ChatLogHandler(boolean enableLogging) { public ChatLogHandler(boolean enableLogging) {
if (!enableLogging) { if (!enableLogging)
ALogger.info("Logging is not enabled on this server.");
return; return;
}
Duration deleteThreshold = Duration.ofDays(Config.CHAT_LOG_DELETE_OLDER_THAN_DAYS); Duration deleteThreshold = Duration.ofDays(Config.CHAT_LOG_DELETE_OLDER_THAN_DAYS);
ChatLogQueries.deleteOldMessages(deleteThreshold).thenAccept(success -> { ChatLogQueries.deleteOldMessages(deleteThreshold).thenAccept(success -> {
if (success) { if (success) {
@@ -41,12 +39,8 @@ public class ChatLogHandler {
} }
}); });
executorService = Executors.newSingleThreadScheduledExecutor(); executorService = Executors.newSingleThreadScheduledExecutor();
executorService.scheduleAtFixedRate(() -> { executorService.scheduleAtFixedRate(() -> saveToDatabase(false),
saveToDatabase(false);
ALogger.info(String.format("Running scheduler to save messages with a %d delay", Config.CHAT_LOG_SAVE_DELAY_MINUTES));
},
Config.CHAT_LOG_SAVE_DELAY_MINUTES, Config.CHAT_LOG_SAVE_DELAY_MINUTES, TimeUnit.MINUTES); Config.CHAT_LOG_SAVE_DELAY_MINUTES, Config.CHAT_LOG_SAVE_DELAY_MINUTES, TimeUnit.MINUTES);
ALogger.info("Logging has started!");
} }
/** /**
@@ -76,27 +70,19 @@ public class ChatLogHandler {
private void saveToDatabase(boolean onMainThread) { private void saveToDatabase(boolean onMainThread) {
savingToDatabase(true); savingToDatabase(true);
ALogger.info(String.format("Saving %d messages to database", chatLogs.size()));
CompletableFuture<Boolean> booleanCompletableFuture = ChatLogQueries.storeMessages(chatLogs); CompletableFuture<Boolean> booleanCompletableFuture = ChatLogQueries.storeMessages(chatLogs);
if (onMainThread) { if (onMainThread) {
booleanCompletableFuture.join(); booleanCompletableFuture.join();
ALogger.info("Finished saving messages on main thread");
return; return;
} }
booleanCompletableFuture.whenComplete((result, throwable) -> { booleanCompletableFuture.whenComplete((result, throwable) -> {
if (throwable == null && result) { if (throwable == null && result) {
chatLogs.clear(); chatLogs.clear();
} else {
ALogger.error("Failed to save chat messages.");
} }
savingToDatabase(false); savingToDatabase(false);
if (!chatLogQueue.isEmpty()) {
ALogger.info("Adding back messages from queue to chatLogs map");
}
while (!chatLogQueue.isEmpty()) { while (!chatLogQueue.isEmpty()) {
addLog(chatLogQueue.remove()); addLog(chatLogQueue.remove());
} }
ALogger.info("Finished saving messages");
}); });
} }
+15 -2
View File
@@ -1,12 +1,25 @@
plugins { plugins {
`java-library` `java-library`
id("io.github.goooler.shadow") version "8.1.8" id("com.github.johnrengelman.shadow") version "7.1.0"
} }
allprojects { allprojects {
group = "com.alttd.chat" group = "com.alttd.chat"
version = "2.0.0-SNAPSHOT" version = "2.0.0-SNAPSHOT"
description = "All in one minecraft chat plugin" description = "All in one minecraft chat plugin"
// repositories {
// mavenCentral()
// maven("https://repo.destro.xyz/snapshots") // Altitude - Galaxy
// maven("https://oss.sonatype.org/content/groups/public/") // Adventure
// maven("https://oss.sonatype.org/content/repositories/snapshots/") // Minimessage
// maven("https://oss.sonatype.org/content/repositories/") // Minimessage
// maven("https://nexus.velocitypowered.com/repository/") // Velocity
// maven("https://nexus.velocitypowered.com/repository/maven-public/") // Velocity
// maven("https://repo.spongepowered.org/maven") // Configurate
// maven("https://repo.extendedclip.com/content/repositories/placeholderapi/") // Papi
// maven("https://jitpack.io")
// }
} }
subprojects { subprojects {
@@ -14,7 +27,7 @@ subprojects {
java { java {
toolchain { toolchain {
languageVersion.set(JavaLanguageVersion.of(21)) languageVersion.set(JavaLanguageVersion.of(17))
} }
} }
+36 -3
View File
@@ -1,25 +1,58 @@
import java.io.FileOutputStream
import java.net.URL
plugins { plugins {
`maven-publish` `maven-publish`
id("io.github.goooler.shadow") id("com.github.johnrengelman.shadow")
id("xyz.jpenilla.run-paper") version "1.0.6"
} }
dependencies { dependencies {
implementation(project(":api")) // API implementation(project(":api")) // API
// compileOnly("com.alttd:Galaxy-API:1.21-R0.1-SNAPSHOT") // Galaxy compileOnly("com.alttd:Galaxy-API:1.20.4-R0.1-SNAPSHOT") // Galaxy
compileOnly("io.papermc.paper:paper-api:1.21-R0.1-SNAPSHOT")
compileOnly("com.gitlab.ruany:LiteBansAPI:0.3.5") // move to proxy compileOnly("com.gitlab.ruany:LiteBansAPI:0.3.5") // move to proxy
compileOnly("org.apache.commons:commons-lang3:3.12.0") // needs an alternative, already removed from upstream api and will be removed in server compileOnly("org.apache.commons:commons-lang3:3.12.0") // needs an alternative, already removed from upstream api and will be removed in server
compileOnly("net.luckperms:api:5.3") // Luckperms compileOnly("net.luckperms:api:5.3") // Luckperms
compileOnly(files("../libs/CMI.jar"))
} }
tasks { tasks {
shadowJar { shadowJar {
archiveFileName.set("${rootProject.name}-${project.name}-${project.version}.jar") archiveFileName.set("${rootProject.name}-${project.name}-${project.version}.jar")
// minimize()
} }
build { build {
// setBuildDir("${rootProject.buildDir}")
dependsOn(shadowJar) dependsOn(shadowJar)
} }
runServer {
val dir = File(System.getProperty("user.home") + "/share/devserver/");
if (!dir.parentFile.exists()) {
dir.parentFile.mkdirs()
}
runDirectory.set(dir)
val fileName = "/galaxy.jar"
var file = File(dir.path + fileName)
if (!file.parentFile.exists()) {
file.parentFile.mkdirs()
}
if (!file.exists()) {
download("https://repo.destro.xyz/snapshots/com/alttd/Galaxy-Server/Galaxy-paperclip-1.19.2-R0.1-SNAPSHOT-reobf.jar", file)
}
serverJar(file)
minecraftVersion("1.19.2")
}
}
fun download(link: String, path: File) {
URL(link).openStream().use { input ->
FileOutputStream(path).use { output ->
input.copyTo(output)
}
}
} }
@@ -38,9 +38,9 @@ public class ChatPlugin extends JavaPlugin {
chatAPI = new ChatImplementation(); chatAPI = new ChatImplementation();
chatHandler = new ChatHandler(); chatHandler = new ChatHandler();
DatabaseConnection.initialize(); DatabaseConnection.initialize();
serverConfig = new ServerConfig(Bukkit.getServer().getName()); serverConfig = new ServerConfig(Bukkit.getServerName());
ChatLogHandler chatLogHandler = ChatLogHandler.getInstance(true); ChatLogHandler chatLogHandler = ChatLogHandler.getInstance(true);
registerListener(new PlayerListener(serverConfig), new ChatListener(chatLogHandler), new BookListener(), new ShutdownListener(chatLogHandler, this)); registerListener(new PlayerListener(serverConfig), new ChatListener(chatLogHandler), new BookListener(), new ShutdownListener(chatLogHandler));
if(serverConfig.GLOBALCHAT) { if(serverConfig.GLOBALCHAT) {
registerCommand("globalchat", new GlobalChat()); registerCommand("globalchat", new GlobalChat());
registerCommand("toggleglobalchat", new ToggleGlobalChat()); registerCommand("toggleglobalchat", new ToggleGlobalChat());
@@ -119,7 +119,7 @@ public class ChatPlugin extends JavaPlugin {
public void ReloadConfig() { public void ReloadConfig() {
chatAPI.ReloadConfig(); chatAPI.ReloadConfig();
chatAPI.ReloadChatFilters(); chatAPI.ReloadChatFilters();
serverConfig = new ServerConfig(Bukkit.getServer().getName()); serverConfig = new ServerConfig(Bukkit.getServerName());
Bukkit.broadcast(Utility.parseMiniMessage("Reloaded ChatPlugin Config."), "command.chat.reloadchat"); Bukkit.broadcast(Utility.parseMiniMessage("Reloaded ChatPlugin Config."), "command.chat.reloadchat");
ALogger.info("Reloaded ChatPlugin config."); ALogger.info("Reloaded ChatPlugin config.");
} }
@@ -38,7 +38,7 @@ public class ChatChannel extends BukkitCommand {
} }
if(args.length == 0 && player.hasPermission(channel.getPermission())) { if(args.length == 0 && player.hasPermission(channel.getPermission())) {
player.sendRichMessage(Config.CUSTOM_CHANNEL_TOGGLED, TagResolver.resolver( player.sendMiniMessage(Config.CUSTOM_CHANNEL_TOGGLED, TagResolver.resolver(
Placeholder.unparsed("channel", channel.getChannelName()), Placeholder.unparsed("channel", channel.getChannelName()),
Placeholder.component("status", toggleableForCustomChannel.toggle(player.getUniqueId()) Placeholder.component("status", toggleableForCustomChannel.toggle(player.getUniqueId())
? Config.TOGGLED_ON : Config.TOGGLED_OFF))); ? Config.TOGGLED_ON : Config.TOGGLED_OFF)));
@@ -27,7 +27,7 @@ public class PartyChat extends Toggleable implements CommandExecutor {
} }
if(args.length == 0) { if(args.length == 0) {
player.sendRichMessage(Config.PARTY_TOGGLED, Placeholder.component("status", player.sendMiniMessage(Config.PARTY_TOGGLED, Placeholder.component("status",
toggle(player.getUniqueId()) ? Config.TOGGLED_ON : Config.TOGGLED_OFF)); toggle(player.getUniqueId()) ? Config.TOGGLED_ON : Config.TOGGLED_OFF));
return true; return true;
} }
@@ -26,7 +26,6 @@ import org.bukkit.inventory.ItemStack;
import java.util.*; import java.util.*;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.stream.Stream;
public class ChatHandler { public class ChatHandler {
@@ -131,7 +130,7 @@ public class ChatHandler {
Placeholder.component("sender", senderName), Placeholder.component("sender", senderName),
Placeholder.component("prefix", prefix), Placeholder.component("prefix", prefix),
Placeholder.component("message", parseMessageContent(player, message)), Placeholder.component("message", parseMessageContent(player, message)),
Placeholder.parsed("server", Bukkit.getServer().getName()) Placeholder.parsed("server", Bukkit.getServerName())
); );
Component component = Utility.parseMiniMessage(Config.GCFORMAT, placeholders); Component component = Utility.parseMiniMessage(Config.GCFORMAT, placeholders);
@@ -165,7 +164,7 @@ public class ChatHandler {
TagResolver placeholders = TagResolver.resolver( TagResolver placeholders = TagResolver.resolver(
Placeholder.component("sender", senderName), Placeholder.component("sender", senderName),
Placeholder.component("message", parseMessageContent(player, message)), Placeholder.component("message", parseMessageContent(player, message)),
Placeholder.parsed("server", Bukkit.getServer().getName()), Placeholder.parsed("server", Bukkit.getServerName()),
Placeholder.parsed("channel", channel.getChannelName()) Placeholder.parsed("channel", channel.getChannelName())
); );
Component component = Utility.parseMiniMessage(channel.getFormat(), placeholders); Component component = Utility.parseMiniMessage(channel.getFormat(), placeholders);
@@ -238,21 +237,12 @@ public class ChatHandler {
} }
private void sendChatChannelMessage(CustomChannel chatChannel, UUID uuid, Component component) { private void sendChatChannelMessage(CustomChannel chatChannel, UUID uuid, Component component) {
if (!chatChannel.getServers().contains(Bukkit.getServer().getName())) { if (!chatChannel.getServers().contains(Bukkit.getServerName())) return;
return;
}
Player player = Bukkit.getPlayer(uuid); Bukkit.getServer().getOnlinePlayers().stream()
if (player == null) { .filter(p -> p.hasPermission(chatChannel.getPermission()))
return; .filter(p -> !ChatUserManager.getChatUser(p.getUniqueId()).getIgnoredPlayers().contains(uuid))
} .forEach(p -> p.sendMessage(component));
Stream<? extends Player> stream = Bukkit.getServer().getOnlinePlayers().stream()
.filter(p -> p.hasPermission(chatChannel.getPermission()));
if (!player.hasPermission("chat.ignorebypass")) {
stream = stream.filter(p -> !ChatUserManager.getChatUser(p.getUniqueId()).getIgnoredPlayers().contains(uuid) && !p.hasPermission("chat.ignorebypass"));
}
stream.forEach(p -> p.sendMessage(component));
} }
private void sendPluginMessage(Player player, String channel, Component component) { private void sendPluginMessage(Player player, String channel, Component component) {
@@ -32,10 +32,8 @@ import org.jetbrains.annotations.NotNull;
import java.util.HashSet; import java.util.HashSet;
import java.util.Set; import java.util.Set;
import java.util.UUID;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.Stream;
public class ChatListener implements Listener { public class ChatListener implements Listener {
@@ -83,14 +81,18 @@ public class ChatListener implements Listener {
} }
Player player = event.getPlayer(); Player player = event.getPlayer();
UUID uuid = player.getUniqueId();
Set<Player> receivers = event.viewers().stream().filter(audience -> audience instanceof Player)
.map(audience -> (Player) audience)
.filter(receiver -> !ChatUserManager.getChatUser(receiver.getUniqueId()).getIgnoredPlayers().contains(player.getUniqueId()))
.collect(Collectors.toSet());
Component input = event.message().colorIfAbsent(NamedTextColor.WHITE); Component input = event.message().colorIfAbsent(NamedTextColor.WHITE);
ModifiableString modifiableString = new ModifiableString(input); ModifiableString modifiableString = new ModifiableString(input);
// todo a better way for this // todo a better way for this
if(!RegexManager.filterText(player.getName(), uuid, modifiableString, true, "chat", filterType -> { if(!RegexManager.filterText(player.getName(), player.getUniqueId(), modifiableString, true, "chat", filterType -> {
if (!filterType.equals(FilterType.PUNISH)) { if (!filterType.equals(FilterType.PUNISH)) {
ALogger.warn("Received another FilterType than punish when filtering chat and executing a filter action"); ALogger.warn("Received another FilterType than punish when filtering chat and executing a filter action");
return; return;
@@ -98,7 +100,7 @@ public class ChatListener implements Listener {
ByteArrayDataOutput out = ByteStreams.newDataOutput(); ByteArrayDataOutput out = ByteStreams.newDataOutput();
out.writeUTF("punish"); out.writeUTF("punish");
out.writeUTF(player.getName()); out.writeUTF(player.getName());
out.writeUTF(uuid.toString()); out.writeUTF(player.getUniqueId().toString());
out.writeUTF(modifiableString.string()); out.writeUTF(modifiableString.string());
player.sendPluginMessage(ChatPlugin.getInstance(), Config.MESSAGECHANNEL, out.toByteArray()); player.sendPluginMessage(ChatPlugin.getInstance(), Config.MESSAGECHANNEL, out.toByteArray());
})) { })) {
@@ -106,19 +108,10 @@ public class ChatListener implements Listener {
GalaxyUtility.sendBlockedNotification("Language", player, GalaxyUtility.sendBlockedNotification("Language", player,
modifiableString.component(), modifiableString.component(),
""); "");
chatLogHandler.addChatLog(uuid, player.getServer().getName(), PlainTextComponentSerializer.plainText().serialize(input), true); chatLogHandler.addChatLog(player.getUniqueId(), player.getServer().getServerName(), PlainTextComponentSerializer.plainText().serialize(input), true);
return; // the message was blocked return; // the message was blocked
} }
Stream<Player> stream = event.viewers().stream().filter(audience -> audience instanceof Player)
.map(audience -> (Player) audience);
if (!player.hasPermission("chat.ignorebypass")) {
stream = stream.filter(receiver -> !ChatUserManager.getChatUser(receiver.getUniqueId()).getIgnoredPlayers().contains(uuid)
&& !receiver.hasPermission("chat.ignorebypass"));
}
Set<Player> receivers = stream.collect(Collectors.toSet());
Set<Player> playersToPing = new HashSet<>(); Set<Player> playersToPing = new HashSet<>();
pingPlayers(playersToPing, modifiableString, player); pingPlayers(playersToPing, modifiableString, player);
@@ -129,7 +122,7 @@ public class ChatListener implements Listener {
for (Player pingPlayer : playersToPing) { for (Player pingPlayer : playersToPing) {
pingPlayer.playSound(pingPlayer.getLocation(), Sound.BLOCK_NOTE_BLOCK_BASS, 1, 1); pingPlayer.playSound(pingPlayer.getLocation(), Sound.BLOCK_NOTE_BLOCK_BASS, 1, 1);
} }
chatLogHandler.addChatLog(uuid, player.getServer().getName(), modifiableString.string(), false); chatLogHandler.addChatLog(player.getUniqueId(), player.getServer().getServerName(), modifiableString.string(), false);
ALogger.info(PlainTextComponentSerializer.plainText().serialize(input)); ALogger.info(PlainTextComponentSerializer.plainText().serialize(input));
} }
@@ -143,12 +136,11 @@ public class ChatListener implements Listener {
Pattern nickPattern = Pattern.compile("\\b(?<!\\\\)" + nickName + "\\b", Pattern.CASE_INSENSITIVE); Pattern nickPattern = Pattern.compile("\\b(?<!\\\\)" + nickName + "\\b", Pattern.CASE_INSENSITIVE);
// Pattern escapedNickPattern = Pattern.compile("\\b\\\\" + nickName + "\\b", Pattern.CASE_INSENSITIVE); // Pattern escapedNickPattern = Pattern.compile("\\b\\\\" + nickName + "\\b", Pattern.CASE_INSENSITIVE);
ChatUser onlinePlayerUser = ChatUserManager.getChatUser(onlinePlayer.getUniqueId());
if (namePattern.matcher(modifiableString.string()).find()) { if (namePattern.matcher(modifiableString.string()).find()) {
modifiableString.replace(TextReplacementConfig.builder() modifiableString.replace(TextReplacementConfig.builder()
.once() .once()
.match(namePattern) .match(namePattern)
.replacement(mention.append(onlinePlayerUser.getDisplayName())) .replacement(mention.append(onlinePlayer.displayName()))
.build()); .build());
//TODO replace all instances of \name with just name but using the match result so the capitalization doesn't change //TODO replace all instances of \name with just name but using the match result so the capitalization doesn't change
// modifiableString.replace(TextReplacementConfig.builder() // modifiableString.replace(TextReplacementConfig.builder()
@@ -158,17 +150,15 @@ public class ChatListener implements Listener {
// String substring = a.group().substring(1); // String substring = a.group().substring(1);
// return ; // return ;
// }); // });
if (!ChatUserManager.getChatUser(onlinePlayer.getUniqueId()).getIgnoredPlayers().contains(player.getUniqueId()) if (!ChatUserManager.getChatUser(onlinePlayer.getUniqueId()).getIgnoredPlayers().contains(player.getUniqueId()))
&& !player.hasPermission("chat.ignorebypass"))
playersToPing.add(onlinePlayer); playersToPing.add(onlinePlayer);
} else if (nickPattern.matcher(modifiableString.string()).find()) { } else if (nickPattern.matcher(modifiableString.string()).find()) {
modifiableString.replace(TextReplacementConfig.builder() modifiableString.replace(TextReplacementConfig.builder()
.once() .once()
.match(nickPattern) .match(nickPattern)
.replacement(mention.append(onlinePlayerUser.getDisplayName())) .replacement(mention.append(onlinePlayer.displayName()))
.build()); .build());
if (!ChatUserManager.getChatUser(onlinePlayer.getUniqueId()).getIgnoredPlayers().contains(player.getUniqueId()) if (!ChatUserManager.getChatUser(onlinePlayer.getUniqueId()).getIgnoredPlayers().contains(player.getUniqueId()))
&& !player.hasPermission("chat.ignorebypass"))
playersToPing.add(onlinePlayer); playersToPing.add(onlinePlayer);
} }
} }
@@ -11,13 +11,11 @@ import com.alttd.chat.objects.Toggleable;
import com.alttd.chat.util.GalaxyUtility; import com.alttd.chat.util.GalaxyUtility;
import com.alttd.chat.util.Utility; import com.alttd.chat.util.Utility;
import net.kyori.adventure.text.Component; import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.TextReplacementConfig;
import net.kyori.adventure.text.format.Style; import net.kyori.adventure.text.format.Style;
import net.kyori.adventure.text.format.TextColor; import net.kyori.adventure.text.format.TextColor;
import net.kyori.adventure.text.format.TextDecoration; import net.kyori.adventure.text.format.TextDecoration;
import net.kyori.adventure.text.minimessage.MiniMessage; import net.kyori.adventure.text.minimessage.MiniMessage;
import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder; import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler; import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority; import org.bukkit.event.EventPriority;
@@ -50,8 +48,8 @@ public class PlayerListener implements Listener {
UUID uuid = player.getUniqueId(); UUID uuid = player.getUniqueId();
Toggleable.disableToggles(uuid); Toggleable.disableToggles(uuid);
if (serverConfig.FIRST_JOIN_MESSAGES && (!player.hasPlayedBefore() || System.currentTimeMillis() - player.getFirstPlayed() < TimeUnit.SECONDS.toMillis(10))) { if (serverConfig.FIRST_JOIN_MESSAGES && System.currentTimeMillis() - player.getFirstPlayed() < TimeUnit.SECONDS.toMillis(10)) {
Bukkit.broadcast(MiniMessage.miniMessage().deserialize(Config.FIRST_JOIN, Placeholder.parsed("player", player.getName()))); player.getServer().sendMessage(MiniMessage.miniMessage().deserialize(Config.FIRST_JOIN, Placeholder.parsed("player", player.getName())));
} }
ChatUser user = ChatUserManager.getChatUser(uuid); ChatUser user = ChatUserManager.getChatUser(uuid);
@@ -105,36 +103,22 @@ public class PlayerListener implements Listener {
Stack<Instant> playerDeathsStack = sendPlayerDeaths.computeIfAbsent(uuid, key -> new Stack<>()); Stack<Instant> playerDeathsStack = sendPlayerDeaths.computeIfAbsent(uuid, key -> new Stack<>());
Instant cutOff = Instant.now().minus(Config.DEATH_MESSAGES_LIMIT_PERIOD_MINUTES, ChronoUnit.MINUTES); Instant cutOff = Instant.now().minus(Config.DEATH_MESSAGES_LIMIT_PERIOD_MINUTES, ChronoUnit.MINUTES);
while (!playerDeathsStack.isEmpty() && playerDeathsStack.peek().isBefore(cutOff)) { while (playerDeathsStack.peek().isBefore(cutOff)) {
playerDeathsStack.pop(); playerDeathsStack.pop();
} }
if (playerDeathsStack.size() > Config.DEATH_MESSAGES_MAX_PER_PERIOD || serverConfig.MUTED) { if (playerDeathsStack.size() > Config.DEATH_MESSAGES_MAX_PER_PERIOD || serverConfig.MUTED) {
event.deathMessage(Component.empty()); event.deathMessage(Component.empty());
return; return;
} } else {
Component component = event.deathMessage(); Component component = event.deathMessage();
if (component != null) {
component = Component.text("* ").append(component);
component = component.style(Style.style(TextColor.color(82, 80, 77), TextDecoration.ITALIC));
event.deathMessage(component);
}
}
playerDeathsStack.push(Instant.now()); playerDeathsStack.push(Instant.now());
if (component == null) {
return;
}
TextReplacementConfig playerReplacement = TextReplacementConfig.builder()
.match(event.getPlayer().getName())
.replacement(event.getPlayer().displayName())
.build();
component = component.replaceText(playerReplacement);
Player killer = event.getPlayer().getKiller();
if (killer != null) {
TextReplacementConfig killerReplacement = TextReplacementConfig.builder()
.match(killer.getName())
.replacement(killer.displayName())
.build();
component = component.replaceText(killerReplacement);
}
component = MiniMessage.miniMessage().deserialize("<dark_red>[</dark_red><red>☠</red><dark_red>]</dark_red> ").append(component);
component = component.style(Style.style(TextColor.color(255, 155, 48), TextDecoration.ITALIC));
event.deathMessage(component);
} }
} }
@@ -15,20 +15,20 @@ import com.alttd.chat.util.Utility;
import com.google.common.io.ByteArrayDataInput; import com.google.common.io.ByteArrayDataInput;
import com.google.common.io.ByteStreams; import com.google.common.io.ByteStreams;
import net.kyori.adventure.text.Component; import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.minimessage.MiniMessage;
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer; import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.Sound; import org.bukkit.Sound;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.plugin.messaging.PluginMessageListener; import org.bukkit.plugin.messaging.PluginMessageListener;
import org.bukkit.scheduler.BukkitRunnable; import org.bukkit.scheduler.BukkitRunnable;
import org.jetbrains.annotations.NotNull;
import java.util.UUID; import java.util.UUID;
public class PluginMessage implements PluginMessageListener { public class PluginMessage implements PluginMessageListener {
@Override @Override
public void onPluginMessageReceived(String channel, @NotNull Player ignored, byte[] bytes) { public void onPluginMessageReceived(String channel, Player player, byte[] bytes) {
if (!channel.equals(Config.MESSAGECHANNEL)) { if (!channel.equals(Config.MESSAGECHANNEL)) {
return; return;
} }
@@ -38,36 +38,35 @@ public class PluginMessage implements PluginMessageListener {
case "privatemessagein": { case "privatemessagein": {
UUID uuid = UUID.fromString(in.readUTF()); UUID uuid = UUID.fromString(in.readUTF());
String target = in.readUTF(); String target = in.readUTF();
Player player = Bukkit.getPlayer(uuid); Player p = Bukkit.getPlayer(uuid);
String message = in.readUTF(); String message = in.readUTF();
UUID targetuuid = UUID.fromString(in.readUTF()); UUID targetuuid = UUID.fromString(in.readUTF());
if (player == null) { if (p != null) {
break; ChatUser chatUser = ChatUserManager.getChatUser(uuid);
} if (!chatUser.getIgnoredPlayers().contains(targetuuid)) {
ChatUser chatUser = ChatUserManager.getChatUser(uuid); p.sendMessage(GsonComponentSerializer.gson().deserialize(message));
if (isTargetNotIgnored(chatUser, targetuuid)) { p.playSound(p.getLocation(), Sound.BLOCK_NOTE_BLOCK_BASS, 1, 1); // todo load this from config
player.sendMessage(GsonComponentSerializer.gson().deserialize(message)); ChatUser user = ChatUserManager.getChatUser(uuid);
player.playSound(player.getLocation(), Sound.BLOCK_NOTE_BLOCK_BASS, 1, 1); // todo load this from config if (!user.getReplyContinueTarget().equalsIgnoreCase(target))
ChatUser user = ChatUserManager.getChatUser(uuid); user.setReplyTarget(target);
if (!user.getReplyContinueTarget().equalsIgnoreCase(target)) }
user.setReplyTarget(target);
} }
break;
} }
case "privatemessageout": { case "privatemessageout": {
UUID uuid = UUID.fromString(in.readUTF()); UUID uuid = UUID.fromString(in.readUTF());
String target = in.readUTF(); String target = in.readUTF();
Player player = Bukkit.getPlayer(uuid); Player p = Bukkit.getPlayer(uuid);
String message = in.readUTF(); String message = in.readUTF();
UUID targetuuid = UUID.fromString(in.readUTF()); UUID targetuuid = UUID.fromString(in.readUTF());
if (player == null) { if (p != null) {
break; ChatUser chatUser = ChatUserManager.getChatUser(uuid);
} if (!chatUser.getIgnoredPlayers().contains(targetuuid)) {
ChatUser chatUser = ChatUserManager.getChatUser(uuid); chatUser.setReplyTarget(target);
if (isTargetNotIgnored(chatUser, targetuuid)) { p.sendMessage(GsonComponentSerializer.gson().deserialize(message));
chatUser.setReplyTarget(target);
player.sendMessage(GsonComponentSerializer.gson().deserialize(message));
// ChatUser user = ChatUserManager.getChatUser(uuid); // ChatUser user = ChatUserManager.getChatUser(uuid);
// user.setReplyTarget(target); // user.setReplyTarget(target);
}
} }
break; break;
} }
@@ -79,7 +78,7 @@ public class PluginMessage implements PluginMessageListener {
Bukkit.getOnlinePlayers().stream().filter(p -> p.hasPermission(Config.GCPERMISSION)).forEach(p -> { Bukkit.getOnlinePlayers().stream().filter(p -> p.hasPermission(Config.GCPERMISSION)).forEach(p -> {
ChatUser chatUser = ChatUserManager.getChatUser(p.getUniqueId()); ChatUser chatUser = ChatUserManager.getChatUser(p.getUniqueId());
if (isTargetNotIgnored(chatUser, uuid)) { if (!chatUser.getIgnoredPlayers().contains(uuid)) {
p.sendMessage(GsonComponentSerializer.gson().deserialize(message)); p.sendMessage(GsonComponentSerializer.gson().deserialize(message));
} }
}); });
@@ -194,7 +193,7 @@ public class PluginMessage implements PluginMessageListener {
ALogger.warn("Received ChatChannel message for non existent channel."); ALogger.warn("Received ChatChannel message for non existent channel.");
return; return;
} }
if (!chatChannel.getServers().contains(Bukkit.getServer().getName())) { if (!chatChannel.getServers().contains(Bukkit.getServerName())) {
ALogger.warn("Received ChatChannel message for the wrong server."); ALogger.warn("Received ChatChannel message for the wrong server.");
return; return;
} }
@@ -217,15 +216,4 @@ public class PluginMessage implements PluginMessageListener {
}.runTaskAsynchronously(ChatPlugin.getInstance()); }.runTaskAsynchronously(ChatPlugin.getInstance());
} }
private boolean isTargetNotIgnored(ChatUser chatUser, UUID targetUUID) {
if (!chatUser.getIgnoredPlayers().contains(targetUUID)) {
return true;
}
Player target = Bukkit.getPlayer(targetUUID);
if (target == null) {
return true;
}
return target.hasPermission("chat.ignorebypass");
}
} }
@@ -4,23 +4,17 @@ import com.alttd.chat.objects.chat_log.ChatLogHandler;
import org.bukkit.event.EventHandler; import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener; import org.bukkit.event.Listener;
import org.bukkit.event.server.PluginDisableEvent; import org.bukkit.event.server.PluginDisableEvent;
import org.bukkit.plugin.Plugin;
public class ShutdownListener implements Listener { public class ShutdownListener implements Listener {
private final ChatLogHandler chatLogHandler; private final ChatLogHandler chatLogHandler;
private final Plugin thisPlugin;
public ShutdownListener(ChatLogHandler chatLogHandler, Plugin thisPlugin) { public ShutdownListener(ChatLogHandler chatLogHandler) {
this.chatLogHandler = chatLogHandler; this.chatLogHandler = chatLogHandler;
this.thisPlugin = thisPlugin;
} }
@EventHandler @EventHandler
public void onShutdown(PluginDisableEvent event) { public void onShutdown(PluginDisableEvent event) {
if (!event.getPlugin().getName().equals(thisPlugin.getName())){
return;
}
chatLogHandler.shutDown(); chatLogHandler.shutDown();
} }
@@ -149,24 +149,24 @@ public class NickUtilities
public static boolean validNick(Player sender, OfflinePlayer target, String nickName) { public static boolean validNick(Player sender, OfflinePlayer target, String nickName) {
if (!noBlockedCodes(nickName)) { if (!noBlockedCodes(nickName)) {
sender.sendRichMessage(Config.NICK_BLOCKED_COLOR_CODES); sender.sendMiniMessage(Config.NICK_BLOCKED_COLOR_CODES, null);
return false; return false;
} }
if (!Utility.checkNickBrightEnough(nickName)) { if (!Utility.checkNickBrightEnough(nickName)) {
sender.sendRichMessage("<red>At least one color must be brighter than 30 for each color</red>"); sender.sendMiniMessage("<red>At least one color must be brighter than 30 for each color</red>", null);
return false; return false;
} }
String cleanNick = NickUtilities.removeAllColors(nickName); String cleanNick = NickUtilities.removeAllColors(nickName);
if (cleanNick.length() < 3 || cleanNick.length() > 16) { if (cleanNick.length() < 3 || cleanNick.length() > 16) {
sender.sendRichMessage(Config.NICK_INVALID_LENGTH); sender.sendMiniMessage(Config.NICK_INVALID_LENGTH, null);
return false; return false;
} }
if (!cleanNick.matches("[a-zA-Z0-9_]*") || nickName.length() > 192) { //192 is if someone puts {#xxxxxx<>} in front of every letter if (!cleanNick.matches("[a-zA-Z0-9_]*") || nickName.length() > 192) { //192 is if someone puts {#xxxxxx<>} in front of every letter
sender.sendRichMessage(Config.NICK_INVALID_CHARACTERS); sender.sendMiniMessage(Config.NICK_INVALID_CHARACTERS, null);
return false; return false;
} }
@@ -183,7 +183,7 @@ public class NickUtilities
if (uniqueId.equals(uuid)){ if (uniqueId.equals(uuid)){
ChatPlugin.getInstance().getLogger().info(uuid + " " + uniqueId); ChatPlugin.getInstance().getLogger().info(uuid + " " + uniqueId);
} }
sender.sendRichMessage(Config.NICK_TAKEN); sender.sendMiniMessage(Config.NICK_TAKEN, null);
return false; return false;
} }
} }
@@ -1,5 +1,7 @@
package com.alttd.chat.nicknames; package com.alttd.chat.nicknames;
import com.Zrips.CMI.CMI;
import com.Zrips.CMI.Containers.CMIUser;
import com.alttd.chat.ChatAPI; import com.alttd.chat.ChatAPI;
import com.alttd.chat.ChatPlugin; import com.alttd.chat.ChatPlugin;
import com.alttd.chat.config.Config; import com.alttd.chat.config.Config;
@@ -11,6 +13,7 @@ import com.alttd.chat.objects.Nick;
import com.alttd.chat.util.Utility; import com.alttd.chat.util.Utility;
import com.google.common.io.ByteArrayDataOutput; import com.google.common.io.ByteArrayDataOutput;
import com.google.common.io.ByteStreams; import com.google.common.io.ByteStreams;
import net.kyori.adventure.text.minimessage.MiniMessage;
import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder; import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder;
import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver; import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver;
import net.luckperms.api.LuckPerms; import net.luckperms.api.LuckPerms;
@@ -111,7 +114,7 @@ public class Nicknames implements CommandExecutor, TabCompleter {
Placeholder.component("nickname", chatUser.getDisplayName()), Placeholder.component("nickname", chatUser.getDisplayName()),
Placeholder.parsed("currentnickname", chatUser.getNickNameString()) Placeholder.parsed("currentnickname", chatUser.getNickNameString())
); );
player.sendRichMessage(Config.NICK_CURRENT, placeholders); player.sendMiniMessage(Config.NICK_CURRENT, placeholders);
} }
break; break;
case "help": case "help":
@@ -381,7 +384,7 @@ public class Nicknames implements CommandExecutor, TabCompleter {
ChatUser user = ChatUserManager.getChatUser(player.getUniqueId()); ChatUser user = ChatUserManager.getChatUser(player.getUniqueId());
user.setDisplayName(player.getName()); user.setDisplayName(player.getName());
player.displayName(user.getDisplayName()); player.displayName(user.getDisplayName());
// updateCMIUser(player, null); updateCMIUser(player, null);
} }
public String getNick(final Player player) { public String getNick(final Player player) {
@@ -396,25 +399,25 @@ public class Nicknames implements CommandExecutor, TabCompleter {
ChatUser user = ChatUserManager.getChatUser(player.getUniqueId()); ChatUser user = ChatUserManager.getChatUser(player.getUniqueId());
user.setDisplayName(nickName); user.setDisplayName(nickName);
player.displayName(user.getDisplayName()); player.displayName(user.getDisplayName());
// updateCMIUser(player, nickName); updateCMIUser(player, nickName);
} }
// public static String format(final String m) { // public static String format(final String m) {
// return NickUtilities.applyColor(m); // return NickUtilities.applyColor(m);
// } // }
// public void updateCMIUser(Player player, String nickName) { public void updateCMIUser(Player player, String nickName) {
// if (!isCMIEnabled()) if (!isCMIEnabled())
// return; return;
//
// CMIUser cmiUser = CMI.getInstance().getPlayerManager().getUser(player); CMIUser cmiUser = CMI.getInstance().getPlayerManager().getUser(player);
// if (nickName == null){ if (nickName == null){
// cmiUser.setNickName(null, true); cmiUser.setNickName(null, true);
// } else { } else {
// cmiUser.setNickName(NickUtilities.applyColor(nickName), true); cmiUser.setNickName(NickUtilities.applyColor(nickName), true);
// } }
// cmiUser.updateDisplayName(); cmiUser.updateDisplayName();
// } }
private Boolean isCMIEnabled = null; private Boolean isCMIEnabled = null;
private Boolean isCMIEnabled() { private Boolean isCMIEnabled() {
@@ -1,8 +1,12 @@
package com.alttd.chat.nicknames; package com.alttd.chat.nicknames;
import com.Zrips.CMI.commands.list.colorlimits;
import com.Zrips.CMI.utils.Util;
import com.alttd.chat.ChatPlugin; import com.alttd.chat.ChatPlugin;
import com.alttd.chat.config.Config; import com.alttd.chat.config.Config;
import com.alttd.chat.database.Queries; import com.alttd.chat.database.Queries;
import com.alttd.chat.managers.ChatUserManager;
import com.alttd.chat.objects.ChatUser;
import com.alttd.chat.objects.Nick; import com.alttd.chat.objects.Nick;
import com.alttd.chat.util.ALogger; import com.alttd.chat.util.ALogger;
import com.google.common.io.ByteArrayDataInput; import com.google.common.io.ByteArrayDataInput;
@@ -41,7 +41,6 @@ public class ToggleableForCustomChannel extends Toggleable {
new BukkitRunnable() { new BukkitRunnable() {
@Override @Override
public void run() { public void run() {
ALogger.info(String.format("%s sent %s message: %s", player.getName(), customChannel.getChannelName(), message));
ChatPlugin.getInstance().getChatHandler().chatChannel(player, customChannel, message); ChatPlugin.getInstance().getChatHandler().chatChannel(player, customChannel, message);
} }
}.runTaskAsynchronously(ChatPlugin.getInstance()); }.runTaskAsynchronously(ChatPlugin.getInstance());
Executable
BIN
View File
Binary file not shown.
+1 -12
View File
@@ -4,14 +4,11 @@ include(":api")
include(":galaxy") include(":galaxy")
include(":velocity") include(":velocity")
val nexusUser = providers.gradleProperty("alttdSnapshotUsername").get()
val nexusPass = providers.gradleProperty("alttdSnapshotPassword").get()
dependencyResolutionManagement { dependencyResolutionManagement {
repositories { repositories {
// mavenLocal() // mavenLocal()
mavenCentral() mavenCentral()
// maven("https://repo.destro.xyz/snapshots") // Altitude - Galaxy maven("https://repo.destro.xyz/snapshots") // Altitude - Galaxy
maven("https://oss.sonatype.org/content/groups/public/") // Adventure maven("https://oss.sonatype.org/content/groups/public/") // Adventure
maven("https://oss.sonatype.org/content/repositories/snapshots/") // Minimessage maven("https://oss.sonatype.org/content/repositories/snapshots/") // Minimessage
maven("https://nexus.velocitypowered.com/repository/") // Velocity maven("https://nexus.velocitypowered.com/repository/") // Velocity
@@ -19,14 +16,6 @@ dependencyResolutionManagement {
maven("https://repo.spongepowered.org/maven") // Configurate maven("https://repo.spongepowered.org/maven") // Configurate
maven("https://repo.extendedclip.com/content/repositories/placeholderapi/") // Papi maven("https://repo.extendedclip.com/content/repositories/placeholderapi/") // Papi
maven("https://jitpack.io") maven("https://jitpack.io")
maven {
name = "nexus"
url = uri("https://repo.alttd.com/repository/alttd-snapshot/")
credentials {
username = nexusUser
password = nexusPass
}
}
} }
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
} }
+2 -2
View File
@@ -1,6 +1,6 @@
plugins { plugins {
`maven-publish` `maven-publish`
id("io.github.goooler.shadow") id("com.github.johnrengelman.shadow")
} }
dependencies { dependencies {
@@ -11,7 +11,7 @@ dependencies {
implementation("org.spongepowered", "configurate-yaml", "4.1.2") implementation("org.spongepowered", "configurate-yaml", "4.1.2")
compileOnly("net.kyori:adventure-text-minimessage:4.10.1") compileOnly("net.kyori:adventure-text-minimessage:4.10.1")
compileOnly("com.gitlab.ruany:LiteBansAPI:0.3.5") compileOnly("com.gitlab.ruany:LiteBansAPI:0.3.5")
compileOnly("com.alttd.proxydiscordlink:ProxyDiscordLink:1.0.1-SNAPSHOT") compileOnly("com.alttd.proxydiscordlink:ProxyDiscordLink:1.0.0-BETA-SNAPSHOT")
} }
tasks { tasks {
@@ -110,10 +110,10 @@ public class VoteToMute {
} }
boolean countLowerRanks = false; boolean countLowerRanks = false;
long count = getTotalEligiblePlayers(server, false); long count = getTotalEligiblePlayers(server, false);
if (count < 6) { if (count < 10) {
countLowerRanks = true; countLowerRanks = true;
count = getTotalEligiblePlayers(server, true); count = getTotalEligiblePlayers(server, true);
if (count < 6) { if (count < 10) {
commandContext.getSource().sendMessage(Utility.parseMiniMessage("<red>Not enough eligible players online to vote.</red>")); commandContext.getSource().sendMessage(Utility.parseMiniMessage("<red>Not enough eligible players online to vote.</red>"));
return 1; return 1;
} }
@@ -16,7 +16,6 @@ import com.velocitypowered.api.proxy.Player;
import com.velocitypowered.api.proxy.ProxyServer; import com.velocitypowered.api.proxy.ProxyServer;
import com.velocitypowered.api.proxy.ServerConnection; import com.velocitypowered.api.proxy.ServerConnection;
import com.velocitypowered.api.proxy.server.RegisteredServer; import com.velocitypowered.api.proxy.server.RegisteredServer;
import jdk.jshell.execution.Util;
import net.kyori.adventure.text.Component; import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder; import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder;
@@ -30,8 +29,6 @@ import java.util.stream.IntStream;
public class VoteToMuteHelper { public class VoteToMuteHelper {
private static final Component prefix = Utility.parseMiniMessage("<gold>[VoteMute]</gold>");
public VoteToMuteHelper(ProxyServer proxyServer) { public VoteToMuteHelper(ProxyServer proxyServer) {
RequiredArgumentBuilder<CommandSource, String> playerNode = RequiredArgumentBuilder RequiredArgumentBuilder<CommandSource, String> playerNode = RequiredArgumentBuilder
.<CommandSource, String>argument("player", StringArgumentType.string()) .<CommandSource, String>argument("player", StringArgumentType.string())
@@ -119,7 +116,7 @@ public class VoteToMuteHelper {
return 1; return 1;
}); });
LiteralArgumentBuilder<CommandSource> enterMessagesNode = LiteralArgumentBuilder LiteralArgumentBuilder<CommandSource> enterPageNode = LiteralArgumentBuilder
.<CommandSource>literal("messages") .<CommandSource>literal("messages")
.requires(commandSource -> commandSource.hasPermission("chat.vote-to-mute")) .requires(commandSource -> commandSource.hasPermission("chat.vote-to-mute"))
.then(RequiredArgumentBuilder.<CommandSource, String>argument("list of messages", StringArgumentType.greedyString()) .then(RequiredArgumentBuilder.<CommandSource, String>argument("list of messages", StringArgumentType.greedyString())
@@ -150,7 +147,7 @@ public class VoteToMuteHelper {
} }
int highestLogEntry = max.get(); int highestLogEntry = max.get();
if (voteToMuteStarter.getTotalLogEntries() < highestLogEntry) { if (voteToMuteStarter.getTotalLogEntries() > highestLogEntry) {
commandContext.getSource().sendMessage(Utility.parseMiniMessage("<red>Some of your selected messages do not exist.</red>")); commandContext.getSource().sendMessage(Utility.parseMiniMessage("<red>Some of your selected messages do not exist.</red>"));
return 1; return 1;
} }
@@ -165,7 +162,7 @@ public class VoteToMuteHelper {
RegisteredServer server = currentServer.get().getServer(); RegisteredServer server = currentServer.get().getServer();
long count = getTotalEligiblePlayers(server, voteToMuteStarter.countLowerRanks()); long count = getTotalEligiblePlayers(server, voteToMuteStarter.countLowerRanks());
new ActiveVoteToMute(voteToMuteStarter.getVotedPlayer(), server, proxyServer, Duration.ofMinutes(5), new ActiveVoteToMute(voteToMuteStarter.getVotedPlayer(), server, proxyServer, Duration.ofMinutes(5),
(int) count, voteToMuteStarter.countLowerRanks(), chatLogs, player) (int) count, voteToMuteStarter.countLowerRanks(), chatLogs)
.start(); .start();
return 1; return 1;
}) })
@@ -179,11 +176,11 @@ public class VoteToMuteHelper {
.then(playerNode .then(playerNode
.then(yesNoNode .then(yesNoNode
.executes(commandContext -> { .executes(commandContext -> {
if (!(commandContext.getSource() instanceof Player player)) { if (!(commandContext.getSource() instanceof Player)) {
commandContext.getSource().sendMessage(Utility.parseMiniMessage( commandContext.getSource().sendMessage(Utility.parseMiniMessage(
"<red>Only players are allowed to vote</red>")); "<red>Only players are allowed to vote</red>"));
return 1;
} }
Player source = (Player) commandContext.getSource();
String playerName = commandContext.getArgument("player", String.class); String playerName = commandContext.getArgument("player", String.class);
Optional<ActiveVoteToMute> optionalActiveVoteToMute = ActiveVoteToMute.getInstance(playerName); Optional<ActiveVoteToMute> optionalActiveVoteToMute = ActiveVoteToMute.getInstance(playerName);
if (optionalActiveVoteToMute.isEmpty()) { if (optionalActiveVoteToMute.isEmpty()) {
@@ -194,25 +191,16 @@ public class VoteToMuteHelper {
ActiveVoteToMute activeVoteToMute = optionalActiveVoteToMute.get(); ActiveVoteToMute activeVoteToMute = optionalActiveVoteToMute.get();
if (!activeVoteToMute.countLowerRanks()) { if (!activeVoteToMute.countLowerRanks()) {
if (!player.hasPermission("chat.vote-to-mute")) { if (!source.hasPermission("chat.vote-to-mute")) {
player.sendMessage(Utility.parseMiniMessage("<red>You are not eligible to vote.</red>")); source.sendMessage(Utility.parseMiniMessage("<red>You are not eligible to vote.</red>"));
return 1; return 1;
} }
} }
String vote = commandContext.getArgument("yesNo", String.class); String vote = commandContext.getArgument("yesno", String.class);
switch (vote.toLowerCase()) { switch (vote.toLowerCase()) {
case "yes" -> { case "yes" -> activeVoteToMute.vote(source.getUniqueId(), true);
activeVoteToMute.vote(player.getUniqueId(), true); case "no" -> activeVoteToMute.vote(source.getUniqueId(), false);
commandContext.getSource().sendMessage(Utility.parseMiniMessage(
"<green>You voted to mute. Thanks for voting, staff will be online soon to review!</green>"));
player.getCurrentServer().ifPresent(serverConnection -> notifyEligiblePlayers(serverConnection.getServer(), activeVoteToMute));
}
case "no" -> {
activeVoteToMute.vote(player.getUniqueId(), false);
commandContext.getSource().sendMessage(Utility.parseMiniMessage(
"<green>You voted <red>not</red> to mute. Thanks for voting, staff will be online soon to review!</green>"));
}
default -> commandContext.getSource().sendMessage(Utility.parseMiniMessage( default -> commandContext.getSource().sendMessage(Utility.parseMiniMessage(
"<red><vote> is not a valid vote option</red>", Placeholder.parsed("vote", vote))); "<red><vote> is not a valid vote option</red>", Placeholder.parsed("vote", vote)));
} }
@@ -231,7 +219,7 @@ public class VoteToMuteHelper {
.requires(commandSource -> commandSource instanceof Player) .requires(commandSource -> commandSource instanceof Player)
.then(voteNode) .then(voteNode)
.then(pageNode) .then(pageNode)
.then(enterMessagesNode) .then(enterPageNode)
.executes(context -> { .executes(context -> {
sendHelpMessage(context.getSource()); sendHelpMessage(context.getSource());
return 1; return 1;
@@ -253,18 +241,6 @@ public class VoteToMuteHelper {
.count(); .count();
} }
private void notifyEligiblePlayers(RegisteredServer server, ActiveVoteToMute activeVoteToMute) {
Component message = Utility.parseMiniMessage("<prefix><green><voted_for> out of <total_votes> players have voted to mute <player></green>",
Placeholder.component("prefix", prefix),
Placeholder.parsed("voted_for", String.valueOf(activeVoteToMute.getVotedFor())),
Placeholder.parsed("total_votes", String.valueOf(activeVoteToMute.getTotalEligibleVoters())),
Placeholder.parsed("player", activeVoteToMute.getVotedPlayer().getUsername()));
boolean countLowerRanks = activeVoteToMute.countLowerRanks();
server.getPlayersConnected().stream()
.filter(player -> countLowerRanks ? player.hasPermission("chat.backup-vote-to-mute") : player.hasPermission("chat.vote-to-mute"))
.forEach(player -> player.sendMessage(message));
}
private void sendHelpMessage(CommandSource commandSource) { private void sendHelpMessage(CommandSource commandSource) {
commandSource.sendMessage(Utility.parseMiniMessage("<red>Use: <gold>/votetomutehelper <player></gold>.</red>")); commandSource.sendMessage(Utility.parseMiniMessage("<red>Use: <gold>/votetomutehelper <player></gold>.</red>"));
} }
@@ -17,6 +17,7 @@ import org.jetbrains.annotations.NotNull;
import java.awt.*; import java.awt.*;
import java.time.Duration; import java.time.Duration;
import java.util.*; import java.util.*;
import java.util.List;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
@@ -28,7 +29,6 @@ public class ActiveVoteToMute {
private static final Component prefix = Utility.parseMiniMessage("<gold>[VoteMute]</gold>"); private static final Component prefix = Utility.parseMiniMessage("<gold>[VoteMute]</gold>");
private final Player votedPlayer; private final Player votedPlayer;
private final Player startedByPlayer;
private HashSet<UUID> votedFor = new HashSet<>(); private HashSet<UUID> votedFor = new HashSet<>();
private HashSet<UUID> votedAgainst = new HashSet<>(); private HashSet<UUID> votedAgainst = new HashSet<>();
private int totalEligibleVoters; private int totalEligibleVoters;
@@ -36,7 +36,6 @@ public class ActiveVoteToMute {
private final RegisteredServer server; private final RegisteredServer server;
private final ProxyServer proxyServer; private final ProxyServer proxyServer;
private final Component chatLogs; private final Component chatLogs;
private boolean endedVote = false;
public static Optional<ActiveVoteToMute> getInstance(String username) { public static Optional<ActiveVoteToMute> getInstance(String username) {
if (!instances.containsKey(username)) if (!instances.containsKey(username))
@@ -75,7 +74,7 @@ public class ActiveVoteToMute {
} }
public ActiveVoteToMute(@NotNull Player votedPlayer, @NotNull RegisteredServer server, ProxyServer proxyServer, Duration duration, public ActiveVoteToMute(@NotNull Player votedPlayer, @NotNull RegisteredServer server, ProxyServer proxyServer, Duration duration,
int totalEligibleVoters, boolean countLowerRanks, Component chatLogs, @NotNull Player startedByPlayer) { int totalEligibleVoters, boolean countLowerRanks, Component chatLogs) {
this.chatLogs = chatLogs; this.chatLogs = chatLogs;
this.votedPlayer = votedPlayer; this.votedPlayer = votedPlayer;
this.totalEligibleVoters = totalEligibleVoters; this.totalEligibleVoters = totalEligibleVoters;
@@ -86,7 +85,6 @@ public class ActiveVoteToMute {
ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor(); ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor();
executorService.schedule(this::endVote, executorService.schedule(this::endVote,
duration.toMinutes(), TimeUnit.MINUTES); duration.toMinutes(), TimeUnit.MINUTES);
this.startedByPlayer = startedByPlayer;
} }
private RegisteredServer getServer() { private RegisteredServer getServer() {
@@ -94,14 +92,12 @@ public class ActiveVoteToMute {
} }
private void endVote() { private void endVote() {
if (endedVote)
return;
instances.remove(votedPlayer.getUsername()); instances.remove(votedPlayer.getUsername());
if (votePassed()) { if (votePassed()) {
mutePlayer(); mutePlayer();
return; return;
} }
Component message = Utility.parseMiniMessage("<prefix> <red>The vote to mute <player> has failed, they will not be muted.</red>", Component message = Utility.parseMiniMessage("<prefix> <red>The vote to mute <player> has failed, they will not be muted.</green>",
Placeholder.component("prefix", prefix), Placeholder.parsed("player", votedPlayer.getUsername())); Placeholder.component("prefix", prefix), Placeholder.parsed("player", votedPlayer.getUsername()));
server.getPlayersConnected().stream() server.getPlayersConnected().stream()
.filter(player -> countLowerRanks ? player.hasPermission("chat.backup-vote-to-mute") : player.hasPermission("chat.vote-to-mute")) .filter(player -> countLowerRanks ? player.hasPermission("chat.backup-vote-to-mute") : player.hasPermission("chat.vote-to-mute"))
@@ -122,7 +118,6 @@ public class ActiveVoteToMute {
if (!votePassed()) { if (!votePassed()) {
return; return;
} }
endedVote = true;
instances.remove(votedPlayer.getUsername()); instances.remove(votedPlayer.getUsername());
mutePlayer(); mutePlayer();
} else { } else {
@@ -133,10 +128,7 @@ public class ActiveVoteToMute {
public boolean votePassed() { public boolean votePassed() {
double totalVotes = (votedFor.size() + votedAgainst.size()); double totalVotes = (votedFor.size() + votedAgainst.size());
if (totalVotes == 0 || votedFor.isEmpty()) { if (totalVotes / totalEligibleVoters < 0.6) {
return false;
}
if (totalVotes / totalEligibleVoters < 0.6) {
return false; return false;
} }
return votedFor.size() / totalVotes > 0.6; return votedFor.size() / totalVotes > 0.6;
@@ -153,7 +145,7 @@ public class ActiveVoteToMute {
.filter(player -> countLowerRanks ? player.hasPermission("chat.backup-vote-to-mute") : player.hasPermission("chat.vote-to-mute")) .filter(player -> countLowerRanks ? player.hasPermission("chat.backup-vote-to-mute") : player.hasPermission("chat.vote-to-mute"))
.forEach(player -> player.sendMessage(message)); .forEach(player -> player.sendMessage(message));
proxyServer.getCommandManager().executeAsync(proxyServer.getConsoleCommandSource(), proxyServer.getCommandManager().executeAsync(proxyServer.getConsoleCommandSource(),
String.format("tempmute %s 1h Muted by the community - under review. -p", votedPlayer.getUsername())); String.format("tempmute %s 1h Muted by the community - under review.", votedPlayer.getUsername()));
String chatLogsString = PlainTextComponentSerializer.plainText().serialize(chatLogs); String chatLogsString = PlainTextComponentSerializer.plainText().serialize(chatLogs);
@@ -181,10 +173,7 @@ public class ActiveVoteToMute {
false); false);
embedBuilder.addField("Server", embedBuilder.addField("Server",
server.getServerInfo().getName().substring(0, 1).toUpperCase() + server.getServerInfo().getName().substring(1), server.getServerInfo().getName().substring(0, 1).toUpperCase() + server.getServerInfo().getName().substring(1),
true); false);
embedBuilder.addField("Started by",
String.format("Username: %s\nUUID: %s", startedByPlayer.getUsername(), startedByPlayer.getUniqueId().toString()),
true);
return embedBuilder; return embedBuilder;
} }
@@ -215,7 +204,7 @@ public class ActiveVoteToMute {
private Component getVoteStartMessage() { private Component getVoteStartMessage() {
return Utility.parseMiniMessage( return Utility.parseMiniMessage(
String.format(""" String.format("""
<prefix> <green>A vote to mute <player> for one hour has been started, please read the logs below before voting.</green> <prefix> <gold>[VoteMute]</gold> <green>A vote to mute <player> for one hour has been started, please read the logs below before voting.</green>
<logs> <logs>
<prefix> Click: <click:run_command:'/votetomutehelper vote %s yes'><red>Mute</red></click> --- <click:run_command:'/votetomutehelper vote %s no'><yellow>Don't mute</yellow></click>""", <prefix> Click: <click:run_command:'/votetomutehelper vote %s yes'><red>Mute</red></click> --- <click:run_command:'/votetomutehelper vote %s no'><yellow>Don't mute</yellow></click>""",
votedPlayer.getUsername(), votedPlayer.getUsername()), votedPlayer.getUsername(), votedPlayer.getUsername()),
@@ -223,16 +212,4 @@ public class ActiveVoteToMute {
Placeholder.parsed("player", votedPlayer.getUsername()), Placeholder.parsed("player", votedPlayer.getUsername()),
Placeholder.component("logs", chatLogs)); Placeholder.component("logs", chatLogs));
} }
public Player getVotedPlayer() {
return votedPlayer;
}
public int getVotedFor() {
return votedFor.size();
}
public int getTotalEligibleVoters() {
return totalEligibleVoters;
}
} }
@@ -42,7 +42,7 @@ public class VoteToMuteStarter {
} }
public void start() { public void start() {
chatLogHandler.retrieveChatLogs(votedPlayer.getUniqueId(), Duration.ofMinutes(10), serverName).whenCompleteAsync((chatLogs, throwable) -> { chatLogHandler.retrieveChatLogs(votedPlayer.getUniqueId(), Duration.ofMinutes(5), serverName).whenCompleteAsync((chatLogs, throwable) -> {
if (throwable != null) { if (throwable != null) {
commandSource.sendMessage(Utility.parseMiniMessage("<prefix> <red>Unable to retrieve messages</red> for player <player>", commandSource.sendMessage(Utility.parseMiniMessage("<prefix> <red>Unable to retrieve messages</red> for player <player>",
Placeholder.component("prefix", prefix), Placeholder.component("prefix", prefix),
@@ -52,41 +52,40 @@ public class VoteToMuteStarter {
parseChatLogs(chatLogs); parseChatLogs(chatLogs);
commandSource.sendMessage(Utility.parseMiniMessage( commandSource.sendMessage(Utility.parseMiniMessage(
"<prefix> <green>Please select up to 10 messages other players should see to decide their vote, seperated by comma's. " + "<prefix> <green>Please select up to 10 messages other players should see to decide their vote, seperated by comma's. " +
"Example: <gold>/votetomutehelper messages 1, 2, 5, 8</gold></green>", Placeholder.component("prefix", prefix))); "Example: <gold>/votetomutehelper messages 1, 2, 5, 8</gold></green>"));
showPage(1); showPage(0);
}); });
} }
private void parseChatLogs(List<ChatLog> chatLogs) { private void parseChatLogs(List<ChatLog> chatLogs) {
TagResolver.Single playerTag = Placeholder.parsed("player", votedPlayer.getUsername()); TagResolver.Single playerTag = Placeholder.parsed("player", votedPlayer.getUsername());
TagResolver.Single prefixTag = Placeholder.component("prefix", prefix); chatLogs.sort(Comparator.comparing(ChatLog::getTimestamp));
chatLogs.sort(Comparator.comparing(ChatLog::getTimestamp).reversed());
parsedChatLogs = IntStream.range(0, chatLogs.size()) parsedChatLogs = IntStream.range(0, chatLogs.size())
.mapToObj(i -> Utility.parseMiniMessage( .mapToObj(i -> Utility.parseMiniMessage(
"<number>. <prefix> <player>: <message>", "<number>. [ChatLog] <player>: <message>",
TagResolver.resolver( TagResolver.resolver(
Placeholder.unparsed("message", chatLogs.get(i).getMessage()), Placeholder.unparsed("message", chatLogs.get(i).getMessage()),
Placeholder.parsed("number", String.valueOf(i + 1)), Placeholder.parsed("number", String.valueOf(i + 1)),
playerTag, prefixTag playerTag
)) ))
) )
.toList(); .toList();
} }
public void showPage(int page) { public void showPage(int page) {
List<Component> collect = parsedChatLogs.stream().skip((page - 1) * 10L).limit(10L).toList(); List<Component> collect = parsedChatLogs.stream().skip(page * 10L).limit(page).toList();
Component chatLogsComponent = Component.join(JoinConfiguration.newlines(), collect); Component chatLogsComponent = Component.join(JoinConfiguration.newlines(), collect);
StringBuilder stringBuilder = new StringBuilder(); StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("<prefix> ChatLogs for <player>\n<logs>\n"); stringBuilder.append("<prefix> ChatLogs for <player>\n<logs>\n");
if (page > 1) { if (page != 0) {
stringBuilder.append("<click:run_command:/votetomutehelper page ") stringBuilder.append("<click:run_command:/votetomute page ")
.append(page - 1) .append(page - 1)
.append("><hover:show_text:'<gold>Click to go to previous page'><gold><previous page></gold></hover></click> "); .append("><hover:show_text:'<gold>Click to go to previous page'><gold><previous page></gold></hover></click> ");
} }
if (parsedChatLogs.size() > page * 10) { if (parsedChatLogs.size() > page * 10) {
stringBuilder.append("<click:run_command:/votetomutehelper page ") stringBuilder.append("<click:run_command:/votetomute page ")
.append(page + 1) .append(page + 1)
.append("><hover:show_text:'<gold>Click to go to next page'><gold><next page></gold></hover></click> "); .append("><hover:show_text:'<gold>Click to go to next page'><gold><previous page></gold></hover></click> ");
} }
commandSource.sendMessage(Utility.parseMiniMessage(stringBuilder.toString(), commandSource.sendMessage(Utility.parseMiniMessage(stringBuilder.toString(),
Placeholder.parsed("player", votedPlayer.getUsername()), Placeholder.parsed("player", votedPlayer.getUsername()),