Compare commits
8
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2962a605ea | ||
|
|
7492dfa418 | ||
|
|
92979e9789 | ||
|
|
af6820d1bf | ||
|
|
8546bda28a | ||
|
|
28894ef245 | ||
|
|
5a508fdf28 | ||
|
|
dc513ac2f0 |
@@ -3,12 +3,19 @@ plugins {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation(project(":web-api")) // Web-API
|
||||
compileOnly("org.projectlombok:lombok:1.18.46")
|
||||
annotationProcessor("org.projectlombok:lombok:1.18.46")
|
||||
// Cosmos
|
||||
compileOnly("com.alttd.cosmos:cosmos-api:1.21.8-R0.1-SNAPSHOT") {
|
||||
isChanging = true
|
||||
}
|
||||
compileOnly("org.spongepowered:configurate-yaml:4.2.0") // Configurate
|
||||
compileOnly("net.luckperms:api:5.5") // Luckperms
|
||||
|
||||
//API validation
|
||||
implementation("org.hibernate.validator:hibernate-validator:9.0.1.Final")
|
||||
implementation("org.glassfish:jakarta.el:5.0.0-M1")
|
||||
}
|
||||
|
||||
publishing {
|
||||
|
||||
@@ -38,9 +38,9 @@ public final class Config {
|
||||
CONFIGPATH = new File(File.separator + "mnt" + File.separator + "configs" + File.separator + "ChatPlugin");
|
||||
CONFIG_FILE = new File(CONFIGPATH, "config.yml");
|
||||
configLoader = YamlConfigurationLoader.builder()
|
||||
.file(CONFIG_FILE)
|
||||
.nodeStyle(NodeStyle.BLOCK)
|
||||
.build();
|
||||
.file(CONFIG_FILE)
|
||||
.nodeStyle(NodeStyle.BLOCK)
|
||||
.build();
|
||||
if (!CONFIG_FILE.getParentFile().exists()) {
|
||||
if (!CONFIG_FILE.getParentFile().mkdirs()) {
|
||||
return;
|
||||
@@ -183,11 +183,15 @@ public final class Config {
|
||||
private static void settings() {
|
||||
PREFIXGROUPS = getList("settings.prefix-groups",
|
||||
Lists.newArrayList("discord", "socialmedia", "eventteam", "eventleader", "youtube", "twitch",
|
||||
"developer"));
|
||||
"developer"
|
||||
)
|
||||
);
|
||||
CONFLICTINGPREFIXGROUPS = getList("settings.prefix-conflicts-groups",
|
||||
Lists.newArrayList("eventteam", "eventleader"));
|
||||
Lists.newArrayList("eventteam", "eventleader")
|
||||
);
|
||||
STAFFGROUPS = getList("settings.staff-groups",
|
||||
Lists.newArrayList("trainee", "moderator", "headmod", "admin", "manager", "owner"));
|
||||
Lists.newArrayList("trainee", "moderator", "headmod", "admin", "manager", "owner")
|
||||
);
|
||||
CONSOLENAME = getString("settings.console-name", CONSOLENAME);
|
||||
CONSOLEUUID = UUID.fromString(getString("settings.console-uuid", CONSOLEUUID.toString()));
|
||||
MINIMIUMSTAFFRANK = getString("settings.minimum-staff-rank", MINIMIUMSTAFFRANK);
|
||||
@@ -282,7 +286,7 @@ public final class Config {
|
||||
public static String NO_PERMISSION = "<red>You don't have permission to use this command.</red>";
|
||||
public static String NO_CONSOLE = "<red>This command can not be used by console</red>";
|
||||
public static String CREATED_PARTY = "<green>You created a chat party called: " +
|
||||
"'<gold><party_name></gold>' with the password: '<gold><party_password></gold>'</green>";
|
||||
"'<gold><party_name></gold>' with the password: '<gold><party_password></gold>'</green>";
|
||||
public static String NOT_IN_A_PARTY = "<red>You're not in a chat party.</red>";
|
||||
public static String NOT_YOUR_PARTY = "<red>You don't own this chat party.</red>";
|
||||
public static String NOT_A_PARTY = "<red>This chat party does not exist.</red>";
|
||||
@@ -307,14 +311,14 @@ public final class Config {
|
||||
public static String ALREADY_IN_THIS_PARTY = "<red>You're already in <party>!</red>";
|
||||
public static String SENT_PARTY_INV = "<green>You send a chat party invite to <player>!</green>";
|
||||
public static String JOIN_PARTY_CLICK_MESSAGE = "<click:run_command:'/party join <party> <party_password>'>" +
|
||||
"<dark_aqua>You received an invite to join <party>, click this message to accept.</dark_aqua></click>";
|
||||
"<dark_aqua>You received an invite to join <party>, click this message to accept.</dark_aqua></click>";
|
||||
public static String PARTY_MEMBER_LOGGED_ON = "<dark_aqua>[ChatParty] <player> joined Altitude...</dark_aqua>";
|
||||
public static String PARTY_MEMBER_LOGGED_OFF = "<dark_aqua>[ChatParty] <player> left Altitude...</dark_aqua>";
|
||||
public static String RENAMED_PARTY =
|
||||
"<dark_aqua>[ChatParty] <owner> changed the party name from <old_name> to <new_name>!</dark_aqua>";
|
||||
public static String CHANGED_PASSWORD = "<green>Password was set to <password></green>";
|
||||
public static String DISBAND_PARTY_CONFIRM = "<green><bold>Are you sure you want to disband your party?</bold> " +
|
||||
"Type <gold>/party disband confirm <party></gold> to confirm.";
|
||||
"Type <gold>/party disband confirm <party></gold> to confirm.";
|
||||
public static String DISBANDED_PARTY =
|
||||
"<dark_aqua>[ChatParty] <owner> has disbanded <party>, everyone has been removed.</dark_aqua>";
|
||||
public static String PARTY_INFO = """
|
||||
@@ -413,7 +417,8 @@ public final class Config {
|
||||
ConfigurationNode node = getNode("chat-channels");
|
||||
if (node.empty()) {
|
||||
getString("chat-channels.ac.format",
|
||||
"<white><gray><sender></gray> <hover:show_text:on <server>><yellow>to <channel></yellow></hover><gray>: <message>");
|
||||
"<white><gray><sender></gray> <hover:show_text:on <server>><yellow>to <channel></yellow></hover><gray>: <message>"
|
||||
);
|
||||
getList("chat-channels.ac.servers", List.of("lobby"));
|
||||
getBoolean("chat-channels.ac.proxy", false);
|
||||
node = getNode("chat-channels");
|
||||
@@ -617,11 +622,15 @@ public final class Config {
|
||||
NICK_WAIT_TIME = getLong("nicknames.wait-time", NICK_WAIT_TIME);
|
||||
NICK_ITEM_LORE = getList("nicknames.item-lore",
|
||||
List.of("<aqua>New nick: <newnick>", "<aqua>Old nick: <oldnick>", "<aqua>Last changed: <lastchanged>",
|
||||
"<green>Left click to Accept <light_purple>| <red>Right click to Deny"));
|
||||
"<green>Left click to Accept <light_purple>| <red>Right click to Deny"
|
||||
)
|
||||
);
|
||||
NICK_BLOCKED_COLOR_CODESLIST = getList("nicknames.blocked-color-codes", List.of("&k", "&l", "&n", "&m", "&o"));
|
||||
NICK_ALLOWED_COLOR_CODESLIST = getList("nicknames.allowed-color-codes",
|
||||
List.of("&0", "&1", "&2", "&3", "&4", "&5", "&6", "&7", "&8", "&9", "&a", "&b", "&c", "&d", "&e", "&f",
|
||||
"&r"));
|
||||
"&r"
|
||||
)
|
||||
);
|
||||
NICK_CURRENT = getString("nicknames.messages.nick-current", NICK_CURRENT);
|
||||
}
|
||||
|
||||
@@ -641,4 +650,10 @@ public final class Config {
|
||||
CHAT_LOG_DELETE_OLDER_THAN_DAYS = getLong("chat-log.delete-older-than-days", CHAT_LOG_DELETE_OLDER_THAN_DAYS);
|
||||
CHAT_LOG_SAVE_DELAY_MINUTES = getLong("chat-log.save-delay-minutes", CHAT_LOG_SAVE_DELAY_MINUTES);
|
||||
}
|
||||
|
||||
public static String CHAT_WEB_SERVER_BASE_URL = "http://10.0.0.121:8080";
|
||||
|
||||
private static void webServerSettings() {
|
||||
CHAT_WEB_SERVER_BASE_URL = getString("web-server.base-url", CHAT_WEB_SERVER_BASE_URL);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,15 +15,25 @@ import java.util.concurrent.CompletionException;
|
||||
public class ChatLogQueries {
|
||||
|
||||
protected static void createChatLogTable() {
|
||||
String nicknamesTableQuery = "CREATE TABLE IF NOT EXISTS chat_log("
|
||||
+ "uuid CHAR(48) NOT NULL,"
|
||||
+ "time_stamp TIMESTAMP(6) NOT NULL, "
|
||||
+ "server VARCHAR(50) NOT NULL, "
|
||||
+ "chat_message VARCHAR(300) NOT NULL, "
|
||||
+ "blocked BIT(1) NOT NULL DEFAULT 0"
|
||||
+ ")";
|
||||
String nicknamesTableQuery = """
|
||||
CREATE TABLE IF NOT EXISTS chat_log (
|
||||
id BIGINT AUTO_INCREMENT PRIMARY KEY,
|
||||
uuid CHAR(36) NOT NULL,
|
||||
time_stamp TIMESTAMP(6) NOT NULL,
|
||||
server VARCHAR(50) NOT NULL,
|
||||
type VARCHAR(16) NOT NULL DEFAULT 'public',
|
||||
channel VARCHAR(36) DEFAULT NULL,
|
||||
receiver CHAR(36) DEFAULT NULL,
|
||||
chat_message VARCHAR(300) NOT NULL,
|
||||
mini_message JSON,
|
||||
blocked BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
|
||||
INDEX idx_time_stamp (time_stamp)
|
||||
)
|
||||
""";
|
||||
|
||||
try (PreparedStatement preparedStatement = DatabaseConnection.getConnection().prepareStatement(nicknamesTableQuery)) {
|
||||
try (PreparedStatement preparedStatement = DatabaseConnection.getConnection().prepareStatement(
|
||||
nicknamesTableQuery)) {
|
||||
preparedStatement.executeUpdate();
|
||||
} catch (Throwable throwable) {
|
||||
ALogger.error("Failed to create chat log table", throwable);
|
||||
@@ -31,7 +41,7 @@ public class ChatLogQueries {
|
||||
}
|
||||
|
||||
public static @NotNull CompletableFuture<Boolean> storeMessages(HashMap<UUID, List<ChatLog>> chatMessages) {
|
||||
String insertQuery = "INSERT INTO chat_log (uuid, time_stamp, server, chat_message, blocked) VALUES (?, ?, ?, ?, ?)";
|
||||
String insertQuery = "INSERT INTO chat_log (uuid, time_stamp, server, type, channel, receiver, chat_message, mini_message, blocked) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)";
|
||||
return CompletableFuture.supplyAsync(() -> {
|
||||
try (Connection connection = DatabaseConnection.createTransactionConnection()) {
|
||||
PreparedStatement preparedStatement = connection.prepareStatement(insertQuery);
|
||||
@@ -60,7 +70,7 @@ public class ChatLogQueries {
|
||||
}
|
||||
|
||||
public static @NotNull CompletableFuture<List<ChatLog>> retrieveMessages(ChatLogHandler chatLogHandler, UUID uuid, Duration duration, String server) {
|
||||
String query = "SELECT * FROM chat_log WHERE uuid = ? AND time_stamp > ? AND server = ?";
|
||||
String query = "SELECT * FROM chat_log WHERE uuid = ? AND time_stamp > ? AND server = ? AND type = 'public'";
|
||||
return CompletableFuture.supplyAsync(() -> {
|
||||
try (Connection connection = DatabaseConnection.getConnection()) {
|
||||
PreparedStatement preparedStatement = connection.prepareStatement(query);
|
||||
@@ -70,13 +80,14 @@ public class ChatLogQueries {
|
||||
ResultSet resultSet = preparedStatement.executeQuery();
|
||||
List<ChatLog> chatLogs = new ArrayList<>();
|
||||
while (resultSet.next()) {
|
||||
ChatLog chatLog = chatLogHandler.loadFromResultSet(resultSet);
|
||||
chatLogs.add(chatLog);
|
||||
chatLogHandler.loadFromResultSet(resultSet).ifPresent(chatLogs::add);
|
||||
}
|
||||
return chatLogs;
|
||||
} catch (SQLException sqlException) {
|
||||
ALogger.error(String.format("Failed to retrieve messages for user %s", uuid), sqlException);
|
||||
throw new CompletionException(String.format("Failed to retrieve messages for user %s", uuid), sqlException);
|
||||
throw new CompletionException(String.format("Failed to retrieve messages for user %s", uuid),
|
||||
sqlException
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -90,8 +101,13 @@ public class ChatLogQueries {
|
||||
preparedStatement.setTimestamp(1, Timestamp.from(Instant.now().minus(duration)));
|
||||
return preparedStatement.execute();
|
||||
} catch (SQLException sqlException) {
|
||||
ALogger.error(String.format("Failed to delete messages older than %s days", duration.toDays()), sqlException);
|
||||
throw new CompletionException(String.format("Failed to delete messages older than %s days", duration.toDays()), sqlException);
|
||||
ALogger.error(String.format("Failed to delete messages older than %s days", duration.toDays()),
|
||||
sqlException
|
||||
);
|
||||
throw new CompletionException(String.format("Failed to delete messages older than %s days",
|
||||
duration.toDays()
|
||||
), sqlException
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package com.alttd.chat.database;
|
||||
|
||||
|
||||
import com.alttd.chat.config.Config;
|
||||
|
||||
import java.sql.Connection;
|
||||
@@ -27,6 +26,7 @@ public class DatabaseConnection {
|
||||
|
||||
/**
|
||||
* Opens the connection if it's not already open.
|
||||
*
|
||||
* @throws SQLException If it can't create the connection.
|
||||
*/
|
||||
public void openConnection() throws SQLException {
|
||||
@@ -45,14 +45,16 @@ public class DatabaseConnection {
|
||||
}
|
||||
|
||||
connection = DriverManager.getConnection(
|
||||
"jdbc:mysql://" + Config.IP + ":" + Config.PORT + "/" + Config.DATABASE + "?autoReconnect=true"+
|
||||
"&useSSL=false",
|
||||
Config.USERNAME, Config.PASSWORD);
|
||||
"jdbc:mysql://" + Config.IP + ":" + Config.PORT + "/" + Config.DATABASE + "?autoReconnect=true" +
|
||||
"&useSSL=false&preserveInstants=true",
|
||||
Config.USERNAME, Config.PASSWORD
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the connection for the database
|
||||
*
|
||||
* @return Returns the connection.
|
||||
*/
|
||||
public static Connection getConnection() {
|
||||
@@ -69,13 +71,15 @@ public class DatabaseConnection {
|
||||
* Creates a transactional database connection.
|
||||
*
|
||||
* @return A {@code Connection} object representing the transactional database connection.
|
||||
*
|
||||
* @throws SQLException If there is an error creating the database connection.
|
||||
*/
|
||||
public static Connection createTransactionConnection() throws SQLException {
|
||||
connection = DriverManager.getConnection(
|
||||
"jdbc:mysql://" + Config.IP + ":" + Config.PORT + "/" + Config.DATABASE + "?autoReconnect=true"+
|
||||
"&useSSL=false",
|
||||
Config.USERNAME, Config.PASSWORD);
|
||||
"jdbc:mysql://" + Config.IP + ":" + Config.PORT + "/" + Config.DATABASE + "?autoReconnect=true" +
|
||||
"&useSSL=false&preserveInstants=true",
|
||||
Config.USERNAME, Config.PASSWORD
|
||||
);
|
||||
connection.setAutoCommit(false);
|
||||
return connection;
|
||||
}
|
||||
@@ -88,4 +92,4 @@ public class DatabaseConnection {
|
||||
return connection != null;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,8 +18,9 @@ public abstract class Toggleable {
|
||||
|
||||
public static Toggleable getToggleable(UUID uuid) {
|
||||
for (Toggleable toggleableClass : togglableClasses) {
|
||||
if (toggleableClass.isToggled(uuid))
|
||||
if (toggleableClass.isToggled(uuid)) {
|
||||
return toggleableClass;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
package com.alttd.chat.objects.chat_log;
|
||||
|
||||
import com.alttd.chat.objects.BatchInsertable;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.sql.PreparedStatement;
|
||||
@@ -9,44 +13,32 @@ import java.sql.Timestamp;
|
||||
import java.time.Instant;
|
||||
import java.util.UUID;
|
||||
|
||||
@AllArgsConstructor
|
||||
@Getter
|
||||
public class ChatLog implements BatchInsertable {
|
||||
|
||||
private final UUID uuid;
|
||||
private final Instant timestamp;
|
||||
private final String server;
|
||||
private final ChatLogType type;
|
||||
private final String channel;
|
||||
private final String receiver;
|
||||
private final String message;
|
||||
private final Component miniMessage;
|
||||
private final boolean blocked;
|
||||
|
||||
protected ChatLog(UUID uuid, Instant timestamp, String server, String message, boolean blocked) {
|
||||
this.uuid = uuid;
|
||||
this.timestamp = timestamp;
|
||||
this.server = server;
|
||||
this.message = message;
|
||||
this.blocked = blocked;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void prepareStatement(@NotNull PreparedStatement preparedStatement) throws SQLException {
|
||||
preparedStatement.setString(1, uuid.toString());
|
||||
preparedStatement.setTimestamp(2, Timestamp.from(timestamp));
|
||||
preparedStatement.setString(3, server);
|
||||
preparedStatement.setString(4, message);
|
||||
preparedStatement.setInt(5, blocked ? 1 : 0);
|
||||
}
|
||||
|
||||
public UUID getUuid() {
|
||||
return uuid;
|
||||
}
|
||||
|
||||
public Instant getTimestamp() {
|
||||
return timestamp;
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
public boolean isBlocked() {
|
||||
return blocked;
|
||||
preparedStatement.setString(4, ChatLogTypeMapper.toDb(type));
|
||||
preparedStatement.setString(5, channel);
|
||||
preparedStatement.setString(6, receiver);
|
||||
preparedStatement.setString(7, message);
|
||||
preparedStatement.setString(8,
|
||||
miniMessage == null ? null : GsonComponentSerializer.gson().serialize(miniMessage)
|
||||
);
|
||||
preparedStatement.setInt(9, blocked ? 1 : 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,9 @@ package com.alttd.chat.objects.chat_log;
|
||||
import com.alttd.chat.config.Config;
|
||||
import com.alttd.chat.database.ChatLogQueries;
|
||||
import com.alttd.chat.util.ALogger;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
@@ -12,14 +15,17 @@ import java.time.Instant;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.*;
|
||||
|
||||
@Slf4j
|
||||
public class ChatLogHandler {
|
||||
|
||||
private final ChatLogWebHandler chatLogWebHandler = new ChatLogWebHandler();
|
||||
private static ChatLogHandler instance = null;
|
||||
private ScheduledExecutorService executorService = null;
|
||||
|
||||
public static ChatLogHandler getInstance(boolean enableLogging) {
|
||||
if (instance == null)
|
||||
if (instance == null) {
|
||||
instance = new ChatLogHandler(enableLogging);
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
@@ -35,23 +41,30 @@ public class ChatLogHandler {
|
||||
Duration deleteThreshold = Duration.ofDays(Config.CHAT_LOG_DELETE_OLDER_THAN_DAYS);
|
||||
ChatLogQueries.deleteOldMessages(deleteThreshold).thenAccept(success -> {
|
||||
if (success) {
|
||||
ALogger.info(String.format("Deleted all messages older than %s days from chat log database.", deleteThreshold.toDays()));
|
||||
ALogger.info(String.format("Deleted all messages older than %s days from chat log database.",
|
||||
deleteThreshold.toDays()
|
||||
));
|
||||
} else {
|
||||
ALogger.warn(String.format("Failed to delete all messages older than %s days from chat log database.", deleteThreshold.toDays()));
|
||||
ALogger.warn(String.format("Failed to delete all messages older than %s days from chat log database.",
|
||||
deleteThreshold.toDays()
|
||||
));
|
||||
}
|
||||
});
|
||||
executorService = Executors.newSingleThreadScheduledExecutor();
|
||||
executorService.scheduleAtFixedRate(() -> {
|
||||
saveToDatabase(false);
|
||||
ALogger.info(String.format("Running scheduler to save messages with a %d delay", Config.CHAT_LOG_SAVE_DELAY_MINUTES));
|
||||
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!");
|
||||
}
|
||||
|
||||
/**
|
||||
* Shuts down the executor service and saves the chat logs to the database.
|
||||
* Will throw an error if called on a ChatLogHandler that was started without logging
|
||||
* Shuts down the executor service and saves the chat logs to the database. Will throw an error if called on a
|
||||
* ChatLogHandler that was started without logging
|
||||
*/
|
||||
public void shutDown() {
|
||||
executorService.shutdown();
|
||||
@@ -66,7 +79,7 @@ public class ChatLogHandler {
|
||||
return isSaving;
|
||||
}
|
||||
|
||||
public synchronized void addLog(ChatLog chatLog) {
|
||||
private synchronized void addLog(ChatLog chatLog) {
|
||||
if (isBlocked()) {
|
||||
chatLogQueue.add(chatLog);
|
||||
} else {
|
||||
@@ -100,17 +113,50 @@ public class ChatLogHandler {
|
||||
});
|
||||
}
|
||||
|
||||
public ChatLog loadFromResultSet(@NotNull ResultSet resultSet) throws SQLException {
|
||||
public Optional<ChatLog> loadFromResultSet(@NotNull ResultSet resultSet) throws SQLException {
|
||||
UUID chatLogUUID = UUID.fromString(resultSet.getString("uuid"));
|
||||
Instant chatTimestamp = resultSet.getTimestamp("time_stamp").toInstant();
|
||||
String server = resultSet.getString("server");
|
||||
String stringType = resultSet.getString("type");
|
||||
ChatLogType type;
|
||||
try {
|
||||
type = ChatLogTypeMapper.fromDb(stringType);
|
||||
} catch (Exception e) {
|
||||
log.error("Failed to load chat log from result set: {}", e.getMessage());
|
||||
return Optional.empty();
|
||||
}
|
||||
String channel = resultSet.getString("channel");
|
||||
String receiver = resultSet.getString("receiver");
|
||||
String chatMessage = resultSet.getString("chat_message");
|
||||
String stringMiniMessage = resultSet.getString("mini_message");
|
||||
Component miniMessage = stringMiniMessage == null ? null : GsonComponentSerializer.gson().deserialize(
|
||||
stringMiniMessage);
|
||||
boolean chatMessageBlocked = resultSet.getInt("blocked") == 1;
|
||||
return new ChatLog(chatLogUUID, chatTimestamp, server, chatMessage, chatMessageBlocked);
|
||||
return Optional.of(new ChatLog(chatLogUUID,
|
||||
chatTimestamp,
|
||||
server,
|
||||
type,
|
||||
channel,
|
||||
receiver,
|
||||
chatMessage,
|
||||
miniMessage,
|
||||
chatMessageBlocked
|
||||
));
|
||||
}
|
||||
|
||||
public void addChatLog(UUID uuid, String server, String message, boolean blocked) {
|
||||
addLog(new ChatLog(uuid, Instant.now(), server, message, blocked));
|
||||
public void addChatLog(UUID uuid, String server, String message, ChatLogType chatLogType, String channel, String receiver, Component miniMessage, boolean blocked) {
|
||||
ChatLog chatLog = new ChatLog(uuid,
|
||||
Instant.now(),
|
||||
server,
|
||||
chatLogType,
|
||||
channel,
|
||||
receiver,
|
||||
message,
|
||||
miniMessage,
|
||||
blocked
|
||||
);
|
||||
addLog(chatLog);
|
||||
chatLogWebHandler.forwardChatLogToWeb(chatLog);
|
||||
}
|
||||
|
||||
public CompletableFuture<List<ChatLog>> retrieveChatLogs(UUID uuid, Duration duration, String server) {
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
package com.alttd.chat.objects.chat_log;
|
||||
|
||||
import com.alttd.altitudeweb.model.ChatMessageDto;
|
||||
import jakarta.validation.ConstraintViolation;
|
||||
import jakarta.validation.Validation;
|
||||
import jakarta.validation.Validator;
|
||||
import jakarta.validation.ValidatorFactory;
|
||||
import lombok.experimental.UtilityClass;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
|
||||
|
||||
import java.time.ZoneOffset;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
|
||||
@Slf4j
|
||||
@UtilityClass
|
||||
public class ChatLogMapper {
|
||||
|
||||
ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
|
||||
Validator validator = factory.getValidator();
|
||||
|
||||
public Optional<ChatMessageDto> toDto(ChatLog chatLog) {
|
||||
ChatMessageDto chatMessageDto = new ChatMessageDto();
|
||||
if (chatLog.getMiniMessage() == null) {
|
||||
throw new IllegalArgumentException("MiniMessage cannot be null");
|
||||
}
|
||||
chatMessageDto.setUuid(chatLog.getUuid());
|
||||
chatMessageDto.setTimestamp(chatLog.getTimestamp().atOffset(ZoneOffset.UTC));
|
||||
chatMessageDto.setServer(chatLog.getServer());
|
||||
chatMessageDto.setType(ChatLogTypeMapper.toDto(chatLog.getType()));
|
||||
chatMessageDto.setChannel(chatLog.getChannel());
|
||||
chatMessageDto.setReceiver(chatLog.getReceiver());
|
||||
chatMessageDto.setMessage(GsonComponentSerializer.gson().serialize(chatLog.getMiniMessage()));
|
||||
chatMessageDto.setBlocked(chatLog.isBlocked());
|
||||
if (checkIsInvalid(chatMessageDto)) {
|
||||
return Optional.empty();
|
||||
}
|
||||
return Optional.of(chatMessageDto);
|
||||
}
|
||||
|
||||
private boolean checkIsInvalid(ChatMessageDto chatMessageDto) {
|
||||
Set<ConstraintViolation<ChatMessageDto>> violations = validator.validate(chatMessageDto);
|
||||
if (violations.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
log.error("Validation failed for chat message: {}, {}", chatMessageDto, violations);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package com.alttd.chat.objects.chat_log;
|
||||
|
||||
public enum ChatLogType {
|
||||
PUBLIC,
|
||||
GLOBAL,
|
||||
PARTY,
|
||||
GAC,
|
||||
MSG,
|
||||
CUSTOM;
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package com.alttd.chat.objects.chat_log;
|
||||
|
||||
import com.alttd.altitudeweb.model.ChatMessageDto;
|
||||
import lombok.experimental.UtilityClass;
|
||||
|
||||
@UtilityClass
|
||||
public class ChatLogTypeMapper {
|
||||
|
||||
public static String toDb(ChatLogType chatLogType) {
|
||||
return switch (chatLogType) {
|
||||
case PUBLIC -> "public";
|
||||
case GLOBAL -> "global";
|
||||
case PARTY -> "party";
|
||||
case GAC -> "gac";
|
||||
case MSG -> "msg";
|
||||
case CUSTOM -> "custom";
|
||||
};
|
||||
}
|
||||
|
||||
public ChatMessageDto.TypeEnum toDto(ChatLogType chatLogType) {
|
||||
return switch (chatLogType) {
|
||||
case PUBLIC -> ChatMessageDto.TypeEnum.PUBLIC;
|
||||
case GLOBAL -> ChatMessageDto.TypeEnum.GLOBAL;
|
||||
case PARTY -> ChatMessageDto.TypeEnum.PARTY;
|
||||
case GAC -> ChatMessageDto.TypeEnum.GAC;
|
||||
case MSG -> ChatMessageDto.TypeEnum.MSG;
|
||||
case CUSTOM -> ChatMessageDto.TypeEnum.CUSTOM;
|
||||
};
|
||||
}
|
||||
|
||||
public ChatLogType fromDb(String dbType) {
|
||||
return switch (dbType) {
|
||||
case "public" -> ChatLogType.PUBLIC;
|
||||
case "global" -> ChatLogType.GLOBAL;
|
||||
case "party" -> ChatLogType.PARTY;
|
||||
case "gac" -> ChatLogType.GAC;
|
||||
case "msg" -> ChatLogType.MSG;
|
||||
case "custom" -> ChatLogType.CUSTOM;
|
||||
default -> throw new IllegalArgumentException("Invalid chat log type: " + dbType);
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
package com.alttd.chat.objects.chat_log;
|
||||
|
||||
import com.alttd.altitudeweb.api.ChatApi;
|
||||
import com.alttd.altitudeweb.invoker.ApiClient;
|
||||
import com.alttd.altitudeweb.invoker.ApiException;
|
||||
import com.alttd.altitudeweb.model.ChatMessageDto;
|
||||
import com.alttd.chat.config.Config;
|
||||
import com.alttd.chat.util.ALogger;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.Queue;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
public class ChatLogWebHandler {
|
||||
|
||||
private static final int MAX_QUEUE_SIZE = 100;
|
||||
private static final Logger log = LoggerFactory.getLogger(ChatLogWebHandler.class);
|
||||
|
||||
private final Queue<ChatLog> queue = new ConcurrentLinkedQueue<>();
|
||||
private final ExecutorService executor = Executors.newSingleThreadExecutor();
|
||||
|
||||
private final ChatApi chatApi;
|
||||
|
||||
public ChatLogWebHandler() {
|
||||
ApiClient apiClient = new ApiClient();
|
||||
apiClient.setBasePath(Config.CHAT_WEB_SERVER_BASE_URL);
|
||||
|
||||
chatApi = new ChatApi(apiClient);
|
||||
}
|
||||
|
||||
private volatile boolean sending;
|
||||
|
||||
public void forwardChatLogToWeb(ChatLog chatLog) {
|
||||
if (queue.size() >= MAX_QUEUE_SIZE) {
|
||||
queue.clear();
|
||||
log.error("Chat log queue overflow, is the web backend still running?");
|
||||
}
|
||||
|
||||
queue.add(chatLog);
|
||||
triggerSend();
|
||||
}
|
||||
|
||||
private void triggerSend() {
|
||||
if (sending) {
|
||||
return;
|
||||
}
|
||||
|
||||
synchronized (this) {
|
||||
if (sending || queue.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
sending = true;
|
||||
}
|
||||
|
||||
executor.execute(this::sendBatch);
|
||||
}
|
||||
|
||||
private void sendBatch() {
|
||||
try {
|
||||
ArrayList<ChatLog> chatLogList = new ArrayList<>();
|
||||
|
||||
ChatLog log;
|
||||
while ((log = queue.poll()) != null) {
|
||||
if (log.getMiniMessage() == null) {
|
||||
ALogger.warn("No mini message for message, skipping");
|
||||
continue;
|
||||
}
|
||||
chatLogList.add(log);
|
||||
}
|
||||
|
||||
List<ChatMessageDto> batch = chatLogList.stream()
|
||||
.map(ChatLogMapper::toDto)
|
||||
.filter(Optional::isPresent)
|
||||
.map(Optional::get)
|
||||
.toList();
|
||||
|
||||
if (!chatLogList.isEmpty()) {
|
||||
try {
|
||||
chatApi.sendChatMessages(batch);
|
||||
} catch (ApiException e) {
|
||||
ALogger.error("Failed to send chat messages to web backend, " +
|
||||
"adding messages back to queue for another try", e
|
||||
);
|
||||
queue.addAll(chatLogList);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
synchronized (this) {
|
||||
sending = false;
|
||||
}
|
||||
|
||||
triggerSend();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11,6 +11,8 @@ dependencies {
|
||||
compileOnly("com.alttd.cosmos:cosmos-api:1.21.8-R0.1-SNAPSHOT") {
|
||||
isChanging = true
|
||||
}
|
||||
compileOnly("org.projectlombok:lombok:1.18.46")
|
||||
annotationProcessor("org.projectlombok:lombok:1.18.46")
|
||||
compileOnly("com.gitlab.ruany:LiteBansAPI:0.6.1") // move to proxy
|
||||
compileOnly("org.apache.commons:commons-lang3:3.17.0") // needs an alternative, already removed from upstream api and will be removed in server
|
||||
compileOnly("net.luckperms:api:5.5") // Luckperms
|
||||
|
||||
@@ -35,11 +35,15 @@ public class ChatPlugin extends JavaPlugin {
|
||||
instance = this;
|
||||
ALogger.init(getSLF4JLogger());
|
||||
chatAPI = new ChatImplementation();
|
||||
chatHandler = new ChatHandler();
|
||||
ChatLogHandler chatLogHandler = ChatLogHandler.getInstance(true);
|
||||
chatHandler = new ChatHandler(chatLogHandler);
|
||||
DatabaseConnection.initialize();
|
||||
serverConfig = new ServerConfig(ServerName.getServerName());
|
||||
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, this)
|
||||
);
|
||||
if (serverConfig.GLOBALCHAT) {
|
||||
registerCommand("globalchat", new GlobalChat());
|
||||
registerCommand("toggleglobalchat", new ToggleGlobalChat());
|
||||
@@ -58,12 +62,15 @@ public class ChatPlugin extends JavaPlugin {
|
||||
if (!(channel instanceof CustomChannel customChannel)) {
|
||||
continue;
|
||||
}
|
||||
this.getServer().getCommandMap().register(channel.getChannelName().toLowerCase(), new ChatChannel(customChannel));
|
||||
this.getServer()
|
||||
.getCommandMap()
|
||||
.register(channel.getChannelName().toLowerCase(), new ChatChannel(customChannel));
|
||||
}
|
||||
|
||||
String messageChannel = Config.MESSAGECHANNEL;
|
||||
getServer().getMessenger().registerOutgoingPluginChannel(this, messageChannel);
|
||||
getServer().getMessenger().registerIncomingPluginChannel(this, messageChannel, new PluginMessage());
|
||||
getServer().getMessenger()
|
||||
.registerIncomingPluginChannel(this, messageChannel, new PluginMessage(chatLogHandler));
|
||||
|
||||
NicknamesEvents nicknamesEvents = new NicknamesEvents();
|
||||
getServer().getMessenger().registerIncomingPluginChannel(this, messageChannel, nicknamesEvents);
|
||||
@@ -110,7 +117,9 @@ public class ChatPlugin extends JavaPlugin {
|
||||
chatAPI.reloadConfig();
|
||||
chatAPI.reloadChatFilters();
|
||||
serverConfig = new ServerConfig(ServerName.getServerName());
|
||||
Bukkit.broadcast(Utility.parseMiniMessage("Reloaded ChatPlugin Config.").asComponent(), "command.chat.reloadchat");
|
||||
Bukkit.broadcast(Utility.parseMiniMessage("Reloaded ChatPlugin Config.").asComponent(),
|
||||
"command.chat.reloadchat"
|
||||
);
|
||||
ALogger.info("Reloaded ChatPlugin config.");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,8 @@ import com.alttd.chat.objects.ChatFilter;
|
||||
import com.alttd.chat.objects.ChatUser;
|
||||
import com.alttd.chat.objects.ModifiableString;
|
||||
import com.alttd.chat.objects.channels.CustomChannel;
|
||||
import com.alttd.chat.objects.chat_log.ChatLogHandler;
|
||||
import com.alttd.chat.objects.chat_log.ChatLogType;
|
||||
import com.alttd.chat.util.ALogger;
|
||||
import com.alttd.chat.util.GalaxyUtility;
|
||||
import com.alttd.chat.util.ServerName;
|
||||
@@ -28,6 +30,7 @@ import org.bukkit.Material;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
@@ -40,8 +43,10 @@ public class ChatHandler {
|
||||
private final ChatPlugin plugin;
|
||||
|
||||
private final ComponentLike GCNOTENABLED;
|
||||
private final ChatLogHandler chatLogHandler;
|
||||
|
||||
public ChatHandler() {
|
||||
public ChatHandler(ChatLogHandler chatLogHandler) {
|
||||
this.chatLogHandler = chatLogHandler;
|
||||
plugin = ChatPlugin.getInstance();
|
||||
GCNOTENABLED = Utility.parseMiniMessage(Config.GCNOTENABLED);
|
||||
}
|
||||
@@ -54,7 +59,7 @@ public class ChatHandler {
|
||||
Placeholder.component("message", parseMessageContent(player, message)),
|
||||
Placeholder.component("sendername", player.name()),
|
||||
Placeholder.parsed("receivername", target)
|
||||
);
|
||||
);
|
||||
|
||||
ComponentLike component = Utility.parseMiniMessage("<message>", placeholders);
|
||||
|
||||
@@ -62,9 +67,10 @@ public class ChatHandler {
|
||||
// todo a better way for this
|
||||
if (!RegexManager.filterText(player.getName(), player.getUniqueId(), modifiableString, "privatemessage")) {
|
||||
GalaxyUtility.sendBlockedNotification("DM Language",
|
||||
player,
|
||||
Utility.parseMiniMessage(Utility.parseColors(modifiableString.string())),
|
||||
target);
|
||||
player,
|
||||
Utility.parseMiniMessage(Utility.parseColors(modifiableString.string())),
|
||||
target
|
||||
);
|
||||
return; // the message was blocked
|
||||
}
|
||||
|
||||
@@ -73,7 +79,8 @@ public class ChatHandler {
|
||||
sendPrivateMessage(player, target, "privatemessage", component.asComponent());
|
||||
ComponentLike spymessage = Utility.parseMiniMessage(Config.MESSAGESPY, placeholders);
|
||||
for (Player pl : Bukkit.getOnlinePlayers()) {
|
||||
if (pl.hasPermission(Config.SPYPERMISSION) && ChatUserManager.getChatUser(pl.getUniqueId()).isSpy() && !pl.equals(player) && !pl.getName().equalsIgnoreCase(target)) {
|
||||
if (pl.hasPermission(Config.SPYPERMISSION) && ChatUserManager.getChatUser(pl.getUniqueId())
|
||||
.isSpy() && !pl.equals(player) && !pl.getName().equalsIgnoreCase(target)) {
|
||||
pl.sendMessage(spymessage);
|
||||
}
|
||||
}
|
||||
@@ -88,15 +95,16 @@ public class ChatHandler {
|
||||
Placeholder.component("message", messageComponent),
|
||||
Placeholder.component("sendername", player.name()),
|
||||
Placeholder.parsed("receivername", target)
|
||||
);
|
||||
);
|
||||
|
||||
ModifiableString modifiableString = new ModifiableString(messageComponent);
|
||||
// todo a better way for this
|
||||
if (!RegexManager.filterText(player.getName(), player.getUniqueId(), modifiableString, "privatemessage")) {
|
||||
GalaxyUtility.sendBlockedNotification("DM Language",
|
||||
player,
|
||||
Utility.parseMiniMessage(Utility.parseColors(modifiableString.string())),
|
||||
target);
|
||||
player,
|
||||
Utility.parseMiniMessage(Utility.parseColors(modifiableString.string())),
|
||||
target
|
||||
);
|
||||
return; // the message was blocked
|
||||
}
|
||||
|
||||
@@ -108,7 +116,8 @@ public class ChatHandler {
|
||||
sendPrivateMessage(player, target, "privatemessage", messageComponent);
|
||||
ComponentLike spymessage = Utility.parseMiniMessage(Config.MESSAGESPY, placeholders);
|
||||
for (Player pl : Bukkit.getOnlinePlayers()) {
|
||||
if (pl.hasPermission(Config.SPYPERMISSION) && ChatUserManager.getChatUser(pl.getUniqueId()).isSpy() && !pl.equals(player) && !pl.getName().equalsIgnoreCase(target)) {
|
||||
if (pl.hasPermission(Config.SPYPERMISSION) && ChatUserManager.getChatUser(pl.getUniqueId())
|
||||
.isSpy() && !pl.equals(player) && !pl.getName().equalsIgnoreCase(target)) {
|
||||
pl.sendMessage(spymessage);
|
||||
}
|
||||
}
|
||||
@@ -127,7 +136,9 @@ public class ChatHandler {
|
||||
|
||||
long timeLeft = TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis() - user.getGcCooldown());
|
||||
if (timeLeft <= Config.GCCOOLDOWN && !player.hasPermission("chat.globalchat.cooldownbypass")) { // player is on cooldown and should wait x seconds
|
||||
player.sendRichMessage(Config.GCONCOOLDOWN, Placeholder.parsed("cooldown", Config.GCCOOLDOWN - timeLeft + ""));
|
||||
player.sendRichMessage(Config.GCONCOOLDOWN,
|
||||
Placeholder.parsed("cooldown", Config.GCCOOLDOWN - timeLeft + "")
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -138,7 +149,7 @@ public class ChatHandler {
|
||||
Placeholder.component("prefix", prefix),
|
||||
Placeholder.component("message", parseMessageContent(player, message)),
|
||||
Placeholder.parsed("server", ServerName.getServerName())
|
||||
);
|
||||
);
|
||||
|
||||
Component component = Utility.parseMiniMessage(Config.GCFORMAT, placeholders).asComponent();
|
||||
|
||||
@@ -146,13 +157,24 @@ public class ChatHandler {
|
||||
// todo a better way for this
|
||||
if (!RegexManager.filterText(player.getName(), player.getUniqueId(), modifiableString, "globalchat")) {
|
||||
GalaxyUtility.sendBlockedNotification("GC Language",
|
||||
player,
|
||||
Utility.parseMiniMessage(Utility.parseColors(modifiableString.string())),
|
||||
"");
|
||||
player,
|
||||
Utility.parseMiniMessage(Utility.parseColors(modifiableString.string())),
|
||||
""
|
||||
);
|
||||
return; // the message was blocked
|
||||
}
|
||||
component = modifiableString.component();
|
||||
|
||||
chatLogHandler.addChatLog(player.getUniqueId(),
|
||||
Bukkit.getServerName(),
|
||||
message,
|
||||
ChatLogType.GLOBAL,
|
||||
null,
|
||||
null,
|
||||
component,
|
||||
false
|
||||
);
|
||||
|
||||
user.setGcCooldown(System.currentTimeMillis());
|
||||
sendPluginMessage(player, "globalchat", component);
|
||||
}
|
||||
@@ -176,15 +198,20 @@ public class ChatHandler {
|
||||
Placeholder.component("message", parseMessageContent(player, message)),
|
||||
Placeholder.parsed("server", ServerName.getServerName()),
|
||||
Placeholder.parsed("channel", channel.getChannelName())
|
||||
);
|
||||
);
|
||||
Component component = Utility.parseMiniMessage(channel.getFormat(), placeholders).asComponent();
|
||||
|
||||
ModifiableString modifiableString = new ModifiableString(component);
|
||||
if (!RegexManager.filterText(player.getName(), player.getUniqueId(), modifiableString, channel.getChannelName())) {
|
||||
if (!RegexManager.filterText(player.getName(),
|
||||
player.getUniqueId(),
|
||||
modifiableString,
|
||||
channel.getChannelName()
|
||||
)) {
|
||||
GalaxyUtility.sendBlockedNotification(channel.getChannelName() + " Language",
|
||||
player,
|
||||
Utility.parseMiniMessage(Utility.parseColors(modifiableString.string())),
|
||||
"");
|
||||
player,
|
||||
Utility.parseMiniMessage(Utility.parseColors(modifiableString.string())),
|
||||
""
|
||||
);
|
||||
ALogger.info("Refusing to send blocked chat message");
|
||||
return;
|
||||
}
|
||||
@@ -205,7 +232,7 @@ public class ChatHandler {
|
||||
out.writeUTF(message);
|
||||
out.writeUTF(GsonComponentSerializer.gson().serialize(
|
||||
itemComponent(player.getInventory().getItemInMainHand())
|
||||
));
|
||||
));
|
||||
player.sendPluginMessage(plugin, Config.MESSAGECHANNEL, out.toByteArray());
|
||||
|
||||
// if (isMuted(player, message, "[" + party.getPartyName() + " Muted] ")) return;
|
||||
@@ -255,16 +282,20 @@ public class ChatHandler {
|
||||
|
||||
if (!chatChannel.getServers().contains(ServerName.getServerName())) {
|
||||
player.sendRichMessage("<red>Unable to send messages to <channel> in this server.</red>",
|
||||
Placeholder.parsed("channel", chatChannel.getChannelName()));
|
||||
Placeholder.parsed("channel", chatChannel.getChannelName())
|
||||
);
|
||||
ALogger.info(String.format("Not sending chat message due to [%s] not being in this channels config",
|
||||
ServerName.getServerName()));
|
||||
ServerName.getServerName()
|
||||
));
|
||||
return;
|
||||
}
|
||||
|
||||
Stream<? extends Player> stream = Bukkit.getServer().getOnlinePlayers().stream()
|
||||
.filter(p -> p.hasPermission(chatChannel.getPermission()));
|
||||
if (!player.hasPermission("chat.ignorebypass")) {
|
||||
stream = stream.filter(receiver -> !ChatUserManager.getChatUser(receiver.getUniqueId()).getIgnoredPlayers().contains(uuid)
|
||||
stream = stream.filter(receiver -> !ChatUserManager.getChatUser(receiver.getUniqueId())
|
||||
.getIgnoredPlayers()
|
||||
.contains(uuid)
|
||||
|| receiver.hasPermission("chat.ignorebypass"));
|
||||
}
|
||||
if (chatChannel.isLocal()) {
|
||||
@@ -283,14 +314,39 @@ public class ChatHandler {
|
||||
List<? extends Player> recipientPlayers = stream.toList();
|
||||
recipientPlayers.forEach(p -> p.sendMessage(component));
|
||||
|
||||
chatLogHandler.addChatLog(player.getUniqueId(),
|
||||
Bukkit.getServerName(),
|
||||
message,
|
||||
ChatLogType.CUSTOM,
|
||||
chatChannel.getChannelName(),
|
||||
getLocationIfLocal(chatChannel, player),
|
||||
component.asComponent(),
|
||||
false
|
||||
);
|
||||
|
||||
List<UUID> recipientUUIDs = recipientPlayers.stream().map(Entity::getUniqueId).toList();
|
||||
Bukkit.getServer().getOnlinePlayers().stream()
|
||||
.filter(onlinePlayer -> onlinePlayer.hasPermission(Config.SPYPERMISSION))
|
||||
.filter(onlinePlayer -> !recipientUUIDs.contains(onlinePlayer.getUniqueId()))
|
||||
.forEach(onlinePlayer -> onlinePlayer.sendRichMessage(Config.CHANNEL_SPY,
|
||||
Placeholder.component("sender", player.name()),
|
||||
Placeholder.parsed("channel", chatChannel.getChannelName()),
|
||||
Placeholder.parsed("message", message)));
|
||||
Placeholder.component("sender", player.name()),
|
||||
Placeholder.parsed("channel", chatChannel.getChannelName()),
|
||||
Placeholder.parsed("message", message)
|
||||
));
|
||||
}
|
||||
|
||||
private static @Nullable String getLocationIfLocal(CustomChannel chatChannel, Player player) {
|
||||
if (!chatChannel.isLocal()) {
|
||||
return null;
|
||||
}
|
||||
String format = String.format("%s;%s",
|
||||
player.getLocation().getBlockX(),
|
||||
player.getLocation().getBlockZ()
|
||||
);
|
||||
if (format.length() > 36) {
|
||||
return null;
|
||||
}
|
||||
return format;
|
||||
}
|
||||
|
||||
private void sendPluginMessage(Player player, String channel, Component component) {
|
||||
@@ -326,9 +382,14 @@ public class ChatHandler {
|
||||
if (user == null) {
|
||||
return false;
|
||||
}
|
||||
if (user.isMuted() || (ChatPlugin.getInstance().serverMuted() && !player.hasPermission("chat.bypass-server-muted"))) {
|
||||
if (user.isMuted() || (ChatPlugin.getInstance().serverMuted() && !player.hasPermission(
|
||||
"chat.bypass-server-muted"))) {
|
||||
// if (Database.get().isPlayerMuted(player.getUniqueId(), null) || (ChatPlugin.getInstance().serverMuted() && !player.hasPermission("chat.bypass-server-muted"))) {
|
||||
GalaxyUtility.sendBlockedNotification(prefix, player, Utility.parseMiniMessage(Utility.stripTokens(message)), "");
|
||||
GalaxyUtility.sendBlockedNotification(prefix,
|
||||
player,
|
||||
Utility.parseMiniMessage(Utility.stripTokens(message)),
|
||||
""
|
||||
);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
@@ -7,6 +7,7 @@ import com.alttd.chat.managers.ChatUserManager;
|
||||
import com.alttd.chat.managers.RegexManager;
|
||||
import com.alttd.chat.objects.*;
|
||||
import com.alttd.chat.objects.chat_log.ChatLogHandler;
|
||||
import com.alttd.chat.objects.chat_log.ChatLogType;
|
||||
import com.alttd.chat.util.ALogger;
|
||||
import com.alttd.chat.util.GalaxyUtility;
|
||||
import com.alttd.chat.util.ServerName;
|
||||
@@ -55,9 +56,14 @@ public class ChatListener implements Listener {
|
||||
}
|
||||
|
||||
Component formatComponent = Component.text("%message%");
|
||||
ComponentLike message = parseMessageContent(event.player(), plainTextComponentSerializer.serialize(event.originalMessage()));
|
||||
ComponentLike message = parseMessageContent(event.player(),
|
||||
plainTextComponentSerializer.serialize(event.originalMessage())
|
||||
);
|
||||
|
||||
event.result(formatComponent.replaceText(TextReplacementConfig.builder().match("%message%").replacement(message).build()));
|
||||
event.result(formatComponent.replaceText(TextReplacementConfig.builder()
|
||||
.match("%message%")
|
||||
.replacement(message)
|
||||
.build()));
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
|
||||
@@ -67,9 +73,14 @@ public class ChatListener implements Listener {
|
||||
}
|
||||
|
||||
Component formatComponent = Component.text("%message%");
|
||||
ComponentLike message = parseMessageContent(event.player(), plainTextComponentSerializer.serialize(event.originalMessage()));
|
||||
ComponentLike message = parseMessageContent(event.player(),
|
||||
plainTextComponentSerializer.serialize(event.originalMessage())
|
||||
);
|
||||
|
||||
event.result(formatComponent.replaceText(TextReplacementConfig.builder().match("%message%").replacement(message).build()));
|
||||
event.result(formatComponent.replaceText(TextReplacementConfig.builder()
|
||||
.match("%message%")
|
||||
.replacement(message)
|
||||
.build()));
|
||||
}
|
||||
|
||||
private final Component mention = MiniMessage.miniMessage().deserialize(Config.MENTIONPLAYERTAG);
|
||||
@@ -92,27 +103,39 @@ public class ChatListener implements Listener {
|
||||
UUID uuid = player.getUniqueId();
|
||||
|
||||
ComponentLike input = event.message().colorIfAbsent(NamedTextColor.WHITE);
|
||||
Component inputComponent = input.asComponent();
|
||||
|
||||
ModifiableString modifiableString = new ModifiableString(input.asComponent());
|
||||
ModifiableString modifiableString = new ModifiableString(inputComponent);
|
||||
|
||||
// todo a better way for this
|
||||
if (!RegexManager.filterText(player.getName(), uuid, modifiableString, true, "chat", filterType -> {
|
||||
if (!filterType.equals(FilterType.PUNISH)) {
|
||||
ALogger.warn("Received another FilterType than punish when filtering chat and executing a filter action");
|
||||
return;
|
||||
}
|
||||
ByteArrayDataOutput out = ByteStreams.newDataOutput();
|
||||
out.writeUTF("punish");
|
||||
out.writeUTF(player.getName());
|
||||
out.writeUTF(uuid.toString());
|
||||
out.writeUTF(modifiableString.string());
|
||||
player.sendPluginMessage(ChatPlugin.getInstance(), Config.MESSAGECHANNEL, out.toByteArray());
|
||||
})) {
|
||||
if (!filterType.equals(FilterType.PUNISH)) {
|
||||
ALogger.warn("Received another FilterType than punish when filtering chat and executing a filter action");
|
||||
return;
|
||||
}
|
||||
ByteArrayDataOutput out = ByteStreams.newDataOutput();
|
||||
out.writeUTF("punish");
|
||||
out.writeUTF(player.getName());
|
||||
out.writeUTF(uuid.toString());
|
||||
out.writeUTF(modifiableString.string());
|
||||
player.sendPluginMessage(ChatPlugin.getInstance(), Config.MESSAGECHANNEL, out.toByteArray());
|
||||
}
|
||||
)) {
|
||||
event.setCancelled(true);
|
||||
GalaxyUtility.sendBlockedNotification("Language", player,
|
||||
modifiableString.component(),
|
||||
"");
|
||||
chatLogHandler.addChatLog(uuid, ServerName.getServerName(), PlainTextComponentSerializer.plainText().serialize(input.asComponent()), true);
|
||||
modifiableString.component(),
|
||||
""
|
||||
);
|
||||
String originalMessage = PlainTextComponentSerializer.plainText().serialize(inputComponent);
|
||||
chatLogHandler.addChatLog(uuid,
|
||||
ServerName.getServerName(),
|
||||
originalMessage,
|
||||
ChatLogType.PUBLIC,
|
||||
null,
|
||||
null,
|
||||
render(player, inputComponent).asComponent(),
|
||||
true
|
||||
);
|
||||
return; // the message was blocked
|
||||
}
|
||||
|
||||
@@ -120,8 +143,13 @@ public class ChatListener implements Listener {
|
||||
.map(audience -> (Player) audience);
|
||||
|
||||
if (!player.hasPermission("chat.ignorebypass")) {
|
||||
stream = stream.filter(receiver -> !ChatUserManager.getChatUser(receiver.getUniqueId()).getIgnoredPlayers().contains(uuid)
|
||||
|| receiver.hasPermission("chat.ignorebypass"));
|
||||
stream = stream.filter(receiver -> {
|
||||
boolean isPlayerIgnored = ChatUserManager
|
||||
.getChatUser(receiver.getUniqueId())
|
||||
.getIgnoredPlayers()
|
||||
.contains(uuid);
|
||||
return !isPlayerIgnored || receiver.hasPermission("chat.ignorebypass");
|
||||
});
|
||||
}
|
||||
Set<Player> receivers = stream.collect(Collectors.toSet());
|
||||
|
||||
@@ -135,8 +163,16 @@ public class ChatListener implements Listener {
|
||||
for (Player pingPlayer : playersToPing) {
|
||||
pingPlayer.playSound(pingPlayer.getLocation(), Sound.BLOCK_NOTE_BLOCK_BASS, 1, 1);
|
||||
}
|
||||
chatLogHandler.addChatLog(uuid, ServerName.getServerName(), modifiableString.string(), false);
|
||||
ALogger.info(PlainTextComponentSerializer.plainText().serialize(input.asComponent()));
|
||||
chatLogHandler.addChatLog(uuid,
|
||||
ServerName.getServerName(),
|
||||
modifiableString.string(),
|
||||
ChatLogType.PUBLIC,
|
||||
null,
|
||||
null,
|
||||
input.asComponent(),
|
||||
false
|
||||
);
|
||||
ALogger.info(PlainTextComponentSerializer.plainText().serialize(inputComponent));
|
||||
}
|
||||
|
||||
private void pingPlayers(Set<Player> playersToPing, ModifiableString modifiableString, Player player) {
|
||||
@@ -152,10 +188,10 @@ public class ChatListener implements Listener {
|
||||
ChatUser onlinePlayerUser = ChatUserManager.getChatUser(onlinePlayer.getUniqueId());
|
||||
if (namePattern.matcher(modifiableString.string()).find()) {
|
||||
modifiableString.replace(TextReplacementConfig.builder()
|
||||
.once()
|
||||
.match(namePattern)
|
||||
.replacement(mention.append(onlinePlayerUser.getDisplayName()))
|
||||
.build());
|
||||
.once()
|
||||
.match(namePattern)
|
||||
.replacement(mention.append(onlinePlayerUser.getDisplayName()))
|
||||
.build());
|
||||
//TODO replace all instances of \name with just name but using the match result so the capitalization doesn't change
|
||||
// modifiableString.replace(TextReplacementConfig.builder()
|
||||
// .once()
|
||||
@@ -165,17 +201,21 @@ public class ChatListener implements Listener {
|
||||
// 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);
|
||||
}
|
||||
} else if (nickPattern.matcher(modifiableString.string()).find()) {
|
||||
modifiableString.replace(TextReplacementConfig.builder()
|
||||
.once()
|
||||
.match(nickPattern)
|
||||
.replacement(mention.append(onlinePlayerUser.getDisplayName()))
|
||||
.build());
|
||||
if (!ChatUserManager.getChatUser(onlinePlayer.getUniqueId()).getIgnoredPlayers().contains(player.getUniqueId())
|
||||
.once()
|
||||
.match(nickPattern)
|
||||
.replacement(mention.append(onlinePlayerUser.getDisplayName()))
|
||||
.build());
|
||||
if (!ChatUserManager.getChatUser(onlinePlayer.getUniqueId())
|
||||
.getIgnoredPlayers()
|
||||
.contains(player.getUniqueId())
|
||||
|| player.hasPermission("chat.ignorebypass")) {
|
||||
playersToPing.add(onlinePlayer);
|
||||
}
|
||||
@@ -192,7 +232,7 @@ public class ChatListener implements Listener {
|
||||
Placeholder.component("prefixall", user.getPrefixAll()),
|
||||
Placeholder.component("staffprefix", user.getStaffPrefix()),
|
||||
Placeholder.component("message", message)
|
||||
);
|
||||
);
|
||||
|
||||
return Utility.parseMiniMessage(Config.CHATFORMAT, placeholders);
|
||||
}
|
||||
|
||||
@@ -10,6 +10,8 @@ import com.alttd.chat.objects.Party;
|
||||
import com.alttd.chat.objects.PartyUser;
|
||||
import com.alttd.chat.objects.channels.Channel;
|
||||
import com.alttd.chat.objects.channels.CustomChannel;
|
||||
import com.alttd.chat.objects.chat_log.ChatLogHandler;
|
||||
import com.alttd.chat.objects.chat_log.ChatLogType;
|
||||
import com.alttd.chat.util.ALogger;
|
||||
import com.alttd.chat.util.ServerName;
|
||||
import com.alttd.chat.util.Utility;
|
||||
@@ -18,6 +20,7 @@ import com.google.common.io.ByteStreams;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.ComponentLike;
|
||||
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
|
||||
import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Sound;
|
||||
import org.bukkit.entity.Player;
|
||||
@@ -29,6 +32,12 @@ import java.util.UUID;
|
||||
|
||||
public class PluginMessage implements PluginMessageListener {
|
||||
|
||||
private final ChatLogHandler chatLogHandler;
|
||||
|
||||
public PluginMessage(ChatLogHandler chatLogHandler) {
|
||||
this.chatLogHandler = chatLogHandler;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPluginMessageReceived(String channel, @NotNull Player ignored, byte[] bytes) {
|
||||
if (!channel.equals(Config.MESSAGECHANNEL)) {
|
||||
@@ -48,13 +57,25 @@ public class PluginMessage implements PluginMessageListener {
|
||||
}
|
||||
ChatUser chatUser = ChatUserManager.getChatUser(uuid);
|
||||
if (isTargetNotIgnored(chatUser, targetuuid)) {
|
||||
player.sendMessage(GsonComponentSerializer.gson().deserialize(message));
|
||||
Component component = GsonComponentSerializer.gson().deserialize(message);
|
||||
player.sendMessage(component);
|
||||
player.playSound(player.getLocation(), Sound.BLOCK_NOTE_BLOCK_BASS, 1,
|
||||
1); // todo load this from config
|
||||
1
|
||||
); // todo load this from config
|
||||
ChatUser user = ChatUserManager.getChatUser(uuid);
|
||||
if (!user.getReplyContinueTarget().equalsIgnoreCase(target)) {
|
||||
user.setReplyTarget(target);
|
||||
}
|
||||
// Handled here since this is after the ignore check and is only send once
|
||||
chatLogHandler.addChatLog(uuid,
|
||||
ServerName.getServerName(),
|
||||
PlainTextComponentSerializer.plainText().serialize(component),
|
||||
ChatLogType.MSG,
|
||||
null,
|
||||
player.getUniqueId().toString(),
|
||||
component,
|
||||
false
|
||||
);
|
||||
}
|
||||
}
|
||||
case "privatemessageout" -> {
|
||||
@@ -69,9 +90,18 @@ public class PluginMessage implements PluginMessageListener {
|
||||
ChatUser chatUser = ChatUserManager.getChatUser(uuid);
|
||||
if (isTargetNotIgnored(chatUser, targetuuid)) {
|
||||
chatUser.setReplyTarget(target);
|
||||
player.sendMessage(GsonComponentSerializer.gson().deserialize(message));
|
||||
// ChatUser user = ChatUserManager.getChatUser(uuid);
|
||||
// user.setReplyTarget(target);
|
||||
Component component = GsonComponentSerializer.gson().deserialize(message);
|
||||
player.sendMessage(component);
|
||||
// Handled here since this is after the ignore check and is only send once
|
||||
chatLogHandler.addChatLog(uuid,
|
||||
ServerName.getServerName(),
|
||||
PlainTextComponentSerializer.plainText().serialize(component),
|
||||
ChatLogType.MSG,
|
||||
null,
|
||||
player.getUniqueId().toString(),
|
||||
component,
|
||||
false
|
||||
);
|
||||
}
|
||||
}
|
||||
case "globalchat" -> {
|
||||
@@ -82,10 +112,11 @@ public class PluginMessage implements PluginMessageListener {
|
||||
UUID uuid = UUID.fromString(in.readUTF());
|
||||
String message = in.readUTF();
|
||||
|
||||
Component component = GsonComponentSerializer.gson().deserialize(message);
|
||||
Bukkit.getOnlinePlayers().stream().filter(p -> p.hasPermission(Config.GCPERMISSION)).forEach(p -> {
|
||||
ChatUser chatUser = ChatUserManager.getChatUser(p.getUniqueId());
|
||||
if (isTargetNotIgnored(chatUser, uuid)) {
|
||||
p.sendMessage(GsonComponentSerializer.gson().deserialize(message));
|
||||
p.sendMessage(component);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -107,6 +138,7 @@ public class PluginMessage implements PluginMessageListener {
|
||||
}
|
||||
|
||||
chatChannel(in);
|
||||
//TODO [Stijn] [2026-07-19]: handle custom channels
|
||||
}
|
||||
case "tmppartyupdate" -> {
|
||||
int id = Integer.parseInt(in.readUTF());
|
||||
|
||||
@@ -35,3 +35,5 @@ pluginManagement {
|
||||
gradlePluginPortal()
|
||||
}
|
||||
}
|
||||
|
||||
include("web-api")
|
||||
@@ -5,6 +5,8 @@ plugins {
|
||||
|
||||
dependencies {
|
||||
implementation(project(":api")) // API
|
||||
compileOnly("org.projectlombok:lombok:1.18.46")
|
||||
annotationProcessor("org.projectlombok:lombok:1.18.46")
|
||||
compileOnly("com.velocitypowered:velocity-api:3.5.0-SNAPSHOT")
|
||||
annotationProcessor("com.velocitypowered:velocity-api:3.5.0-SNAPSHOT")
|
||||
implementation("mysql:mysql-connector-java:8.0.33") // mysql
|
||||
|
||||
@@ -2,20 +2,20 @@ package com.alttd.velocitychat;
|
||||
|
||||
import com.alttd.chat.ChatAPI;
|
||||
import com.alttd.chat.ChatImplementation;
|
||||
import com.alttd.chat.config.Config;
|
||||
import com.alttd.chat.database.DatabaseConnection;
|
||||
import com.alttd.chat.managers.ChatUserManager;
|
||||
import com.alttd.chat.managers.PartyManager;
|
||||
import com.alttd.chat.objects.ChatUser;
|
||||
import com.alttd.chat.objects.chat_log.ChatLogHandler;
|
||||
import com.alttd.chat.util.ALogger;
|
||||
import com.alttd.velocitychat.commands.*;
|
||||
import com.alttd.chat.config.Config;
|
||||
import com.alttd.chat.database.DatabaseConnection;
|
||||
import com.alttd.velocitychat.handlers.ChatHandler;
|
||||
import com.alttd.velocitychat.handlers.ServerHandler;
|
||||
import com.alttd.velocitychat.listeners.ChatListener;
|
||||
import com.alttd.velocitychat.listeners.LiteBansListener;
|
||||
import com.alttd.velocitychat.listeners.ProxyPlayerListener;
|
||||
import com.alttd.velocitychat.listeners.PluginMessageListener;
|
||||
import com.alttd.chat.util.ALogger;
|
||||
import com.alttd.velocitychat.listeners.ProxyPlayerListener;
|
||||
import com.google.common.io.ByteArrayDataOutput;
|
||||
import com.google.common.io.ByteStreams;
|
||||
import com.google.inject.Inject;
|
||||
@@ -36,7 +36,7 @@ import java.nio.file.Path;
|
||||
description = "A chat plugin for Altitude Minecraft Server",
|
||||
authors = {"destro174", "teri"},
|
||||
dependencies = {@Dependency(id = "luckperms"), @Dependency(id = "litebans"), @Dependency(id = "proxydiscordlink")}
|
||||
)
|
||||
)
|
||||
public class VelocityChat {
|
||||
|
||||
private static VelocityChat plugin;
|
||||
@@ -67,7 +67,8 @@ public class VelocityChat {
|
||||
PartyManager.initialize(); // load the parties from the db and add the previously loaded users to them
|
||||
|
||||
serverHandler = new ServerHandler();
|
||||
chatHandler = new ChatHandler();
|
||||
ChatLogHandler chatLogHandler = new ChatLogHandler(true);
|
||||
chatHandler = new ChatHandler(chatLogHandler);
|
||||
server.getEventManager().register(this, new ChatListener());
|
||||
server.getEventManager().register(this, new ProxyPlayerListener());
|
||||
new LiteBansListener().init(); // init the litebans api listeners
|
||||
@@ -89,7 +90,11 @@ public class VelocityChat {
|
||||
ByteArrayDataOutput buf = ByteStreams.newDataOutput();
|
||||
buf.writeUTF("reloadconfig");
|
||||
ALogger.info("Reloaded ChatPlugin proxy config.");
|
||||
getProxy().getAllServers().stream().forEach(registeredServer -> registeredServer.sendPluginMessage(getChannelIdentifier(), buf.toByteArray()));
|
||||
getProxy().getAllServers()
|
||||
.stream()
|
||||
.forEach(registeredServer -> registeredServer.sendPluginMessage(getChannelIdentifier(),
|
||||
buf.toByteArray()
|
||||
));
|
||||
}
|
||||
|
||||
public File getDataDirectory() {
|
||||
|
||||
@@ -6,6 +6,8 @@ import com.alttd.chat.managers.ChatUserManager;
|
||||
import com.alttd.chat.managers.PartyManager;
|
||||
import com.alttd.chat.managers.RegexManager;
|
||||
import com.alttd.chat.objects.*;
|
||||
import com.alttd.chat.objects.chat_log.ChatLogHandler;
|
||||
import com.alttd.chat.objects.chat_log.ChatLogType;
|
||||
import com.alttd.chat.util.ALogger;
|
||||
import com.alttd.chat.util.Utility;
|
||||
import com.alttd.velocitychat.VelocityChat;
|
||||
@@ -32,6 +34,12 @@ import java.util.UUID;
|
||||
|
||||
public class ChatHandler {
|
||||
|
||||
private final ChatLogHandler chatLogHandler;
|
||||
|
||||
public ChatHandler(ChatLogHandler chatLogHandler) {
|
||||
this.chatLogHandler = chatLogHandler;
|
||||
}
|
||||
|
||||
public void privateMessage(String sender, String target, String message) {
|
||||
UUID uuid = UUID.fromString(sender);
|
||||
ChatUser senderUser = ChatUserManager.getChatUser(uuid);
|
||||
@@ -54,15 +62,23 @@ public class ChatHandler {
|
||||
Placeholder.component("receiver", targetUser.getDisplayName()),
|
||||
Placeholder.unparsed("receivername", player2.getUsername()),
|
||||
Placeholder.component("message", GsonComponentSerializer.gson().deserialize(message)),
|
||||
Placeholder.unparsed("server", player.getCurrentServer().isPresent() ? player.getCurrentServer().get().getServerInfo().getName() : "Altitude"));
|
||||
Placeholder.unparsed("server",
|
||||
player.getCurrentServer().isPresent() ? player.getCurrentServer()
|
||||
.get()
|
||||
.getServerInfo()
|
||||
.getName() : "Altitude"
|
||||
)
|
||||
);
|
||||
|
||||
ServerConnection serverConnection;
|
||||
//Log handled on receiving server since it is only received on one server and that's where the ignore check happens
|
||||
if (player.getCurrentServer().isPresent() && player2.getCurrentServer().isPresent()) {
|
||||
// redirect to the sender
|
||||
serverConnection = player.getCurrentServer().get();
|
||||
Component component = Utility.parseMiniMessage(Config.MESSAGESENDER
|
||||
.replaceAll("<sendername>", player.getUsername())
|
||||
.replaceAll("<receivername>", player2.getUsername()), Placeholders).asComponent();
|
||||
.replaceAll("<sendername>", player.getUsername())
|
||||
.replaceAll("<receivername>", player2.getUsername()), Placeholders
|
||||
).asComponent();
|
||||
ByteArrayDataOutput buf = ByteStreams.newDataOutput();
|
||||
buf.writeUTF("privatemessageout");
|
||||
buf.writeUTF(player.getUniqueId().toString());
|
||||
@@ -74,8 +90,9 @@ public class ChatHandler {
|
||||
//redirect to the receiver
|
||||
serverConnection = player2.getCurrentServer().get();
|
||||
component = Utility.parseMiniMessage(Config.MESSAGERECIEVER
|
||||
.replaceAll("<sendername>", player.getUsername())
|
||||
.replaceAll("<receivername>", player2.getUsername()), Placeholders).asComponent();
|
||||
.replaceAll("<sendername>", player.getUsername())
|
||||
.replaceAll("<receivername>", player2.getUsername()), Placeholders
|
||||
).asComponent();
|
||||
buf = ByteStreams.newDataOutput();
|
||||
buf.writeUTF("privatemessagein");
|
||||
buf.writeUTF(player2.getUniqueId().toString());
|
||||
@@ -93,7 +110,7 @@ public class ChatHandler {
|
||||
Placeholder.parsed("displayname", Utility.getDisplayName(player.getUniqueId(), player.getUsername())),
|
||||
Placeholder.unparsed("target", (target.isEmpty() ? " tried to say: " : " -> " + target + ": ")),
|
||||
Placeholder.unparsed("input", input)
|
||||
);
|
||||
);
|
||||
ComponentLike blockedNotification = Utility.parseMiniMessage(Config.NOTIFICATIONFORMAT, Placeholders);
|
||||
|
||||
serverConnection.getServer().getPlayersConnected().forEach(pl -> {
|
||||
@@ -134,15 +151,15 @@ public class ChatHandler {
|
||||
}
|
||||
ComponentLike senderName = user.getDisplayName();
|
||||
|
||||
TagResolver Placeholders = TagResolver.resolver(
|
||||
TagResolver placeholders = TagResolver.resolver(
|
||||
Placeholder.component("sender", senderName),
|
||||
Placeholder.component("sendername", senderName),
|
||||
Placeholder.unparsed("partyname", party.getPartyName()),
|
||||
Placeholder.component("message", parseMessageContent(player, message)),
|
||||
Placeholder.unparsed("server", serverConnection.getServer().getServerInfo().getName())
|
||||
);
|
||||
);
|
||||
|
||||
Component partyMessage = Utility.parseMiniMessage(Config.PARTY_FORMAT, Placeholders).asComponent()
|
||||
Component partyMessage = Utility.parseMiniMessage(Config.PARTY_FORMAT, placeholders).asComponent()
|
||||
.replaceText(TextReplacementConfig.builder().once().matchLiteral("[i]").replacement(item).build());
|
||||
|
||||
ModifiableString modifiableString = new ModifiableString(partyMessage);
|
||||
@@ -155,7 +172,17 @@ public class ChatHandler {
|
||||
|
||||
sendPartyMessage(party, partyMessage, user.getIgnoredBy());
|
||||
|
||||
ComponentLike spyMessage = Utility.parseMiniMessage(Config.PARTY_SPY, Placeholders);
|
||||
chatLogHandler.addChatLog(uuid,
|
||||
serverConnection.getServer().getServerInfo().getName(),
|
||||
PlainTextComponentSerializer.plainText().serialize(partyMessage),
|
||||
ChatLogType.PARTY,
|
||||
String.valueOf(party.getPartyId()),
|
||||
null,
|
||||
partyMessage,
|
||||
false
|
||||
);
|
||||
|
||||
ComponentLike spyMessage = Utility.parseMiniMessage(Config.PARTY_SPY, placeholders);
|
||||
for (Player pl : serverConnection.getServer().getPlayersConnected()) {
|
||||
if (pl.hasPermission(Config.SPYPERMISSION) && !party.getPartyUsersUuid().contains(pl.getUniqueId())) {
|
||||
pl.sendMessage(spyMessage);
|
||||
@@ -171,6 +198,17 @@ public class ChatHandler {
|
||||
.stream()
|
||||
.filter(target -> target.hasPermission("command.chat.globaladminchat"))
|
||||
.forEach(target -> target.sendMessage(component));
|
||||
|
||||
chatLogHandler.addChatLog(
|
||||
new UUID(0, 0), //No origin uuid for GAC
|
||||
"GAC", //No server for GAC
|
||||
PlainTextComponentSerializer.plainText().serialize(component),
|
||||
ChatLogType.GAC,
|
||||
null,
|
||||
null,
|
||||
component,
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
public void globalAdminChat(CommandSource commandSource, String message) {
|
||||
@@ -182,13 +220,17 @@ public class ChatHandler {
|
||||
return;
|
||||
}
|
||||
senderName = user.getDisplayName();
|
||||
serverName = sender.getCurrentServer().isPresent() ? sender.getCurrentServer().get().getServerInfo().getName() : "Altitude";
|
||||
serverName = sender.getCurrentServer().isPresent() ? sender.getCurrentServer()
|
||||
.get()
|
||||
.getServerInfo()
|
||||
.getName() : "Altitude";
|
||||
}
|
||||
|
||||
TagResolver Placeholders = TagResolver.resolver(
|
||||
Placeholder.component("message", parseMessageContent(commandSource, message)),
|
||||
Placeholder.component("sender", senderName),
|
||||
Placeholder.unparsed("server", serverName));
|
||||
Placeholder.unparsed("server", serverName)
|
||||
);
|
||||
|
||||
ComponentLike component = Utility.parseMiniMessage(Config.GACFORMAT, Placeholders);
|
||||
|
||||
@@ -210,7 +252,8 @@ public class ChatHandler {
|
||||
if (optionalPlayer.isEmpty()) {
|
||||
targetUUID = ServerHandler.getPlayerUUID(recipient);
|
||||
if (targetUUID == null) {
|
||||
commandSource.sendMessage(Utility.parseMiniMessage("<red>A player with this name hasn't logged in recently.")); // TOOD load from config
|
||||
commandSource.sendMessage(Utility.parseMiniMessage(
|
||||
"<red>A player with this name hasn't logged in recently.")); // TOOD load from config
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
@@ -274,8 +317,10 @@ public class ChatHandler {
|
||||
Placeholder.component("sender", chatUser.getDisplayName()),
|
||||
Placeholder.component("message", Utility.parseMiniMessage(mail.getMessage())),
|
||||
Placeholder.unparsed("date", date.toString()),
|
||||
Placeholder.unparsed("time_ago", getTimeAgo(Duration.between(date.toInstant(), new Date().toInstant())))
|
||||
);
|
||||
Placeholder.unparsed("time_ago",
|
||||
getTimeAgo(Duration.between(date.toInstant(), new Date().toInstant()))
|
||||
)
|
||||
);
|
||||
ComponentLike mailMessage = Utility.parseMiniMessage(Config.mailBody, Placeholders);
|
||||
component = component.append(Component.newline()).append(mailMessage);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
plugins {
|
||||
java
|
||||
id("org.openapi.generator") version "7.12.0"
|
||||
}
|
||||
|
||||
group = "com.alttd.chat"
|
||||
version = "2.0.0-SNAPSHOT"
|
||||
|
||||
dependencies {
|
||||
implementation("io.swagger.core.v3:swagger-annotations:2.2.28")
|
||||
|
||||
implementation("com.squareup.okhttp3:okhttp:4.12.0")
|
||||
implementation("com.squareup.okhttp3:logging-interceptor:4.12.0")
|
||||
|
||||
implementation("com.google.code.gson:gson:2.12.1")
|
||||
implementation("io.gsonfire:gson-fire:1.9.0")
|
||||
|
||||
implementation("javax.annotation:javax.annotation-api:1.3.2")
|
||||
implementation("jakarta.annotation:jakarta.annotation-api:2.1.1")
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
main {
|
||||
java {
|
||||
srcDir("${projectDir}/build/generated-sources/client/src/main/java")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tasks.named<org.openapitools.generator.gradle.plugin.tasks.GenerateTask>("openApiGenerate") {
|
||||
generatorName.set("java")
|
||||
inputSpec.set("${projectDir}/src/main/resources/chat-api.yml")
|
||||
configFile.set("${projectDir}/src/main/resources/config_backend.json")
|
||||
outputDir.set("${projectDir}/build/generated-sources/client")
|
||||
|
||||
apiPackage.set("com.alttd.altitudeweb.api")
|
||||
modelPackage.set("com.alttd.altitudeweb.model")
|
||||
|
||||
modelNameSuffix.set("Dto")
|
||||
|
||||
additionalProperties.set(
|
||||
mapOf(
|
||||
"dateLibrary" to "java8",
|
||||
"library" to "okhttp-gson"
|
||||
)
|
||||
)
|
||||
|
||||
generateApiTests.set(false)
|
||||
generateApiDocumentation.set(false)
|
||||
generateModelTests.set(false)
|
||||
generateModelDocumentation.set(false)
|
||||
|
||||
generateAliasAsModel.set(true)
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
main {
|
||||
java {
|
||||
srcDir(layout.buildDirectory.dir("generated/openapi/src/main/java"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tasks.compileJava {
|
||||
dependsOn("openApiGenerate")
|
||||
}
|
||||
@@ -0,0 +1,144 @@
|
||||
openapi: 3.0.3
|
||||
|
||||
info:
|
||||
title: Minecraft Network API
|
||||
version: 1.0.0
|
||||
|
||||
servers:
|
||||
- url: http://localhost:8080/api
|
||||
|
||||
tags:
|
||||
- name: chat
|
||||
description: Data for displaying Chat messages to clients
|
||||
|
||||
paths:
|
||||
/chat/send/chat/message:
|
||||
post:
|
||||
tags:
|
||||
- chat
|
||||
summary: Sends one or more chat messages
|
||||
operationId: sendChatMessages
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
$ref: "#/components/schemas/ChatMessage"
|
||||
responses:
|
||||
"202":
|
||||
description: Accepted
|
||||
|
||||
/chat/send/servers/state:
|
||||
post:
|
||||
tags:
|
||||
- chat
|
||||
summary: Update server states
|
||||
operationId: updateServerStates
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/ServerState"
|
||||
responses:
|
||||
"202":
|
||||
description: Accepted
|
||||
|
||||
components:
|
||||
schemas:
|
||||
User:
|
||||
type: object
|
||||
required:
|
||||
- uuid
|
||||
- name
|
||||
- styledName
|
||||
# TODO [Stijn] [2026-07-19]: Add who they ignore and who they are ignored by
|
||||
|
||||
properties:
|
||||
uuid:
|
||||
type: string
|
||||
format: uuid
|
||||
name:
|
||||
type: string
|
||||
styledName:
|
||||
type: string
|
||||
|
||||
ChatMessage:
|
||||
type: object
|
||||
required:
|
||||
- uuid
|
||||
- message
|
||||
- server
|
||||
- type
|
||||
- timestamp
|
||||
- blocked
|
||||
properties:
|
||||
uuid:
|
||||
type: string
|
||||
format: uuid
|
||||
message:
|
||||
type: string
|
||||
server:
|
||||
type: string
|
||||
type:
|
||||
type: string
|
||||
enum:
|
||||
- PUBLIC
|
||||
- GLOBAL
|
||||
- PARTY
|
||||
- GAC
|
||||
- MSG
|
||||
- CUSTOM
|
||||
channel:
|
||||
type: string
|
||||
maxLength: 36
|
||||
receiver:
|
||||
type: string
|
||||
maxLength: 36
|
||||
timestamp:
|
||||
type: string
|
||||
format: date-time
|
||||
blocked:
|
||||
type: boolean
|
||||
|
||||
PrivateMessage:
|
||||
type: object
|
||||
required:
|
||||
- sender
|
||||
- receiver
|
||||
- message
|
||||
- senderServer
|
||||
- receiverServer
|
||||
properties:
|
||||
sender:
|
||||
type: string
|
||||
format: uuid
|
||||
receiver:
|
||||
type: string
|
||||
format: uuid
|
||||
message:
|
||||
type: string
|
||||
senderServer:
|
||||
type: string
|
||||
receiverServer:
|
||||
type: string
|
||||
|
||||
Server:
|
||||
type: object
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
players:
|
||||
type: array
|
||||
items:
|
||||
$ref: "#/components/schemas/User"
|
||||
|
||||
ServerState:
|
||||
type: object
|
||||
properties:
|
||||
servers:
|
||||
type: array
|
||||
items:
|
||||
$ref: "#/components/schemas/Server"
|
||||
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"library": "okhttp-gson",
|
||||
"hideGenerationTimestamp": true,
|
||||
"modelPackage": "com.alttd.altitudeweb.model",
|
||||
"apiPackage": "com.alttd.altitudeweb.api",
|
||||
"invokerPackage": "com.alttd.altitudeweb.invoker",
|
||||
"serializableModel": true,
|
||||
"openApiNullable": false,
|
||||
"useTags": true,
|
||||
"generateApis": true,
|
||||
"generateApiTests": false,
|
||||
"generateApiDocumentation": false,
|
||||
"generateModels": true,
|
||||
"generateModelTests": false,
|
||||
"generateSupportingFiles": true,
|
||||
"modelNameSuffix": "Dto",
|
||||
"generateTests": false,
|
||||
"dateLibrary": "java8",
|
||||
"enumUnknownDefaultCase": true,
|
||||
"disallowAdditionalPropertiesIfNotPresent": false,
|
||||
"useJakartaEe": true
|
||||
}
|
||||
Reference in New Issue
Block a user