diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..c65bcf4
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,115 @@
+# User-specific stuff
+.idea/
+
+*.iml
+*.ipr
+*.iws
+
+# IntelliJ
+out/
+
+# Compiled class file
+*.class
+
+# Log file
+*.log
+
+# BlueJ files
+*.ctxt
+
+# Package Files #
+*.jar
+*.war
+*.nar
+*.ear
+*.zip
+*.tar.gz
+*.rar
+
+# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
+hs_err_pid*
+
+*~
+
+# temporary files which can be created if a process still has a handle open of a deleted file
+.fuse_hidden*
+
+# KDE directory preferences
+.directory
+
+# Linux trash folder which might appear on any partition or disk
+.Trash-*
+
+# .nfs files are created when an open file is removed but is still being accessed
+.nfs*
+
+# General
+.DS_Store
+.AppleDouble
+.LSOverride
+
+# Icon must end with two \r
+Icon
+
+# Thumbnails
+._*
+
+# Files that might appear in the root of a volume
+.DocumentRevisions-V100
+.fseventsd
+.Spotlight-V100
+.TemporaryItems
+.Trashes
+.VolumeIcon.icns
+.com.apple.timemachine.donotpresent
+
+# Directories potentially created on remote AFP share
+.AppleDB
+.AppleDesktop
+Network Trash Folder
+Temporary Items
+.apdisk
+
+# Windows thumbnail cache files
+Thumbs.db
+Thumbs.db:encryptable
+ehthumbs.db
+ehthumbs_vista.db
+
+# Dump file
+*.stackdump
+
+# Folder config file
+[Dd]esktop.ini
+
+# Recycle Bin used on file shares
+$RECYCLE.BIN/
+
+# Windows Installer files
+*.cab
+*.msi
+*.msix
+*.msm
+*.msp
+
+# Windows shortcuts
+*.lnk
+
+target/
+
+pom.xml.tag
+pom.xml.releaseBackup
+pom.xml.versionsBackup
+pom.xml.next
+
+release.properties
+dependency-reduced-pom.xml
+buildNumber.properties
+.mvn/timing.properties
+.mvn/wrapper/maven-wrapper.jar
+.flattened-pom.xml
+
+# Common working directory
+run/
+
+.junie
diff --git a/.mvn/wrapper/maven-wrapper.properties b/.mvn/wrapper/maven-wrapper.properties
new file mode 100644
index 0000000..7c6b218
--- /dev/null
+++ b/.mvn/wrapper/maven-wrapper.properties
@@ -0,0 +1,3 @@
+wrapperVersion=3.3.4
+distributionType=only-script
+distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.6/apache-maven-3.9.6-bin.zip
diff --git a/api/pom.xml b/api/pom.xml
index 41f94d2..c314078 100644
--- a/api/pom.xml
+++ b/api/pom.xml
@@ -122,16 +122,6 @@
org.apache.maven.plugins
maven-compiler-plugin
- ${maven-compiler-plugin.version}
-
-
-
- org.projectlombok
- lombok
- ${lombok.version}
-
-
-
diff --git a/api/src/main/java/org/btuk/proxy/api/impl/BuildingsApiImpl.java b/api/src/main/java/org/btuk/proxy/api/impl/BuildingsApiImpl.java
index df80fea..362f123 100644
--- a/api/src/main/java/org/btuk/proxy/api/impl/BuildingsApiImpl.java
+++ b/api/src/main/java/org/btuk/proxy/api/impl/BuildingsApiImpl.java
@@ -1,5 +1,7 @@
package org.btuk.proxy.api.impl;
+import jakarta.inject.Inject;
+import jakarta.ws.rs.Path;
import jakarta.ws.rs.core.Response;
import org.btuk.proxy.api.BuildingsApi;
import org.btuk.proxy.api.model.Building;
@@ -17,17 +19,16 @@
import java.util.UUID;
import java.util.stream.Collectors;
+@Path("/buildings")
public class BuildingsApiImpl implements BuildingsApi {
private final GlobalSQL globalSQL;
+ @Inject
public BuildingsApiImpl(GlobalSQL globalSQL) {
this.globalSQL = globalSQL;
}
-
-
-
@Override
public Response getBuildingsByArea(Double minLat, Double maxLat, Double minLon, Double maxLon, UUID playerUuid) {
String playerUuidStr = playerUuid != null ? playerUuid.toString() : null;
diff --git a/api/src/main/java/org/btuk/proxy/api/impl/PlayerApiImpl.java b/api/src/main/java/org/btuk/proxy/api/impl/PlayerApiImpl.java
index a67946d..dcf0e2e 100644
--- a/api/src/main/java/org/btuk/proxy/api/impl/PlayerApiImpl.java
+++ b/api/src/main/java/org/btuk/proxy/api/impl/PlayerApiImpl.java
@@ -1,8 +1,10 @@
package org.btuk.proxy.api.impl;
+import jakarta.inject.Inject;
+import jakarta.ws.rs.Path;
import jakarta.ws.rs.core.Response;
-import net.bteuk.network.lib.dto.DirectMessage;
-import net.bteuk.network.lib.utils.ChatUtils;
+import org.btuk.network.lib.dto.DirectMessage;
+import org.btuk.network.lib.utils.ChatUtils;
import org.btuk.proxy.api.PlayerApi;
import org.btuk.proxy.api.model.Message;
import org.btuk.proxy.api.model.Player;
@@ -14,14 +16,15 @@
import java.util.UUID;
import java.util.stream.Collectors;
-import static net.bteuk.network.lib.enums.ChatChannels.GLOBAL;
+import static org.btuk.network.lib.enums.ChatChannels.GLOBAL;
import static org.btuk.proxy.core.utils.Constants.SERVER_SENDER;
-
+@Path("/player")
public class PlayerApiImpl implements PlayerApi {
private final GlobalSQL globalSQL;
private final ChatManager chatManager;
+ @Inject
public PlayerApiImpl(GlobalSQL globalSQL, ChatManager chatManager) {
this.globalSQL = globalSQL;this.chatManager = chatManager;
}
@@ -63,7 +66,7 @@ public Response sendPlayerMessage(String playerID, Message message){
try {
String messagePlainText = message.getMessage();
- DirectMessage m = new DirectMessage(GLOBAL.getChannelName(), playerID.toString(), SERVER_SENDER, ChatUtils.success(messagePlainText), true);
+ DirectMessage m = new DirectMessage(GLOBAL.getChannelName(), playerID, SERVER_SENDER, ChatUtils.success(messagePlainText), true);
chatManager.sendDirectMessage(m);
return Response.status(Response.Status.CREATED).build();
}catch (Exception e)
diff --git a/api/src/main/java/org/btuk/proxy/api/impl/StatusApiImpl.java b/api/src/main/java/org/btuk/proxy/api/impl/StatusApiImpl.java
index 5433870..6326ba6 100644
--- a/api/src/main/java/org/btuk/proxy/api/impl/StatusApiImpl.java
+++ b/api/src/main/java/org/btuk/proxy/api/impl/StatusApiImpl.java
@@ -1,9 +1,11 @@
package org.btuk.proxy.api.impl;
+import jakarta.ws.rs.Path;
import jakarta.ws.rs.core.Response;
import org.btuk.proxy.api.StatusApi;
import org.btuk.proxy.api.model.Status;
+@Path("/status")
public class StatusApiImpl implements StatusApi {
@Override
diff --git a/api/src/main/java/org/btuk/proxy/api/server/ProxyApi.java b/api/src/main/java/org/btuk/proxy/api/server/ProxyApi.java
index 6feadaa..5723b78 100644
--- a/api/src/main/java/org/btuk/proxy/api/server/ProxyApi.java
+++ b/api/src/main/java/org/btuk/proxy/api/server/ProxyApi.java
@@ -9,6 +9,7 @@
import org.glassfish.grizzly.http.server.HttpServer;
import org.glassfish.jersey.grizzly2.httpserver.GrizzlyHttpServerFactory;
+import org.glassfish.jersey.internal.inject.AbstractBinder;
import org.glassfish.jersey.server.ResourceConfig;
import java.net.URI;
@@ -43,10 +44,34 @@ public void start() {
String baseUri = "http://0.0.0.0:" + apiPort + "/api/";
- ResourceConfig rc = new ResourceConfig()
- .register(new StatusApiImpl())
- .register(new PlayerApiImpl(globalSQL,chatManager))
- .register(new BuildingsApiImpl(globalSQL));
+
+ ResourceConfig rc = new ResourceConfig();
+
+ // 1. Disable WADL warning
+ rc.property("jersey.config.server.wadl.disableWadl", true);
+
+ // 2. Bind SQL and ChatManager dependencies for injection
+ rc.register(new AbstractBinder() {
+ @Override
+ protected void configure() {
+ bind(globalSQL).to(GlobalSQL.class);
+ bind(chatManager).to(ChatManager.class);
+ }
+ });
+
+ // 3. Register the implementation CLASSES (or scan the package)
+ rc.register(StatusApiImpl.class);
+ rc.register(PlayerApiImpl.class);
+ rc.register(BuildingsApiImpl.class);
+
+// ResourceConfig rc = new ResourceConfig()
+// .property("jersey.config.server.wadl.disableWadl", true)
+// .packages("org.btuk.proxy.api.impl");
+
+// ResourceConfig rc = new ResourceConfig()
+// .register(new StatusApiImpl())
+// .register(new PlayerApiImpl(globalSQL,chatManager))
+// .register(new BuildingsApiImpl(globalSQL));
try {
server = GrizzlyHttpServerFactory.createHttpServer(URI.create(baseUri), rc);
diff --git a/api/src/main/resources/openapi.yaml b/api/src/main/resources/openapi.yaml
index f3c2dbd..3eb16fe 100644
--- a/api/src/main/resources/openapi.yaml
+++ b/api/src/main/resources/openapi.yaml
@@ -84,7 +84,7 @@ paths:
responses:
"201":
description: Message Added
- /players/online:
+ /player/online:
get:
tags:
- Player
diff --git a/app/pom.xml b/app/pom.xml
new file mode 100644
index 0000000..b24d3cf
--- /dev/null
+++ b/app/pom.xml
@@ -0,0 +1,96 @@
+
+
+ 4.0.0
+
+ org.btuk
+ Proxy
+ 1.13.0-SNAPSHOT
+
+
+ org.btuk.proxy
+ app
+ App
+
+
+ 21
+ 21
+ UTF-8
+
+
+
+
+ org.btuk.proxy
+ api
+
+
+ org.btuk.proxy
+ core
+
+
+ org.btuk.proxy
+ database
+
+
+
+ com.github.BuildtheUK
+ NetworkLib
+
+
+
+ org.projectlombok
+ lombok
+
+
+
+ org.apache.logging.log4j
+ log4j-core
+ provided
+
+
+ org.apache.logging.log4j
+ log4j-slf4j2-impl
+ provided
+
+
+ org.slf4j
+ jul-to-slf4j
+
+
+
+ net.dv8tion
+ JDA
+
+
+
+ net.kyori
+ adventure-text-serializer-plain
+ 4.16.0
+
+
+ net.kyori
+ adventure-text-minimessage
+ 4.16.0
+
+
+
+ org.yaml
+ snakeyaml
+
+
+
+ org.apache.commons
+ commons-lang3
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+
+
+
+
\ No newline at end of file
diff --git a/plugin/src/main/java/org/btuk/proxy/ProxyController.java b/app/src/main/java/org.btuk.proxy.app/ProxyController.java
similarity index 92%
rename from plugin/src/main/java/org/btuk/proxy/ProxyController.java
rename to app/src/main/java/org.btuk.proxy.app/ProxyController.java
index 698fe0e..b7e9aab 100644
--- a/plugin/src/main/java/org/btuk/proxy/ProxyController.java
+++ b/app/src/main/java/org.btuk.proxy.app/ProxyController.java
@@ -1,29 +1,12 @@
-package org.btuk.proxy;
+package org.btuk.proxy.app;
import lombok.Getter;
import lombok.extern.java.Log;
-import net.bteuk.network.lib.dto.OnlineUserRemove;
-
-import org.btuk.proxy.core.chat.automod.AutoMod;
-import org.btuk.proxy.database.DatabaseInit;
-import org.btuk.proxy.database.sql.GlobalSQL;
-import org.btuk.proxy.database.sql.PlotSQL;
-import org.btuk.proxy.database.sql.RegionSQL;
-
-import org.slf4j.bridge.SLF4JBridgeHandler;
-
-import javax.sql.DataSource;
-import java.io.File;
-import java.io.IOException;
-import java.sql.SQLException;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicInteger;
-import java.util.function.Consumer;
-
+import org.btuk.network.lib.dto.OnlineUserRemove;
import org.btuk.proxy.api.server.ProxyApi;
import org.btuk.proxy.core.chat.ChatHandler;
import org.btuk.proxy.core.chat.ChatManager;
+import org.btuk.proxy.core.chat.automod.AutoMod;
import org.btuk.proxy.core.config.Config;
import org.btuk.proxy.core.discord.Discord;
import org.btuk.proxy.core.discord.ReviewStatus;
@@ -38,9 +21,22 @@
import org.btuk.proxy.core.utils.Analytics;
import org.btuk.proxy.core.utils.Constants;
import org.btuk.proxy.core.utils.Moderation;
+import org.btuk.proxy.database.DatabaseInit;
+import org.btuk.proxy.database.sql.GlobalSQL;
+import org.btuk.proxy.database.sql.PlotSQL;
+import org.btuk.proxy.database.sql.RegionSQL;
+import org.slf4j.bridge.SLF4JBridgeHandler;
+
+import javax.sql.DataSource;
+import java.io.File;
+import java.io.IOException;
+import java.sql.SQLException;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.function.Consumer;
import static java.awt.Color.RED;
-import static org.btuk.proxy.core.utils.Constants.LEAVE_MESSAGE;
/**
* Controller of the core proxy functionality; can be enabled by the proxy or external plugins that want to use the proxy functions.
@@ -102,8 +98,8 @@ public ProxyController(File dataFolder) {
this.enabled = true;
}
-
- public void start(ChatHandler chatHandler, Scheduler scheduler, CoreServerManager coreServerManager, PlayerManager playerManager, TabManager tabManager, Consumer socketInitializer) throws IOException {
+ public void start(ChatHandler chatHandler, Scheduler scheduler, CoreServerManager coreServerManager, PlayerManager playerManager, TabManager tabManager,
+ Consumer socketInitializer) throws IOException {
if (!enabled) {
log.severe("Proxy is not enabled, see previous logs for errors.");
@@ -119,9 +115,10 @@ public void start(ChatHandler chatHandler, Scheduler scheduler, CoreServerManage
Moderation moderation = new Moderation(globalSQL);
AutoMod automod = new AutoMod(coreUserManager, new Config(dataFolder, AUTOMOD_CONFIG_NAME), moderation, discord, chatHandler, tabManager);
- ChatManager chatManager = new ChatManager(chatHandler, coreUserManager, analytics, globalSQL, moderation, automod);
+ ChatManager chatManager = new ChatManager(chatHandler, coreUserManager, analytics, globalSQL, moderation, automod, discord);
- this.userManager = new UserManager(coreUserManager, chatHandler, tabManager, globalSQL, plotSQL, regionSQL, coreServerManager, scheduler, chatManager, playerManager, analytics, discord, automod);
+ this.userManager = new UserManager(coreUserManager, chatHandler, tabManager, globalSQL, plotSQL, regionSQL, coreServerManager, scheduler, chatManager, playerManager,
+ analytics, discord, automod);
ServerManager serverManager = new ServerManager(coreServerManager, scheduler, globalSQL, chatHandler, tabManager, coreUserManager, userManager);
@@ -129,10 +126,10 @@ public void start(ChatHandler chatHandler, Scheduler scheduler, CoreServerManage
new ReviewStatus(config, globalSQL, plotSQL, regionSQL, discord, scheduler);
this.discord.addJDAEventListeners(chatManager, coreUserManager, tabManager, plotSQL);
- this.proxyApi = new ProxyApi(config.getBoolean("api.enabled"), config.getInt("api.port"), globalSQL,chatManager);
+ this.proxyApi = new ProxyApi(config.getBoolean("api.enabled"), config.getInt("api.port"), globalSQL, chatManager);
serverManager.initOnlineServers();
- socketInitializer.accept(new ProxySocketHandler(chatManager, discord, userManager, serverManager, tabManager));
+ socketInitializer.accept(new ProxySocketHandler(chatManager, discord, userManager, serverManager));
proxyApi.start();
@@ -151,7 +148,7 @@ public void stop() {
coreUserManager.runForEachOnline(user -> {
if (user.isOnline()) {
- discord.sendConnectEmbed(LEAVE_MESSAGE, user.getName(), user.getUuid(), user.getPlayerSkin(), RED, (reply) -> {
+ discord.sendConnectEmbed(Constants.LEAVE_MESSAGE, user.getName(), user.getUuid(), user.getPlayerSkin(), RED, (reply) -> {
users.decrementAndGet();
disconnectLatch.countDown();
});
@@ -172,7 +169,7 @@ public void stop() {
// Clear JDA listeners
if (discord.getJda() != null) {
- //Unregister listeners.
+ // Unregister listeners.
discord.getJda().getEventManager().getRegisteredListeners().forEach(listener -> discord.getJda().getEventManager().unregister(listener));
}
diff --git a/core/pom.xml b/core/pom.xml
index 9f00e77..76da412 100644
--- a/core/pom.xml
+++ b/core/pom.xml
@@ -26,7 +26,7 @@
- com.github.BTEUK
+ com.github.BuildtheUK
NetworkLib
@@ -75,6 +75,11 @@
org.apache.commons
commons-lang3
+
+ org.junit.jupiter
+ junit-jupiter
+ test
+
@@ -82,16 +87,6 @@
org.apache.maven.plugins
maven-compiler-plugin
- ${maven-compiler-plugin.version}
-
-
-
- org.projectlombok
- lombok
- ${lombok.version}
-
-
-
diff --git a/core/src/main/java/org/btuk/proxy/core/chat/ChatHandler.java b/core/src/main/java/org/btuk/proxy/core/chat/ChatHandler.java
index 8280fdf..434d042 100644
--- a/core/src/main/java/org/btuk/proxy/core/chat/ChatHandler.java
+++ b/core/src/main/java/org/btuk/proxy/core/chat/ChatHandler.java
@@ -1,6 +1,6 @@
package org.btuk.proxy.core.chat;
-import net.bteuk.network.lib.dto.AbstractTransferObject;
+import org.btuk.network.lib.dto.AbstractTransferObject;
import org.btuk.proxy.core.exceptions.ServerNotFoundException;
diff --git a/core/src/main/java/org/btuk/proxy/core/chat/ChatManager.java b/core/src/main/java/org/btuk/proxy/core/chat/ChatManager.java
index 8e99beb..fa64c5f 100644
--- a/core/src/main/java/org/btuk/proxy/core/chat/ChatManager.java
+++ b/core/src/main/java/org/btuk/proxy/core/chat/ChatManager.java
@@ -1,26 +1,25 @@
package org.btuk.proxy.core.chat;
-import net.bteuk.network.lib.dto.ChatMessage;
-import net.bteuk.network.lib.dto.DirectMessage;
-import net.bteuk.network.lib.dto.PrivateMessage;
-import net.bteuk.network.lib.dto.ReplyMessage;
-import net.bteuk.network.lib.utils.ChatUtils;
-
-import org.btuk.proxy.core.chat.automod.AutoMod;
-import org.btuk.proxy.database.sql.GlobalSQL;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
-
-import java.util.List;
-
+import org.btuk.network.lib.dto.ChatMessage;
+import org.btuk.network.lib.dto.DirectMessage;
+import org.btuk.network.lib.dto.PrivateMessage;
+import org.btuk.network.lib.dto.ReplyMessage;
+import org.btuk.network.lib.utils.ChatUtils;
+import org.btuk.proxy.core.chat.automod.AutoMod;
+import org.btuk.proxy.core.discord.Discord;
import org.btuk.proxy.core.user.CoreUserManager;
import org.btuk.proxy.core.user.User;
import org.btuk.proxy.core.utils.Analytics;
import org.btuk.proxy.core.utils.Moderation;
import org.btuk.proxy.core.utils.Time;
+import org.btuk.proxy.database.sql.GlobalSQL;
+
+import java.util.List;
-import static net.bteuk.network.lib.enums.ChatChannels.GLOBAL;
+import static org.btuk.network.lib.enums.ChatChannels.GLOBAL;
import static org.btuk.proxy.core.utils.Constants.DISCORD_SENDER;
import static org.btuk.proxy.core.utils.Constants.SERVER_SENDER;
@@ -41,17 +40,20 @@ public class ChatManager {
private final AutoMod autoMod;
+ private final Discord discord;
+
private static final List SERVER_USERS = List.of(new String[]{SERVER_SENDER, DISCORD_SENDER});
private static final String FOCUS_ENABLED_PRESET = "%s is in focus mode, unable to send message.";
- public ChatManager(ChatHandler chatHandler, CoreUserManager userManager, Analytics analytics, GlobalSQL globalSQL, Moderation moderation, AutoMod autoMod) {
+ public ChatManager(ChatHandler chatHandler, CoreUserManager userManager, Analytics analytics, GlobalSQL globalSQL, Moderation moderation, AutoMod autoMod, Discord discord) {
this.chatHandler = chatHandler;
this.userManager = userManager;
this.analytics = analytics;
this.globalSQL = globalSQL;
this.moderation = moderation;
this.autoMod = autoMod;
+ this.discord = discord;
}
/**
@@ -70,6 +72,10 @@ public void handle(ChatMessage chatMessage) {
if (player) {
analytics.addMessage(chatMessage.getSender(), Time.getDate(Time.currentTime()));
}
+ // Send the message to discord.
+ if (player) {
+ discord.handle(chatMessage);
+ }
}
/**
diff --git a/core/src/main/java/org/btuk/proxy/core/chat/automod/AutoMod.java b/core/src/main/java/org/btuk/proxy/core/chat/automod/AutoMod.java
index 00c9d28..2cbd378 100644
--- a/core/src/main/java/org/btuk/proxy/core/chat/automod/AutoMod.java
+++ b/core/src/main/java/org/btuk/proxy/core/chat/automod/AutoMod.java
@@ -1,16 +1,10 @@
package org.btuk.proxy.core.chat.automod;
import lombok.extern.java.Log;
-import net.bteuk.network.lib.dto.DirectMessage;
-import net.bteuk.network.lib.utils.ChatUtils;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer;
-
-import java.time.Duration;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-
+import org.btuk.network.lib.dto.DirectMessage;
+import org.btuk.network.lib.utils.ChatUtils;
import org.btuk.proxy.core.chat.ChatHandler;
import org.btuk.proxy.core.config.Config;
import org.btuk.proxy.core.discord.Discord;
@@ -20,7 +14,11 @@
import org.btuk.proxy.core.utils.Moderation;
import org.btuk.proxy.core.utils.Time;
-import static net.bteuk.network.lib.enums.ChatChannels.GLOBAL;
+import java.time.Duration;
+import java.util.Collections;
+import java.util.List;
+
+import static org.btuk.network.lib.enums.ChatChannels.GLOBAL;
import static org.btuk.proxy.core.utils.Constants.SERVER_SENDER;
/**
@@ -93,7 +91,7 @@ public boolean moderate(String sender, Component messageComponent) {
* @return true if the message should be blocked
*/
private boolean checkMessage(User user, String message) {
- Map candidateWords = AutoModRule.getCandidateWords(message);
+ List candidateWords = AutoModRule.getCandidateWords(message);
boolean blockMessage = false;
for (AutoModRule rule : autoModConfig.getRules()) {
blockMessage |= checkRule(rule, candidateWords, user, message);
@@ -123,7 +121,7 @@ private void checkUser(User user) {
}
}
- private boolean checkRule(AutoModRule rule, Map candidateWords, User user, String message) {
+ private boolean checkRule(AutoModRule rule, List candidateWords, User user, String message) {
List matches = rule.getMatches(candidateWords);
if (matches.isEmpty()) {
return false;
diff --git a/core/src/main/java/org/btuk/proxy/core/chat/automod/AutoModRule.java b/core/src/main/java/org/btuk/proxy/core/chat/automod/AutoModRule.java
index a69fcd5..3904f04 100644
--- a/core/src/main/java/org/btuk/proxy/core/chat/automod/AutoModRule.java
+++ b/core/src/main/java/org/btuk/proxy/core/chat/automod/AutoModRule.java
@@ -4,13 +4,13 @@
import java.text.Normalizer;
import java.time.Duration;
-import java.util.LinkedHashMap;
+import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
-import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
+import java.util.stream.Collectors;
public abstract class AutoModRule {
@@ -26,13 +26,29 @@ public abstract class AutoModRule {
@Getter
private final Duration duration;
+ private final int maxLength;
+
public AutoModRule(String id, List flaggedWords, Duration duration) {
+ int maxLength = 0;
this.id = id;
- this.flaggedWords = flaggedWords.stream()
- .map(AutoModRule::normalize)
- .filter(word -> !word.isBlank())
- .collect(java.util.stream.Collectors.toUnmodifiableSet());
+ java.util.Set normalizedSet = new java.util.HashSet<>();
+ for (String word : flaggedWords) {
+ String normalized = normalize(word);
+ List tokens = new ArrayList<>();
+ Matcher matcher = TOKEN_PATTERN.matcher(normalized);
+ while (matcher.find()) {
+ tokens.add(matcher.group());
+ }
+ if (tokens.isEmpty()) continue;
+
+ normalizedSet.add(String.join(" ", tokens));
+ String joined = String.join("", tokens);
+ maxLength = Math.max(maxLength, joined.length());
+ normalizedSet.add(joined);
+ }
+ this.flaggedWords = java.util.Collections.unmodifiableSet(normalizedSet);
this.duration = duration;
+ this.maxLength = maxLength;
}
public abstract boolean blockMessage();
@@ -40,58 +56,90 @@ public AutoModRule(String id, List flaggedWords, Duration duration) {
/**
* Matches words against flagged words.
*
- * @param candidateWords map of candidate words keyed by normalized value
+ * @param candidateWords list of candidate words in order
* @return list of matches
*/
- public List getMatches(Map candidateWords) {
- return candidateWords.values().stream()
- .filter(candidateWord -> flaggedWords.contains(candidateWord.normalized()))
- .flatMap(candidateWord -> candidateWord.originals().stream()
- .map(original -> new AutoModMatch(original, candidateWord.normalized())))
- .toList();
+ public List getMatches(List candidateWords) {
+ List matches = new ArrayList<>();
+ int n = candidateWords.size();
+ for (int i = 0; i < n; i++) {
+ // Check single word and phrases up to maxLength tokens.
+ for (int len = 1; len <= maxLength && i + len <= n; len++) {
+ List sub = candidateWords.subList(i, i + len);
+
+ // Try joining with spaces
+ String normalizedPhrase = sub.stream()
+ .map(CandidateWord::normalized)
+ .collect(Collectors.joining(" "));
+
+ if (flaggedWords.contains(normalizedPhrase)) {
+ String originalPhrase = sub.stream()
+ .map(CandidateWord::original)
+ .collect(Collectors.joining(" "));
+ matches.add(new AutoModMatch(originalPhrase, normalizedPhrase));
+ continue;
+ }
+
+ // Try joining without spaces to catch things like "b a d" if "bad" is flagged
+ String noSpacePhrase = sub.stream()
+ .map(CandidateWord::normalized)
+ .collect(Collectors.joining(""));
+ if (flaggedWords.contains(noSpacePhrase)) {
+ String originalPhrase = sub.stream()
+ .map(CandidateWord::original)
+ .collect(Collectors.joining(""));
+ matches.add(new AutoModMatch(originalPhrase, noSpacePhrase));
+ }
+ }
+ }
+ return matches;
}
/**
- * Gets a map of candidate words based on a message.
+ * Gets a list of candidate words based on a message.
*
* @param message the message to get candidates for
- * @return map of candidate words keyed by normalized value
+ * @return list of candidate words in order
*/
- public static LinkedHashMap getCandidateWords(String message) {
- LinkedHashMap candidates = new LinkedHashMap<>();
-
- Matcher tokenMatcher = TOKEN_PATTERN.matcher(message);
- while (tokenMatcher.find()) {
- String originalToken = tokenMatcher.group();
- String normalizedToken = normalize(originalToken);
-
- addCandidate(candidates, normalizedToken, originalToken);
- }
+ public static List getCandidateWords(String message) {
+ List candidates = new ArrayList<>();
Matcher chunkMatcher = NON_WHITESPACE_PATTERN.matcher(message);
while (chunkMatcher.find()) {
String originalChunk = chunkMatcher.group();
-
- // Plain alphanumeric words are already handled by TOKEN_PATTERN,
- // so only process chunks that contain punctuation/symbols.
- if (originalChunk.chars().allMatch(Character::isLetterOrDigit)) {
- continue;
- }
-
String normalizedChunk = NON_ALPHANUMERIC.matcher(normalize(originalChunk)).replaceAll("");
- addCandidate(candidates, normalizedChunk, originalChunk);
- }
+ if (normalizedChunk.isBlank()) continue;
- return candidates;
- }
+ // Try to see if this chunk contains multiple words
+ Matcher tokenMatcher = TOKEN_PATTERN.matcher(originalChunk);
+ List subTokens = new ArrayList<>();
+ while (tokenMatcher.find()) {
+ subTokens.add(tokenMatcher.group());
+ }
- private static void addCandidate(LinkedHashMap candidates, String normalized, String original) {
- if (normalized.isBlank() || original.isBlank()) {
- return;
+ if (subTokens.size() > 1) {
+ // If it contains multi-character tokens, it's likely multiple words (e.g., "bad-word")
+ if (subTokens.stream().anyMatch(t -> t.length() > 1)) {
+ for (String sub : subTokens) {
+ candidates.add(new CandidateWord(normalize(sub), sub));
+ }
+ // Also add the combined version if it's different from simple concatenation
+ String joinedSub = subTokens.stream().map(AutoModRule::normalize).collect(Collectors.joining(""));
+ if (!normalizedChunk.equals(joinedSub)) {
+ candidates.add(new CandidateWord(normalizedChunk, originalChunk));
+ }
+ } else {
+ // All single letters, likely a single word broken up (e.g., "b.a.d")
+ candidates.add(new CandidateWord(normalizedChunk, originalChunk));
+ }
+ } else {
+ // Single token or no sub-tokens (punctuation only)
+ candidates.add(new CandidateWord(normalizedChunk, originalChunk));
+ }
}
- candidates.computeIfAbsent(normalized, CandidateWord::new).addOriginal(original);
+ return candidates;
}
private static String normalize(String input) {
diff --git a/core/src/main/java/org/btuk/proxy/core/chat/automod/CandidateWord.java b/core/src/main/java/org/btuk/proxy/core/chat/automod/CandidateWord.java
index b57d434..8bb43e3 100644
--- a/core/src/main/java/org/btuk/proxy/core/chat/automod/CandidateWord.java
+++ b/core/src/main/java/org/btuk/proxy/core/chat/automod/CandidateWord.java
@@ -1,17 +1,4 @@
package org.btuk.proxy.core.chat.automod;
-import java.util.ArrayList;
-import java.util.LinkedHashSet;
-import java.util.List;
-import java.util.Set;
-
-public record CandidateWord(String normalized, List originals) {
-
- public CandidateWord(String normalized) {
- this(normalized, new ArrayList<>());
- }
-
- public void addOriginal(String original) {
- originals.add(original);
- }
+public record CandidateWord(String normalized, String original) {
}
\ No newline at end of file
diff --git a/core/src/main/java/org/btuk/proxy/core/discord/BotChatListener.java b/core/src/main/java/org/btuk/proxy/core/discord/BotChatListener.java
index 87945af..03bbc68 100644
--- a/core/src/main/java/org/btuk/proxy/core/discord/BotChatListener.java
+++ b/core/src/main/java/org/btuk/proxy/core/discord/BotChatListener.java
@@ -1,16 +1,15 @@
package org.btuk.proxy.core.discord;
import lombok.extern.java.Log;
-import net.bteuk.network.lib.dto.DiscordLinking;
import net.dv8tion.jda.api.entities.channel.ChannelType;
import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
import net.dv8tion.jda.api.hooks.ListenerAdapter;
import org.apache.commons.lang3.StringUtils;
+import org.btuk.network.lib.dto.DiscordLinking;
+import org.btuk.proxy.core.chat.ChatHandler;
import java.util.List;
-import org.btuk.proxy.core.chat.ChatHandler;
-
@Log
public class BotChatListener extends ListenerAdapter {
diff --git a/core/src/main/java/org/btuk/proxy/core/discord/Discord.java b/core/src/main/java/org/btuk/proxy/core/discord/Discord.java
index a435367..afcda52 100644
--- a/core/src/main/java/org/btuk/proxy/core/discord/Discord.java
+++ b/core/src/main/java/org/btuk/proxy/core/discord/Discord.java
@@ -3,20 +3,15 @@
import lombok.Getter;
import lombok.Setter;
import lombok.extern.java.Log;
-import net.bteuk.network.lib.dto.ChatMessage;
-import net.bteuk.network.lib.dto.DiscordDirectMessage;
-import net.bteuk.network.lib.dto.DiscordEmbed;
-import net.bteuk.network.lib.dto.DiscordLinking;
-import net.bteuk.network.lib.dto.DiscordRole;
-
-import org.btuk.proxy.core.chat.automod.AutoModMatch;
-import org.btuk.proxy.core.user.User;
-import org.btuk.proxy.database.sql.GlobalSQL;
-import org.btuk.proxy.database.sql.PlotSQL;
import net.dv8tion.jda.api.EmbedBuilder;
import net.dv8tion.jda.api.JDA;
import net.dv8tion.jda.api.JDABuilder;
-import net.dv8tion.jda.api.entities.*;
+import net.dv8tion.jda.api.entities.Activity;
+import net.dv8tion.jda.api.entities.Member;
+import net.dv8tion.jda.api.entities.Message;
+import net.dv8tion.jda.api.entities.MessageEmbed;
+import net.dv8tion.jda.api.entities.Role;
+import net.dv8tion.jda.api.entities.UserSnowflake;
import net.dv8tion.jda.api.entities.channel.concrete.TextChannel;
import net.dv8tion.jda.api.requests.GatewayIntent;
import net.dv8tion.jda.api.utils.ChunkingFilter;
@@ -28,6 +23,22 @@
import net.kyori.adventure.text.format.TextDecoration;
import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer;
import org.apache.commons.lang3.time.DurationFormatUtils;
+import org.btuk.network.lib.dto.ChatMessage;
+import org.btuk.network.lib.dto.DiscordDirectMessage;
+import org.btuk.network.lib.dto.DiscordEmbed;
+import org.btuk.network.lib.dto.DiscordLinking;
+import org.btuk.network.lib.dto.DiscordRole;
+import org.btuk.proxy.core.chat.ChatHandler;
+import org.btuk.proxy.core.chat.ChatManager;
+import org.btuk.proxy.core.chat.automod.AutoModMatch;
+import org.btuk.proxy.core.config.Config;
+import org.btuk.proxy.core.discord.command.CommandManager;
+import org.btuk.proxy.core.scheduler.Scheduler;
+import org.btuk.proxy.core.tab.TabManager;
+import org.btuk.proxy.core.user.CoreUserManager;
+import org.btuk.proxy.core.user.User;
+import org.btuk.proxy.database.sql.GlobalSQL;
+import org.btuk.proxy.database.sql.PlotSQL;
import java.awt.Color;
import java.nio.charset.StandardCharsets;
@@ -39,14 +50,6 @@
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
-import org.btuk.proxy.core.chat.ChatHandler;
-import org.btuk.proxy.core.chat.ChatManager;
-import org.btuk.proxy.core.config.Config;
-import org.btuk.proxy.core.discord.command.CommandManager;
-import org.btuk.proxy.core.scheduler.Scheduler;
-import org.btuk.proxy.core.tab.TabManager;
-import org.btuk.proxy.core.user.CoreUserManager;
-
@Log
public class Discord {
@@ -116,7 +119,7 @@ public Discord(Config config, GlobalSQL globalSQL, ChatHandler chatHandler, Sche
this.moderatorChat = jda.getTextChannelById(moderatorChannel);
//Load all members into cache.
- chat.getGuild().loadMembers().onSuccess(members -> {
+ chat.getGuild().loadMembers().onSuccess(_ -> {
log.info("Loaded all discord members into cache");
//Enable role syncing.
@@ -132,7 +135,7 @@ public void addJDAEventListeners(ChatManager chatManager, CoreUserManager coreUs
jda.addEventListener(new DiscordChatListener(this, chatManager, chatChannelId, staffChannelId));
jda.addEventListener(new BotChatListener(chatHandler, linking));
- CommandManager commandManager = new CommandManager(coreUserManager, tabManager, globalSQL, plotSQL);
+ CommandManager commandManager = new CommandManager(coreUserManager, tabManager, globalSQL, plotSQL, config);
jda.addEventListener(commandManager);
jda.getGuilds().forEach(commandManager::registerCommands);
}
@@ -338,7 +341,7 @@ public void addRole(long userId, long role_id, boolean sync) {
if (!member.getRoles().contains(role)) {
// If successful, resync if enabled.
chat.getGuild().addRoleToMember(member, role).queue(
- (user) -> {
+ _ -> {
if (sync && hasRoles != null && giveRoles != null) {
syncRoles();
}
@@ -368,7 +371,7 @@ public void removeRole(long userId, long role_id, boolean sync) {
// If the member does not have the role, add it.
if (member.getRoles().contains(role)) {
chat.getGuild().removeRoleFromMember(member, role).queue(
- (user) -> {
+ _ -> {
if (sync && hasRoles != null && giveRoles != null) {
syncRoles();
}
diff --git a/core/src/main/java/org/btuk/proxy/core/discord/DiscordChatListener.java b/core/src/main/java/org/btuk/proxy/core/discord/DiscordChatListener.java
index 8e075e1..c3673d2 100644
--- a/core/src/main/java/org/btuk/proxy/core/discord/DiscordChatListener.java
+++ b/core/src/main/java/org/btuk/proxy/core/discord/DiscordChatListener.java
@@ -1,9 +1,6 @@
package org.btuk.proxy.core.discord;
import lombok.extern.java.Log;
-import net.bteuk.network.lib.dto.ChatMessage;
-import net.bteuk.network.lib.enums.ChatChannels;
-import net.bteuk.network.lib.utils.ChatUtils;
import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
import net.dv8tion.jda.api.hooks.ListenerAdapter;
import net.kyori.adventure.text.Component;
@@ -11,7 +8,9 @@
import net.kyori.adventure.text.format.TextColor;
import net.kyori.adventure.text.format.TextDecoration;
import org.apache.commons.lang3.StringUtils;
-
+import org.btuk.network.lib.dto.ChatMessage;
+import org.btuk.network.lib.enums.ChatChannels;
+import org.btuk.network.lib.utils.ChatUtils;
import org.btuk.proxy.core.chat.ChatManager;
import static org.btuk.proxy.core.utils.Constants.DISCORD_SENDER;
diff --git a/core/src/main/java/org/btuk/proxy/core/discord/command/CommandManager.java b/core/src/main/java/org/btuk/proxy/core/discord/command/CommandManager.java
index 54c1fb5..fccf6c1 100644
--- a/core/src/main/java/org/btuk/proxy/core/discord/command/CommandManager.java
+++ b/core/src/main/java/org/btuk/proxy/core/discord/command/CommandManager.java
@@ -1,8 +1,5 @@
package org.btuk.proxy.core.discord.command;
-import org.btuk.proxy.database.sql.GlobalSQL;
-import org.btuk.proxy.database.sql.PlotSQL;
-
import lombok.extern.java.Log;
import net.dv8tion.jda.api.entities.Guild;
import net.dv8tion.jda.api.events.guild.GuildJoinEvent;
@@ -14,14 +11,16 @@
import net.dv8tion.jda.api.interactions.commands.build.CommandData;
import net.dv8tion.jda.api.interactions.commands.build.Commands;
import net.dv8tion.jda.api.interactions.commands.build.OptionData;
+import org.btuk.proxy.core.config.Config;
+import org.btuk.proxy.core.tab.TabManager;
+import org.btuk.proxy.core.user.CoreUserManager;
+import org.btuk.proxy.database.sql.GlobalSQL;
+import org.btuk.proxy.database.sql.PlotSQL;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.List;
-import org.btuk.proxy.core.tab.TabManager;
-import org.btuk.proxy.core.user.CoreUserManager;
-
/**
* Manages all Discord commands.
* Each command is stored in a map so when a command interaction is run it can be routed accordingly.
@@ -39,11 +38,14 @@ public class CommandManager extends ListenerAdapter {
private final PlotSQL plotSQL;
- public CommandManager(CoreUserManager userManager, TabManager tabManager, GlobalSQL globalSQL, PlotSQL plotSQL) {
+ private final Config config;
+
+ public CommandManager(CoreUserManager userManager, TabManager tabManager, GlobalSQL globalSQL, PlotSQL plotSQL, Config config) {
this.userManager = userManager;
this.tabManager = tabManager;
this.globalSQL = globalSQL;
this.plotSQL = plotSQL;
+ this.config = config;
commands = new ArrayList<>();
}
@@ -97,7 +99,17 @@ public void registerCommands(Guild guild) {
//Create commands.
commands.add(new Playerlist(userManager, tabManager, "playerlist", "List all online players on the Minecraft server."));
- //commands.add(new Map("map", "Sends a link to the UK progress map.")); // The progress map is no longer available.
+ String progressMap = config.getString("progress_map");
+ if (progressMap != null && !progressMap.isBlank()) {
+ commands.add(new Map("map", "Sends a link to the UK progress map.", progressMap));
+ commands.add(new Map("progress", "Sends a link to the UK progress map.", progressMap));
+ commands.add(new Map("progressmap", "Sends a link to the UK progress map.", progressMap));
+ }
+
+ String websiteLink = config.getString("website");
+ if (websiteLink != null && !websiteLink.isBlank()) {
+ commands.add(new Website("website", "Sends a link of the website", websiteLink));
+ }
commands.add(new ClaimedPlots(globalSQL, plotSQL, "claimedplots", "List all plots that are currently claimed.", playerOption));
commands.add(new SubmittedPlots(globalSQL, plotSQL, "submittedplots", "List all plots that are currently submitted.", playerOption));
diff --git a/core/src/main/java/org/btuk/proxy/core/discord/command/Map.java b/core/src/main/java/org/btuk/proxy/core/discord/command/Map.java
index 9d23928..7c0d58a 100644
--- a/core/src/main/java/org/btuk/proxy/core/discord/command/Map.java
+++ b/core/src/main/java/org/btuk/proxy/core/discord/command/Map.java
@@ -1,29 +1,27 @@
-//package org.btuk.proxy.core.discord.command;
-//
-//import org.btuk.proxy.Proxy;
-//import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
-//import net.dv8tion.jda.api.requests.restaction.interactions.ReplyCallbackAction;
-//
-//public class Map extends AbstractCommand {
-//
-// /**
-// * Constructor, saved the name and description of the command.
-// * Also registers the command in Discord.
-// * @param name Name of the command
-// * @param description Description of the command
-// */
-// public Map(String name, String description) {
-// super(name, description);
-// }
-//
-// @Override
-// public void onCommand(SlashCommandInteractionEvent event) {
-//
-// String playerListMessage = Proxy.getInstance().getConfig().getString("progress_map");
-//
-// ReplyCallbackAction reply = event.reply(playerListMessage);
-// reply = reply.setEphemeral(true);
-// reply.queue();
-//
-// }
-//}
\ No newline at end of file
+package org.btuk.proxy.core.discord.command;
+
+import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
+import net.dv8tion.jda.api.requests.restaction.interactions.ReplyCallbackAction;
+
+public class Map extends AbstractCommand {
+
+ private final String link;
+
+ /**
+ * Constructor, saved the name and description of the command.
+ * Also registers the command in Discord.
+ * @param name Name of the command
+ * @param description Description of the command
+ */
+ public Map(String name, String description, String link) {
+ super(name, description);
+ this.link = link;
+ }
+
+ @Override
+ public void onCommand(SlashCommandInteractionEvent event) {
+ ReplyCallbackAction reply = event.reply(link);
+ reply = reply.setEphemeral(true);
+ reply.queue();
+ }
+}
\ No newline at end of file
diff --git a/core/src/main/java/org/btuk/proxy/core/discord/command/Playerlist.java b/core/src/main/java/org/btuk/proxy/core/discord/command/Playerlist.java
index e1eef47..2004a8f 100644
--- a/core/src/main/java/org/btuk/proxy/core/discord/command/Playerlist.java
+++ b/core/src/main/java/org/btuk/proxy/core/discord/command/Playerlist.java
@@ -1,20 +1,19 @@
package org.btuk.proxy.core.discord.command;
-import net.bteuk.network.lib.dto.OnlineUser;
-import net.bteuk.network.lib.dto.TabPlayer;
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
import net.dv8tion.jda.api.requests.restaction.interactions.ReplyCallbackAction;
import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer;
+import org.btuk.network.lib.dto.OnlineUser;
+import org.btuk.network.lib.dto.TabPlayer;
+import org.btuk.proxy.core.tab.TabManager;
+import org.btuk.proxy.core.user.CoreUserManager;
+import org.btuk.proxy.core.user.User;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Optional;
import java.util.Set;
-import org.btuk.proxy.core.tab.TabManager;
-import org.btuk.proxy.core.user.CoreUserManager;
-import org.btuk.proxy.core.user.User;
-
public class Playerlist extends AbstractCommand {
private final CoreUserManager userManager;
diff --git a/core/src/main/java/org/btuk/proxy/core/discord/command/Website.java b/core/src/main/java/org/btuk/proxy/core/discord/command/Website.java
new file mode 100644
index 0000000..098552f
--- /dev/null
+++ b/core/src/main/java/org/btuk/proxy/core/discord/command/Website.java
@@ -0,0 +1,27 @@
+package org.btuk.proxy.core.discord.command;
+
+import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
+import net.dv8tion.jda.api.requests.restaction.interactions.ReplyCallbackAction;
+
+public class Website extends AbstractCommand {
+
+ private final String link;
+
+ /**
+ * Constructor, saved the name and description of the command.
+ * Also registers the command in Discord.
+ * @param name Name of the command
+ * @param description Description of the command
+ */
+ public Website(String name, String description, String link) {
+ super(name, description);
+ this.link = link;
+ }
+
+ @Override
+ public void onCommand(SlashCommandInteractionEvent event) {
+ ReplyCallbackAction reply = event.reply(link);
+ reply = reply.setEphemeral(true);
+ reply.queue();
+ }
+}
\ No newline at end of file
diff --git a/core/src/main/java/org/btuk/proxy/core/server/ServerManager.java b/core/src/main/java/org/btuk/proxy/core/server/ServerManager.java
index e072d55..00986e6 100644
--- a/core/src/main/java/org/btuk/proxy/core/server/ServerManager.java
+++ b/core/src/main/java/org/btuk/proxy/core/server/ServerManager.java
@@ -1,18 +1,11 @@
package org.btuk.proxy.core.server;
import lombok.extern.java.Log;
-import net.bteuk.network.lib.dto.OnlineUserRemove;
-import net.bteuk.network.lib.dto.OnlineUsersReply;
-import net.bteuk.network.lib.dto.ServerShutdown;
-import net.bteuk.network.lib.dto.ServerStartup;
-import org.btuk.proxy.database.sql.GlobalSQL;
-
-import java.util.List;
-import java.util.Optional;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.TimeUnit;
+import org.btuk.network.lib.dto.OnlineUserRemove;
+import org.btuk.network.lib.dto.OnlineUsersReply;
+import org.btuk.network.lib.dto.ServerShutdown;
+import org.btuk.network.lib.dto.ServerStartup;
import org.btuk.proxy.core.chat.ChatHandler;
import org.btuk.proxy.core.scheduler.Scheduler;
import org.btuk.proxy.core.tab.TabManager;
@@ -20,12 +13,18 @@
import org.btuk.proxy.core.user.User;
import org.btuk.proxy.core.user.UserManager;
import org.btuk.proxy.core.utils.Time;
+import org.btuk.proxy.database.sql.GlobalSQL;
+
+import java.util.List;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
@Log
public class ServerManager {
private final CoreServerManager coreServerManager;
-
+ private final Scheduler scheduler;
private final GlobalSQL globalSQL;
private final ChatHandler chatHandler;
@@ -40,6 +39,7 @@ public class ServerManager {
public ServerManager(CoreServerManager coreServerManager, Scheduler scheduler, GlobalSQL globalSQL, ChatHandler chatHandler, TabManager tabManager, CoreUserManager coreUserManager, UserManager userManager) {
this.coreServerManager = coreServerManager;
+ this.scheduler = scheduler;
this.globalSQL = globalSQL;
this.chatHandler = chatHandler;
this.tabManager = tabManager;
@@ -58,30 +58,30 @@ public void initOnlineServers() {
}
public void addServer(ServerStartup serverStartup) {
- // It is possible the server is already set to online, this probably means it crashed,
- // first clear all players that are 'connected' to this server and remove them.
- Optional optionalServer = coreServerManager.getServers().stream().filter(server -> server.getName().equals(serverStartup.getServerName())).findFirst();
- optionalServer.ifPresent(this::removeServerDueToTimeout);
+ String serverName = serverStartup.getServerName();
+ // It is possible the server was already set to online, this probably means it crashed.
+ // Even if the server is not currently tracked, there might be 'ghost' players.
+ cleanupServer(serverName);
try {
- Server server = coreServerManager.createServer(serverStartup.getServerName());
+ Server server = coreServerManager.createServer(serverName);
threadExecutor.submit(() -> addServerIfOnline(server));
} catch (RuntimeException e) {
- log.warning("Unable to add server " + serverStartup.getServerName() + ", it can not be found.");
+ log.warning("Unable to add server " + serverName + ", it can not be found.");
}
}
public void removeServer(ServerShutdown serverShutdown) {
- Optional optionalServer = coreServerManager.getServers().stream().filter(server -> server.getName().equals(serverShutdown.getServerName())).findFirst();
- optionalServer.ifPresent(coreServerManager::removeServer);
-
- // Set the server offline in the database.
- globalSQL.update("UPDATE server_data SET online=0 WHERE name='" + serverShutdown.getServerName() + "';");
+ cleanupServer(serverShutdown.getServerName());
}
private void addServerIfOnline(Server server) {
+ addServerIfOnline(server, 0);
+ }
+
+ private void addServerIfOnline(Server server, int attempt) {
// Skip if the server is already added.
- if (coreServerManager.getServers().stream().anyMatch(server::equals)) {
+ if (coreServerManager.getServers().stream().anyMatch(s -> s.getName().equals(server.getName()))) {
return;
}
if (server.canPing()) {
@@ -95,34 +95,48 @@ private void addServerIfOnline(Server server) {
tabManager.sendAddTeam();
} else {
// The server is not online.
- log.warning(String.format("Server " + server.getName() + " is not online."));
+ if (attempt < 30) {
+ scheduler.createDelayedTask(() -> threadExecutor.submit(() -> addServerIfOnline(server, attempt + 1)), 1, TimeUnit.SECONDS);
+ } else {
+ log.warning(String.format("Server " + server.getName() + " is not online."));
+ }
}
}
private void pingServers() {
coreServerManager.getServers().forEach(server -> threadExecutor.submit(() -> updatePing(server)));
- // If any server has a ping of more than 120 seconds, set the server to offline and remove all online players that were connected to the server.
+ // If any server has a ping of more than 60 seconds, set the server to offline and remove all online players that were connected to the server.
// This probably means the server crashed.
- List offlineServers = coreServerManager.getServers().stream().filter(server -> server.getLastPing() < Time.currentTime() - 1000 * 120).toList();
+ List offlineServers = coreServerManager.getServers().stream().filter(server -> server.getLastPing() < Time.currentTime() - 1000 * 60).toList();
offlineServers.forEach(this::removeServerDueToTimeout);
}
- private void removeServerDueToTimeout(Server server) {
+ private void cleanupServer(String serverName) {
// Set the server offline in the database.
- globalSQL.update("UPDATE server_data SET online=0 WHERE name='" + server.getName() + "';");
+ globalSQL.update("UPDATE server_data SET online=0 WHERE name='" + serverName + "';");
- // Remove all users connected to this server,
+ // Remove all users connected to this server
// and also send a message to all other online servers to remove these users from their list.
- List offlineServerUsers = coreUserManager.getUsersOnServer(server.getName());
- offlineServerUsers.forEach(user -> {
- OnlineUserRemove onlineUserRemove = new OnlineUserRemove(user.getUuid());
- chatHandler.handle(onlineUserRemove);
- userManager.disconnectUser(user);
- }
- );
+ // Delay this by a second so the switch server events have time to be processed.
+ scheduler.createDelayedTask(() -> {
+ List offlineServerUsers = coreUserManager.getUsersOnServer(serverName);
+ offlineServerUsers.forEach(user -> {
+ if (user.getSwitchServer() != null && user.getSwitchServer().getFromServer().equals(serverName)) {
+ log.info("User " + user.getName() + " is switching servers on shutdown.");
+ } else {
+ OnlineUserRemove onlineUserRemove = new OnlineUserRemove(user.getUuid());
+ chatHandler.handle(onlineUserRemove);
+ userManager.disconnectUser(user);
+ }
+ });
+ }, 1, TimeUnit.SECONDS);
+
+ // Remove server from the list if it exists.
+ coreServerManager.getServer(serverName).ifPresent(coreServerManager::removeServer);
+ }
- // Remove server from the list.
- coreServerManager.removeServer(server);
+ private void removeServerDueToTimeout(Server server) {
+ cleanupServer(server.getName());
}
private void updatePing(Server server) {
diff --git a/core/src/main/java/org/btuk/proxy/core/socket/ProxySocketHandler.java b/core/src/main/java/org/btuk/proxy/core/socket/ProxySocketHandler.java
index c59fe66..0324333 100644
--- a/core/src/main/java/org/btuk/proxy/core/socket/ProxySocketHandler.java
+++ b/core/src/main/java/org/btuk/proxy/core/socket/ProxySocketHandler.java
@@ -1,13 +1,30 @@
package org.btuk.proxy.core.socket;
import lombok.extern.java.Log;
-import net.bteuk.network.lib.dto.*;
-import net.bteuk.network.lib.socket.SocketHandler;
-
+import org.btuk.network.lib.dto.AbstractTransferObject;
+import org.btuk.network.lib.dto.ChatMessage;
+import org.btuk.network.lib.dto.DirectMessage;
+import org.btuk.network.lib.dto.DiscordDirectMessage;
+import org.btuk.network.lib.dto.DiscordEmbed;
+import org.btuk.network.lib.dto.DiscordLinking;
+import org.btuk.network.lib.dto.DiscordRole;
+import org.btuk.network.lib.dto.FocusEvent;
+import org.btuk.network.lib.dto.ModerationEvent;
+import org.btuk.network.lib.dto.MuteEvent;
+import org.btuk.network.lib.dto.PlotMessage;
+import org.btuk.network.lib.dto.PrivateMessage;
+import org.btuk.network.lib.dto.ReplyMessage;
+import org.btuk.network.lib.dto.ServerShutdown;
+import org.btuk.network.lib.dto.ServerStartup;
+import org.btuk.network.lib.dto.SwitchServerEvent;
+import org.btuk.network.lib.dto.TeleportEvent;
+import org.btuk.network.lib.dto.UserConnectRequest;
+import org.btuk.network.lib.dto.UserDisconnect;
+import org.btuk.network.lib.dto.UserUpdate;
+import org.btuk.network.lib.socket.SocketHandler;
import org.btuk.proxy.core.chat.ChatManager;
import org.btuk.proxy.core.discord.Discord;
import org.btuk.proxy.core.server.ServerManager;
-import org.btuk.proxy.core.tab.TabManager;
import org.btuk.proxy.core.user.UserManager;
@Log
@@ -17,14 +34,12 @@ public class ProxySocketHandler implements SocketHandler {
private final Discord discord;
private final UserManager userManager;
private final ServerManager serverManager;
- private final TabManager tabManager;
- public ProxySocketHandler(ChatManager chatManager, Discord discord, UserManager userManager, ServerManager serverManager, TabManager tabManager) {
+ public ProxySocketHandler(ChatManager chatManager, Discord discord, UserManager userManager, ServerManager serverManager) {
this.chatManager = chatManager;
this.discord = discord;
this.userManager = userManager;
this.serverManager = serverManager;
- this.tabManager = tabManager;
}
@Override
@@ -33,7 +48,6 @@ public synchronized AbstractTransferObject handle(AbstractTransferObject abstrac
switch (abstractTransferObject) {
case ChatMessage chatMessage -> {
chatManager.handle(chatMessage);
- discord.handle(chatMessage);
}
case DirectMessage directMessage -> chatManager.handle(directMessage);
case PrivateMessage privateMessage -> chatManager.handle(privateMessage);
diff --git a/core/src/main/java/org/btuk/proxy/core/tab/AbstractTabManager.java b/core/src/main/java/org/btuk/proxy/core/tab/AbstractTabManager.java
index 125ff8e..d1ab730 100644
--- a/core/src/main/java/org/btuk/proxy/core/tab/AbstractTabManager.java
+++ b/core/src/main/java/org/btuk/proxy/core/tab/AbstractTabManager.java
@@ -1,14 +1,20 @@
package org.btuk.proxy.core.tab;
import lombok.Getter;
-import net.bteuk.network.lib.dto.AddTeamEvent;
-import net.bteuk.network.lib.dto.TabPlayer;
-import net.bteuk.network.lib.utils.ChatUtils;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;
import net.kyori.adventure.text.format.Style;
import net.kyori.adventure.text.format.TextDecoration;
import net.kyori.adventure.text.minimessage.MiniMessage;
+import org.btuk.network.lib.dto.AddTeamEvent;
+import org.btuk.network.lib.dto.TabPlayer;
+import org.btuk.network.lib.utils.ChatUtils;
+import org.btuk.proxy.core.chat.ChatHandler;
+import org.btuk.proxy.core.config.Config;
+import org.btuk.proxy.core.player.Player;
+import org.btuk.proxy.core.scheduler.Scheduler;
+import org.btuk.proxy.core.user.CoreUserManager;
+import org.btuk.proxy.core.user.User;
import org.jetbrains.annotations.Nullable;
import java.util.HashSet;
@@ -17,13 +23,6 @@
import java.util.Set;
import java.util.concurrent.TimeUnit;
-import org.btuk.proxy.core.chat.ChatHandler;
-import org.btuk.proxy.core.config.Config;
-import org.btuk.proxy.core.player.Player;
-import org.btuk.proxy.core.scheduler.Scheduler;
-import org.btuk.proxy.core.user.CoreUserManager;
-import org.btuk.proxy.core.user.User;
-
public abstract class AbstractTabManager implements TabManager {
private final Config config;
diff --git a/core/src/main/java/org/btuk/proxy/core/tab/TabManager.java b/core/src/main/java/org/btuk/proxy/core/tab/TabManager.java
index c50ef3a..b552bb6 100644
--- a/core/src/main/java/org/btuk/proxy/core/tab/TabManager.java
+++ b/core/src/main/java/org/btuk/proxy/core/tab/TabManager.java
@@ -1,11 +1,10 @@
package org.btuk.proxy.core.tab;
-import net.bteuk.network.lib.dto.TabPlayer;
+import org.btuk.network.lib.dto.TabPlayer;
+import org.btuk.proxy.core.user.User;
import java.util.Optional;
-import org.btuk.proxy.core.user.User;
-
public interface TabManager {
void updatePlayerInTablistOfPlayer(User user, User userToUpdate);
diff --git a/core/src/main/java/org/btuk/proxy/core/user/CoreUserManager.java b/core/src/main/java/org/btuk/proxy/core/user/CoreUserManager.java
index 1145525..b8b13c2 100644
--- a/core/src/main/java/org/btuk/proxy/core/user/CoreUserManager.java
+++ b/core/src/main/java/org/btuk/proxy/core/user/CoreUserManager.java
@@ -1,6 +1,6 @@
package org.btuk.proxy.core.user;
-import net.bteuk.network.lib.dto.OnlineUser;
+import org.btuk.network.lib.dto.OnlineUser;
import java.util.ArrayList;
import java.util.Collections;
diff --git a/core/src/main/java/org/btuk/proxy/core/user/User.java b/core/src/main/java/org/btuk/proxy/core/user/User.java
index 7b39b29..eb3fa63 100644
--- a/core/src/main/java/org/btuk/proxy/core/user/User.java
+++ b/core/src/main/java/org/btuk/proxy/core/user/User.java
@@ -5,30 +5,37 @@
import lombok.Getter;
import lombok.Setter;
import lombok.extern.java.Log;
-import net.bteuk.network.lib.dto.DirectMessage;
-import net.bteuk.network.lib.dto.TeleportEvent;
-import net.bteuk.network.lib.dto.UserConnectReply;
-import net.bteuk.network.lib.dto.UserConnectRequest;
-import net.bteuk.network.lib.enums.ChatChannels;
-import net.bteuk.network.lib.enums.TeleportRequestType;
-import net.bteuk.network.lib.utils.ChatUtils;
-
-import org.btuk.proxy.core.exceptions.ServerNotFoundException;
-import org.btuk.proxy.core.utils.TeleportRequest;
-
+import net.kyori.adventure.text.Component;
+import net.kyori.adventure.text.format.NamedTextColor;
+import net.kyori.adventure.text.format.Style;
+import net.kyori.adventure.text.format.TextDecoration;
+import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
+import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer;
+import org.btuk.network.lib.dto.DirectMessage;
+import org.btuk.network.lib.dto.TeleportEvent;
+import org.btuk.network.lib.dto.UserConnectReply;
+import org.btuk.network.lib.dto.UserConnectRequest;
+import org.btuk.network.lib.enums.ChatChannels;
+import org.btuk.network.lib.enums.TeleportRequestType;
+import org.btuk.network.lib.utils.ChatUtils;
+import org.btuk.proxy.core.chat.ChatHandler;
import org.btuk.proxy.core.chat.automod.AutoMod;
import org.btuk.proxy.core.chat.automod.AutoModFlag;
import org.btuk.proxy.core.chat.automod.AutoModFlagRule;
import org.btuk.proxy.core.chat.automod.AutoModMatch;
import org.btuk.proxy.core.chat.automod.AutoModRule;
+import org.btuk.proxy.core.exceptions.ServerNotFoundException;
+import org.btuk.proxy.core.player.Player;
+import org.btuk.proxy.core.scheduler.ScheduledTask;
+import org.btuk.proxy.core.scheduler.Scheduler;
+import org.btuk.proxy.core.scheduler.TaskStatus;
+import org.btuk.proxy.core.tab.TabManager;
+import org.btuk.proxy.core.utils.Analytics;
+import org.btuk.proxy.core.utils.SwitchServer;
+import org.btuk.proxy.core.utils.TeleportRequest;
+import org.btuk.proxy.core.utils.Time;
import org.btuk.proxy.database.dto.AutoModFlagDTO;
import org.btuk.proxy.database.sql.GlobalSQL;
-import net.kyori.adventure.text.Component;
-import net.kyori.adventure.text.format.NamedTextColor;
-import net.kyori.adventure.text.format.Style;
-import net.kyori.adventure.text.format.TextDecoration;
-import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
-import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer;
import java.io.IOException;
import java.net.HttpURLConnection;
@@ -47,16 +54,6 @@
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
-import org.btuk.proxy.core.chat.ChatHandler;
-import org.btuk.proxy.core.player.Player;
-import org.btuk.proxy.core.scheduler.ScheduledTask;
-import org.btuk.proxy.core.scheduler.Scheduler;
-import org.btuk.proxy.core.scheduler.TaskStatus;
-import org.btuk.proxy.core.tab.TabManager;
-import org.btuk.proxy.core.utils.Analytics;
-import org.btuk.proxy.core.utils.SwitchServer;
-import org.btuk.proxy.core.utils.Time;
-
import static org.btuk.proxy.core.utils.Constants.SERVER_SENDER;
/**
@@ -135,10 +132,6 @@ public class User {
@Getter
private boolean focusEnabled;
- @Getter
- @Setter
- private boolean blockNextDisconnect = false;
-
@Getter
@Setter
private int previousPlotSubmissionCount = 0;
@@ -243,6 +236,10 @@ public void reconnect() {
online = true;
// Can't be afk on reconnect.
afk = false;
+ cancelDisconnectTask();
+ }
+
+ public void cancelDisconnectTask() {
if (disconnectTask != null && disconnectTask.getStatus() == TaskStatus.SCHEDULED) {
disconnectTask.cancel();
}
@@ -253,10 +250,7 @@ public void reconnect() {
* Delete the user instance.
*/
public void delete() {
- // If the disconnectTask is running cancel.
- if (disconnectTask != null && disconnectTask.getStatus() == TaskStatus.SCHEDULED) {
- disconnectTask.cancel();
- }
+ cancelDisconnectTask();
}
public void mute(User user) {
diff --git a/core/src/main/java/org/btuk/proxy/core/user/UserManager.java b/core/src/main/java/org/btuk/proxy/core/user/UserManager.java
index 4f8c9ae..a2ac078 100644
--- a/core/src/main/java/org/btuk/proxy/core/user/UserManager.java
+++ b/core/src/main/java/org/btuk/proxy/core/user/UserManager.java
@@ -2,37 +2,55 @@
import lombok.Getter;
import lombok.extern.java.Log;
-import net.bteuk.network.lib.dto.*;
-import net.bteuk.network.lib.enums.ChatChannels;
-import net.bteuk.network.lib.enums.ModerationAction;
-import net.bteuk.network.lib.enums.TeleportRequestType;
-import net.bteuk.network.lib.utils.ChatUtils;
-import org.btuk.proxy.database.sql.GlobalSQL;
-import org.btuk.proxy.database.sql.PlotSQL;
-import org.btuk.proxy.database.sql.RegionSQL;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;
-
-import java.awt.Color;
-import java.util.*;
-import java.util.concurrent.TimeUnit;
-
-import org.btuk.proxy.core.chat.automod.AutoMod;
-import org.btuk.proxy.core.discord.Discord;
-import org.btuk.proxy.core.tab.TabManager;
+import org.btuk.network.lib.dto.ChatMessage;
+import org.btuk.network.lib.dto.DirectMessage;
+import org.btuk.network.lib.dto.FocusEvent;
+import org.btuk.network.lib.dto.ModerationEvent;
+import org.btuk.network.lib.dto.MuteEvent;
+import org.btuk.network.lib.dto.OnlineUser;
+import org.btuk.network.lib.dto.OnlineUserAdd;
+import org.btuk.network.lib.dto.OnlineUserRemove;
+import org.btuk.network.lib.dto.PlotMessage;
+import org.btuk.network.lib.dto.SwitchServerEvent;
+import org.btuk.network.lib.dto.TeleportEvent;
+import org.btuk.network.lib.dto.UserConnectReply;
+import org.btuk.network.lib.dto.UserConnectRequest;
+import org.btuk.network.lib.dto.UserDisconnect;
+import org.btuk.network.lib.dto.UserRemove;
+import org.btuk.network.lib.dto.UserUpdate;
+import org.btuk.network.lib.enums.ChatChannels;
+import org.btuk.network.lib.enums.ModerationAction;
+import org.btuk.network.lib.enums.TeleportRequestType;
+import org.btuk.network.lib.utils.ChatUtils;
import org.btuk.proxy.core.chat.ChatHandler;
import org.btuk.proxy.core.chat.ChatManager;
+import org.btuk.proxy.core.chat.automod.AutoMod;
+import org.btuk.proxy.core.discord.Discord;
import org.btuk.proxy.core.exceptions.ErrorMessage;
import org.btuk.proxy.core.exceptions.ServerNotFoundException;
import org.btuk.proxy.core.player.PlayerManager;
import org.btuk.proxy.core.scheduler.Scheduler;
import org.btuk.proxy.core.server.CoreServerManager;
+import org.btuk.proxy.core.tab.TabManager;
import org.btuk.proxy.core.utils.Analytics;
import org.btuk.proxy.core.utils.SwitchServer;
import org.btuk.proxy.core.utils.Time;
+import org.btuk.proxy.database.sql.GlobalSQL;
+import org.btuk.proxy.database.sql.PlotSQL;
+import org.btuk.proxy.database.sql.RegionSQL;
-import static net.bteuk.network.lib.enums.ChatChannels.GLOBAL;
-import static org.btuk.proxy.core.utils.Constants.*;
+import java.awt.Color;
+import java.util.Optional;
+import java.util.concurrent.TimeUnit;
+
+import static org.btuk.network.lib.enums.ChatChannels.GLOBAL;
+import static org.btuk.proxy.core.utils.Constants.JOIN_MESSAGE;
+import static org.btuk.proxy.core.utils.Constants.LEAVE_MESSAGE;
+import static org.btuk.proxy.core.utils.Constants.RECONNECT_MESSAGE;
+import static org.btuk.proxy.core.utils.Constants.SERVER_SENDER;
+import static org.btuk.proxy.core.utils.Constants.WELCOME_MESSAGE;
/**
* Class to manage the users on the network.
@@ -113,9 +131,9 @@ public void handleUserDisconnect(UserDisconnect disconnect) {
return;
}
- if (user.isBlockNextDisconnect()) {
- log.warning("User has already reconnected, cancelling disconnect.");
- user.setBlockNextDisconnect(false);
+ // If the player is not on the server they disconnected from, it implies they switched server.
+ if (!user.getServer().equals(disconnect.getServer())) {
+ log.warning("User disconnect received but they are on a different server, cancelling disconnect.");
return;
}
@@ -271,11 +289,8 @@ public User addUser(UserConnectRequest request) {
switchServer.cancelTimeout();
user.setSwitchServer(null);
+ user.cancelDisconnectTask();
} else {
- // If the user is still online, quickly cancel the disconnect event.
- if (user.isOnline()) {
- user.setBlockNextDisconnect(true);
- }
// Cancel disconnect task.
user.reconnect();
diff --git a/core/src/main/java/org/btuk/proxy/core/utils/SwitchServer.java b/core/src/main/java/org/btuk/proxy/core/utils/SwitchServer.java
index 20049d3..176ba56 100644
--- a/core/src/main/java/org/btuk/proxy/core/utils/SwitchServer.java
+++ b/core/src/main/java/org/btuk/proxy/core/utils/SwitchServer.java
@@ -29,6 +29,7 @@ public class SwitchServer {
private final User user;
+ @Getter
private final String fromServer;
@Getter
diff --git a/core/src/main/resources/proxy-config.yml b/core/src/main/resources/proxy-config.yml
index ad24a34..0350500 100644
--- a/core/src/main/resources/proxy-config.yml
+++ b/core/src/main/resources/proxy-config.yml
@@ -1,5 +1,5 @@
#Config version (do not update)
-version: "1.12.0-SNAPSHOT"
+version: "1.13.0-SNAPSHOT"
#Bot token
token: "insert token here"
@@ -86,4 +86,7 @@ tab:
footer: "\nServer Info: /help\nMore Info: /discord"
#Discord user activity playing status (your server name or IP)
-DiscordPlaying: "server.net"
\ No newline at end of file
+DiscordPlaying: "server.net"
+
+progress_map: "https://progress.buildtheuk.org"
+website: "https://btuk.org"
\ No newline at end of file
diff --git a/core/src/test/java/org/btuk/proxy/core/chat/automod/AutoModRuleTest.java b/core/src/test/java/org/btuk/proxy/core/chat/automod/AutoModRuleTest.java
new file mode 100644
index 0000000..beaa868
--- /dev/null
+++ b/core/src/test/java/org/btuk/proxy/core/chat/automod/AutoModRuleTest.java
@@ -0,0 +1,59 @@
+package org.btuk.proxy.core.chat.automod;
+
+import org.junit.jupiter.api.Test;
+
+import java.time.Duration;
+import java.util.List;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+class AutoModRuleTest {
+
+ @Test
+ void testTooBadMatch() {
+ AutoModRule rule = new AutoModFlagRule("test", List.of("too bad"), 1, Duration.ZERO, true);
+ List candidates = AutoModRule.getCandidateWords("this is too bad");
+ List matches = rule.getMatches(candidates);
+ assertFalse(matches.isEmpty(), "Should match 'too bad'");
+ assertEquals("too bad", matches.getFirst().flaggedWord());
+ assertEquals("too bad", matches.getFirst().messageWord());
+ }
+
+ @Test
+ void testTooBadLeetspeakMatch() {
+ AutoModRule rule = new AutoModFlagRule("test", List.of("too bad"), 1, Duration.ZERO, true);
+ List candidates = AutoModRule.getCandidateWords("this is t00 b.a.d");
+ List matches = rule.getMatches(candidates);
+ assertFalse(matches.isEmpty(), "Should match 't00 b.a.d' against 'too bad'");
+ assertEquals("too bad", matches.getFirst().flaggedWord());
+ }
+
+ @Test
+ void testPunctuationInFlaggedWord() {
+ // Test case where flagged word has punctuation
+ AutoModRule rule = new AutoModFlagRule("test", List.of("bad-word"), 1, Duration.ZERO, true);
+ List candidates = AutoModRule.getCandidateWords("you are a bad-word");
+ List matches = rule.getMatches(candidates);
+
+ assertFalse(matches.isEmpty(), "Should match 'bad-word' even if flagged as 'bad-word'");
+ assertTrue(matches.stream().anyMatch(m -> m.flaggedWord().equals("badword") || m.flaggedWord().equals("bad word")));
+ }
+
+ @Test
+ void testDoubleSpaceInMessage() {
+ AutoModRule rule = new AutoModFlagRule("test", List.of("too bad"), 1, Duration.ZERO, true);
+ List candidates = AutoModRule.getCandidateWords("this is too bad");
+ List matches = rule.getMatches(candidates);
+ assertFalse(matches.isEmpty(), "Should match 'too bad' (double space) against 'too bad'");
+ }
+
+ @Test
+ void testMixedPunctuationAndLeetspeak() {
+ AutoModRule rule = new AutoModFlagRule("test", List.of("bad word"), 1, Duration.ZERO, true);
+ List candidates = AutoModRule.getCandidateWords("you are b.a.d-w.0.r.d");
+ List matches = rule.getMatches(candidates);
+ assertFalse(matches.isEmpty(), "Should match 'b.a.d-w.0.r.d' against 'bad word'");
+ }
+}
diff --git a/database/pom.xml b/database/pom.xml
index 7ef8e1d..e73de01 100644
--- a/database/pom.xml
+++ b/database/pom.xml
@@ -13,7 +13,7 @@
- com.github.BTEUK
+ com.github.BuildtheUK
NetworkLib
@@ -42,16 +42,6 @@
org.apache.maven.plugins
maven-compiler-plugin
- ${maven-compiler-plugin.version}
-
-
-
- org.projectlombok
- lombok
- ${lombok.version}
-
-
-
diff --git a/database/src/main/java/org/btuk/proxy/database/sql/PlotSQL.java b/database/src/main/java/org/btuk/proxy/database/sql/PlotSQL.java
index 2274dbd..a277f92 100644
--- a/database/src/main/java/org/btuk/proxy/database/sql/PlotSQL.java
+++ b/database/src/main/java/org/btuk/proxy/database/sql/PlotSQL.java
@@ -1,8 +1,8 @@
package org.btuk.proxy.database.sql;
import lombok.extern.java.Log;
-import net.bteuk.network.lib.enums.PlotDifficulties;
-import net.bteuk.network.lib.utils.Reviewing;
+import org.btuk.network.lib.enums.PlotDifficulties;
+import org.btuk.network.lib.utils.Reviewing;
import org.btuk.proxy.database.sql.migration.AcceptData;
import org.btuk.proxy.database.sql.migration.DenyData;
import org.btuk.proxy.database.sql.migration.PlotSubmissions;
diff --git a/jitpack.yml b/jitpack.yml
index 13ceb6c..18cdc8e 100644
--- a/jitpack.yml
+++ b/jitpack.yml
@@ -1,4 +1,4 @@
jdk:
- openjdk21
install:
- - mvn install -Dmaven.javadoc.skip=true -DskipTests -pl :database,:core -am
\ No newline at end of file
+ - ./mvnw install -Dmaven.javadoc.skip=true -DskipTests -pl :database,:core,:app -am
\ No newline at end of file
diff --git a/mvnw b/mvnw
new file mode 100755
index 0000000..bd8896b
--- /dev/null
+++ b/mvnw
@@ -0,0 +1,295 @@
+#!/bin/sh
+# ----------------------------------------------------------------------------
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+# ----------------------------------------------------------------------------
+
+# ----------------------------------------------------------------------------
+# Apache Maven Wrapper startup batch script, version 3.3.4
+#
+# Optional ENV vars
+# -----------------
+# JAVA_HOME - location of a JDK home dir, required when download maven via java source
+# MVNW_REPOURL - repo url base for downloading maven distribution
+# MVNW_USERNAME/MVNW_PASSWORD - user and password for downloading maven
+# MVNW_VERBOSE - true: enable verbose log; debug: trace the mvnw script; others: silence the output
+# ----------------------------------------------------------------------------
+
+set -euf
+[ "${MVNW_VERBOSE-}" != debug ] || set -x
+
+# OS specific support.
+native_path() { printf %s\\n "$1"; }
+case "$(uname)" in
+CYGWIN* | MINGW*)
+ [ -z "${JAVA_HOME-}" ] || JAVA_HOME="$(cygpath --unix "$JAVA_HOME")"
+ native_path() { cygpath --path --windows "$1"; }
+ ;;
+esac
+
+# set JAVACMD and JAVACCMD
+set_java_home() {
+ # For Cygwin and MinGW, ensure paths are in Unix format before anything is touched
+ if [ -n "${JAVA_HOME-}" ]; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ]; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ JAVACCMD="$JAVA_HOME/jre/sh/javac"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ JAVACCMD="$JAVA_HOME/bin/javac"
+
+ if [ ! -x "$JAVACMD" ] || [ ! -x "$JAVACCMD" ]; then
+ echo "The JAVA_HOME environment variable is not defined correctly, so mvnw cannot run." >&2
+ echo "JAVA_HOME is set to \"$JAVA_HOME\", but \"\$JAVA_HOME/bin/java\" or \"\$JAVA_HOME/bin/javac\" does not exist." >&2
+ return 1
+ fi
+ fi
+ else
+ JAVACMD="$(
+ 'set' +e
+ 'unset' -f command 2>/dev/null
+ 'command' -v java
+ )" || :
+ JAVACCMD="$(
+ 'set' +e
+ 'unset' -f command 2>/dev/null
+ 'command' -v javac
+ )" || :
+
+ if [ ! -x "${JAVACMD-}" ] || [ ! -x "${JAVACCMD-}" ]; then
+ echo "The java/javac command does not exist in PATH nor is JAVA_HOME set, so mvnw cannot run." >&2
+ return 1
+ fi
+ fi
+}
+
+# hash string like Java String::hashCode
+hash_string() {
+ str="${1:-}" h=0
+ while [ -n "$str" ]; do
+ char="${str%"${str#?}"}"
+ h=$(((h * 31 + $(LC_CTYPE=C printf %d "'$char")) % 4294967296))
+ str="${str#?}"
+ done
+ printf %x\\n $h
+}
+
+verbose() { :; }
+[ "${MVNW_VERBOSE-}" != true ] || verbose() { printf %s\\n "${1-}"; }
+
+die() {
+ printf %s\\n "$1" >&2
+ exit 1
+}
+
+trim() {
+ # MWRAPPER-139:
+ # Trims trailing and leading whitespace, carriage returns, tabs, and linefeeds.
+ # Needed for removing poorly interpreted newline sequences when running in more
+ # exotic environments such as mingw bash on Windows.
+ printf "%s" "${1}" | tr -d '[:space:]'
+}
+
+scriptDir="$(dirname "$0")"
+scriptName="$(basename "$0")"
+
+# parse distributionUrl and optional distributionSha256Sum, requires .mvn/wrapper/maven-wrapper.properties
+while IFS="=" read -r key value; do
+ case "${key-}" in
+ distributionUrl) distributionUrl=$(trim "${value-}") ;;
+ distributionSha256Sum) distributionSha256Sum=$(trim "${value-}") ;;
+ esac
+done <"$scriptDir/.mvn/wrapper/maven-wrapper.properties"
+[ -n "${distributionUrl-}" ] || die "cannot read distributionUrl property in $scriptDir/.mvn/wrapper/maven-wrapper.properties"
+
+case "${distributionUrl##*/}" in
+maven-mvnd-*bin.*)
+ MVN_CMD=mvnd.sh _MVNW_REPO_PATTERN=/maven/mvnd/
+ case "${PROCESSOR_ARCHITECTURE-}${PROCESSOR_ARCHITEW6432-}:$(uname -a)" in
+ *AMD64:CYGWIN* | *AMD64:MINGW*) distributionPlatform=windows-amd64 ;;
+ :Darwin*x86_64) distributionPlatform=darwin-amd64 ;;
+ :Darwin*arm64) distributionPlatform=darwin-aarch64 ;;
+ :Linux*x86_64*) distributionPlatform=linux-amd64 ;;
+ *)
+ echo "Cannot detect native platform for mvnd on $(uname)-$(uname -m), use pure java version" >&2
+ distributionPlatform=linux-amd64
+ ;;
+ esac
+ distributionUrl="${distributionUrl%-bin.*}-$distributionPlatform.zip"
+ ;;
+maven-mvnd-*) MVN_CMD=mvnd.sh _MVNW_REPO_PATTERN=/maven/mvnd/ ;;
+*) MVN_CMD="mvn${scriptName#mvnw}" _MVNW_REPO_PATTERN=/org/apache/maven/ ;;
+esac
+
+# apply MVNW_REPOURL and calculate MAVEN_HOME
+# maven home pattern: ~/.m2/wrapper/dists/{apache-maven-,maven-mvnd--}/
+[ -z "${MVNW_REPOURL-}" ] || distributionUrl="$MVNW_REPOURL$_MVNW_REPO_PATTERN${distributionUrl#*"$_MVNW_REPO_PATTERN"}"
+distributionUrlName="${distributionUrl##*/}"
+distributionUrlNameMain="${distributionUrlName%.*}"
+distributionUrlNameMain="${distributionUrlNameMain%-bin}"
+MAVEN_USER_HOME="${MAVEN_USER_HOME:-${HOME}/.m2}"
+MAVEN_HOME="${MAVEN_USER_HOME}/wrapper/dists/${distributionUrlNameMain-}/$(hash_string "$distributionUrl")"
+
+exec_maven() {
+ unset MVNW_VERBOSE MVNW_USERNAME MVNW_PASSWORD MVNW_REPOURL || :
+ exec "$MAVEN_HOME/bin/$MVN_CMD" "$@" || die "cannot exec $MAVEN_HOME/bin/$MVN_CMD"
+}
+
+if [ -d "$MAVEN_HOME" ]; then
+ verbose "found existing MAVEN_HOME at $MAVEN_HOME"
+ exec_maven "$@"
+fi
+
+case "${distributionUrl-}" in
+*?-bin.zip | *?maven-mvnd-?*-?*.zip) ;;
+*) die "distributionUrl is not valid, must match *-bin.zip or maven-mvnd-*.zip, but found '${distributionUrl-}'" ;;
+esac
+
+# prepare tmp dir
+if TMP_DOWNLOAD_DIR="$(mktemp -d)" && [ -d "$TMP_DOWNLOAD_DIR" ]; then
+ clean() { rm -rf -- "$TMP_DOWNLOAD_DIR"; }
+ trap clean HUP INT TERM EXIT
+else
+ die "cannot create temp dir"
+fi
+
+mkdir -p -- "${MAVEN_HOME%/*}"
+
+# Download and Install Apache Maven
+verbose "Couldn't find MAVEN_HOME, downloading and installing it ..."
+verbose "Downloading from: $distributionUrl"
+verbose "Downloading to: $TMP_DOWNLOAD_DIR/$distributionUrlName"
+
+# select .zip or .tar.gz
+if ! command -v unzip >/dev/null; then
+ distributionUrl="${distributionUrl%.zip}.tar.gz"
+ distributionUrlName="${distributionUrl##*/}"
+fi
+
+# verbose opt
+__MVNW_QUIET_WGET=--quiet __MVNW_QUIET_CURL=--silent __MVNW_QUIET_UNZIP=-q __MVNW_QUIET_TAR=''
+[ "${MVNW_VERBOSE-}" != true ] || __MVNW_QUIET_WGET='' __MVNW_QUIET_CURL='' __MVNW_QUIET_UNZIP='' __MVNW_QUIET_TAR=v
+
+# normalize http auth
+case "${MVNW_PASSWORD:+has-password}" in
+'') MVNW_USERNAME='' MVNW_PASSWORD='' ;;
+has-password) [ -n "${MVNW_USERNAME-}" ] || MVNW_USERNAME='' MVNW_PASSWORD='' ;;
+esac
+
+if [ -z "${MVNW_USERNAME-}" ] && command -v wget >/dev/null; then
+ verbose "Found wget ... using wget"
+ wget ${__MVNW_QUIET_WGET:+"$__MVNW_QUIET_WGET"} "$distributionUrl" -O "$TMP_DOWNLOAD_DIR/$distributionUrlName" || die "wget: Failed to fetch $distributionUrl"
+elif [ -z "${MVNW_USERNAME-}" ] && command -v curl >/dev/null; then
+ verbose "Found curl ... using curl"
+ curl ${__MVNW_QUIET_CURL:+"$__MVNW_QUIET_CURL"} -f -L -o "$TMP_DOWNLOAD_DIR/$distributionUrlName" "$distributionUrl" || die "curl: Failed to fetch $distributionUrl"
+elif set_java_home; then
+ verbose "Falling back to use Java to download"
+ javaSource="$TMP_DOWNLOAD_DIR/Downloader.java"
+ targetZip="$TMP_DOWNLOAD_DIR/$distributionUrlName"
+ cat >"$javaSource" <<-END
+ public class Downloader extends java.net.Authenticator
+ {
+ protected java.net.PasswordAuthentication getPasswordAuthentication()
+ {
+ return new java.net.PasswordAuthentication( System.getenv( "MVNW_USERNAME" ), System.getenv( "MVNW_PASSWORD" ).toCharArray() );
+ }
+ public static void main( String[] args ) throws Exception
+ {
+ setDefault( new Downloader() );
+ java.nio.file.Files.copy( java.net.URI.create( args[0] ).toURL().openStream(), java.nio.file.Paths.get( args[1] ).toAbsolutePath().normalize() );
+ }
+ }
+ END
+ # For Cygwin/MinGW, switch paths to Windows format before running javac and java
+ verbose " - Compiling Downloader.java ..."
+ "$(native_path "$JAVACCMD")" "$(native_path "$javaSource")" || die "Failed to compile Downloader.java"
+ verbose " - Running Downloader.java ..."
+ "$(native_path "$JAVACMD")" -cp "$(native_path "$TMP_DOWNLOAD_DIR")" Downloader "$distributionUrl" "$(native_path "$targetZip")"
+fi
+
+# If specified, validate the SHA-256 sum of the Maven distribution zip file
+if [ -n "${distributionSha256Sum-}" ]; then
+ distributionSha256Result=false
+ if [ "$MVN_CMD" = mvnd.sh ]; then
+ echo "Checksum validation is not supported for maven-mvnd." >&2
+ echo "Please disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." >&2
+ exit 1
+ elif command -v sha256sum >/dev/null; then
+ if echo "$distributionSha256Sum $TMP_DOWNLOAD_DIR/$distributionUrlName" | sha256sum -c - >/dev/null 2>&1; then
+ distributionSha256Result=true
+ fi
+ elif command -v shasum >/dev/null; then
+ if echo "$distributionSha256Sum $TMP_DOWNLOAD_DIR/$distributionUrlName" | shasum -a 256 -c >/dev/null 2>&1; then
+ distributionSha256Result=true
+ fi
+ else
+ echo "Checksum validation was requested but neither 'sha256sum' or 'shasum' are available." >&2
+ echo "Please install either command, or disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." >&2
+ exit 1
+ fi
+ if [ $distributionSha256Result = false ]; then
+ echo "Error: Failed to validate Maven distribution SHA-256, your Maven distribution might be compromised." >&2
+ echo "If you updated your Maven version, you need to update the specified distributionSha256Sum property." >&2
+ exit 1
+ fi
+fi
+
+# unzip and move
+if command -v unzip >/dev/null; then
+ unzip ${__MVNW_QUIET_UNZIP:+"$__MVNW_QUIET_UNZIP"} "$TMP_DOWNLOAD_DIR/$distributionUrlName" -d "$TMP_DOWNLOAD_DIR" || die "failed to unzip"
+else
+ tar xzf${__MVNW_QUIET_TAR:+"$__MVNW_QUIET_TAR"} "$TMP_DOWNLOAD_DIR/$distributionUrlName" -C "$TMP_DOWNLOAD_DIR" || die "failed to untar"
+fi
+
+# Find the actual extracted directory name (handles snapshots where filename != directory name)
+actualDistributionDir=""
+
+# First try the expected directory name (for regular distributions)
+if [ -d "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain" ]; then
+ if [ -f "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain/bin/$MVN_CMD" ]; then
+ actualDistributionDir="$distributionUrlNameMain"
+ fi
+fi
+
+# If not found, search for any directory with the Maven executable (for snapshots)
+if [ -z "$actualDistributionDir" ]; then
+ # enable globbing to iterate over items
+ set +f
+ for dir in "$TMP_DOWNLOAD_DIR"/*; do
+ if [ -d "$dir" ]; then
+ if [ -f "$dir/bin/$MVN_CMD" ]; then
+ actualDistributionDir="$(basename "$dir")"
+ break
+ fi
+ fi
+ done
+ set -f
+fi
+
+if [ -z "$actualDistributionDir" ]; then
+ verbose "Contents of $TMP_DOWNLOAD_DIR:"
+ verbose "$(ls -la "$TMP_DOWNLOAD_DIR")"
+ die "Could not find Maven distribution directory in extracted archive"
+fi
+
+verbose "Found extracted Maven distribution directory: $actualDistributionDir"
+printf %s\\n "$distributionUrl" >"$TMP_DOWNLOAD_DIR/$actualDistributionDir/mvnw.url"
+mv -- "$TMP_DOWNLOAD_DIR/$actualDistributionDir" "$MAVEN_HOME" || [ -d "$MAVEN_HOME" ] || die "fail to move MAVEN_HOME"
+
+clean || :
+exec_maven "$@"
diff --git a/mvnw.cmd b/mvnw.cmd
new file mode 100644
index 0000000..92450f9
--- /dev/null
+++ b/mvnw.cmd
@@ -0,0 +1,189 @@
+<# : batch portion
+@REM ----------------------------------------------------------------------------
+@REM Licensed to the Apache Software Foundation (ASF) under one
+@REM or more contributor license agreements. See the NOTICE file
+@REM distributed with this work for additional information
+@REM regarding copyright ownership. The ASF licenses this file
+@REM to you under the Apache License, Version 2.0 (the
+@REM "License"); you may not use this file except in compliance
+@REM with the License. You may obtain a copy of the License at
+@REM
+@REM http://www.apache.org/licenses/LICENSE-2.0
+@REM
+@REM Unless required by applicable law or agreed to in writing,
+@REM software distributed under the License is distributed on an
+@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+@REM KIND, either express or implied. See the License for the
+@REM specific language governing permissions and limitations
+@REM under the License.
+@REM ----------------------------------------------------------------------------
+
+@REM ----------------------------------------------------------------------------
+@REM Apache Maven Wrapper startup batch script, version 3.3.4
+@REM
+@REM Optional ENV vars
+@REM MVNW_REPOURL - repo url base for downloading maven distribution
+@REM MVNW_USERNAME/MVNW_PASSWORD - user and password for downloading maven
+@REM MVNW_VERBOSE - true: enable verbose log; others: silence the output
+@REM ----------------------------------------------------------------------------
+
+@IF "%__MVNW_ARG0_NAME__%"=="" (SET __MVNW_ARG0_NAME__=%~nx0)
+@SET __MVNW_CMD__=
+@SET __MVNW_ERROR__=
+@SET __MVNW_PSMODULEP_SAVE=%PSModulePath%
+@SET PSModulePath=
+@FOR /F "usebackq tokens=1* delims==" %%A IN (`powershell -noprofile "& {$scriptDir='%~dp0'; $script='%__MVNW_ARG0_NAME__%'; icm -ScriptBlock ([Scriptblock]::Create((Get-Content -Raw '%~f0'))) -NoNewScope}"`) DO @(
+ IF "%%A"=="MVN_CMD" (set __MVNW_CMD__=%%B) ELSE IF "%%B"=="" (echo %%A) ELSE (echo %%A=%%B)
+)
+@SET PSModulePath=%__MVNW_PSMODULEP_SAVE%
+@SET __MVNW_PSMODULEP_SAVE=
+@SET __MVNW_ARG0_NAME__=
+@SET MVNW_USERNAME=
+@SET MVNW_PASSWORD=
+@IF NOT "%__MVNW_CMD__%"=="" ("%__MVNW_CMD__%" %*)
+@echo Cannot start maven from wrapper >&2 && exit /b 1
+@GOTO :EOF
+: end batch / begin powershell #>
+
+$ErrorActionPreference = "Stop"
+if ($env:MVNW_VERBOSE -eq "true") {
+ $VerbosePreference = "Continue"
+}
+
+# calculate distributionUrl, requires .mvn/wrapper/maven-wrapper.properties
+$distributionUrl = (Get-Content -Raw "$scriptDir/.mvn/wrapper/maven-wrapper.properties" | ConvertFrom-StringData).distributionUrl
+if (!$distributionUrl) {
+ Write-Error "cannot read distributionUrl property in $scriptDir/.mvn/wrapper/maven-wrapper.properties"
+}
+
+switch -wildcard -casesensitive ( $($distributionUrl -replace '^.*/','') ) {
+ "maven-mvnd-*" {
+ $USE_MVND = $true
+ $distributionUrl = $distributionUrl -replace '-bin\.[^.]*$',"-windows-amd64.zip"
+ $MVN_CMD = "mvnd.cmd"
+ break
+ }
+ default {
+ $USE_MVND = $false
+ $MVN_CMD = $script -replace '^mvnw','mvn'
+ break
+ }
+}
+
+# apply MVNW_REPOURL and calculate MAVEN_HOME
+# maven home pattern: ~/.m2/wrapper/dists/{apache-maven-,maven-mvnd--}/
+if ($env:MVNW_REPOURL) {
+ $MVNW_REPO_PATTERN = if ($USE_MVND -eq $False) { "/org/apache/maven/" } else { "/maven/mvnd/" }
+ $distributionUrl = "$env:MVNW_REPOURL$MVNW_REPO_PATTERN$($distributionUrl -replace "^.*$MVNW_REPO_PATTERN",'')"
+}
+$distributionUrlName = $distributionUrl -replace '^.*/',''
+$distributionUrlNameMain = $distributionUrlName -replace '\.[^.]*$','' -replace '-bin$',''
+
+$MAVEN_M2_PATH = "$HOME/.m2"
+if ($env:MAVEN_USER_HOME) {
+ $MAVEN_M2_PATH = "$env:MAVEN_USER_HOME"
+}
+
+if (-not (Test-Path -Path $MAVEN_M2_PATH)) {
+ New-Item -Path $MAVEN_M2_PATH -ItemType Directory | Out-Null
+}
+
+$MAVEN_WRAPPER_DISTS = $null
+if ((Get-Item $MAVEN_M2_PATH).Target[0] -eq $null) {
+ $MAVEN_WRAPPER_DISTS = "$MAVEN_M2_PATH/wrapper/dists"
+} else {
+ $MAVEN_WRAPPER_DISTS = (Get-Item $MAVEN_M2_PATH).Target[0] + "/wrapper/dists"
+}
+
+$MAVEN_HOME_PARENT = "$MAVEN_WRAPPER_DISTS/$distributionUrlNameMain"
+$MAVEN_HOME_NAME = ([System.Security.Cryptography.SHA256]::Create().ComputeHash([byte[]][char[]]$distributionUrl) | ForEach-Object {$_.ToString("x2")}) -join ''
+$MAVEN_HOME = "$MAVEN_HOME_PARENT/$MAVEN_HOME_NAME"
+
+if (Test-Path -Path "$MAVEN_HOME" -PathType Container) {
+ Write-Verbose "found existing MAVEN_HOME at $MAVEN_HOME"
+ Write-Output "MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD"
+ exit $?
+}
+
+if (! $distributionUrlNameMain -or ($distributionUrlName -eq $distributionUrlNameMain)) {
+ Write-Error "distributionUrl is not valid, must end with *-bin.zip, but found $distributionUrl"
+}
+
+# prepare tmp dir
+$TMP_DOWNLOAD_DIR_HOLDER = New-TemporaryFile
+$TMP_DOWNLOAD_DIR = New-Item -Itemtype Directory -Path "$TMP_DOWNLOAD_DIR_HOLDER.dir"
+$TMP_DOWNLOAD_DIR_HOLDER.Delete() | Out-Null
+trap {
+ if ($TMP_DOWNLOAD_DIR.Exists) {
+ try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null }
+ catch { Write-Warning "Cannot remove $TMP_DOWNLOAD_DIR" }
+ }
+}
+
+New-Item -Itemtype Directory -Path "$MAVEN_HOME_PARENT" -Force | Out-Null
+
+# Download and Install Apache Maven
+Write-Verbose "Couldn't find MAVEN_HOME, downloading and installing it ..."
+Write-Verbose "Downloading from: $distributionUrl"
+Write-Verbose "Downloading to: $TMP_DOWNLOAD_DIR/$distributionUrlName"
+
+$webclient = New-Object System.Net.WebClient
+if ($env:MVNW_USERNAME -and $env:MVNW_PASSWORD) {
+ $webclient.Credentials = New-Object System.Net.NetworkCredential($env:MVNW_USERNAME, $env:MVNW_PASSWORD)
+}
+[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
+$webclient.DownloadFile($distributionUrl, "$TMP_DOWNLOAD_DIR/$distributionUrlName") | Out-Null
+
+# If specified, validate the SHA-256 sum of the Maven distribution zip file
+$distributionSha256Sum = (Get-Content -Raw "$scriptDir/.mvn/wrapper/maven-wrapper.properties" | ConvertFrom-StringData).distributionSha256Sum
+if ($distributionSha256Sum) {
+ if ($USE_MVND) {
+ Write-Error "Checksum validation is not supported for maven-mvnd. `nPlease disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties."
+ }
+ Import-Module $PSHOME\Modules\Microsoft.PowerShell.Utility -Function Get-FileHash
+ if ((Get-FileHash "$TMP_DOWNLOAD_DIR/$distributionUrlName" -Algorithm SHA256).Hash.ToLower() -ne $distributionSha256Sum) {
+ Write-Error "Error: Failed to validate Maven distribution SHA-256, your Maven distribution might be compromised. If you updated your Maven version, you need to update the specified distributionSha256Sum property."
+ }
+}
+
+# unzip and move
+Expand-Archive "$TMP_DOWNLOAD_DIR/$distributionUrlName" -DestinationPath "$TMP_DOWNLOAD_DIR" | Out-Null
+
+# Find the actual extracted directory name (handles snapshots where filename != directory name)
+$actualDistributionDir = ""
+
+# First try the expected directory name (for regular distributions)
+$expectedPath = Join-Path "$TMP_DOWNLOAD_DIR" "$distributionUrlNameMain"
+$expectedMvnPath = Join-Path "$expectedPath" "bin/$MVN_CMD"
+if ((Test-Path -Path $expectedPath -PathType Container) -and (Test-Path -Path $expectedMvnPath -PathType Leaf)) {
+ $actualDistributionDir = $distributionUrlNameMain
+}
+
+# If not found, search for any directory with the Maven executable (for snapshots)
+if (!$actualDistributionDir) {
+ Get-ChildItem -Path "$TMP_DOWNLOAD_DIR" -Directory | ForEach-Object {
+ $testPath = Join-Path $_.FullName "bin/$MVN_CMD"
+ if (Test-Path -Path $testPath -PathType Leaf) {
+ $actualDistributionDir = $_.Name
+ }
+ }
+}
+
+if (!$actualDistributionDir) {
+ Write-Error "Could not find Maven distribution directory in extracted archive"
+}
+
+Write-Verbose "Found extracted Maven distribution directory: $actualDistributionDir"
+Rename-Item -Path "$TMP_DOWNLOAD_DIR/$actualDistributionDir" -NewName $MAVEN_HOME_NAME | Out-Null
+try {
+ Move-Item -Path "$TMP_DOWNLOAD_DIR/$MAVEN_HOME_NAME" -Destination $MAVEN_HOME_PARENT | Out-Null
+} catch {
+ if (! (Test-Path -Path "$MAVEN_HOME" -PathType Container)) {
+ Write-Error "fail to move MAVEN_HOME"
+ }
+} finally {
+ try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null }
+ catch { Write-Warning "Cannot remove $TMP_DOWNLOAD_DIR" }
+}
+
+Write-Output "MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD"
diff --git a/plugin/pom.xml b/plugin/pom.xml
index b76825c..9df8608 100644
--- a/plugin/pom.xml
+++ b/plugin/pom.xml
@@ -30,7 +30,11 @@
false
Proxy-${project.version}
true
-
+
+
+ io.netty:*
+
+
*:*
@@ -57,20 +61,24 @@
- com.github.BTEUK:NetworkLib
+ com.github.BuildtheUK:NetworkLib
com/fasterxml/**
com/google/gson/**
net/kyori/**
org/jetbrains/**
org/intellij/**
- META-INF/**
+ META-INF/MANIFEST.MF
+ META-INF/*.SF
+ META-INF/*.DSA
+ META-INF/*.RSA
-
+
@@ -79,7 +87,6 @@
org.apache.maven.plugins
maven-compiler-plugin
- ${maven-compiler-plugin.version}
@@ -105,6 +112,10 @@
+
+ org.btuk.proxy
+ app
+
org.btuk.proxy
core
diff --git a/plugin/src/main/java/org/btuk/proxy/Proxy.java b/plugin/src/main/java/org/btuk/proxy/Proxy.java
index 2250eac..9ca99d9 100644
--- a/plugin/src/main/java/org/btuk/proxy/Proxy.java
+++ b/plugin/src/main/java/org/btuk/proxy/Proxy.java
@@ -10,21 +10,18 @@
import com.velocitypowered.api.proxy.ProxyServer;
import com.velocitypowered.api.proxy.server.RegisteredServer;
import lombok.Getter;
-import net.bteuk.network.lib.socket.InputSocket;
-
+import org.btuk.network.lib.socket.InputSocket;
+import org.btuk.proxy.app.ProxyController;
import org.btuk.proxy.chat.ProxyChatHandler;
-
+import org.btuk.proxy.core.socket.ProxySocketHandler;
import org.btuk.proxy.listener.CommandListener;
import org.btuk.proxy.listener.ServerConnectListener;
import org.btuk.proxy.player.ProxyPlayerManager;
import org.btuk.proxy.scheduler.ProxyScheduler;
import org.btuk.proxy.server.ProxyCoreServerManager;
-import org.btuk.proxy.core.socket.ProxySocketHandler;
-
import org.btuk.proxy.tab.ProxyTabManager;
import org.slf4j.Logger;
-
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
@@ -38,7 +35,7 @@
import java.util.UUID;
import java.util.function.Consumer;
-@Plugin(id = "proxy", name = "Proxy", version = "1.12.0-SNAPSHOT",
+@Plugin(id = "proxy", name = "Proxy", version = "1.13.0-SNAPSHOT",
url = "https://github.com/BTEUK/Proxy", description = "Proxy plugin, managed chat, discord and server related actions.", authors = {"ELgamer"})
public class Proxy {
@@ -69,7 +66,6 @@ public Proxy(ProxyServer server, Logger logger) {
@Subscribe
public void onProxyInitialization(ProxyInitializeEvent event) throws IOException {
-
this.proxyController = new ProxyController(getDataFolder());
this.defaultServer = proxyController.getConfig().getString("default_server");
diff --git a/plugin/src/main/java/org/btuk/proxy/chat/ProxyChatHandler.java b/plugin/src/main/java/org/btuk/proxy/chat/ProxyChatHandler.java
index 38baaf6..25e6f27 100644
--- a/plugin/src/main/java/org/btuk/proxy/chat/ProxyChatHandler.java
+++ b/plugin/src/main/java/org/btuk/proxy/chat/ProxyChatHandler.java
@@ -1,21 +1,20 @@
package org.btuk.proxy.chat;
import lombok.extern.java.Log;
-import net.bteuk.network.lib.dto.AbstractTransferObject;
-import net.bteuk.network.lib.socket.OutputSocket;
+import org.btuk.network.lib.dto.AbstractTransferObject;
+import org.btuk.network.lib.socket.OutputSocket;
+import org.btuk.proxy.core.chat.ChatHandler;
+import org.btuk.proxy.core.config.Config;
+import org.btuk.proxy.core.config.ConfigSocket;
import org.btuk.proxy.core.exceptions.ServerNotFoundException;
+import org.btuk.proxy.core.server.CoreServerManager;
+import org.btuk.proxy.core.server.Server;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
-import org.btuk.proxy.core.chat.ChatHandler;
-import org.btuk.proxy.core.config.Config;
-import org.btuk.proxy.core.config.ConfigSocket;
-import org.btuk.proxy.core.server.Server;
-import org.btuk.proxy.core.server.CoreServerManager;
-
@Log
public class ProxyChatHandler implements ChatHandler {
diff --git a/plugin/src/main/java/org/btuk/proxy/tab/ProxyTabManager.java b/plugin/src/main/java/org/btuk/proxy/tab/ProxyTabManager.java
index 6534f61..e8c03d7 100644
--- a/plugin/src/main/java/org/btuk/proxy/tab/ProxyTabManager.java
+++ b/plugin/src/main/java/org/btuk/proxy/tab/ProxyTabManager.java
@@ -3,13 +3,16 @@
import com.velocitypowered.api.proxy.ProxyServer;
import com.velocitypowered.api.proxy.player.TabListEntry;
import com.velocitypowered.api.util.GameProfile;
-import net.bteuk.network.lib.dto.TabPlayer;
-
+import net.kyori.adventure.text.Component;
+import org.btuk.network.lib.dto.TabPlayer;
+import org.btuk.proxy.core.chat.ChatHandler;
+import org.btuk.proxy.core.config.Config;
+import org.btuk.proxy.core.player.Player;
import org.btuk.proxy.core.scheduler.Scheduler;
import org.btuk.proxy.core.tab.AbstractTabManager;
+import org.btuk.proxy.core.user.CoreUserManager;
+import org.btuk.proxy.core.user.User;
import org.btuk.proxy.player.ProxyPlayer;
-
-import net.kyori.adventure.text.Component;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
@@ -17,12 +20,6 @@
import java.util.List;
import java.util.Optional;
-import org.btuk.proxy.core.chat.ChatHandler;
-import org.btuk.proxy.core.config.Config;
-import org.btuk.proxy.core.player.Player;
-import org.btuk.proxy.core.user.CoreUserManager;
-import org.btuk.proxy.core.user.User;
-
/**
* Keeps track of all users and their tab information.
* Sends updates to the servers when things change.
diff --git a/pom.xml b/pom.xml
index dff10c7..813c04a 100644
--- a/pom.xml
+++ b/pom.xml
@@ -15,21 +15,22 @@
api
core
plugin
+ app
- 21
+ 25
UTF-8
${java-version}
- 3.11.0
- 3.6.1
+ 3.15.0
+ 3.6.2
- 955372d721
+ 5dee061bcb
- 3.5.0-SNAPSHOT
+ 4.1.0-SNAPSHOT
- 1.18.34
+ 1.18.46
2.25.2
2.0.17
@@ -71,12 +72,12 @@
org.btuk.proxy
- database
+ api
${project.version}
org.btuk.proxy
- api
+ app
${project.version}
@@ -84,9 +85,14 @@
core
${project.version}
+
+ org.btuk.proxy
+ database
+ ${project.version}
+
- com.github.BTEUK
+ com.github.BuildtheUK
NetworkLib
${networklib.version}
@@ -160,4 +166,25 @@
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ ${maven-compiler-plugin.version}
+
+
+
+ org.projectlombok
+ lombok
+ ${lombok.version}
+
+
+
+
+
+
+
\ No newline at end of file