mirror of
https://github.com/RayzsYT/ProAntiTab.git
synced 2026-11-04 17:00:18 -05:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
11ee68fa3f | ||
|
|
2c3d3fac92 | ||
|
|
e524f898da | ||
|
|
c181cfbbc4 | ||
|
|
1110466235 | ||
|
|
a965dd231b | ||
|
|
6418e4f42a | ||
|
|
e71909fcd7 | ||
|
|
c6f9fc8d3e | ||
|
|
88cb03c82e |
No files matched your search
+29
@@ -0,0 +1,29 @@
|
||||
# Maven
|
||||
/target/
|
||||
|
||||
# IntelliJ IDEA
|
||||
/.idea/
|
||||
*.iml
|
||||
*.iws
|
||||
*.ipr
|
||||
|
||||
# Eclipse
|
||||
/.classpath
|
||||
/.project
|
||||
/.settings/
|
||||
|
||||
# VS Code
|
||||
/.vscode/
|
||||
|
||||
# Local environment and logs
|
||||
.env
|
||||
.env.*
|
||||
*.log
|
||||
*.tmp
|
||||
|
||||
# OS files
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
|
||||
# Maven Shade Plugin
|
||||
dependency-reduced-pom.xml
|
||||
@@ -14,6 +14,11 @@
|
||||
</properties>
|
||||
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>papermc</id>
|
||||
<url>https://repo.papermc.io/repository/maven-public/</url>
|
||||
</repository>
|
||||
|
||||
<repository>
|
||||
<id>spigot-repo</id>
|
||||
<url>https://hub.spigotmc.org/nexus/content/repositories/snapshots/</url>
|
||||
@@ -24,14 +29,15 @@
|
||||
<url>https://oss.sonatype.org/content/repositories/snapshots</url>
|
||||
</repository>
|
||||
|
||||
<repository>
|
||||
<id>papermc</id>
|
||||
<url>https://repo.papermc.io/repository/maven-public/</url>
|
||||
</repository>
|
||||
|
||||
<repository>
|
||||
<id>jitpack.io</id>
|
||||
<url>https://jitpack.io</url>
|
||||
<releases>
|
||||
<enabled>true</enabled>
|
||||
</releases>
|
||||
<snapshots>
|
||||
<enabled>false</enabled>
|
||||
</snapshots>
|
||||
</repository>
|
||||
|
||||
<repository>
|
||||
@@ -77,17 +83,14 @@
|
||||
<url>https://central.sonatype.com/repository/maven-snapshots/</url>
|
||||
</repository>
|
||||
|
||||
<repository>
|
||||
<id>AlessioDP</id>
|
||||
<url>https://repo.alessiodp.com/releases/</url>
|
||||
</repository>
|
||||
|
||||
</repositories>
|
||||
|
||||
<dependencies>
|
||||
|
||||
<dependency>
|
||||
<groupId>dev.folia</groupId>
|
||||
<artifactId>folia-api</artifactId>
|
||||
<version>1.20.1-R0.1-SNAPSHOT</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.papermc.paper</groupId>
|
||||
<artifactId>paper-api</artifactId>
|
||||
@@ -95,20 +98,6 @@
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.spigotmc</groupId>
|
||||
<artifactId>spigot-api</artifactId>
|
||||
<version>1.19-R0.1-SNAPSHOT</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.netty</groupId>
|
||||
<artifactId>netty-all</artifactId>
|
||||
<version>4.2.0.Final</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>net.md-5</groupId>
|
||||
<artifactId>bungeecord-api</artifactId>
|
||||
@@ -116,77 +105,6 @@
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>net.md-5</groupId>
|
||||
<artifactId>bungeecord-protocol</artifactId>
|
||||
<version>1.16-R0.4</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
|
||||
<dependency>
|
||||
<groupId>com.mojang</groupId>
|
||||
<artifactId>authlib</artifactId>
|
||||
<version>4.0.43</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.github.ElgarL</groupId>
|
||||
<artifactId>groupmanager</artifactId>
|
||||
<version>3.2</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.mojang</groupId>
|
||||
<artifactId>brigadier</artifactId>
|
||||
<version>1.1.8</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.mojang</groupId>
|
||||
<artifactId>datafixerupper</artifactId>
|
||||
<version>6.0.8</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.mojang</groupId>
|
||||
<artifactId>logging</artifactId>
|
||||
<version>1.1.1</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.maven</groupId>
|
||||
<artifactId>maven-resolver-provider</artifactId>
|
||||
<version>3.8.5</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.maven.resolver</groupId>
|
||||
<artifactId>maven-resolver-connector-basic</artifactId>
|
||||
<version>1.7.3</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.maven.resolver</groupId>
|
||||
<artifactId>maven-resolver-transport-http</artifactId>
|
||||
<version>1.7.3</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.logging.log4j</groupId>
|
||||
<artifactId>log4j-core</artifactId>
|
||||
<version>2.18.0</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.github.waterfallmc</groupId>
|
||||
<artifactId>waterfall-api</artifactId>
|
||||
@@ -194,13 +112,6 @@
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>net.william278</groupId>
|
||||
<artifactId>papiproxybridge</artifactId>
|
||||
<version>1.4</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.velocitypowered</groupId>
|
||||
<artifactId>velocity-api</artifactId>
|
||||
@@ -221,56 +132,64 @@
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
|
||||
<dependency>
|
||||
<groupId>org.sonatype.sisu</groupId>
|
||||
<artifactId>sisu-guice</artifactId>
|
||||
<version>2.1.7</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.spongepowered</groupId>
|
||||
<artifactId>configurate-hocon</artifactId>
|
||||
<version>4.1.2</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>net.kyori</groupId>
|
||||
<artifactId>adventure-text-minimessage</artifactId>
|
||||
<version>5.2.0</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>net.kyori</groupId>
|
||||
<artifactId>adventure-api</artifactId>
|
||||
<version>5.2.0</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>net.kyori</groupId>
|
||||
<artifactId>adventure-platform-api</artifactId>
|
||||
<version>4.4.1</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>net.kyori</groupId>
|
||||
<artifactId>adventure-platform-bungeecord</artifactId>
|
||||
<version>4.4.1</version>
|
||||
<scope>compile</scope>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>net.kyori</groupId>
|
||||
<artifactId>adventure-platform-bukkit</artifactId>
|
||||
<version>4.4.1</version>
|
||||
<scope>compile</scope>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>net.kyori</groupId>
|
||||
<artifactId>adventure-text-serializer-legacy</artifactId>
|
||||
<version>5.2.0</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.netty</groupId>
|
||||
<artifactId>netty-all</artifactId>
|
||||
<version>4.2.0.Final</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter</artifactId>
|
||||
<version>5.11.4</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
|
||||
<!-- PLUGIN COMPATIBILITIES -->
|
||||
|
||||
|
||||
<!-- Permission plugins -->
|
||||
|
||||
<dependency>
|
||||
<groupId>net.luckperms</groupId>
|
||||
<artifactId>api</artifactId>
|
||||
<version>5.5</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.github.ElgarL</groupId>
|
||||
<artifactId>groupmanager</artifactId>
|
||||
<version>3.2</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
|
||||
<!-- PAPI -->
|
||||
|
||||
<dependency>
|
||||
<groupId>me.clip</groupId>
|
||||
<artifactId>placeholderapi</artifactId>
|
||||
@@ -279,12 +198,15 @@
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>net.luckperms</groupId>
|
||||
<artifactId>api</artifactId>
|
||||
<version>5.5</version>
|
||||
<groupId>net.william278</groupId>
|
||||
<artifactId>papiproxybridge</artifactId>
|
||||
<version>1.4</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
|
||||
<!-- Extras -->
|
||||
|
||||
<dependency>
|
||||
<groupId>com.viaversion</groupId>
|
||||
<artifactId>viaversion-api</artifactId>
|
||||
@@ -294,50 +216,5 @@
|
||||
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<finalName>IgnoreThisJar</finalName>
|
||||
|
||||
<resources>
|
||||
<resource>
|
||||
<directory>src/main/resources</directory>
|
||||
<excludes>
|
||||
<exclude>*.txt</exclude>
|
||||
</excludes>
|
||||
</resource>
|
||||
</resources>
|
||||
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-shade-plugin</artifactId>
|
||||
<version>3.3.0</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>shade</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
<configuration>
|
||||
<finalName>ProAntiTab</finalName>
|
||||
<shadedArtifactAttached>false</shadedArtifactAttached>
|
||||
<shadedClassifierName>shaded</shadedClassifierName>
|
||||
<artifactSet>
|
||||
<excludes/>
|
||||
</artifactSet>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
<source>17</source>
|
||||
<target>17</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
|
||||
</project>
|
||||
@@ -1,5 +1,6 @@
|
||||
package de.rayzs.pat.api.storage;
|
||||
|
||||
import java.security.SecureRandom;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@@ -61,7 +62,7 @@ public class Storage {
|
||||
|
||||
public static final List<UUID> NOTIFY_PLAYERS = new ArrayList<>();
|
||||
|
||||
public static String TOKEN = "", HASHED_TOKEN = "", CENSORED_TOKEN = "", SERVER_NAME = null, CURRENT_VERSION = "", NEWER_VERSION = "";
|
||||
public static String TOKEN = "", CENSORED_TOKEN = "", SERVER_NAME = null, CURRENT_VERSION = "", NEWER_VERSION = "";
|
||||
public static boolean OUTDATED = false, SEND_CONSOLE_NOTIFICATION = true;
|
||||
public static boolean USE_PLACEHOLDERAPI = false, USE_PAPIPROXYBRIDGE = false, USE_VIAVERSION = false;
|
||||
|
||||
@@ -91,6 +92,12 @@ public class Storage {
|
||||
Logger.warning("Read more about it here: https://rayzs.de/products/proantitab/nkppf");
|
||||
}
|
||||
|
||||
private static String generateToken() {
|
||||
byte[] bytes = new byte[32];
|
||||
new SecureRandom().nextBytes(bytes);
|
||||
return Base64.getUrlEncoder().withoutPadding().encodeToString(bytes);
|
||||
}
|
||||
|
||||
public static PermissionPlugin getPermissionPlugin() {
|
||||
return PERMISSION_PLUGIN;
|
||||
}
|
||||
@@ -140,11 +147,9 @@ public class Storage {
|
||||
|
||||
if (useDefaultToken) {
|
||||
TOKEN = Reflection.isProxyServer()
|
||||
? (String) Files.TOKEN.getOrSet("token", UUID.randomUUID().toString())
|
||||
? (String) Files.TOKEN.getOrSet("token", generateToken())
|
||||
: ConfigSections.Settings.HANDLE_THROUGH_PROXY.TOKEN;
|
||||
}
|
||||
|
||||
HASHED_TOKEN = Objects.requireNonNullElse(StringUtils.hashString(TOKEN, "SHA-256"), TOKEN);
|
||||
}
|
||||
|
||||
public static void loadConfig() {
|
||||
@@ -414,7 +419,7 @@ public class Storage {
|
||||
public static String findAndReplace(Player player, String request) {
|
||||
String result = null, param = "";
|
||||
|
||||
if(USE_PLACEHOLDERAPI) {
|
||||
if (USE_PLACEHOLDERAPI) {
|
||||
for (PlaceholderStorage storage : PLACEHOLDERS) {
|
||||
if (!storage.getRequest().startsWith(request)) continue;
|
||||
|
||||
@@ -430,7 +435,7 @@ public class Storage {
|
||||
|
||||
// Second time because of nested placeholders
|
||||
if (result != null && result.contains("%")) {
|
||||
result = PlaceholderReplacer.replace(player, result);
|
||||
result = PlaceholderReplacer.applyPlaceholders(CommandSender.from(player), result);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ import de.rayzs.pat.utils.group.Group;
|
||||
import de.rayzs.pat.utils.hooks.GroupManagerHook;
|
||||
import de.rayzs.pat.utils.configuration.Configurator;
|
||||
import de.rayzs.pat.utils.configuration.updater.ConfigUpdater;
|
||||
import de.rayzs.pat.utils.message.MessageTranslator;
|
||||
import de.rayzs.pat.utils.message.MessageHelper;
|
||||
import de.rayzs.pat.utils.permission.PermissionUtil;
|
||||
import de.rayzs.pat.utils.hooks.ViaVersionHook;
|
||||
import de.rayzs.pat.plugin.system.communication.Communicator;
|
||||
@@ -95,7 +95,7 @@ public class BukkitLoader extends JavaPlugin implements PluginLoader {
|
||||
if (Bukkit.getServer().getPluginManager().getPlugin("PlaceholderAPI") != null)
|
||||
new PlaceholderHook().register();
|
||||
|
||||
MessageTranslator.initialize();
|
||||
MessageHelper.initialize();
|
||||
|
||||
Communicator.initialize(new BukkitPluginMessageClient(), new BukkitCommunicationHandler());
|
||||
BackendUpdater.initialize();
|
||||
@@ -159,6 +159,11 @@ public class BukkitLoader extends JavaPlugin implements PluginLoader {
|
||||
});
|
||||
|
||||
|
||||
|
||||
// Register permissions for LuckPerms to recognise.
|
||||
|
||||
addPermission("bypass");
|
||||
|
||||
for (final ProCommand command : CommandProcess.getCommands()) {
|
||||
addPermission(command.getName());
|
||||
}
|
||||
@@ -190,7 +195,7 @@ public class BukkitLoader extends JavaPlugin implements PluginLoader {
|
||||
public void onDisable() {
|
||||
BackendUpdater.get().stop();
|
||||
BukkitPacketAnalyzer.uninjectAll();
|
||||
MessageTranslator.closeAudiences();
|
||||
MessageHelper.closeAudiences();
|
||||
}
|
||||
|
||||
public void registerCommand(String... commands) {
|
||||
|
||||
@@ -11,7 +11,7 @@ import de.rayzs.pat.plugin.packetanalyzer.proxy.BungeePacketAnalyzer;
|
||||
import de.rayzs.pat.plugin.system.subargument.SubArgument;
|
||||
import de.rayzs.pat.utils.configuration.Configurator;
|
||||
import de.rayzs.pat.utils.configuration.updater.ConfigUpdater;
|
||||
import de.rayzs.pat.utils.message.MessageTranslator;
|
||||
import de.rayzs.pat.utils.message.MessageHelper;
|
||||
import de.rayzs.pat.utils.hooks.LuckPermsHook;
|
||||
import de.rayzs.pat.plugin.system.communication.Communicator;
|
||||
import de.rayzs.pat.utils.response.ResponseHandler;
|
||||
@@ -64,7 +64,7 @@ public class BungeeLoader extends Plugin implements PluginLoader {
|
||||
|
||||
Storage.loadAll(true);
|
||||
|
||||
MessageTranslator.initialize();
|
||||
MessageHelper.initialize();
|
||||
GroupManager.initialize();
|
||||
|
||||
bStats.initialize(this);
|
||||
@@ -121,7 +121,7 @@ public class BungeeLoader extends Plugin implements PluginLoader {
|
||||
@Override
|
||||
public void onDisable() {
|
||||
BungeePacketAnalyzer.uninjectAll();
|
||||
MessageTranslator.closeAudiences();
|
||||
MessageHelper.closeAudiences();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -18,7 +18,7 @@ import com.velocitypowered.api.scheduler.ScheduledTask;
|
||||
import de.rayzs.pat.utils.configuration.Configurator;
|
||||
import de.rayzs.pat.utils.configuration.updater.ConfigUpdater;
|
||||
import de.rayzs.pat.plugin.command.impl.VelocityCommand;
|
||||
import de.rayzs.pat.utils.message.MessageTranslator;
|
||||
import de.rayzs.pat.utils.message.MessageHelper;
|
||||
import de.rayzs.pat.plugin.system.communication.Communicator;
|
||||
import de.rayzs.pat.utils.hooks.LuckPermsHook;
|
||||
import com.velocitypowered.api.proxy.ProxyServer;
|
||||
@@ -40,16 +40,6 @@ import de.rayzs.pat.utils.sender.CommandSender;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
@Plugin(name = "ProAntiTab",
|
||||
id = "proantitab",
|
||||
version = "2.5.1",
|
||||
authors = "Rayzs_YT",
|
||||
description = "Hides more than just your plugins.",
|
||||
url = "https://www.rayzs.de/products/proantitab/page",
|
||||
dependencies = {
|
||||
@Dependency(id = "luckperms", optional = true),
|
||||
@Dependency(id = "papiproxybridge", optional = true)
|
||||
})
|
||||
public class VelocityLoader implements PluginLoader {
|
||||
|
||||
private static VelocityLoader instance;
|
||||
@@ -91,7 +81,7 @@ public class VelocityLoader implements PluginLoader {
|
||||
VersionComparer.get().setCurrentVersion(Storage.CURRENT_VERSION);
|
||||
|
||||
Storage.loadAll(true);
|
||||
MessageTranslator.initialize();
|
||||
MessageHelper.initialize();
|
||||
GroupManager.initialize();
|
||||
|
||||
metricsFactory.make(this, 21638);
|
||||
|
||||
@@ -61,7 +61,7 @@ public class BukkitAntiTabListener implements Listener {
|
||||
return;
|
||||
}
|
||||
|
||||
if (Reflection.isCraftbukkit() && !Bukkit.getOnlinePlayers().contains(player)) {
|
||||
if (Reflection.isBukkit() && !Bukkit.getOnlinePlayers().contains(player)) {
|
||||
event.getCommands().clear();
|
||||
|
||||
PATScheduler.createScheduler(player::updateCommands, 10);
|
||||
|
||||
+17
-17
@@ -20,7 +20,7 @@ import de.rayzs.pat.api.event.events.ExecuteCommandEvent;
|
||||
import de.rayzs.pat.api.storage.Storage;
|
||||
import de.rayzs.pat.plugin.logger.Logger;
|
||||
import de.rayzs.pat.utils.StringUtils;
|
||||
import de.rayzs.pat.utils.message.MessageTranslator;
|
||||
import de.rayzs.pat.utils.message.MessageHelper;
|
||||
import de.rayzs.pat.utils.permission.PermissionUtil;
|
||||
|
||||
public class BukkitBlockCommandListener implements Listener {
|
||||
@@ -44,7 +44,7 @@ public class BukkitBlockCommandListener implements Listener {
|
||||
return;
|
||||
|
||||
event.setCancelled(true);
|
||||
MessageTranslator.send(player, Storage.ConfigSections.Settings.CUSTOM_UNKNOWN_COMMAND.MESSAGE, "%command%", command, "%world%", world.getName());
|
||||
MessageHelper.sendMessage(sender, Storage.ConfigSections.Settings.CUSTOM_UNKNOWN_COMMAND.MESSAGE, "%command%", command, "%world%", world.getName());
|
||||
}
|
||||
|
||||
@EventHandler (priority = EventPriority.LOWEST)
|
||||
@@ -89,17 +89,16 @@ public class BukkitBlockCommandListener implements Listener {
|
||||
}
|
||||
|
||||
final String displayCommand = StringUtils.replaceTriggers(command, "", "\\", "<", ">", "&");
|
||||
|
||||
List<String> notificationMessage = MessageTranslator.replaceMessageList(
|
||||
Storage.ConfigSections.Messages.NOTIFICATION.ALERT,
|
||||
final String notificationMessage = StringUtils.replace(
|
||||
Storage.ConfigSections.Messages.NOTIFICATION.ALERT.getLines(),
|
||||
"%player%", player.getName(),
|
||||
"%command%", displayCommand,
|
||||
"%world%", worldName);
|
||||
|
||||
if (Storage.ConfigSections.Settings.CUSTOM_PLUGIN.isCommand(command)) {
|
||||
|
||||
MessageTranslator.send(
|
||||
player,
|
||||
MessageHelper.sendMessage(
|
||||
sender,
|
||||
Storage.ConfigSections.Settings.CUSTOM_PLUGIN.MESSAGE,
|
||||
"%command%", StringUtils.getFirstArg(displayCommand)
|
||||
);
|
||||
@@ -108,9 +107,9 @@ public class BukkitBlockCommandListener implements Listener {
|
||||
Logger.info(notificationMessage);
|
||||
|
||||
Storage.NOTIFY_PLAYERS.forEach(uuid -> {
|
||||
Object p = Storage.getLoader().getPlayerObjByUUID(uuid);
|
||||
if (p != null) {
|
||||
MessageTranslator.send(p, notificationMessage);
|
||||
final CommandSender otherSender = CommandSender.from(uuid);
|
||||
if (otherSender != null) {
|
||||
MessageHelper.sendMessage(otherSender, notificationMessage);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -120,8 +119,8 @@ public class BukkitBlockCommandListener implements Listener {
|
||||
|
||||
if (Storage.ConfigSections.Settings.CUSTOM_VERSION.isCommand(command)) {
|
||||
|
||||
MessageTranslator.send(
|
||||
player,
|
||||
MessageHelper.sendMessage(
|
||||
sender,
|
||||
Storage.ConfigSections.Settings.CUSTOM_VERSION.MESSAGE,
|
||||
"%command%", StringUtils.getFirstArg(displayCommand)
|
||||
);
|
||||
@@ -132,7 +131,7 @@ public class BukkitBlockCommandListener implements Listener {
|
||||
Storage.NOTIFY_PLAYERS.forEach(uuid -> {
|
||||
Object p = Storage.getLoader().getPlayerObjByUUID(uuid);
|
||||
if (p != null) {
|
||||
MessageTranslator.send(p, notificationMessage);
|
||||
MessageHelper.sendMessage(sender, notificationMessage);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -169,7 +168,8 @@ public class BukkitBlockCommandListener implements Listener {
|
||||
if (executeCommandEvent.isBlocked()) {
|
||||
event.setCancelled(true);
|
||||
|
||||
MessageTranslator.send(
|
||||
|
||||
MessageHelper.sendMessage(
|
||||
sender,
|
||||
ResponseHandler.getResponse(
|
||||
sender.getUniqueId(),
|
||||
@@ -187,8 +187,8 @@ public class BukkitBlockCommandListener implements Listener {
|
||||
Logger.info(notificationMessage);
|
||||
|
||||
Storage.NOTIFY_PLAYERS.stream().filter(uuid -> Bukkit.getServer().getPlayer(uuid) != null).forEach(uuid -> {
|
||||
Player target = Bukkit.getServer().getPlayer(uuid);
|
||||
MessageTranslator.send(target, notificationMessage);
|
||||
final CommandSender otherSender = CommandSender.from(uuid);
|
||||
MessageHelper.sendMessage(otherSender, notificationMessage);
|
||||
});
|
||||
|
||||
}
|
||||
@@ -207,7 +207,7 @@ public class BukkitBlockCommandListener implements Listener {
|
||||
if (executeCommandEvent.isBlocked()) {
|
||||
event.setCancelled(true);
|
||||
|
||||
MessageTranslator.send(
|
||||
MessageHelper.sendMessage(
|
||||
sender,
|
||||
ResponseHandler.getResponse(
|
||||
sender.getUniqueId(),
|
||||
|
||||
@@ -7,7 +7,8 @@ import de.rayzs.pat.plugin.packetanalyzer.bukkit.BukkitPacketAnalyzer;
|
||||
import de.rayzs.pat.plugin.system.communication.BackendUpdater;
|
||||
import de.rayzs.pat.plugin.logger.Logger;
|
||||
import de.rayzs.pat.plugin.system.subargument.SubArgument;
|
||||
import de.rayzs.pat.utils.message.MessageTranslator;
|
||||
import de.rayzs.pat.utils.message.MessageHelper;
|
||||
import de.rayzs.pat.utils.message.replacer.PlaceholderReplacer;
|
||||
import de.rayzs.pat.utils.permission.PermissionPlugin;
|
||||
import de.rayzs.pat.utils.permission.PermissionUtil;
|
||||
import de.rayzs.pat.api.storage.Storage;
|
||||
@@ -52,19 +53,23 @@ public class BukkitPlayerListener implements Listener {
|
||||
}, 20);
|
||||
}
|
||||
|
||||
if (!BukkitPacketAnalyzer.inject(player)) {
|
||||
|
||||
final BukkitPacketAnalyzer.InjectionState injectionState = BukkitPacketAnalyzer.inject(player);
|
||||
|
||||
|
||||
if (injectionState == BukkitPacketAnalyzer.InjectionState.FAILED) {
|
||||
PATScheduler.createScheduler(() -> {
|
||||
if (player.isOnline()) {
|
||||
if (!BukkitPacketAnalyzer.inject(player)) {
|
||||
if (BukkitPacketAnalyzer.inject(player) == BukkitPacketAnalyzer.InjectionState.FAILED) {
|
||||
|
||||
if (Storage.ConfigSections.Settings.INJECTION_FAILED.ENABLED) {
|
||||
|
||||
Logger.info(MessageTranslator.replaceMessage(
|
||||
Logger.info(PlaceholderReplacer.applyPlaceholders(
|
||||
sender,
|
||||
Storage.ConfigSections.Settings.INJECTION_FAILED.CONSOLE_MESSAGE
|
||||
));
|
||||
|
||||
player.kickPlayer(MessageTranslator.replaceMessage(
|
||||
player.kickPlayer(PlaceholderReplacer.applyPlaceholders(
|
||||
sender,
|
||||
Storage.ConfigSections.Settings.INJECTION_FAILED.KICK_MESSAGE
|
||||
));
|
||||
@@ -73,12 +78,14 @@ public class BukkitPlayerListener implements Listener {
|
||||
}
|
||||
}
|
||||
}, 10);
|
||||
} else if (injectionState == BukkitPacketAnalyzer.InjectionState.SKIPPED) {
|
||||
Logger.warning("Skipped injection for " + player.getName() + ". Player seems to have a corrupted pipeline. (A fake player?)");
|
||||
}
|
||||
|
||||
if (Storage.OUTDATED && PermissionUtil.hasPermission(sender, "joinupdate", isOperator)) {
|
||||
PATScheduler.createScheduler(() -> {
|
||||
if (player.isOnline()) {
|
||||
MessageTranslator.send(player, Storage.ConfigSections.Settings.UPDATE.OUTDATED.getLines());
|
||||
MessageHelper.sendMessage(sender, Storage.ConfigSections.Settings.UPDATE.OUTDATED.getLines());
|
||||
}
|
||||
}, 20);
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import de.rayzs.pat.api.storage.Storage;
|
||||
import de.rayzs.pat.utils.ExpireCache;
|
||||
import de.rayzs.pat.utils.StringUtils;
|
||||
import de.rayzs.pat.utils.message.replacer.PlaceholderReplacer;
|
||||
import de.rayzs.pat.utils.sender.CommandSender;
|
||||
import org.bukkit.event.*;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.profile.PlayerTextures;
|
||||
@@ -105,7 +106,9 @@ public class PaperServerListPing implements Listener {
|
||||
.replace("%online%", String.valueOf(online))
|
||||
.replace("%max%", String.valueOf(max));
|
||||
|
||||
return replaced.contains("%") ? PlaceholderReplacer.replace(null, replaced) : replaced;
|
||||
return replaced.contains("%")
|
||||
? PlaceholderReplacer.applyPlaceholders(CommandSender.from(Bukkit.getConsoleSender()), replaced)
|
||||
: replaced;
|
||||
}
|
||||
|
||||
private static class ProtocolHoverLine implements PlayerProfile {
|
||||
@@ -218,7 +221,7 @@ public class PaperServerListPing implements Listener {
|
||||
}
|
||||
|
||||
@Override
|
||||
public org.bukkit.profile.@NotNull PlayerProfile clone() {
|
||||
public PlayerProfile clone() {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
+20
-18
@@ -6,7 +6,7 @@ import de.rayzs.pat.plugin.system.subargument.SubArgument;
|
||||
import de.rayzs.pat.utils.group.Group;
|
||||
import de.rayzs.pat.utils.group.GroupManager;
|
||||
import de.rayzs.pat.utils.permission.PermissionUtil;
|
||||
import de.rayzs.pat.utils.message.MessageTranslator;
|
||||
import de.rayzs.pat.utils.message.MessageHelper;
|
||||
import de.rayzs.pat.utils.response.ResponseHandler;
|
||||
import de.rayzs.pat.utils.sender.CommandSender;
|
||||
import net.md_5.bungee.api.event.ChatEvent;
|
||||
@@ -50,8 +50,8 @@ public class BungeeBlockCommandListener implements Listener {
|
||||
final String displayCommand = StringUtils.replaceTriggers(command, "", "\\", "<", ">", "&");
|
||||
|
||||
|
||||
final List<String> notificationMessage = MessageTranslator.replaceMessageList(
|
||||
Storage.ConfigSections.Messages.NOTIFICATION.ALERT,
|
||||
final String notificationMessage = StringUtils.replace(
|
||||
Storage.ConfigSections.Messages.NOTIFICATION.ALERT.getLines(),
|
||||
"%player%", player.getName(),
|
||||
"%command%", displayCommand,
|
||||
"%server%", serverName);
|
||||
@@ -60,8 +60,8 @@ public class BungeeBlockCommandListener implements Listener {
|
||||
|
||||
Communicator.Proxy2Backend.sendNotification(player.getUniqueId(), serverName, displayCommand);
|
||||
|
||||
MessageTranslator.send(
|
||||
player,
|
||||
MessageHelper.sendMessage(
|
||||
sender,
|
||||
Storage.ConfigSections.Settings.CUSTOM_PLUGIN.MESSAGE,
|
||||
"%command%", StringUtils.getFirstArg(displayCommand)
|
||||
);
|
||||
@@ -70,9 +70,10 @@ public class BungeeBlockCommandListener implements Listener {
|
||||
Logger.info(notificationMessage);
|
||||
|
||||
Storage.NOTIFY_PLAYERS.stream().forEach(uuid -> {
|
||||
Object p = Storage.getLoader().getPlayerObjByUUID(uuid);
|
||||
if (p != null) {
|
||||
MessageTranslator.send(p, notificationMessage);
|
||||
final CommandSender otherSender = CommandSender.from(uuid);
|
||||
|
||||
if (otherSender != null) {
|
||||
MessageHelper.sendMessage(otherSender, notificationMessage);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -84,8 +85,8 @@ public class BungeeBlockCommandListener implements Listener {
|
||||
|
||||
Communicator.Proxy2Backend.sendNotification(player.getUniqueId(), serverName, displayCommand);
|
||||
|
||||
MessageTranslator.send(
|
||||
player,
|
||||
MessageHelper.sendMessage(
|
||||
sender,
|
||||
Storage.ConfigSections.Settings.CUSTOM_VERSION.MESSAGE,
|
||||
"%command%", StringUtils.getFirstArg(displayCommand)
|
||||
);
|
||||
@@ -94,9 +95,10 @@ public class BungeeBlockCommandListener implements Listener {
|
||||
Logger.info(notificationMessage);
|
||||
|
||||
Storage.NOTIFY_PLAYERS.forEach(uuid -> {
|
||||
Object p = Storage.getLoader().getPlayerObjByUUID(uuid);
|
||||
if (p != null) {
|
||||
MessageTranslator.send(p, notificationMessage);
|
||||
final CommandSender otherSender = CommandSender.from(uuid);
|
||||
|
||||
if (otherSender != null) {
|
||||
MessageHelper.sendMessage(otherSender, notificationMessage);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -133,7 +135,7 @@ public class BungeeBlockCommandListener implements Listener {
|
||||
if (executeCommandEvent.isBlocked()) {
|
||||
event.setCancelled(true);
|
||||
|
||||
MessageTranslator.send(
|
||||
MessageHelper.sendMessage(
|
||||
sender,
|
||||
ResponseHandler.getResponse(
|
||||
sender.getUniqueId(),
|
||||
@@ -153,10 +155,10 @@ public class BungeeBlockCommandListener implements Listener {
|
||||
Logger.info(notificationMessage);
|
||||
|
||||
Storage.NOTIFY_PLAYERS.forEach(uuid -> {
|
||||
Object p = Storage.getLoader().getPlayerObjByUUID(uuid);
|
||||
final CommandSender otherSender = CommandSender.from(uuid);
|
||||
|
||||
if (p != null) {
|
||||
MessageTranslator.send(p, notificationMessage);
|
||||
if (otherSender != null) {
|
||||
MessageHelper.sendMessage(otherSender, notificationMessage);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -176,7 +178,7 @@ public class BungeeBlockCommandListener implements Listener {
|
||||
if (executeCommandEvent.isBlocked()) {
|
||||
event.setCancelled(true);
|
||||
|
||||
MessageTranslator.send(
|
||||
MessageHelper.sendMessage(
|
||||
sender,
|
||||
ResponseHandler.getResponse(
|
||||
sender.getUniqueId(),
|
||||
|
||||
+2
-2
@@ -6,7 +6,7 @@ import de.rayzs.pat.api.event.events.ServerPlayersChangeEvent;
|
||||
import de.rayzs.pat.plugin.packetanalyzer.proxy.BungeePacketAnalyzer;
|
||||
import de.rayzs.pat.plugin.system.subargument.SubArgument;
|
||||
import de.rayzs.pat.utils.permission.PermissionUtil;
|
||||
import de.rayzs.pat.utils.message.MessageTranslator;
|
||||
import de.rayzs.pat.utils.message.MessageHelper;
|
||||
import de.rayzs.pat.utils.sender.CommandSender;
|
||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||
|
||||
@@ -39,7 +39,7 @@ public class BungeePlayerConnectionListener implements Listener {
|
||||
if (Storage.OUTDATED && PermissionUtil.hasPermission(sender, "joinupdate", false)) {
|
||||
ProxyServer.getInstance().getScheduler().schedule(BungeeLoader.getPlugin(), () -> {
|
||||
if (player.isConnected()) {
|
||||
MessageTranslator.send(player, Storage.ConfigSections.Settings.UPDATE.OUTDATED, "%player%", player.getName());
|
||||
MessageHelper.sendMessage(sender, Storage.ConfigSections.Settings.UPDATE.OUTDATED, "%player%", player.getName());
|
||||
}
|
||||
}, 1, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
+25
-24
@@ -3,14 +3,12 @@ package de.rayzs.pat.plugin.listeners.velocity;
|
||||
import com.velocitypowered.api.event.Subscribe;
|
||||
import com.velocitypowered.api.event.command.CommandExecuteEvent;
|
||||
import com.velocitypowered.api.command.CommandSource;
|
||||
import de.rayzs.pat.plugin.logger.Logger;
|
||||
import de.rayzs.pat.plugin.system.communication.Communicator;
|
||||
import de.rayzs.pat.api.event.events.ExecuteCommandEvent;
|
||||
import de.rayzs.pat.plugin.system.subargument.SubArgument;
|
||||
import de.rayzs.pat.plugin.system.subargument.argument.Arguments;
|
||||
import de.rayzs.pat.utils.group.Group;
|
||||
import de.rayzs.pat.utils.group.GroupManager;
|
||||
import de.rayzs.pat.utils.message.MessageTranslator;
|
||||
import de.rayzs.pat.utils.message.MessageHelper;
|
||||
import de.rayzs.pat.utils.permission.PermissionUtil;
|
||||
import com.velocitypowered.api.proxy.Player;
|
||||
import de.rayzs.pat.api.storage.Storage;
|
||||
@@ -38,7 +36,7 @@ public class VelocityBlockCommandListener {
|
||||
}
|
||||
|
||||
final CommandSource commandSource = event.getCommandSource();
|
||||
final Object consoleSender = Storage.getLoader().getConsoleSender();
|
||||
final CommandSender consoleSender = CommandSender.from(Storage.getLoader().getConsoleSender());
|
||||
|
||||
if(! (commandSource instanceof Player))
|
||||
return event;
|
||||
@@ -64,8 +62,8 @@ public class VelocityBlockCommandListener {
|
||||
final String displayCommand = StringUtils.replaceTriggers(command, "", "\\", "<", ">", "&");
|
||||
|
||||
|
||||
final List<String> notificationMessage = MessageTranslator.replaceMessageList(
|
||||
Storage.ConfigSections.Messages.NOTIFICATION.ALERT,
|
||||
final String notificationMessage = StringUtils.replace(
|
||||
Storage.ConfigSections.Messages.NOTIFICATION.ALERT.getLines(),
|
||||
"%player%", player.getUsername(),
|
||||
"%command%", displayCommand,
|
||||
"%server%", serverName
|
||||
@@ -75,19 +73,20 @@ public class VelocityBlockCommandListener {
|
||||
|
||||
Communicator.Proxy2Backend.sendNotification(player.getUniqueId(), serverName, displayCommand);
|
||||
|
||||
MessageTranslator.send(
|
||||
player,
|
||||
MessageHelper.sendMessage(
|
||||
sender,
|
||||
Storage.ConfigSections.Settings.CUSTOM_PLUGIN.MESSAGE,
|
||||
"%command%", StringUtils.getFirstArg(displayCommand)
|
||||
);
|
||||
|
||||
if (Storage.SEND_CONSOLE_NOTIFICATION)
|
||||
MessageTranslator.send(consoleSender, notificationMessage);
|
||||
MessageHelper.sendMessage(consoleSender, notificationMessage);
|
||||
|
||||
Storage.NOTIFY_PLAYERS.forEach(uuid -> {
|
||||
Object p = Storage.getLoader().getPlayerObjByUUID(uuid);
|
||||
if (p != null) {
|
||||
MessageTranslator.send(p, notificationMessage);
|
||||
final CommandSender otherSender = CommandSender.from(uuid);
|
||||
|
||||
if (otherSender != null) {
|
||||
MessageHelper.sendMessage(otherSender, notificationMessage);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -99,19 +98,20 @@ public class VelocityBlockCommandListener {
|
||||
|
||||
Communicator.Proxy2Backend.sendNotification(player.getUniqueId(), serverName, displayCommand);
|
||||
|
||||
MessageTranslator.send(
|
||||
player,
|
||||
MessageHelper.sendMessage(
|
||||
sender,
|
||||
Storage.ConfigSections.Settings.CUSTOM_VERSION.MESSAGE,
|
||||
"%command%", StringUtils.getFirstArg(displayCommand)
|
||||
);
|
||||
|
||||
if (Storage.SEND_CONSOLE_NOTIFICATION)
|
||||
MessageTranslator.send(consoleSender, notificationMessage);
|
||||
MessageHelper.sendMessage(consoleSender, notificationMessage);
|
||||
|
||||
Storage.NOTIFY_PLAYERS.forEach(uuid -> {
|
||||
Object p = Storage.getLoader().getPlayerObjByUUID(uuid);
|
||||
if (p != null) {
|
||||
MessageTranslator.send(p, notificationMessage);
|
||||
final CommandSender otherSender = CommandSender.from(uuid);
|
||||
|
||||
if (otherSender != null) {
|
||||
MessageHelper.sendMessage(otherSender, notificationMessage);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -151,7 +151,7 @@ public class VelocityBlockCommandListener {
|
||||
if (executeCommandEvent.isBlocked()) {
|
||||
event.setResult(CommandExecuteEvent.CommandResult.denied());
|
||||
|
||||
MessageTranslator.send(
|
||||
MessageHelper.sendMessage(
|
||||
sender,
|
||||
ResponseHandler.getResponse(
|
||||
sender.getUniqueId(),
|
||||
@@ -168,12 +168,13 @@ public class VelocityBlockCommandListener {
|
||||
Communicator.Proxy2Backend.sendNotification(player.getUniqueId(), serverName, displayCommand);
|
||||
|
||||
if (Storage.SEND_CONSOLE_NOTIFICATION)
|
||||
MessageTranslator.send(consoleSender, notificationMessage);
|
||||
MessageHelper.sendMessage(consoleSender, notificationMessage);
|
||||
|
||||
Storage.NOTIFY_PLAYERS.forEach(uuid -> {
|
||||
Object p = Storage.getLoader().getPlayerObjByUUID(uuid);
|
||||
if (p != null) {
|
||||
MessageTranslator.send(p, notificationMessage);
|
||||
final CommandSender otherSender = CommandSender.from(uuid);
|
||||
|
||||
if (otherSender != null) {
|
||||
MessageHelper.sendMessage(otherSender, notificationMessage);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -209,7 +210,7 @@ public class VelocityBlockCommandListener {
|
||||
|
||||
event.setResult(CommandExecuteEvent.CommandResult.denied());
|
||||
|
||||
MessageTranslator.send(
|
||||
MessageHelper.sendMessage(
|
||||
sender,
|
||||
ResponseHandler.getResponse(
|
||||
sender.getUniqueId(),
|
||||
|
||||
+8
-7
@@ -8,7 +8,8 @@ import de.rayzs.pat.api.event.events.ServerPlayersChangeEvent;
|
||||
import de.rayzs.pat.plugin.packetanalyzer.proxy.VelocityPacketAnalyzer;
|
||||
import de.rayzs.pat.plugin.logger.Logger;
|
||||
import de.rayzs.pat.plugin.system.subargument.SubArgument;
|
||||
import de.rayzs.pat.utils.message.MessageTranslator;
|
||||
import de.rayzs.pat.utils.message.MessageHelper;
|
||||
import de.rayzs.pat.utils.message.replacer.PlaceholderReplacer;
|
||||
import de.rayzs.pat.utils.permission.PermissionUtil;
|
||||
import com.velocitypowered.api.event.Subscribe;
|
||||
import com.velocitypowered.api.event.player.*;
|
||||
@@ -55,7 +56,7 @@ public class VelocityConnectionListener {
|
||||
if (Storage.OUTDATED && PermissionUtil.hasPermission(sender, "joinupdate", false)) {
|
||||
server.getScheduler().buildTask(loader, () -> {
|
||||
if (player.isActive())
|
||||
MessageTranslator.send(player, Storage.ConfigSections.Settings.UPDATE.OUTDATED, "%player%", player.getUsername());
|
||||
MessageHelper.sendMessage(sender, Storage.ConfigSections.Settings.UPDATE.OUTDATED, "%player%", player.getUsername());
|
||||
}).delay(1, TimeUnit.SECONDS).schedule();
|
||||
}
|
||||
}
|
||||
@@ -63,6 +64,7 @@ public class VelocityConnectionListener {
|
||||
@Subscribe
|
||||
public void onServerSwitch(ServerConnectedEvent event) {
|
||||
final Player player = event.getPlayer();
|
||||
final CommandSender sender = CommandSender.from(player);
|
||||
|
||||
if (!VelocityPacketAnalyzer.isInjected(player)) {
|
||||
|
||||
@@ -71,14 +73,14 @@ public class VelocityConnectionListener {
|
||||
if (!VelocityPacketAnalyzer.inject(player)) {
|
||||
if (Storage.ConfigSections.Settings.INJECTION_FAILED.ENABLED) {
|
||||
|
||||
Logger.info(MessageTranslator.replaceMessage(
|
||||
player,
|
||||
Logger.info(PlaceholderReplacer.applyPlaceholders(
|
||||
sender,
|
||||
Storage.ConfigSections.Settings.INJECTION_FAILED.CONSOLE_MESSAGE
|
||||
));
|
||||
|
||||
player.disconnect(Component.text(
|
||||
MessageTranslator.replaceMessage(
|
||||
player,
|
||||
PlaceholderReplacer.applyPlaceholders(
|
||||
sender,
|
||||
Storage.ConfigSections.Settings.INJECTION_FAILED.KICK_MESSAGE
|
||||
)
|
||||
));
|
||||
@@ -93,7 +95,6 @@ public class VelocityConnectionListener {
|
||||
final ServerInfo serverInfo = event.getServer().getServerInfo();
|
||||
if (serverInfo != null) Storage.tempCachePlayerToServer(player.getUniqueId(), serverInfo.getName());
|
||||
|
||||
CommandSender sender = CommandSender.from(player);
|
||||
Objects.requireNonNull(sender);
|
||||
PermissionUtil.reloadPermissions(sender);
|
||||
}
|
||||
|
||||
@@ -1,13 +1,16 @@
|
||||
package de.rayzs.pat.plugin.logger.impl;
|
||||
|
||||
import de.rayzs.pat.utils.message.MessageTranslator;
|
||||
import de.rayzs.pat.utils.message.MessageHelper;
|
||||
import de.rayzs.pat.plugin.BukkitLoader;
|
||||
import de.rayzs.pat.plugin.logger.*;
|
||||
import de.rayzs.pat.utils.message.replacer.PlaceholderReplacer;
|
||||
import de.rayzs.pat.utils.sender.CommandSender;
|
||||
import org.bukkit.Bukkit;
|
||||
import java.util.*;
|
||||
|
||||
public class BukkitLogger implements LoggerTemplate {
|
||||
|
||||
private final CommandSender console = CommandSender.from(Bukkit.getServer().getConsoleSender());
|
||||
private final java.util.logging.Logger logger = BukkitLoader.getPluginLogger();
|
||||
|
||||
@Override
|
||||
@@ -37,10 +40,10 @@ public class BukkitLogger implements LoggerTemplate {
|
||||
|
||||
@Override
|
||||
public void send(LoggerPriority priority, String message) {
|
||||
message = MessageTranslator.replaceMessage(message);
|
||||
message = PlaceholderReplacer.applyPlaceholders(null, message);
|
||||
|
||||
if (message.contains("§")) {
|
||||
MessageTranslator.send(Bukkit.getServer().getConsoleSender(), message);
|
||||
MessageHelper.sendMessage(console, message);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,13 +1,17 @@
|
||||
package de.rayzs.pat.plugin.logger.impl;
|
||||
|
||||
import de.rayzs.pat.utils.message.MessageTranslator;
|
||||
import de.rayzs.pat.utils.message.MessageHelper;
|
||||
import de.rayzs.pat.plugin.BungeeLoader;
|
||||
import de.rayzs.pat.utils.message.replacer.PlaceholderReplacer;
|
||||
import de.rayzs.pat.utils.sender.CommandSender;
|
||||
import net.md_5.bungee.api.ProxyServer;
|
||||
import de.rayzs.pat.plugin.logger.*;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class BungeeLogger implements LoggerTemplate {
|
||||
|
||||
private final CommandSender console = CommandSender.from(ProxyServer.getInstance().getConsole());
|
||||
private final java.util.logging.Logger logger = BungeeLoader.getPluginLogger();
|
||||
|
||||
@Override
|
||||
@@ -37,10 +41,10 @@ public class BungeeLogger implements LoggerTemplate {
|
||||
|
||||
@Override
|
||||
public void send(LoggerPriority priority, String message) {
|
||||
message = MessageTranslator.replaceMessage(message);
|
||||
message = PlaceholderReplacer.applyPlaceholders(null, message);
|
||||
|
||||
if (message.contains("§")) {
|
||||
MessageTranslator.send(ProxyServer.getInstance().getConsole(), message);
|
||||
MessageHelper.sendMessage(console, message);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,13 +1,16 @@
|
||||
package de.rayzs.pat.plugin.logger.impl;
|
||||
|
||||
import de.rayzs.pat.utils.message.MessageTranslator;
|
||||
import de.rayzs.pat.utils.message.MessageHelper;
|
||||
import de.rayzs.pat.plugin.VelocityLoader;
|
||||
import de.rayzs.pat.plugin.logger.*;
|
||||
import de.rayzs.pat.utils.message.replacer.PlaceholderReplacer;
|
||||
import de.rayzs.pat.utils.sender.CommandSender;
|
||||
import org.slf4j.Logger;
|
||||
import java.util.*;
|
||||
|
||||
public class VelocityLogger implements LoggerTemplate {
|
||||
|
||||
private final CommandSender console = CommandSender.from(VelocityLoader.getServer().getConsoleCommandSource());
|
||||
private final Logger logger = VelocityLoader.getPluginLogger();
|
||||
|
||||
@Override
|
||||
@@ -37,10 +40,10 @@ public class VelocityLogger implements LoggerTemplate {
|
||||
|
||||
@Override
|
||||
public void send(LoggerPriority priority, String message) {
|
||||
message = MessageTranslator.replaceMessage(message);
|
||||
message = PlaceholderReplacer.applyPlaceholders(null, message);
|
||||
|
||||
if (message.contains("§")) {
|
||||
MessageTranslator.send(VelocityLoader.getServer().getConsoleCommandSource(), message);
|
||||
MessageHelper.sendMessage(console, message);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -53,15 +53,15 @@ public class BukkitPacketAnalyzer {
|
||||
channel.pipeline().writeAndFlush(object);
|
||||
}
|
||||
|
||||
public static boolean inject(Player player) {
|
||||
public static InjectionState inject(Player player) {
|
||||
if (Storage.ConfigSections.Settings.HANDLE_THROUGH_PROXY.ENABLED && !Storage.ConfigSections.Settings.HIDE_PLUGIN_CHANNELS.ENABLED)
|
||||
return true;
|
||||
return InjectionState.SKIPPED;
|
||||
|
||||
try {
|
||||
Channel channel = Reflection.getPlayerChannel(player);
|
||||
|
||||
if (channel == null) {
|
||||
return false;
|
||||
if (channel == null || !channel.pipeline().names().contains(PIPELINE_NAME)) {
|
||||
return InjectionState.SKIPPED;
|
||||
}
|
||||
|
||||
if (channel.pipeline().names().contains(BukkitPacketAnalyzer.HANDLER_NAME))
|
||||
@@ -77,36 +77,36 @@ public class BukkitPacketAnalyzer {
|
||||
// changed the compilation and therefore the variables again.
|
||||
|
||||
Reflection.toggleInjectionMethod();
|
||||
final boolean success = inject(player);
|
||||
final InjectionState state = inject(player);
|
||||
|
||||
if (!success) {
|
||||
if (state == InjectionState.FAILED) {
|
||||
Logger.warning("Both injection methods failed! Please report this back to me on my Discord! (https://www.rayzs.de/discord)");
|
||||
}
|
||||
|
||||
return success;
|
||||
return state;
|
||||
|
||||
} catch (NoSuchFieldException noSuchFieldException) {
|
||||
|
||||
if (!Storage.ConfigSections.Settings.INJECTION_FAILED.ENABLED) {
|
||||
return true;
|
||||
return InjectionState.SUCCESS;
|
||||
}
|
||||
|
||||
Logger.warning("Failed to inject into " + player.getName() + " and kicked the player as result, to avoid any security risks.");
|
||||
Logger.warning("You can read more about it here: https://www.rayzs.de/products/proantitab/pkafi");
|
||||
Logger.warning("Error details: " + noSuchFieldException.getMessage());
|
||||
|
||||
return false;
|
||||
return InjectionState.FAILED;
|
||||
|
||||
} catch (Exception exception) {
|
||||
if (!Storage.ConfigSections.Settings.INJECTION_FAILED.SUPPRESS_EXCEPTIONS) {
|
||||
exception.printStackTrace();
|
||||
}
|
||||
|
||||
return false;
|
||||
return InjectionState.FAILED;
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
return InjectionState.SUCCESS;
|
||||
}
|
||||
|
||||
public static void uninject(UUID uuid) {
|
||||
@@ -133,6 +133,10 @@ public class BukkitPacketAnalyzer {
|
||||
}
|
||||
}
|
||||
|
||||
public enum InjectionState {
|
||||
SUCCESS, FAILED, SKIPPED
|
||||
}
|
||||
|
||||
public static String getPlayerInput(Player player) {
|
||||
String input = PLAYER_INPUT_CACHE.get(player);
|
||||
PLAYER_INPUT_CACHE.remove(player);
|
||||
|
||||
+3
-3
@@ -23,7 +23,7 @@ import de.rayzs.pat.api.storage.Storage;
|
||||
import de.rayzs.pat.plugin.logger.Logger;
|
||||
import de.rayzs.pat.utils.Reflection;
|
||||
import de.rayzs.pat.utils.StringUtils;
|
||||
import de.rayzs.pat.utils.message.MessageTranslator;
|
||||
import de.rayzs.pat.utils.message.MessageHelper;
|
||||
import de.rayzs.pat.utils.scheduler.PATScheduler;
|
||||
|
||||
public class ModernPacketHandler implements BukkitPacketHandler {
|
||||
@@ -48,8 +48,8 @@ public class ModernPacketHandler implements BukkitPacketHandler {
|
||||
if (!text.isBlank() && text.charAt(0) != '/') text = '/' + text;
|
||||
|
||||
if (Storage.ConfigSections.Settings.PATCH_EXPLOITS.isMalicious(text)) {
|
||||
MessageTranslator.send(
|
||||
Bukkit.getConsoleSender(),
|
||||
MessageHelper.sendMessage(
|
||||
CommandSender.from(Bukkit.getConsoleSender()),
|
||||
Storage.ConfigSections.Settings.PATCH_EXPLOITS.ALERT_MESSAGE.get().replace("%player%", player.getName())
|
||||
);
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ import de.rayzs.pat.utils.Reflection;
|
||||
import de.rayzs.pat.utils.StringUtils;
|
||||
import de.rayzs.pat.utils.group.Group;
|
||||
import de.rayzs.pat.utils.group.GroupManager;
|
||||
import de.rayzs.pat.utils.message.MessageTranslator;
|
||||
import de.rayzs.pat.utils.message.MessageHelper;
|
||||
import de.rayzs.pat.utils.node.ProxyCommandNodeHelper;
|
||||
import de.rayzs.pat.utils.permission.PermissionUtil;
|
||||
import de.rayzs.pat.utils.sender.CommandSender;
|
||||
@@ -310,7 +310,7 @@ public class VelocityPacketAnalyzer {
|
||||
if (request.getCommand() != null) {
|
||||
|
||||
if (Storage.ConfigSections.Settings.PATCH_EXPLOITS.isMalicious(request.getCommand())) {
|
||||
MessageTranslator.send(VelocityLoader.getServer().getConsoleCommandSource(), Storage.ConfigSections.Settings.PATCH_EXPLOITS.ALERT_MESSAGE.get().replace("%player%", player.getUsername()));
|
||||
MessageHelper.sendMessage(CommandSender.from(VelocityLoader.getServer().getConsoleCommandSource()), Storage.ConfigSections.Settings.PATCH_EXPLOITS.ALERT_MESSAGE.get().replace("%player%", player.getUsername()));
|
||||
player.disconnect(LegacyComponentSerializer.legacyAmpersand().deserialize(Storage.ConfigSections.Settings.PATCH_EXPLOITS.KICK_MESSAGE.get()));
|
||||
} else {
|
||||
insertPlayerInput(player, request.getCommand());
|
||||
|
||||
@@ -186,10 +186,6 @@ public class Communicator {
|
||||
|
||||
// BACKEND -> PROXY
|
||||
public void handleB2PPacket(String serverName, CommunicationPackets.PATPacket incomingPacket) {
|
||||
if (!incomingPacket.tokenMatches(Storage.TOKEN)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (incomingPacket instanceof CommunicationPackets.Backend2Proxy.KeepAlivePacket packet) {
|
||||
final Client client = clients.get(serverName);
|
||||
if (client == null) return;
|
||||
@@ -253,10 +249,6 @@ public class Communicator {
|
||||
|
||||
// PROXY -> BACKEND
|
||||
public void handleP2BPacket(CommunicationPackets.PATPacket incomingPacket) {
|
||||
if (!incomingPacket.tokenMatches(Storage.TOKEN)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (incomingPacket instanceof CommunicationPackets.Proxy2Backend.KeepAliveResponsePacket packet) {
|
||||
|
||||
lastReceivedKeepAliveResponse = System.currentTimeMillis();
|
||||
|
||||
+6
-4
@@ -6,7 +6,8 @@ import de.rayzs.pat.plugin.system.communication.cph.CommunicationPacketHandler;
|
||||
import de.rayzs.pat.plugin.logger.Logger;
|
||||
import de.rayzs.pat.utils.CommunicationPackets;
|
||||
import de.rayzs.pat.utils.Reflection;
|
||||
import de.rayzs.pat.utils.message.MessageTranslator;
|
||||
import de.rayzs.pat.utils.StringUtils;
|
||||
import de.rayzs.pat.utils.message.MessageHelper;
|
||||
import de.rayzs.pat.utils.scheduler.PATScheduler;
|
||||
import de.rayzs.pat.utils.sender.CommandSender;
|
||||
import org.bukkit.Bukkit;
|
||||
@@ -59,12 +60,13 @@ public class BukkitCommunicationHandler implements CommunicationPacketHandler {
|
||||
return;
|
||||
}
|
||||
|
||||
final List<String> notificationMessage = MessageTranslator.replaceMessageList(
|
||||
Storage.ConfigSections.Messages.NOTIFICATION.ALERT,
|
||||
final String notificationMessage = StringUtils.replace(
|
||||
Storage.ConfigSections.Messages.NOTIFICATION.ALERT.getLines(),
|
||||
"%player%", player.getName(),
|
||||
"%command%", packet.command(),
|
||||
"%server%", Storage.SERVER_NAME,
|
||||
"%world%", player.getWorld().getName());
|
||||
"%world%", player.getWorld().getName()
|
||||
);
|
||||
|
||||
Logger.info(notificationMessage);
|
||||
}
|
||||
|
||||
+6
-1
@@ -80,7 +80,12 @@ public class BungeePluginMessageClient implements PluginMessageClient, Listener
|
||||
return;
|
||||
}
|
||||
|
||||
final Server server = (Server) event.getSender();
|
||||
// Private channel: never forward matching traffic between a player and backend.
|
||||
event.setCancelled(true);
|
||||
|
||||
if (!(event.getSender() instanceof Server server)) {
|
||||
return;
|
||||
}
|
||||
final String serverName = server.getInfo().getName();
|
||||
final UUID clientId = Communicator.get().getClientId(serverName);
|
||||
|
||||
|
||||
+8
-2
@@ -76,11 +76,17 @@ public class VelocityPluginMessageClient implements PluginMessageClient {
|
||||
|
||||
@Subscribe
|
||||
public void onQueryReceive(PluginMessageEvent event) {
|
||||
if (event.getIdentifier() != IDENTIFIER) {
|
||||
if (!IDENTIFIER.equals(event.getIdentifier())) {
|
||||
return;
|
||||
}
|
||||
|
||||
final ServerConnection server = (ServerConnection) event.getSource();
|
||||
// This is a private proxy/backend channel. Mark it handled before inspecting
|
||||
// the source so player-originated messages are never forwarded downstream.
|
||||
event.setResult(PluginMessageEvent.ForwardResult.handled());
|
||||
|
||||
if (!(event.getSource() instanceof ServerConnection server)) {
|
||||
return;
|
||||
}
|
||||
final String serverName = server.getServerInfo().getName();
|
||||
final UUID clientId = Communicator.get().getClientId(serverName);
|
||||
|
||||
|
||||
@@ -2,12 +2,15 @@ package de.rayzs.pat.plugin.system.serverbrand.impl;
|
||||
|
||||
import de.rayzs.pat.plugin.packetanalyzer.bukkit.BukkitPacketAnalyzer;
|
||||
import de.rayzs.pat.plugin.system.serverbrand.ServerBrand;
|
||||
import de.rayzs.pat.utils.message.MessageTranslator;
|
||||
import de.rayzs.pat.utils.message.MessageHelper;
|
||||
import de.rayzs.pat.api.storage.Storage;
|
||||
import de.rayzs.pat.plugin.BukkitLoader;
|
||||
import de.rayzs.pat.utils.message.replacer.PlaceholderReplacer;
|
||||
import de.rayzs.pat.utils.scheduler.PATScheduler;
|
||||
import de.rayzs.pat.utils.scheduler.PATSchedulerTask;
|
||||
import de.rayzs.pat.utils.sender.CommandSender;
|
||||
import io.netty.channel.Channel;
|
||||
import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import de.rayzs.pat.utils.*;
|
||||
@@ -137,7 +140,7 @@ public class BukkitServerBrand implements ServerBrand {
|
||||
|
||||
if (!Reflection.isWeird()) {
|
||||
final PacketUtils.BrandManipulate serverBrand = new PacketUtils.BrandManipulate(
|
||||
MessageTranslator.replaceMessage(player, customBrand)
|
||||
PlaceholderReplacer.applyPlaceholders(CommandSender.from(player), customBrand)
|
||||
);
|
||||
|
||||
player.sendPluginMessage(
|
||||
@@ -158,7 +161,7 @@ public class BukkitServerBrand implements ServerBrand {
|
||||
|
||||
final Object brandPayloadObj = brandPayloadClass
|
||||
.getDeclaredConstructor(String.class)
|
||||
.newInstance(MessageTranslator.replaceMessage(player, customBrand));
|
||||
.newInstance(PlaceholderReplacer.applyPlaceholders(CommandSender.from(player), customBrand));
|
||||
|
||||
final Object customPacketPayloadPacket = clientBoundCustomPacketPayloadPacketClass
|
||||
.getDeclaredConstructor(customPacketPayloadPacketClass)
|
||||
|
||||
@@ -2,7 +2,8 @@ package de.rayzs.pat.plugin.system.serverbrand.impl;
|
||||
|
||||
import de.rayzs.pat.plugin.system.serverbrand.ServerBrand;
|
||||
import de.rayzs.pat.utils.StringUtils;
|
||||
import de.rayzs.pat.utils.message.MessageTranslator;
|
||||
import de.rayzs.pat.utils.message.MessageHelper;
|
||||
import de.rayzs.pat.utils.message.replacer.PlaceholderReplacer;
|
||||
import net.md_5.bungee.api.scheduler.ScheduledTask;
|
||||
import net.md_5.bungee.protocol.ProtocolConstants;
|
||||
import net.md_5.bungee.api.connection.*;
|
||||
@@ -29,7 +30,7 @@ public class BungeeServerBrand implements ServerBrand {
|
||||
}
|
||||
|
||||
if (Storage.ConfigSections.Settings.CUSTOM_BRAND.REPEAT_DELAY == -1) {
|
||||
BRAND = MessageTranslator.replaceMessage(
|
||||
BRAND = PlaceholderReplacer.applyPlaceholders(null,
|
||||
Storage.ConfigSections.Settings.CUSTOM_BRAND.BRANDS.getLines().get(0)
|
||||
) + "§r";
|
||||
|
||||
@@ -46,7 +47,7 @@ public class BungeeServerBrand implements ServerBrand {
|
||||
public void run() {
|
||||
animationPos = (++animationPos) % length;
|
||||
|
||||
BRAND = MessageTranslator.replaceMessage(
|
||||
BRAND = PlaceholderReplacer.applyPlaceholders(null,
|
||||
Storage.ConfigSections.Settings.CUSTOM_BRAND.BRANDS.getLines().get(animationPos)
|
||||
) + "§r";
|
||||
|
||||
|
||||
@@ -2,7 +2,8 @@ package de.rayzs.pat.plugin.system.serverbrand.impl;
|
||||
|
||||
import com.velocitypowered.api.scheduler.ScheduledTask;
|
||||
import de.rayzs.pat.plugin.system.serverbrand.ServerBrand;
|
||||
import de.rayzs.pat.utils.message.MessageTranslator;
|
||||
import de.rayzs.pat.utils.message.MessageHelper;
|
||||
import de.rayzs.pat.utils.message.replacer.PlaceholderReplacer;
|
||||
import net.md_5.bungee.protocol.ProtocolConstants;
|
||||
import de.rayzs.pat.plugin.VelocityLoader;
|
||||
import de.rayzs.pat.api.storage.Storage;
|
||||
@@ -49,7 +50,7 @@ public class VelocityServerBrand implements ServerBrand {
|
||||
}
|
||||
|
||||
if (Storage.ConfigSections.Settings.CUSTOM_BRAND.REPEAT_DELAY == -1) {
|
||||
BRAND = MessageTranslator.replaceMessage(Storage.ConfigSections.Settings.CUSTOM_BRAND.BRANDS.getLines().get(0)) + "§r";
|
||||
BRAND = PlaceholderReplacer.applyPlaceholders(null, Storage.ConfigSections.Settings.CUSTOM_BRAND.BRANDS.getLines().get(0)) + "§r";
|
||||
SERVER.getAllPlayers().forEach(this::send);
|
||||
} else {
|
||||
TASK = SERVER.getScheduler().buildTask(VelocityLoader.getInstance(), new Runnable() {
|
||||
@@ -61,7 +62,7 @@ public class VelocityServerBrand implements ServerBrand {
|
||||
public void run() {
|
||||
animationPos = (++animationPos) % length;
|
||||
|
||||
BRAND = MessageTranslator.replaceMessage(
|
||||
BRAND = PlaceholderReplacer.applyPlaceholders(null,
|
||||
Storage.ConfigSections.Settings.CUSTOM_BRAND.BRANDS.getLines().get(animationPos)
|
||||
) + "§r";
|
||||
|
||||
|
||||
@@ -1,50 +1,93 @@
|
||||
package de.rayzs.pat.utils;
|
||||
|
||||
import de.rayzs.pat.plugin.system.communication.Communicator;
|
||||
import de.rayzs.pat.api.storage.Storage;
|
||||
import de.rayzs.pat.plugin.system.communication.Communicator;
|
||||
import de.rayzs.pat.utils.configuration.helper.MultipleMessagesHelper;
|
||||
|
||||
import java.util.*;
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.Mac;
|
||||
import javax.crypto.spec.GCMParameterSpec;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
import java.io.*;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.security.SecureRandom;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Wire codec for communication between proxy and backend servers.
|
||||
*
|
||||
* <p>Packets are explicitly encoded and protected with AES-256-GCM before
|
||||
* transmission. Encryption keys are derived from {@link Storage#TOKEN},
|
||||
* using backend UUIDs only as derivation context.
|
||||
*
|
||||
* <p>The codec does not use native Java deserialization for network data,
|
||||
* and all variable-length fields are bounded before allocation.
|
||||
*/
|
||||
public class CommunicationPackets {
|
||||
|
||||
|
||||
public static final byte PROTOCOL_VERSION = 1;
|
||||
private static final byte INIT_PACKET = 0;
|
||||
private static final byte NOT_INIT_PACKET = 1;
|
||||
|
||||
private static final int HEADER_LENGTH = 2;
|
||||
private static final int NONCE_LENGTH = 12;
|
||||
private static final int GCM_TAG_BITS = 128;
|
||||
private static final int GCM_TAG_LENGTH = GCM_TAG_BITS / 8;
|
||||
// Velocity defaults to 32,767 bytes for plugin message payloads.
|
||||
private static final int MAX_WIRE_BYTES = 32_767;
|
||||
private static final int MAX_PLAINTEXT_BYTES = MAX_WIRE_BYTES - HEADER_LENGTH - NONCE_LENGTH - GCM_TAG_LENGTH;
|
||||
private static final SecureRandom RANDOM = new SecureRandom();
|
||||
private static final byte[] HKDF_SALT = "ProAntiTab/plugin-messaging/v1".getBytes(StandardCharsets.UTF_8);
|
||||
|
||||
// Stable packet IDs. Do not reorder/reuse IDs without a protocol-version bump.
|
||||
private static final byte P_UPDATE = 1;
|
||||
private static final byte P_IDENTITY = 2;
|
||||
private static final byte P_NOTIFICATION = 3;
|
||||
private static final byte P_EXEC_CONSOLE = 4;
|
||||
private static final byte P_EXEC_PLAYER = 5;
|
||||
private static final byte P_CONSOLE_MESSAGE = 6;
|
||||
private static final byte P_KEEPALIVE_RESPONSE = 7;
|
||||
private static final byte P_DATA_SYNC = 8;
|
||||
private static final byte P_IDENTITY_REQUEST = 20;
|
||||
private static final byte P_IDENTITY_RESPONSE = 21;
|
||||
private static final byte P_DATA_SYNC_RECEIVED = 22;
|
||||
private static final byte P_KEEPALIVE = 23;
|
||||
private static final byte P_PLAYER_PERMISSION_CHANGE = 24;
|
||||
private static final byte P_GROUP_PERMISSION_CHANGE = 25;
|
||||
|
||||
public static byte[] preparePacket(Object object) {
|
||||
return preparePacket(object, Communicator.get().getId());
|
||||
}
|
||||
|
||||
public static byte[] preparePacket(Object object, UUID id) {
|
||||
if (!isValidPacket(object)) {
|
||||
if (!isValidPacket(object) || Storage.TOKEN == null || Storage.TOKEN.isBlank()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final boolean isInitialPacket = isInitialPacket(object);
|
||||
final ByteArrayOutputStream arrayOutputStream = new ByteArrayOutputStream();
|
||||
try {
|
||||
final boolean initial = isInitialPacket(object);
|
||||
if (!initial && id == null) {
|
||||
return null;
|
||||
}
|
||||
final byte[] plaintext = encodePacket((PATPacket) object);
|
||||
final byte[] nonce = new byte[NONCE_LENGTH];
|
||||
RANDOM.nextBytes(nonce);
|
||||
|
||||
try (ObjectOutputStream outputStream = new ObjectOutputStream(arrayOutputStream)) {
|
||||
outputStream.writeObject(object);
|
||||
outputStream.flush();
|
||||
// Wire format: [version:1][init:1][nonce:12][ciphertext + GCM tag:16].
|
||||
// The version and init flag are authenticated as GCM additional authenticated data.
|
||||
final byte[] header = new byte[]{PROTOCOL_VERSION, initial ? INIT_PACKET : NOT_INIT_PACKET};
|
||||
final SecretKeySpec key = deriveKey(Storage.TOKEN, initial ? null : id);
|
||||
final byte[] ciphertext = encrypt(plaintext, key, nonce, header);
|
||||
|
||||
final byte[] encryptedBytes = xor(arrayOutputStream.toByteArray(), isInitialPacket
|
||||
? Storage.TOKEN
|
||||
: id.toString()
|
||||
);
|
||||
|
||||
final byte[] bytes = new byte[encryptedBytes.length + 1];
|
||||
|
||||
bytes[0] = isInitialPacket ? INIT_PACKET : NOT_INIT_PACKET;
|
||||
System.arraycopy(encryptedBytes, 0, bytes, 1, bytes.length - 1);
|
||||
|
||||
return bytes;
|
||||
|
||||
} catch (Exception ignored) { }
|
||||
|
||||
return null;
|
||||
final byte[] result = new byte[header.length + NONCE_LENGTH + ciphertext.length];
|
||||
System.arraycopy(header, 0, result, 0, header.length);
|
||||
System.arraycopy(nonce, 0, result, header.length, NONCE_LENGTH);
|
||||
System.arraycopy(ciphertext, 0, result, header.length + NONCE_LENGTH, ciphertext.length);
|
||||
return result;
|
||||
} catch (IOException | GeneralSecurityException ignored) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static Object readPacket(byte[] bytes) {
|
||||
@@ -52,147 +95,265 @@ public class CommunicationPackets {
|
||||
}
|
||||
|
||||
public static Object readPacket(byte[] bytes, UUID id) {
|
||||
if (bytes.length == 0) {
|
||||
if (bytes == null || bytes.length < HEADER_LENGTH + NONCE_LENGTH + GCM_TAG_LENGTH
|
||||
|| bytes.length > MAX_WIRE_BYTES || Storage.TOKEN == null || Storage.TOKEN.isBlank()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final byte init = bytes[0];
|
||||
bytes = Arrays.copyOfRange(bytes, 1, bytes.length);
|
||||
|
||||
bytes = xor(bytes, isInitialPacket(init)
|
||||
? Storage.TOKEN
|
||||
: id.toString()
|
||||
);
|
||||
|
||||
final ByteArrayInputStream arrayInputStream = new ByteArrayInputStream(bytes);
|
||||
|
||||
try (ObjectInput input = new ObjectInputStream(arrayInputStream)) {
|
||||
final Object object = input.readObject();
|
||||
|
||||
if (object.getClass() == null || !isValidPacket(object)) {
|
||||
try {
|
||||
final byte version = bytes[0];
|
||||
final byte initFlag = bytes[1];
|
||||
if (version != PROTOCOL_VERSION || (initFlag != INIT_PACKET && initFlag != NOT_INIT_PACKET)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return object;
|
||||
} catch (Exception ignored) { }
|
||||
final boolean initial = initFlag == INIT_PACKET;
|
||||
if (!initial && id == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return null;
|
||||
final byte[] header = Arrays.copyOfRange(bytes, 0, 2);
|
||||
final byte[] nonce = Arrays.copyOfRange(bytes, 2, 2 + NONCE_LENGTH);
|
||||
final byte[] ciphertext = Arrays.copyOfRange(bytes, 2 + NONCE_LENGTH, bytes.length);
|
||||
|
||||
final SecretKeySpec key = deriveKey(Storage.TOKEN, initial ? null : id);
|
||||
// Authentication is verified by GCM before decodePacket() sees any plaintext.
|
||||
final byte[] plaintext = decrypt(ciphertext, key, nonce, header);
|
||||
return decodePacket(plaintext, initial);
|
||||
} catch (IOException | GeneralSecurityException ignored) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// Yes, I am aware that xor is not the best encryption out there,
|
||||
// but it will suffice for now since the encryption shouldn't be too heavy.
|
||||
private static byte[] xor(byte[] bytes, String key) {
|
||||
final byte[] output = new byte[bytes.length];
|
||||
final byte[] secret = key.getBytes();
|
||||
private static SecretKeySpec deriveKey(String token, UUID id) throws GeneralSecurityException {
|
||||
// RFC 5869 HKDF-SHA-256. The token is the input keying material; the UUID is
|
||||
// public context used to separate normal-session keys between backend identities.
|
||||
final Mac mac = Mac.getInstance("HmacSHA256");
|
||||
|
||||
int pos = 0;
|
||||
// HKDF-Extract(salt, IKM)
|
||||
mac.init(new SecretKeySpec(HKDF_SALT, "HmacSHA256"));
|
||||
final byte[] prk = mac.doFinal(token.getBytes(StandardCharsets.UTF_8));
|
||||
|
||||
for (int i = 0; i < bytes.length; i++) {
|
||||
output[i] = (byte) (bytes[i] ^ secret[pos]);
|
||||
pos += 1;
|
||||
// HKDF-Expand(PRK, info, 32). One HMAC block is sufficient for an AES-256 key.
|
||||
final String context = id == null ? "initial" : "backend:" + id;
|
||||
final byte[] info = context.getBytes(StandardCharsets.UTF_8);
|
||||
mac.init(new SecretKeySpec(prk, "HmacSHA256"));
|
||||
mac.update(info);
|
||||
mac.update((byte) 0x01);
|
||||
final byte[] okm = mac.doFinal();
|
||||
return new SecretKeySpec(okm, "AES");
|
||||
}
|
||||
|
||||
if (pos >= secret.length) {
|
||||
pos = 0;
|
||||
private static byte[] encrypt(byte[] plaintext, SecretKeySpec key, byte[] nonce, byte[] aad) throws GeneralSecurityException {
|
||||
final Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
|
||||
cipher.init(Cipher.ENCRYPT_MODE, key, new GCMParameterSpec(GCM_TAG_BITS, nonce));
|
||||
cipher.updateAAD(aad);
|
||||
return cipher.doFinal(plaintext);
|
||||
}
|
||||
|
||||
private static byte[] decrypt(byte[] ciphertext, SecretKeySpec key, byte[] nonce, byte[] aad) throws GeneralSecurityException {
|
||||
final Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
|
||||
cipher.init(Cipher.DECRYPT_MODE, key, new GCMParameterSpec(GCM_TAG_BITS, nonce));
|
||||
cipher.updateAAD(aad);
|
||||
return cipher.doFinal(ciphertext);
|
||||
}
|
||||
|
||||
private static byte[] encodePacket(PATPacket packet) throws IOException {
|
||||
final ByteArrayOutputStream buffer = new ByteArrayOutputStream();
|
||||
try (DataOutputStream out = new DataOutputStream(new BoundedOutputStream(buffer, MAX_PLAINTEXT_BYTES))) {
|
||||
if (packet instanceof Proxy2Backend.UpdatePacket p) {
|
||||
out.writeByte(P_UPDATE); writeNullableUuid(out, p.playerId());
|
||||
} else if (packet instanceof Proxy2Backend.IdentityPacket p) {
|
||||
out.writeByte(P_IDENTITY); writeUuid(out, p.targetServerId()); writeString(out, p.serverName());
|
||||
} else if (packet instanceof Proxy2Backend.NotificationPacket p) {
|
||||
out.writeByte(P_NOTIFICATION); writeUuid(out, p.playerId()); writeString(out, p.command());
|
||||
} else if (packet instanceof Proxy2Backend.ExecuteConsoleCommandPacket p) {
|
||||
out.writeByte(P_EXEC_CONSOLE); writeString(out, p.command());
|
||||
} else if (packet instanceof Proxy2Backend.ExecutePlayerCommandPacket p) {
|
||||
out.writeByte(P_EXEC_PLAYER); writeUuid(out, p.playerId()); writeString(out, p.command());
|
||||
} else if (packet instanceof Proxy2Backend.ConsoleMessagePacket p) {
|
||||
out.writeByte(P_CONSOLE_MESSAGE); writeString(out, p.message());
|
||||
} else if (packet instanceof Proxy2Backend.KeepAliveResponsePacket) {
|
||||
out.writeByte(P_KEEPALIVE_RESPONSE);
|
||||
} else if (packet instanceof Proxy2Backend.DataSyncPacket p) {
|
||||
out.writeByte(P_DATA_SYNC);
|
||||
writeString(out, p.messages().prefix());
|
||||
out.writeBoolean(p.autoLowerCase().enabled());
|
||||
out.writeBoolean(p.unknownCommand().enabled());
|
||||
final List<String> lines = p.unknownCommand().message().getLines();
|
||||
out.writeInt(lines.size());
|
||||
for (String line : lines) writeString(out, line);
|
||||
} else if (packet instanceof Backend2Proxy.IdentityRequestPacket p) {
|
||||
out.writeByte(P_IDENTITY_REQUEST); writeUuid(out, p.serverId());
|
||||
} else if (packet instanceof Backend2Proxy.IdentityResponsePacket p) {
|
||||
out.writeByte(P_IDENTITY_RESPONSE); writeUuid(out, p.serverId());
|
||||
} else if (packet instanceof Backend2Proxy.DataSyncReceivedPacket) {
|
||||
out.writeByte(P_DATA_SYNC_RECEIVED);
|
||||
} else if (packet instanceof Backend2Proxy.KeepAlivePacket) {
|
||||
out.writeByte(P_KEEPALIVE);
|
||||
} else if (packet instanceof Backend2Proxy.AnnouncePlayerPermissionChanges p) {
|
||||
out.writeByte(P_PLAYER_PERMISSION_CHANGE); writeUuid(out, p.playerId());
|
||||
} else if (packet instanceof Backend2Proxy.AnnounceGroupPermissionChanges p) {
|
||||
out.writeByte(P_GROUP_PERMISSION_CHANGE);
|
||||
out.writeInt(p.playerIds().size());
|
||||
for (UUID uuid : p.playerIds()) writeUuid(out, uuid);
|
||||
} else {
|
||||
throw new IOException("Unknown packet type");
|
||||
}
|
||||
}
|
||||
|
||||
return output;
|
||||
if (buffer.size() > MAX_PLAINTEXT_BYTES) throw new IOException("Packet too large");
|
||||
return buffer.toByteArray();
|
||||
}
|
||||
|
||||
public static boolean isValidPacket(Object object) {
|
||||
return object instanceof PATPacket;
|
||||
}
|
||||
private static PATPacket decodePacket(byte[] bytes, boolean initial) throws IOException {
|
||||
if (bytes.length == 0 || bytes.length > MAX_PLAINTEXT_BYTES) throw new IOException("Invalid packet length");
|
||||
try (DataInputStream in = new DataInputStream(new ByteArrayInputStream(bytes))) {
|
||||
final int type = in.readUnsignedByte();
|
||||
final PATPacket packet = switch (type) {
|
||||
case P_UPDATE -> new Proxy2Backend.UpdatePacket(readNullableUuid(in));
|
||||
case P_IDENTITY -> new Proxy2Backend.IdentityPacket(readUuid(in), readString(in));
|
||||
case P_NOTIFICATION -> new Proxy2Backend.NotificationPacket(readUuid(in), readString(in));
|
||||
case P_EXEC_CONSOLE -> new Proxy2Backend.ExecuteConsoleCommandPacket(readString(in));
|
||||
case P_EXEC_PLAYER -> new Proxy2Backend.ExecutePlayerCommandPacket(readUuid(in), readString(in));
|
||||
case P_CONSOLE_MESSAGE -> new Proxy2Backend.ConsoleMessagePacket(readString(in));
|
||||
case P_KEEPALIVE_RESPONSE -> new Proxy2Backend.KeepAliveResponsePacket();
|
||||
case P_DATA_SYNC -> {
|
||||
final Proxy2Backend.DataSyncPacket.Messages messages =
|
||||
new Proxy2Backend.DataSyncPacket.Messages(readString(in));
|
||||
final Proxy2Backend.DataSyncPacket.AutoLowerCase autoLowerCase =
|
||||
new Proxy2Backend.DataSyncPacket.AutoLowerCase(in.readBoolean());
|
||||
final boolean unknownEnabled = in.readBoolean();
|
||||
final int count = readCount(in, Integer.BYTES);
|
||||
final List<String> lines = new ArrayList<>(count);
|
||||
for (int i = 0; i < count; i++) lines.add(readString(in));
|
||||
final Proxy2Backend.DataSyncPacket.UnknownCommand unknown =
|
||||
new Proxy2Backend.DataSyncPacket.UnknownCommand(
|
||||
unknownEnabled, new MultipleMessagesHelper(lines));
|
||||
yield new Proxy2Backend.DataSyncPacket(messages, autoLowerCase, unknown);
|
||||
}
|
||||
case P_IDENTITY_REQUEST -> new Backend2Proxy.IdentityRequestPacket(readUuid(in));
|
||||
case P_IDENTITY_RESPONSE -> new Backend2Proxy.IdentityResponsePacket(readUuid(in));
|
||||
case P_DATA_SYNC_RECEIVED -> new Backend2Proxy.DataSyncReceivedPacket();
|
||||
case P_KEEPALIVE -> new Backend2Proxy.KeepAlivePacket();
|
||||
case P_PLAYER_PERMISSION_CHANGE -> new Backend2Proxy.AnnouncePlayerPermissionChanges(readUuid(in));
|
||||
case P_GROUP_PERMISSION_CHANGE -> {
|
||||
final int count = readCount(in, 2 * Long.BYTES);
|
||||
final Set<UUID> ids = new HashSet<>(Math.max(16, count));
|
||||
for (int i = 0; i < count; i++) ids.add(readUuid(in));
|
||||
yield new Backend2Proxy.AnnounceGroupPermissionChanges(ids);
|
||||
}
|
||||
default -> throw new IOException("Unknown packet type: " + type);
|
||||
};
|
||||
|
||||
public static boolean isP2BPacket(Object object) {
|
||||
return object instanceof P2BPacket;
|
||||
}
|
||||
|
||||
public static boolean isB2PPacket(Object object) {
|
||||
return object instanceof B2PPacket;
|
||||
}
|
||||
|
||||
public static boolean isInitialPacket(Object object) {
|
||||
return object instanceof InitialPacket;
|
||||
}
|
||||
|
||||
public static boolean isInitialPacket(byte[] bytes) {
|
||||
return bytes.length > 0 && isInitialPacket(bytes[0]);
|
||||
}
|
||||
|
||||
public static boolean isInitialPacket(byte b) {
|
||||
return b == INIT_PACKET;
|
||||
}
|
||||
|
||||
public interface PATPacket extends Serializable {
|
||||
String token = Storage.TOKEN;
|
||||
|
||||
default boolean tokenMatches(String token) {
|
||||
return PATPacket.token.equals(token);
|
||||
if (in.available() != 0) throw new IOException("Trailing packet data");
|
||||
if (initial != isInitialPacket(packet)) throw new IOException("Packet/header type mismatch");
|
||||
return packet;
|
||||
}
|
||||
}
|
||||
|
||||
// Reject oversized plaintext as it is written, rather than after allocating it.
|
||||
private static final class BoundedOutputStream extends FilterOutputStream {
|
||||
private final int limit;
|
||||
private int written;
|
||||
|
||||
private interface InitialPacket extends PATPacket {}
|
||||
private interface Synchronizable extends Serializable {}
|
||||
private BoundedOutputStream(OutputStream out, int limit) {
|
||||
super(out);
|
||||
this.limit = limit;
|
||||
}
|
||||
|
||||
private interface P2BPacket extends PATPacket {}
|
||||
private interface B2PPacket extends PATPacket {}
|
||||
@Override
|
||||
public void write(int value) throws IOException {
|
||||
if (written >= limit) throw new IOException("Packet too large");
|
||||
out.write(value);
|
||||
written++;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(byte[] bytes, int offset, int length) throws IOException {
|
||||
if (length > limit - written) throw new IOException("Packet too large");
|
||||
out.write(bytes, offset, length);
|
||||
written += length;
|
||||
}
|
||||
}
|
||||
|
||||
private static void writeString(DataOutputStream out, String value) throws IOException {
|
||||
if (value == null) throw new IOException("Null string");
|
||||
final byte[] bytes = value.getBytes(StandardCharsets.UTF_8);
|
||||
out.writeInt(bytes.length);
|
||||
out.write(bytes);
|
||||
}
|
||||
|
||||
private static String readString(DataInputStream in) throws IOException {
|
||||
final int length = in.readInt();
|
||||
if (length < 0 || length > in.available()) {
|
||||
throw new IOException("Invalid string length");
|
||||
}
|
||||
return new String(in.readNBytes(length), StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
private static int readCount(DataInputStream in, int minimumEntryBytes) throws IOException {
|
||||
final int count = in.readInt();
|
||||
if (count < 0 || count > in.available() / minimumEntryBytes) {
|
||||
throw new IOException("Invalid collection size");
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
private static void writeUuid(DataOutputStream out, UUID uuid) throws IOException {
|
||||
if (uuid == null) throw new IOException("Null UUID");
|
||||
out.writeLong(uuid.getMostSignificantBits());
|
||||
out.writeLong(uuid.getLeastSignificantBits());
|
||||
}
|
||||
|
||||
private static UUID readUuid(DataInputStream in) throws IOException {
|
||||
return new UUID(in.readLong(), in.readLong());
|
||||
}
|
||||
|
||||
private static void writeNullableUuid(DataOutputStream out, UUID uuid) throws IOException {
|
||||
out.writeBoolean(uuid != null);
|
||||
if (uuid != null) writeUuid(out, uuid);
|
||||
}
|
||||
|
||||
private static UUID readNullableUuid(DataInputStream in) throws IOException {
|
||||
return in.readBoolean() ? readUuid(in) : null;
|
||||
}
|
||||
|
||||
public static boolean isValidPacket(Object object) { return object instanceof PATPacket; }
|
||||
public static boolean isP2BPacket(Object object) { return object instanceof P2BPacket; }
|
||||
public static boolean isB2PPacket(Object object) { return object instanceof B2PPacket; }
|
||||
public static boolean isInitialPacket(Object object) { return object instanceof InitialPacket; }
|
||||
// Routing hint only; the flag is authenticated by readPacket().
|
||||
public static boolean isInitialPacket(byte[] bytes) { return bytes != null && bytes.length > 1 && bytes[0] == PROTOCOL_VERSION && bytes[1] == INIT_PACKET; }
|
||||
|
||||
public interface PATPacket { }
|
||||
private interface InitialPacket extends PATPacket { }
|
||||
private interface Synchronizable { }
|
||||
private interface P2BPacket extends PATPacket { }
|
||||
private interface B2PPacket extends PATPacket { }
|
||||
|
||||
public static class Proxy2Backend {
|
||||
|
||||
private Proxy2Backend() { }
|
||||
|
||||
public record UpdatePacket(UUID playerId) implements P2BPacket {
|
||||
public boolean forEveryone() { return playerId == null; }
|
||||
}
|
||||
|
||||
public record UpdatePacket(UUID playerId) implements P2BPacket { public boolean forEveryone() { return playerId == null; } }
|
||||
public record IdentityPacket(UUID targetServerId, String serverName) implements InitialPacket, P2BPacket { }
|
||||
|
||||
public record NotificationPacket(UUID playerId, String command) implements P2BPacket { }
|
||||
|
||||
public record ExecuteConsoleCommandPacket(String command) implements P2BPacket { }
|
||||
|
||||
public record ExecutePlayerCommandPacket(UUID playerId, String command) implements P2BPacket { }
|
||||
|
||||
public record ConsoleMessagePacket(String message) implements P2BPacket { }
|
||||
|
||||
public record KeepAliveResponsePacket() implements P2BPacket { }
|
||||
|
||||
public record DataSyncPacket(
|
||||
Messages messages,
|
||||
AutoLowerCase autoLowerCase,
|
||||
UnknownCommand unknownCommand
|
||||
) implements P2BPacket {
|
||||
|
||||
public record Messages(String prefix)
|
||||
implements Synchronizable {}
|
||||
|
||||
public record AutoLowerCase(boolean enabled)
|
||||
implements Synchronizable {}
|
||||
|
||||
public record UnknownCommand(boolean enabled, MultipleMessagesHelper message)
|
||||
implements Synchronizable {}
|
||||
|
||||
public record DataSyncPacket(Messages messages, AutoLowerCase autoLowerCase, UnknownCommand unknownCommand) implements P2BPacket {
|
||||
public record Messages(String prefix) implements Synchronizable { }
|
||||
public record AutoLowerCase(boolean enabled) implements Synchronizable { }
|
||||
public record UnknownCommand(boolean enabled, MultipleMessagesHelper message) implements Synchronizable { }
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class Backend2Proxy {
|
||||
|
||||
private Backend2Proxy() { }
|
||||
|
||||
public record IdentityRequestPacket(UUID serverId) implements InitialPacket, B2PPacket { }
|
||||
|
||||
public record IdentityResponsePacket(UUID serverId) implements InitialPacket, B2PPacket { }
|
||||
|
||||
public record DataSyncReceivedPacket() implements B2PPacket { }
|
||||
|
||||
public record KeepAlivePacket() implements B2PPacket { }
|
||||
|
||||
public record AnnouncePlayerPermissionChanges(UUID playerId) implements B2PPacket { }
|
||||
|
||||
public record AnnounceGroupPermissionChanges(Set<UUID> playerIds) implements B2PPacket { }
|
||||
|
||||
}
|
||||
}
|
||||
@@ -66,10 +66,14 @@ public class Reflection {
|
||||
return software == Software.FOLIA;
|
||||
}
|
||||
|
||||
public static boolean isCraftbukkit() {
|
||||
public static boolean isBukkit() {
|
||||
return software == Software.BUKKIT;
|
||||
}
|
||||
|
||||
public static boolean isSpigot() {
|
||||
return software == Software.SPIGOT;
|
||||
}
|
||||
|
||||
public static boolean isArclight() {
|
||||
return software == Software.ARCLIGHT;
|
||||
}
|
||||
@@ -77,6 +81,11 @@ public class Reflection {
|
||||
public static boolean isProxyServer() {
|
||||
return software.isProxySoftware();
|
||||
}
|
||||
|
||||
public static boolean isBungeeServer() {
|
||||
return software == Software.BUNGEECORD;
|
||||
}
|
||||
|
||||
public static boolean isVelocityServer() {
|
||||
return software == Software.VELOCITY;
|
||||
}
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
package de.rayzs.pat.utils;
|
||||
|
||||
import de.rayzs.pat.utils.message.MessageTranslator;
|
||||
import de.rayzs.pat.utils.message.MessageHelper;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.MessageDigest;
|
||||
import java.util.*;
|
||||
|
||||
public class StringUtils {
|
||||
@@ -26,7 +24,7 @@ public class StringUtils {
|
||||
String line = lines.get(i);
|
||||
|
||||
if (line.startsWith(centerVariable)) {
|
||||
line = MessageTranslator.colorless(line.substring(centerVariable.length()));
|
||||
line = MessageHelper.strip(line.substring(centerVariable.length()));
|
||||
|
||||
int size = line.length();
|
||||
sizes.put(i, size);
|
||||
@@ -51,31 +49,6 @@ public class StringUtils {
|
||||
}
|
||||
}
|
||||
|
||||
public static String hashString(final String string, final String algorithm) {
|
||||
try {
|
||||
final MessageDigest messageDigest = MessageDigest.getInstance(algorithm);
|
||||
final byte[] hash = messageDigest.digest(string.getBytes(StandardCharsets.UTF_8));
|
||||
final StringBuilder hexString = new StringBuilder(2 * hash.length);
|
||||
|
||||
for (final byte b : hash) {
|
||||
final String hex = Integer.toHexString(0xff & b);
|
||||
|
||||
if (hex.length() == 1) {
|
||||
hexString.append('0');
|
||||
}
|
||||
|
||||
hexString.append(hex);
|
||||
}
|
||||
|
||||
return hexString.toString();
|
||||
|
||||
} catch (Exception exception) {
|
||||
exception.printStackTrace();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static String replaceFirst(String input, String trigger, String replacement) {
|
||||
|
||||
if (!input.contains(trigger)) {
|
||||
@@ -151,28 +124,33 @@ public class StringUtils {
|
||||
return input;
|
||||
}
|
||||
|
||||
public static String replace(List<String> input, String... replacements) {
|
||||
return replace(String.join("\n", input), replacements);
|
||||
}
|
||||
|
||||
public static String replace(String input, String... replacements) {
|
||||
final HashMap<String, String> REPLACEMENTS = new HashMap<>();
|
||||
if (replacements.length == 0) {
|
||||
return input;
|
||||
}
|
||||
|
||||
if (replacements.length > 0) {
|
||||
String firstReplacementInput = null, secondReplacementInput = null;
|
||||
|
||||
for (String replacement : replacements) {
|
||||
if (firstReplacementInput == null) firstReplacementInput = replacement;
|
||||
else secondReplacementInput = replacement;
|
||||
final HashMap<String, String> cache = new HashMap<>();
|
||||
String firstReplacementInput = null, secondReplacementInput = null;
|
||||
|
||||
if (firstReplacementInput != null && secondReplacementInput != null) {
|
||||
REPLACEMENTS.put(firstReplacementInput, secondReplacementInput);
|
||||
firstReplacementInput = null;
|
||||
secondReplacementInput = null;
|
||||
}
|
||||
for (String replacement : replacements) {
|
||||
if (firstReplacementInput == null) firstReplacementInput = replacement;
|
||||
else secondReplacementInput = replacement;
|
||||
|
||||
if (firstReplacementInput != null && secondReplacementInput != null) {
|
||||
cache.put(firstReplacementInput, secondReplacementInput);
|
||||
firstReplacementInput = null;
|
||||
secondReplacementInput = null;
|
||||
}
|
||||
}
|
||||
|
||||
String text = input;
|
||||
if (replacements.length > 0)
|
||||
for (Map.Entry<String, String> entry : REPLACEMENTS.entrySet())
|
||||
text = text.replace(entry.getKey(), entry.getValue());
|
||||
for (Map.Entry<String, String> entry : cache.entrySet())
|
||||
text = text.replace(entry.getKey(), entry.getValue());
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
@@ -8,6 +8,11 @@ public class MultipleMessagesHelper implements Serializable {
|
||||
|
||||
private final List<String> lines;
|
||||
|
||||
/** Construct a message set from authenticated wire data. */
|
||||
public MultipleMessagesHelper(List<String> lines) {
|
||||
this.lines = new ArrayList<>(lines);
|
||||
}
|
||||
|
||||
public MultipleMessagesHelper(ConfigStorage config, String path, List<String> input) {
|
||||
final ConfigSectionHelper<ArrayList<String>> sectionHelper = new ConfigSectionHelper<>(config, path, input);
|
||||
final Object resultObj = sectionHelper.getOrSet();
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
package de.rayzs.pat.utils.message;
|
||||
|
||||
import de.rayzs.pat.plugin.logger.Logger;
|
||||
import de.rayzs.pat.utils.configuration.helper.MultipleMessagesHelper;
|
||||
import de.rayzs.pat.utils.message.replacer.PlaceholderReplacer;
|
||||
import de.rayzs.pat.utils.message.translators.*;
|
||||
import de.rayzs.pat.utils.*;
|
||||
import de.rayzs.pat.utils.sender.CommandSender;
|
||||
|
||||
import java.sql.Ref;
|
||||
import java.util.List;
|
||||
|
||||
public class MessageHelper {
|
||||
|
||||
private static boolean support;
|
||||
private static Translator translator = null;
|
||||
|
||||
public static void initialize() {
|
||||
|
||||
if (Reflection.isBukkit() || Reflection.isSpigot()) {
|
||||
Logger.warning("MiniMessage support disabled! Your server software is too old. Please switch to a more modern paper-based fork such as Paper, Purpur, Leaf..., etc to enable MiniMessage support.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (Reflection.isBungeeServer() && !Reflection.doesClassExist("net.kyori.adventure.util.Buildable$Builder")) {
|
||||
Logger.warning("MiniMessage support disabled! Since MiniMessage isn't supported for Bungeecord anymore and this version of Bungeecord is too advanced, MiniMessage support is disabled!");
|
||||
return;
|
||||
}
|
||||
|
||||
support = true;
|
||||
translator = Reflection.isVelocityServer() ? new VelocityMessageTranslator()
|
||||
: Reflection.isProxyServer() ? new BungeeMessageTranslator()
|
||||
: Reflection.isPaper() ? new PaperMessageTranslator()
|
||||
: new BukkitMessageTranslator();
|
||||
}
|
||||
|
||||
public static void sendMessage(CommandSender sender, MultipleMessagesHelper texts, String... replacements) {
|
||||
sendMessage(sender, texts.getLines(), replacements);
|
||||
}
|
||||
|
||||
public static void sendMessage(CommandSender sender, List<String> texts, String... replacements) {
|
||||
sendMessage(sender, StringUtils.getStringList(texts, "\n"), replacements);
|
||||
}
|
||||
|
||||
public static void sendMessage(CommandSender sender, String text, String... replacements) {
|
||||
if (text.isEmpty()) return;
|
||||
|
||||
|
||||
if (!Reflection.isProxyServer()) {
|
||||
text = PlaceholderReplacer.applyPlaceholders(sender, text, replacements);
|
||||
|
||||
if (support) {
|
||||
translator.send(sender, text);
|
||||
return;
|
||||
}
|
||||
|
||||
sender.sendMessage(text);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (support) {
|
||||
PlaceholderReplacer.applyProxyPlaceholders(sender, text, result -> translator.send(sender, result), replacements);
|
||||
return;
|
||||
}
|
||||
|
||||
PlaceholderReplacer.applyProxyPlaceholders(sender, text, sender::sendMessage, replacements);
|
||||
}
|
||||
|
||||
public static void sendActionbar(CommandSender sender, String message) {
|
||||
if (!support) {
|
||||
sender.sendActionbar(message);
|
||||
return;
|
||||
}
|
||||
|
||||
translator.sendActionbar(sender, message);
|
||||
}
|
||||
|
||||
public static void sendTitle(CommandSender sender, String title, String subtitle, int fadeIn, int stay, int fadeOut) {
|
||||
if (!support) {
|
||||
sender.sendTitle(title, subtitle, fadeIn, stay, fadeOut);
|
||||
return;
|
||||
}
|
||||
|
||||
translator.sendTitle(sender, title, subtitle, fadeIn, stay, fadeOut);
|
||||
}
|
||||
|
||||
public static void playSound(CommandSender sender, String soundKey, float volume, float pitch) throws Exception {
|
||||
translator.playSound(sender, soundKey, volume, pitch);
|
||||
}
|
||||
|
||||
public static String strip(String text) {
|
||||
return translator.strip(text);
|
||||
}
|
||||
|
||||
public static void closeAudiences() {
|
||||
if (translator == null) return;
|
||||
translator.close();
|
||||
}
|
||||
|
||||
public static boolean isSupported() {
|
||||
return support;
|
||||
}
|
||||
}
|
||||
@@ -1,229 +0,0 @@
|
||||
package de.rayzs.pat.utils.message;
|
||||
|
||||
import de.rayzs.pat.plugin.logger.Logger;
|
||||
import de.rayzs.pat.utils.configuration.helper.MultipleMessagesHelper;
|
||||
import de.rayzs.pat.utils.message.replacer.PlaceholderReplacer;
|
||||
import de.rayzs.pat.utils.message.translators.*;
|
||||
import de.rayzs.pat.api.storage.Storage;
|
||||
import de.rayzs.pat.utils.*;
|
||||
import de.rayzs.pat.utils.sender.CommandSender;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class MessageTranslator {
|
||||
|
||||
private static final HashMap<Character, String> colors = new HashMap<>(), endingColors = new HashMap<>();
|
||||
private static boolean support;
|
||||
private static Translator translator = null;
|
||||
|
||||
public static void initialize() {
|
||||
colors.put('1', "<dark_blue>");
|
||||
colors.put('2', "<dark_green>");
|
||||
colors.put('3', "<dark_aqua>");
|
||||
colors.put('4', "<dark_red>");
|
||||
colors.put('5', "<dark_purple>");
|
||||
colors.put('6', "<gold>");
|
||||
colors.put('7', "<gray>");
|
||||
colors.put('8', "<dark_gray>");
|
||||
colors.put('9', "<blue>");
|
||||
colors.put('a', "<green>");
|
||||
colors.put('b', "<aqua>");
|
||||
colors.put('c', "<red>");
|
||||
colors.put('d', "<light_purple>");
|
||||
colors.put('e', "<yellow>");
|
||||
colors.put('f', "<white>");
|
||||
colors.put('m', "<st>");
|
||||
colors.put('k', "<obf>");
|
||||
colors.put('r', "<reset>");
|
||||
colors.put('o', "<i>");
|
||||
colors.put('l', "<b>");
|
||||
|
||||
for (Map.Entry<Character, String> entry : colors.entrySet())
|
||||
endingColors.put(entry.getKey(), "</" + entry.getValue().substring(1));
|
||||
|
||||
support = !Reflection.isArclight()
|
||||
&& !Reflection.isCraftbukkit()
|
||||
&& (Reflection.isAtLeast(1, 18) || Reflection.isProxyServer());
|
||||
|
||||
if (Reflection.isAtLeast(26, 2) && !Reflection.getSoftware().isPaperBased()) {
|
||||
support = false;
|
||||
|
||||
Logger.warning("Due to an incompatibility issue, MiniMessage support is not given for non-Paper based server softwares as of now!");
|
||||
}
|
||||
|
||||
if (Reflection.getSoftware() == Reflection.Software.BUNGEECORD && !Reflection.doesClassExist("net.kyori.adventure.util.Buildable$Builder")) {
|
||||
support = false;
|
||||
|
||||
Logger.warning("Since MiniMessage isn't supported for Bungeecord anymore and this version of Bungeecord is too advanced, MiniMessage support is disabled!");
|
||||
}
|
||||
|
||||
if (support) {
|
||||
translator = Reflection.isVelocityServer() ? new VelocityMessageTranslator()
|
||||
: Reflection.isProxyServer() ? new BungeeMessageTranslator()
|
||||
: new BukkitMessageTranslator();
|
||||
}
|
||||
}
|
||||
|
||||
public static String translateLegacy(String text) {
|
||||
text = replaceMessage(text);
|
||||
if(!text.contains("§")) return text;
|
||||
|
||||
for (Map.Entry<Character, String> entry : colors.entrySet())
|
||||
text = text.replace("§" + entry.getKey(), entry.getValue());
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
public static String colorless(String text) {
|
||||
text = replaceMessage(text);
|
||||
if(!text.contains("§")) return text;
|
||||
|
||||
for (Map.Entry<Character, String> entry : colors.entrySet())
|
||||
text = text.replace("§" + entry.getKey(), "");
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
public static void send(Object target, MultipleMessagesHelper texts) {
|
||||
String stringList = StringUtils.getStringList(texts.getLines(), "\n");
|
||||
send(target, stringList);
|
||||
}
|
||||
|
||||
public static void send(Object target, MultipleMessagesHelper texts, String... replacements) {
|
||||
String stringList = StringUtils.getStringList(texts.getLines(), "\n");
|
||||
send(target, stringList, replacements);
|
||||
}
|
||||
|
||||
public static void send(Object target, List<String> texts) {
|
||||
String stringList = StringUtils.getStringList(texts, "\n");
|
||||
send(target, stringList);
|
||||
}
|
||||
|
||||
public static void send(Object target, List<String> texts, String... replacements) {
|
||||
texts = replaceMessageList(texts, replacements);
|
||||
send(target, texts);
|
||||
}
|
||||
|
||||
public static void send(Object target, String text, String... replacements) {
|
||||
if (text.isEmpty()) return;
|
||||
|
||||
text = replaceMessageString(target, text, replacements);
|
||||
|
||||
if (text.contains("%no-message%")) return;
|
||||
|
||||
if(translator == null) {
|
||||
|
||||
CommandSender sender = target instanceof CommandSender
|
||||
? (CommandSender) target
|
||||
: CommandSender.from(target);
|
||||
|
||||
if (!PlaceholderReplacer.process(sender, text, sender::sendMessage))
|
||||
sender.sendMessage(text);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
final Object tmpTarget = target instanceof CommandSender sender
|
||||
? sender.getSenderObject() : target;
|
||||
|
||||
if (PlaceholderReplacer.process(target, text, result -> translator.send(tmpTarget, result))) {
|
||||
return;
|
||||
}
|
||||
|
||||
translator.send(tmpTarget, text);
|
||||
}
|
||||
|
||||
public static String replaceMessage(String text) {
|
||||
return replaceMessage(null, text);
|
||||
}
|
||||
|
||||
public static String replaceMessage(Object targetObj, String text) {
|
||||
CommandSender sender = targetObj == null ? null
|
||||
: targetObj instanceof CommandSender
|
||||
? (CommandSender) targetObj
|
||||
: CommandSender.from(targetObj);
|
||||
|
||||
String executorName = (sender == null || sender.isConsole())
|
||||
? ""
|
||||
: sender.getName();
|
||||
|
||||
String token = (Storage.ConfigSections.Settings.HANDLE_THROUGH_PROXY.ENABLED || Reflection.isProxyServer())
|
||||
? Storage.CENSORED_TOKEN
|
||||
: "/";
|
||||
|
||||
String serverName = Storage.SERVER_NAME == null ? "/" : Storage.SERVER_NAME;
|
||||
|
||||
text = StringUtils.replace(text,
|
||||
"&", "§",
|
||||
"\\n", "\n",
|
||||
"%executor%", executorName,
|
||||
"%prefix%", Storage.ConfigSections.Messages.PREFIX.PREFIX,
|
||||
"%pat_general_prefix%", Storage.ConfigSections.Messages.PREFIX.PREFIX,
|
||||
"%token%", token,
|
||||
"%sync_server_name%", serverName,
|
||||
"%server%", serverName,
|
||||
"%current_version%", Storage.CURRENT_VERSION,
|
||||
"%newest_version%", Storage.NEWER_VERSION
|
||||
);
|
||||
|
||||
return PlaceholderReplacer.replace(targetObj, text);
|
||||
}
|
||||
|
||||
public static String replaceMessageString(Object targetObj, String rawText, String... replacements) {
|
||||
return replaceMessage(targetObj, StringUtils.replace(rawText, replacements));
|
||||
}
|
||||
|
||||
public static List<String> replaceMessageList(MultipleMessagesHelper rawText, String... replacements) {
|
||||
return replaceMessageList(rawText.getLines(), replacements);
|
||||
}
|
||||
|
||||
public static List<String> replaceMessageList(List<String> rawText, String... replacements) {
|
||||
final HashMap<String, String> REPLACEMENTS = new HashMap<>();
|
||||
List<String> result = new ArrayList<>();
|
||||
|
||||
if(replacements != null) {
|
||||
String firstReplacementInput = null, secondReplacementInput = null;
|
||||
for (String replacement : replacements) {
|
||||
if (firstReplacementInput == null) firstReplacementInput = replacement;
|
||||
else secondReplacementInput = replacement;
|
||||
|
||||
if (firstReplacementInput != null && secondReplacementInput != null) {
|
||||
REPLACEMENTS.put(firstReplacementInput, secondReplacementInput);
|
||||
firstReplacementInput = null;
|
||||
secondReplacementInput = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rawText.forEach(text -> {
|
||||
if(replacements != null)
|
||||
for (Map.Entry<String, String> entry : REPLACEMENTS.entrySet())
|
||||
text = text.replace(entry.getKey(), entry.getValue());
|
||||
String resultText = replaceMessage(text);
|
||||
result.add(resultText);
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static void sendActionbar(Object targetObj, String message) {
|
||||
translator.sendActionbar(targetObj, message);
|
||||
}
|
||||
|
||||
public static void sendTitle(Object targetObj, String title, String subtitle, int fadeIn, int stay, int fadeOut) {
|
||||
translator.sendTitle(targetObj, title, subtitle, fadeIn, stay, fadeOut);
|
||||
}
|
||||
|
||||
public static void playSound(Object targetObj, String soundKey, float volume, float pitch) throws Exception {
|
||||
translator.playSound(targetObj, soundKey, volume, pitch);
|
||||
}
|
||||
|
||||
public static void closeAudiences() {
|
||||
if(translator == null) return;
|
||||
translator.close();
|
||||
}
|
||||
|
||||
public static boolean isSupported() {
|
||||
return support;
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
package de.rayzs.pat.utils.message;
|
||||
|
||||
import de.rayzs.pat.utils.StringUtils;
|
||||
import de.rayzs.pat.utils.sender.CommandSender;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.minimessage.MiniMessage;
|
||||
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
|
||||
@@ -9,21 +10,21 @@ public interface Translator {
|
||||
|
||||
MiniMessage miniMessage = MiniMessage.miniMessage();
|
||||
|
||||
String translate(String text);
|
||||
String strip(String text);
|
||||
|
||||
void send(Object target, String text);
|
||||
void send(CommandSender sender, String text);
|
||||
|
||||
void sendActionbar(Object target, String text);
|
||||
void sendActionbar(CommandSender sender, String text);
|
||||
|
||||
void sendTitle(Object target, String title, String subtitle, int fadeIn, int stay, int fadeOut);
|
||||
void sendTitle(CommandSender sender, String title, String subtitle, int fadeIn, int stay, int fadeOut);
|
||||
|
||||
void playSound(Object target, String soundKey, float volume, float pitch) throws Exception;
|
||||
void playSound(CommandSender sender, String soundKey, float volume, float pitch) throws Exception;
|
||||
|
||||
default Component toComponent(String text) {
|
||||
text = StringUtils.replace(text, "§", "&");
|
||||
|
||||
Component legacy = LegacyComponentSerializer.legacyAmpersand().deserialize(text);
|
||||
text = StringUtils.replace(miniMessage.serialize(legacy), "\\", "");
|
||||
final Component legacy = LegacyComponentSerializer.legacyAmpersand().deserialize(text);
|
||||
text = miniMessage.serialize(legacy).replace("\\", "");
|
||||
|
||||
return miniMessage.deserialize(text);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,12 @@
|
||||
package de.rayzs.pat.utils.message.replacer;
|
||||
|
||||
import de.rayzs.pat.utils.Reflection;
|
||||
import de.rayzs.pat.utils.StringUtils;
|
||||
import de.rayzs.pat.utils.message.replacer.impl.*;
|
||||
import de.rayzs.pat.api.storage.Storage;
|
||||
import de.rayzs.pat.utils.sender.CommandSender;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public class PlaceholderReplacer {
|
||||
@@ -9,8 +14,10 @@ public class PlaceholderReplacer {
|
||||
private static BukkitPlaceholderReplacer BUKKIT_PLACEHOLDER_REPLACER = null;
|
||||
private static ProxyPlaceholderReplacer PROXY_PLACEHOLDER_REPLACER = null;
|
||||
|
||||
public static String replace(Object playerObj, String text) {
|
||||
if (!Storage.USE_PLACEHOLDERAPI)
|
||||
public static String applyPlaceholders(CommandSender sender, String text, String... replacements) {
|
||||
text = applyGeneralReplacements(sender, text, replacements);
|
||||
|
||||
if (Reflection.isProxyServer() || !Storage.USE_PLACEHOLDERAPI)
|
||||
return text;
|
||||
|
||||
if (!text.contains("%"))
|
||||
@@ -19,18 +26,51 @@ public class PlaceholderReplacer {
|
||||
if (BUKKIT_PLACEHOLDER_REPLACER == null)
|
||||
BUKKIT_PLACEHOLDER_REPLACER = new BukkitPlaceholderReplacer();
|
||||
|
||||
return BUKKIT_PLACEHOLDER_REPLACER.process(playerObj, text);
|
||||
return BUKKIT_PLACEHOLDER_REPLACER.process(sender, text);
|
||||
}
|
||||
|
||||
public static boolean process(Object playerObj, String text, Consumer<String> consumer) {
|
||||
if (!Storage.USE_PAPIPROXYBRIDGE)
|
||||
return false;
|
||||
public static void applyProxyPlaceholders(CommandSender sender, String text, Consumer<String> consumer, String... replacements) {
|
||||
text = applyPlaceholders(sender, text, replacements);
|
||||
|
||||
if (!text.contains("%")) return false;
|
||||
if (!Storage.USE_PAPIPROXYBRIDGE) {
|
||||
consumer.accept(text);
|
||||
return;
|
||||
}
|
||||
|
||||
if (PROXY_PLACEHOLDER_REPLACER == null)
|
||||
if (!text.contains("%")) {
|
||||
consumer.accept(text);
|
||||
return;
|
||||
}
|
||||
|
||||
if (PROXY_PLACEHOLDER_REPLACER == null) {
|
||||
PROXY_PLACEHOLDER_REPLACER = new ProxyPlaceholderReplacer();
|
||||
}
|
||||
|
||||
return PROXY_PLACEHOLDER_REPLACER.process(playerObj, text, consumer);
|
||||
if (!PROXY_PLACEHOLDER_REPLACER.process(sender, text, consumer)) {
|
||||
consumer.accept(text);
|
||||
}
|
||||
}
|
||||
|
||||
private static String applyGeneralReplacements(CommandSender sender, String text, String... replacements) {
|
||||
final String executorName = sender == null ? "" : sender.getName();
|
||||
|
||||
final String token = (Storage.ConfigSections.Settings.HANDLE_THROUGH_PROXY.ENABLED || Reflection.isProxyServer())
|
||||
? Storage.CENSORED_TOKEN
|
||||
: "/";
|
||||
|
||||
final String serverName = Objects.requireNonNullElse(Storage.SERVER_NAME, "/");
|
||||
|
||||
return StringUtils.replace(StringUtils.replace(text, replacements),
|
||||
"&", "§",
|
||||
"\\n", "\n",
|
||||
"%executor%", executorName,
|
||||
"%prefix%", Storage.ConfigSections.Messages.PREFIX.PREFIX,
|
||||
"%pat_general_prefix%", Storage.ConfigSections.Messages.PREFIX.PREFIX,
|
||||
"%token%", token,
|
||||
"%sync_server_name%", serverName,
|
||||
"%server%", serverName,
|
||||
"%current_version%", Storage.CURRENT_VERSION,
|
||||
"%newest_version%", Storage.NEWER_VERSION
|
||||
);
|
||||
}
|
||||
}
|
||||
+5
-10
@@ -6,17 +6,12 @@ import org.bukkit.entity.Player;
|
||||
|
||||
public class BukkitPlaceholderReplacer {
|
||||
|
||||
public String process(Object playerObj, String text) {
|
||||
Player player = null;
|
||||
public String process(CommandSender sender, String text) {
|
||||
|
||||
if(playerObj != null)
|
||||
if(playerObj instanceof CommandSender) {
|
||||
CommandSender sender = (CommandSender) playerObj;
|
||||
player = sender.isPlayer() ? (Player) sender.getSenderObject() : null;
|
||||
} else if(playerObj instanceof Player)
|
||||
player = (Player) playerObj;
|
||||
if (sender.isPlayer() && sender.getSenderObject() instanceof Player player) {
|
||||
return PlaceholderAPI.setPlaceholders(player, text);
|
||||
}
|
||||
|
||||
|
||||
return PlaceholderAPI.setPlaceholders(player, text);
|
||||
return PlaceholderAPI.setPlaceholders(null, text);
|
||||
}
|
||||
}
|
||||
+3
-26
@@ -15,33 +15,10 @@ public class ProxyPlaceholderReplacer {
|
||||
placeholderAPI.setRequestTimeout(1500);
|
||||
}
|
||||
|
||||
public boolean process(Object playerObj, String text, Consumer<String> consumer) {
|
||||
UUID uuid = null;
|
||||
|
||||
if(playerObj != null)
|
||||
|
||||
if (playerObj instanceof CommandSender) {
|
||||
|
||||
uuid = ((CommandSender) playerObj).getUniqueId();
|
||||
|
||||
} else if (Reflection.isVelocityServer()) {
|
||||
|
||||
if (playerObj instanceof com.velocitypowered.api.proxy.Player)
|
||||
uuid = ((com.velocitypowered.api.proxy.Player) playerObj).getUniqueId();
|
||||
|
||||
} else if (Reflection.isProxyServer()) {
|
||||
|
||||
if (playerObj instanceof net.md_5.bungee.api.connection.ProxiedPlayer)
|
||||
uuid = ((net.md_5.bungee.api.connection.ProxiedPlayer) playerObj).getUniqueId();
|
||||
|
||||
} else {
|
||||
if (playerObj instanceof org.bukkit.entity.Player)
|
||||
uuid = ((org.bukkit.entity.Player) playerObj).getUniqueId();
|
||||
}
|
||||
|
||||
if(uuid == null) return false;
|
||||
placeholderAPI.formatPlaceholders(text, uuid).thenAccept(consumer);
|
||||
public boolean process(CommandSender sender, String text, Consumer<String> consumer) {
|
||||
if (sender == null || !sender.isPlayer()) return false;
|
||||
|
||||
placeholderAPI.formatPlaceholders(text, sender.getUniqueId()).thenAccept(consumer);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,10 @@
|
||||
package de.rayzs.pat.utils.message.translators;
|
||||
|
||||
import de.rayzs.pat.utils.Reflection;
|
||||
import net.kyori.adventure.platform.bukkit.BukkitAudiences;
|
||||
import net.kyori.adventure.audience.Audience;
|
||||
import de.rayzs.pat.plugin.BukkitLoader;
|
||||
import net.kyori.adventure.title.Title;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.Sound;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import de.rayzs.pat.utils.message.*;
|
||||
@@ -21,76 +21,67 @@ public class BukkitMessageTranslator implements Translator {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String translate(String text) {
|
||||
return miniMessage.serialize(miniMessage.deserialize(MessageTranslator.translateLegacy(text)));
|
||||
public String strip(String text) {
|
||||
return ChatColor.stripColor(miniMessage.stripTags(text));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void send(Object target, String text) {
|
||||
if (Reflection.getSoftware().isPaperBased()) {
|
||||
if (target instanceof Player player) {
|
||||
player.sendMessage(toComponent(text));
|
||||
} else if (target instanceof CommandSender sender) {
|
||||
sender.sendMessage(toComponent(text));
|
||||
}
|
||||
public void send(de.rayzs.pat.utils.sender.CommandSender sender, String text) {
|
||||
final Audience audience = sender.getSenderObject() instanceof Player player
|
||||
? audiences.player(player)
|
||||
: sender.getSenderObject() instanceof CommandSender commandSender
|
||||
? audiences.sender(commandSender)
|
||||
: null;
|
||||
|
||||
|
||||
if (audience == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
Audience audience = target instanceof Player
|
||||
? audiences.player((Player) target)
|
||||
: audiences.sender((CommandSender) target);
|
||||
|
||||
audience.sendMessage(toComponent(text));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendActionbar(Object target, String text) {
|
||||
public void sendActionbar(de.rayzs.pat.utils.sender.CommandSender sender, String text) {
|
||||
final Audience audience = sender.getSenderObject() instanceof Player player
|
||||
? audiences.player(player)
|
||||
: sender.getSenderObject() instanceof CommandSender commandSender
|
||||
? audiences.sender(commandSender)
|
||||
: null;
|
||||
|
||||
if (Reflection.getSoftware().isPaperBased()) {
|
||||
if (target instanceof Player player) {
|
||||
player.sendActionBar(toComponent(text));
|
||||
} else if (target instanceof CommandSender sender) {
|
||||
sender.sendActionBar(toComponent(text));
|
||||
}
|
||||
|
||||
if (audience == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
Audience audience = target instanceof Player
|
||||
? audiences.player((Player) target)
|
||||
: audiences.sender((CommandSender) target);
|
||||
|
||||
audience.sendActionBar(toComponent(text));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendTitle(Object target, String titleStr, String subtitleStr, int fadeIn, int stay, int fadeOut) {
|
||||
Title.Times times = Title.Times.times(Duration.ofMillis(fadeIn), Duration.ofMillis(stay), Duration.ofMillis(fadeOut));
|
||||
Title title = Title.title(toComponent(titleStr), toComponent(subtitleStr), times);
|
||||
public void sendTitle(de.rayzs.pat.utils.sender.CommandSender sender, String titleStr, String subtitleStr, int fadeIn, int stay, int fadeOut) {
|
||||
|
||||
if (Reflection.getSoftware().isPaperBased()) {
|
||||
if (target instanceof Player player) {
|
||||
player.showTitle(title);
|
||||
} else if (target instanceof CommandSender sender) {
|
||||
sender.showTitle(title);
|
||||
}
|
||||
final Audience audience = sender.getSenderObject() instanceof Player player
|
||||
? audiences.player(player)
|
||||
: sender.getSenderObject() instanceof CommandSender commandSender
|
||||
? audiences.sender(commandSender)
|
||||
: null;
|
||||
|
||||
|
||||
if (audience == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Audience audience = target instanceof Player
|
||||
? audiences.player((Player) target)
|
||||
: audiences.sender((CommandSender) target);
|
||||
|
||||
final Title.Times times = Title.Times.times(Duration.ofMillis(fadeIn), Duration.ofMillis(stay), Duration.ofMillis(fadeOut));
|
||||
final Title title = Title.title(toComponent(titleStr), toComponent(subtitleStr), times);
|
||||
|
||||
audience.showTitle(title);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void playSound(Object target, String soundKey, float volume, float pitch) throws Exception {
|
||||
if (target instanceof Player player) {
|
||||
public void playSound(de.rayzs.pat.utils.sender.CommandSender sender, String soundKey, float volume, float pitch) throws Exception {
|
||||
if (sender.getSenderObject() instanceof Player player) {
|
||||
Sound sound = Sound.valueOf(soundKey);
|
||||
player.playSound(player.getLocation(), sound, volume, pitch);
|
||||
}
|
||||
|
||||
@@ -1,17 +1,15 @@
|
||||
package de.rayzs.pat.utils.message.translators;
|
||||
|
||||
import de.rayzs.pat.utils.StringUtils;
|
||||
import net.kyori.adventure.key.Key;
|
||||
import net.kyori.adventure.sound.Sound;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.platform.bungeecord.BungeeAudiences;
|
||||
import net.kyori.adventure.title.Title;
|
||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||
import de.rayzs.pat.utils.message.MessageTranslator;
|
||||
import net.kyori.adventure.audience.Audience;
|
||||
import de.rayzs.pat.utils.message.Translator;
|
||||
import net.md_5.bungee.api.CommandSender;
|
||||
import de.rayzs.pat.plugin.BungeeLoader;
|
||||
import org.bukkit.ChatColor;
|
||||
|
||||
import java.time.Duration;
|
||||
|
||||
@@ -24,39 +22,79 @@ public class BungeeMessageTranslator implements Translator {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String translate(String text) {
|
||||
return miniMessage.serialize(miniMessage.deserialize(MessageTranslator.translateLegacy(text)));
|
||||
public String strip(String text) {
|
||||
return ChatColor.stripColor(miniMessage.stripTags(text));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void send(Object target, String text) {
|
||||
Audience audience = target instanceof ProxiedPlayer ? audiences.player((ProxiedPlayer) target) : audiences.sender((CommandSender) target);
|
||||
public void send(de.rayzs.pat.utils.sender.CommandSender sender, String text) {
|
||||
final Audience audience = sender.getSenderObject() instanceof ProxiedPlayer player
|
||||
? audiences.player(player)
|
||||
: sender.getSenderObject() instanceof CommandSender commandSender
|
||||
? audiences.sender(commandSender)
|
||||
: null;
|
||||
|
||||
|
||||
if (audience == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
audience.sendMessage(toComponent(text));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendActionbar(Object target, String text) {
|
||||
Audience audience = target instanceof ProxiedPlayer ? audiences.player((ProxiedPlayer) target) : audiences.sender((CommandSender) target);
|
||||
public void sendActionbar(de.rayzs.pat.utils.sender.CommandSender sender, String text) {
|
||||
final Audience audience = sender.getSenderObject() instanceof ProxiedPlayer player
|
||||
? audiences.player(player)
|
||||
: sender.getSenderObject() instanceof CommandSender commandSender
|
||||
? audiences.sender(commandSender)
|
||||
: null;
|
||||
|
||||
|
||||
if (audience == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
audience.sendActionBar(toComponent(text));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendTitle(Object target, String titleStr, String subtitleStr, int fadeIn, int stay, int fadeOut) {
|
||||
Audience audience = target instanceof ProxiedPlayer ? audiences.player((ProxiedPlayer) target) : audiences.sender((CommandSender) target);
|
||||
public void sendTitle(de.rayzs.pat.utils.sender.CommandSender sender, String titleStr, String subtitleStr, int fadeIn, int stay, int fadeOut) {
|
||||
final Audience audience = sender.getSenderObject() instanceof ProxiedPlayer player
|
||||
? audiences.player(player)
|
||||
: sender.getSenderObject() instanceof CommandSender commandSender
|
||||
? audiences.sender(commandSender)
|
||||
: null;
|
||||
|
||||
Title.Times times = Title.Times.times(Duration.ofMillis(fadeIn), Duration.ofMillis(stay), Duration.ofMillis(fadeOut));
|
||||
Title title = Title.title(toComponent(titleStr), toComponent(subtitleStr), times);
|
||||
|
||||
if (audience == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
final Title.Times times = Title.Times.times(Duration.ofMillis(fadeIn), Duration.ofMillis(stay), Duration.ofMillis(fadeOut));
|
||||
final Title title = Title.title(toComponent(titleStr), toComponent(subtitleStr), times);
|
||||
|
||||
audience.showTitle(title);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void playSound(Object target, String soundKey, float volume, float pitch) throws Exception {
|
||||
Audience audience = target instanceof ProxiedPlayer ? audiences.player((ProxiedPlayer) target) : audiences.sender((CommandSender) target);
|
||||
Sound sound = Sound.sound(Key.key(soundKey), Sound.Source.MASTER, 1f, 1f);
|
||||
public void playSound(de.rayzs.pat.utils.sender.CommandSender sender, String soundKey, float volume, float pitch) throws Exception {
|
||||
final Audience audience = sender.getSenderObject() instanceof ProxiedPlayer player
|
||||
? audiences.player(player)
|
||||
: sender.getSenderObject() instanceof CommandSender commandSender
|
||||
? audiences.sender(commandSender)
|
||||
: null;
|
||||
|
||||
|
||||
if (audience == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
final Sound sound = Sound.sound(Key.key(soundKey), Sound.Source.MASTER, 1f, 1f);
|
||||
audience.playSound(sound, Sound.Emitter.self());
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
package de.rayzs.pat.utils.message.translators;
|
||||
|
||||
import de.rayzs.pat.utils.message.Translator;
|
||||
import net.kyori.adventure.title.Title;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.Sound;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.time.Duration;
|
||||
|
||||
public class PaperMessageTranslator implements Translator {
|
||||
|
||||
@Override
|
||||
public String strip(String text) {
|
||||
return ChatColor.stripColor(miniMessage.stripTags(text));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void send(de.rayzs.pat.utils.sender.CommandSender sender, String text) {
|
||||
if (sender.getSenderObject() instanceof Player player) {
|
||||
player.sendMessage(toComponent(text));
|
||||
} else if (sender.getSenderObject() instanceof CommandSender commandSender) {
|
||||
commandSender.sendMessage(toComponent(text));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendActionbar(de.rayzs.pat.utils.sender.CommandSender sender, String text) {
|
||||
if (sender.getSenderObject() instanceof Player player) {
|
||||
player.sendActionBar(toComponent(text));
|
||||
} else if (sender.getSenderObject() instanceof CommandSender commandSender) {
|
||||
commandSender.sendActionBar(toComponent(text));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendTitle(de.rayzs.pat.utils.sender.CommandSender sender, String titleStr, String subtitleStr, int fadeIn, int stay, int fadeOut) {
|
||||
final Title.Times times = Title.Times.times(Duration.ofMillis(fadeIn), Duration.ofMillis(stay), Duration.ofMillis(fadeOut));
|
||||
final Title title = Title.title(toComponent(titleStr), toComponent(subtitleStr), times);
|
||||
|
||||
if (sender.getSenderObject() instanceof Player player) {
|
||||
player.showTitle(title);
|
||||
} else if (sender.getSenderObject() instanceof CommandSender commandSender) {
|
||||
commandSender.showTitle(title);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void playSound(de.rayzs.pat.utils.sender.CommandSender sender, String soundKey, float volume, float pitch) throws Exception {
|
||||
if (sender.getSenderObject() instanceof Player player) {
|
||||
final Sound sound = Sound.valueOf(soundKey);
|
||||
player.playSound(player.getLocation(), sound, volume, pitch);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {}
|
||||
}
|
||||
+13
-14
@@ -12,39 +12,38 @@ import java.time.Duration;
|
||||
public class VelocityMessageTranslator implements Translator {
|
||||
|
||||
@Override
|
||||
public String translate(String text) {
|
||||
return MiniMessage.miniMessage().serialize(miniMessage.deserialize(MessageTranslator.translateLegacy(text)));
|
||||
public String strip(String text) {
|
||||
return miniMessage.stripTags(text);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void send(Object target, String text) {
|
||||
if (target instanceof CommandSource source) {
|
||||
public void send(de.rayzs.pat.utils.sender.CommandSender sender, String text) {
|
||||
if (sender.getSenderObject() instanceof CommandSource source) {
|
||||
source.sendMessage(toComponent(text));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendActionbar(Object target, String text) {
|
||||
if (target instanceof CommandSource source) {
|
||||
public void sendActionbar(de.rayzs.pat.utils.sender.CommandSender sender, String text) {
|
||||
if (sender.getSenderObject() instanceof CommandSource source) {
|
||||
source.sendActionBar(toComponent(text));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendTitle(Object target, String titleStr, String subtitleStr, int fadeIn, int stay, int fadeOut) {
|
||||
Title.Times times = Title.Times.times(Duration.ofMillis(fadeIn), Duration.ofMillis(stay), Duration.ofMillis(fadeOut));
|
||||
Title title = Title.title(toComponent(titleStr), toComponent(subtitleStr), times);
|
||||
public void sendTitle(de.rayzs.pat.utils.sender.CommandSender sender, String titleStr, String subtitleStr, int fadeIn, int stay, int fadeOut) {
|
||||
final Title.Times times = Title.Times.times(Duration.ofMillis(fadeIn), Duration.ofMillis(stay), Duration.ofMillis(fadeOut));
|
||||
final Title title = Title.title(toComponent(titleStr), toComponent(subtitleStr), times);
|
||||
|
||||
if (target instanceof CommandSource source) {
|
||||
if (sender.getSenderObject() instanceof CommandSource source) {
|
||||
source.showTitle(title);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void playSound(Object target, String soundKey, float volume, float pitch) throws Exception {
|
||||
if (target instanceof CommandSource source) {
|
||||
Sound sound = Sound.sound(Key.key(soundKey), Sound.Source.MASTER, 1f, 1f);
|
||||
|
||||
public void playSound(de.rayzs.pat.utils.sender.CommandSender sender, String soundKey, float volume, float pitch) throws Exception {
|
||||
if (sender.getSenderObject() instanceof CommandSource source) {
|
||||
final Sound sound = Sound.sound(Key.key(soundKey), Sound.Source.MASTER, 1f, 1f);
|
||||
source.playSound(sound, Sound.Emitter.self());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,8 @@ import de.rayzs.pat.plugin.system.communication.Communicator;
|
||||
import de.rayzs.pat.api.storage.Storage;
|
||||
import de.rayzs.pat.plugin.logger.Logger;
|
||||
import de.rayzs.pat.utils.StringUtils;
|
||||
import de.rayzs.pat.utils.message.MessageTranslator;
|
||||
import de.rayzs.pat.utils.message.MessageHelper;
|
||||
import de.rayzs.pat.utils.sender.CommandSender;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
@@ -25,8 +26,8 @@ public interface Action {
|
||||
final String displayCommand = StringUtils.replaceTriggers(command, "", "\\", "<", ">", "&");
|
||||
|
||||
|
||||
final List<String> notificationMessage = MessageTranslator.replaceMessageList(
|
||||
Storage.ConfigSections.Messages.NOTIFICATION.ALERT,
|
||||
final String notificationMessage = StringUtils.replace(
|
||||
Storage.ConfigSections.Messages.NOTIFICATION.ALERT.getLines(),
|
||||
"%player%", playerName,
|
||||
"%command%", displayCommand,
|
||||
"%server%", serverName);
|
||||
@@ -36,10 +37,11 @@ public interface Action {
|
||||
if (Storage.SEND_CONSOLE_NOTIFICATION)
|
||||
Logger.info(notificationMessage);
|
||||
|
||||
Storage.NOTIFY_PLAYERS.stream().forEach(tmpUUID -> {
|
||||
Object p = Storage.getLoader().getPlayerObjByUUID(tmpUUID);
|
||||
if (p != null) {
|
||||
MessageTranslator.send(p, notificationMessage);
|
||||
Storage.NOTIFY_PLAYERS.stream().forEach(otherUuid -> {
|
||||
final CommandSender otherSender = CommandSender.from(otherUuid);
|
||||
|
||||
if (otherSender != null) {
|
||||
MessageHelper.sendMessage(otherSender, notificationMessage);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
package de.rayzs.pat.utils.response.action;
|
||||
|
||||
import de.rayzs.pat.utils.response.action.impl.BungeeAction;
|
||||
import de.rayzs.pat.utils.response.action.impl.ModernBukkitAction;
|
||||
import de.rayzs.pat.utils.response.action.impl.OldBukkitAction;
|
||||
import de.rayzs.pat.utils.response.action.impl.BukkitAction;
|
||||
import de.rayzs.pat.utils.response.action.impl.VelocityAction;
|
||||
import de.rayzs.pat.utils.Reflection;
|
||||
import java.util.UUID;
|
||||
@@ -11,8 +10,7 @@ public class ActionHandler {
|
||||
|
||||
private static final Action ACTION = Reflection.isProxyServer() ? Reflection.isVelocityServer()
|
||||
? new VelocityAction() : new BungeeAction()
|
||||
: Reflection.isAtMost(1, 16)
|
||||
? new OldBukkitAction() : new ModernBukkitAction();
|
||||
: new BukkitAction();
|
||||
|
||||
public static void initialize() {}
|
||||
|
||||
|
||||
+24
-23
@@ -2,10 +2,11 @@ package de.rayzs.pat.utils.response.action.impl;
|
||||
|
||||
import de.rayzs.pat.plugin.logger.Logger;
|
||||
import de.rayzs.pat.utils.StringUtils;
|
||||
import de.rayzs.pat.utils.message.MessageTranslator;
|
||||
import de.rayzs.pat.utils.message.MessageHelper;
|
||||
import de.rayzs.pat.utils.message.replacer.PlaceholderReplacer;
|
||||
import de.rayzs.pat.utils.response.ResponseHandler;
|
||||
import de.rayzs.pat.utils.response.action.Action;
|
||||
import de.rayzs.pat.utils.sender.CommandSender;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.potion.PotionEffect;
|
||||
@@ -13,19 +14,19 @@ import org.bukkit.potion.PotionEffectType;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class ModernBukkitAction implements Action {
|
||||
public class BukkitAction implements Action {
|
||||
|
||||
@Override
|
||||
public void executeConsoleCommand(String action, UUID uuid, String command, String message) {
|
||||
Player player = Bukkit.getPlayer(uuid);
|
||||
final CommandSender sender = CommandSender.from(uuid);
|
||||
message = ResponseHandler.replaceArgsVariables(message, command);
|
||||
|
||||
if (player != null) {
|
||||
message = StringUtils.replace(message, "%player%", player.getName());
|
||||
if (sender != null) {
|
||||
message = StringUtils.replace(message, "%player%", sender.getName());
|
||||
}
|
||||
|
||||
if (message.contains("%")) {
|
||||
message = PlaceholderReplacer.replace(player, message);
|
||||
message = PlaceholderReplacer.applyPlaceholders(sender, message);
|
||||
}
|
||||
|
||||
Bukkit.dispatchCommand(Bukkit.getConsoleSender(), message);
|
||||
@@ -33,37 +34,37 @@ public class ModernBukkitAction implements Action {
|
||||
|
||||
@Override
|
||||
public void executePlayerCommand(String action, UUID uuid, String command, String message) {
|
||||
Player player = Bukkit.getPlayer(uuid);
|
||||
final CommandSender sender = CommandSender.from(uuid);
|
||||
|
||||
if (player == null) {
|
||||
if (sender == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
message = StringUtils.replace(message, "%player%", player.getName());
|
||||
message = StringUtils.replace(message, "%player%", sender.getName());
|
||||
message = ResponseHandler.replaceArgsVariables(message, command);
|
||||
|
||||
if (message.contains("%")) {
|
||||
message = PlaceholderReplacer.replace(player, message);
|
||||
message = PlaceholderReplacer.applyPlaceholders(sender, message);
|
||||
}
|
||||
|
||||
Bukkit.dispatchCommand(player, message);
|
||||
sender.execute(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendTitle(String action, UUID uuid, String command, String title, String subTitle, int fadeIn, int stay, int fadeOut) {
|
||||
Player player = Bukkit.getPlayer(uuid);
|
||||
final CommandSender sender = CommandSender.from(uuid);
|
||||
|
||||
if (player == null) {
|
||||
if (sender == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
title = ResponseHandler.replaceArgsVariables(title, command);
|
||||
subTitle = ResponseHandler.replaceArgsVariables(subTitle, command);
|
||||
|
||||
title = StringUtils.replace(title, "&", "§", "%player%", player.getName());
|
||||
subTitle = StringUtils.replace(subTitle, "&", "§", "%player%", player.getName());
|
||||
title = StringUtils.replace(title, "%player%", sender.getName());
|
||||
subTitle = StringUtils.replace(subTitle, "%player%", sender.getName());
|
||||
|
||||
MessageTranslator.sendTitle(player, title, subTitle, fadeIn, stay, fadeOut);
|
||||
MessageHelper.sendTitle(sender, title, subTitle, fadeIn, stay, fadeOut);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -92,14 +93,14 @@ public class ModernBukkitAction implements Action {
|
||||
|
||||
@Override
|
||||
public void playSound(String action, UUID uuid, String soundName, float volume, float pitch) {
|
||||
Player player = Bukkit.getPlayer(uuid);
|
||||
final CommandSender sender = CommandSender.from(uuid);
|
||||
|
||||
if (player == null) {
|
||||
if (sender == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
MessageTranslator.playSound(player, soundName, volume, pitch);
|
||||
MessageHelper.playSound(sender, soundName, volume, pitch);
|
||||
} catch (Exception exception) {
|
||||
Logger.warning("! Failed to read action: " + action);
|
||||
Logger.warning(" > The sound \"" + soundName + "\" could not be found!");
|
||||
@@ -110,15 +111,15 @@ public class ModernBukkitAction implements Action {
|
||||
|
||||
@Override
|
||||
public void sendActionbar(String action, UUID uuid, String command, String message) {
|
||||
Player player = Bukkit.getPlayer(uuid);
|
||||
final CommandSender sender = CommandSender.from(uuid);
|
||||
|
||||
if (player == null) {
|
||||
if (sender == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
message = StringUtils.replace(message, "%player%", player.getName());
|
||||
message = StringUtils.replace(message, "%player%", sender.getName());
|
||||
message = ResponseHandler.replaceArgsVariables(message, command);
|
||||
|
||||
MessageTranslator.sendActionbar(player, message);
|
||||
MessageHelper.sendActionbar(sender, message);
|
||||
}
|
||||
}
|
||||
@@ -2,9 +2,10 @@ package de.rayzs.pat.utils.response.action.impl;
|
||||
|
||||
import de.rayzs.pat.plugin.logger.Logger;
|
||||
import de.rayzs.pat.utils.StringUtils;
|
||||
import de.rayzs.pat.utils.message.MessageTranslator;
|
||||
import de.rayzs.pat.utils.message.MessageHelper;
|
||||
import de.rayzs.pat.utils.response.ResponseHandler;
|
||||
import de.rayzs.pat.utils.response.action.Action;
|
||||
import de.rayzs.pat.utils.sender.CommandSender;
|
||||
import net.md_5.bungee.api.ProxyServer;
|
||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||
|
||||
@@ -40,19 +41,19 @@ public class BungeeAction implements Action {
|
||||
|
||||
@Override
|
||||
public void sendTitle(String action, UUID uuid, String command, String title, String subTitle, int fadeIn, int stay, int fadeOut) {
|
||||
ProxiedPlayer player = ProxyServer.getInstance().getPlayer(uuid);
|
||||
final CommandSender sender = CommandSender.from(uuid);
|
||||
|
||||
if (player == null) {
|
||||
if (sender == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
title = ResponseHandler.replaceArgsVariables(title, command);
|
||||
subTitle = ResponseHandler.replaceArgsVariables(subTitle, command);
|
||||
|
||||
title = StringUtils.replace(title, "%player%", player.getName());
|
||||
subTitle = StringUtils.replace(subTitle, "%player%", player.getName());
|
||||
title = StringUtils.replace(title, "%player%", sender.getName());
|
||||
subTitle = StringUtils.replace(subTitle, "%player%", sender.getName());
|
||||
|
||||
MessageTranslator.sendTitle(player, title, subTitle, fadeIn, stay, fadeOut);
|
||||
MessageHelper.sendTitle(sender, title, subTitle, fadeIn, stay, fadeOut);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -61,14 +62,14 @@ public class BungeeAction implements Action {
|
||||
|
||||
@Override
|
||||
public void playSound(String action, UUID uuid, String soundName, float volume, float pitch) {
|
||||
ProxiedPlayer player = ProxyServer.getInstance().getPlayer(uuid);
|
||||
final CommandSender sender = CommandSender.from(uuid);
|
||||
|
||||
if (player == null) {
|
||||
if (sender == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
MessageTranslator.playSound(player, soundName, volume, pitch);
|
||||
MessageHelper.playSound(sender, soundName, volume, pitch);
|
||||
} catch (Exception exception) {
|
||||
Logger.warning("! Failed to read action: " + action);
|
||||
Logger.warning(" > The sound \"" + soundName + "\" could not be found!");
|
||||
@@ -79,14 +80,14 @@ public class BungeeAction implements Action {
|
||||
|
||||
@Override
|
||||
public void sendActionbar(String action, UUID uuid, String command, String message) {
|
||||
ProxiedPlayer player = ProxyServer.getInstance().getPlayer(uuid);
|
||||
final CommandSender sender = CommandSender.from(uuid);
|
||||
|
||||
if (player == null) {
|
||||
if (sender == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
message = StringUtils.replace(message, "%player%", player.getName());
|
||||
message = StringUtils.replace(message, "%player%", sender.getName());
|
||||
message = ResponseHandler.replaceArgsVariables(message, command);
|
||||
MessageTranslator.sendActionbar(player, message);
|
||||
MessageHelper.sendActionbar(sender, message);
|
||||
}
|
||||
}
|
||||
@@ -1,156 +0,0 @@
|
||||
package de.rayzs.pat.utils.response.action.impl;
|
||||
|
||||
import de.rayzs.pat.plugin.logger.Logger;
|
||||
import de.rayzs.pat.utils.Reflection;
|
||||
import de.rayzs.pat.utils.StringUtils;
|
||||
import de.rayzs.pat.utils.message.replacer.PlaceholderReplacer;
|
||||
import de.rayzs.pat.utils.response.ResponseHandler;
|
||||
import de.rayzs.pat.utils.response.action.Action;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Sound;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.potion.PotionEffect;
|
||||
import org.bukkit.potion.PotionEffectType;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.Objects;
|
||||
import java.util.UUID;
|
||||
|
||||
public class OldBukkitAction implements Action {
|
||||
|
||||
private String versionPackage = null;
|
||||
|
||||
@Override
|
||||
public void executeConsoleCommand(String action, UUID uuid, String command, String message) {
|
||||
Player player = Bukkit.getPlayer(uuid);
|
||||
message = ResponseHandler.replaceArgsVariables(message, command);
|
||||
|
||||
if(player != null) {
|
||||
message = StringUtils.replace(message, "%player%", player.getName());
|
||||
}
|
||||
|
||||
if (message.contains("%")) {
|
||||
message = PlaceholderReplacer.replace(player, message);
|
||||
}
|
||||
|
||||
Bukkit.dispatchCommand(Bukkit.getConsoleSender(), message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void executePlayerCommand(String action, UUID uuid, String command, String message) {
|
||||
Player player = Bukkit.getPlayer(uuid);
|
||||
|
||||
if (player == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
message = ResponseHandler.replaceArgsVariables(message, command);
|
||||
message = StringUtils.replace(message, "%player%", player.getName());
|
||||
|
||||
if (message.contains("%")) {
|
||||
message = PlaceholderReplacer.replace(player, message);
|
||||
}
|
||||
|
||||
Bukkit.dispatchCommand(player, message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendTitle(String action, UUID uuid, String command, String title, String subTitle, int fadeIn, int stay, int fadeOut) {
|
||||
Player player = Bukkit.getPlayer(uuid);
|
||||
|
||||
if (player == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
title = StringUtils.replace(title, "&", "§", "%player%", player.getName());
|
||||
subTitle = StringUtils.replace(title, "&", "§", "%player%", player.getName());
|
||||
|
||||
title = ResponseHandler.replaceArgsVariables(title, command);
|
||||
subTitle = ResponseHandler.replaceArgsVariables(subTitle, command);
|
||||
|
||||
title = PlaceholderReplacer.replace(player, title);
|
||||
subTitle = PlaceholderReplacer.replace(player, subTitle);
|
||||
|
||||
player.sendTitle(title, subTitle);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addPotionEffect(String action, UUID uuid, String potionEffectTypeName, int duration, int amplifier) {
|
||||
Player player = Bukkit.getPlayer(uuid);
|
||||
|
||||
if (player == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
PotionEffectType potionEffectType = null;
|
||||
try {
|
||||
potionEffectType = PotionEffectType.getByName(potionEffectTypeName);
|
||||
} catch (Exception ignored) { }
|
||||
|
||||
if (potionEffectType == null) {
|
||||
Logger.warning("! Failed to read action: " + action);
|
||||
Logger.warning(" > The effect \"" + potionEffectTypeName + "\" could not be found!");
|
||||
Logger.warning(" > Here's an example of an existing effect:");
|
||||
Logger.warning(" > BLINDNESS, REGENERATION");
|
||||
return;
|
||||
}
|
||||
|
||||
player.addPotionEffect(new PotionEffect(potionEffectType, duration, amplifier));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void playSound(String action, UUID uuid, String soundName, float volume, float pitch) {
|
||||
Player player = Bukkit.getPlayer(uuid);
|
||||
|
||||
if(player == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
Sound sound = Sound.valueOf(soundName);
|
||||
player.playSound(player.getLocation(), sound, volume, pitch);
|
||||
} catch (Exception exception) {
|
||||
Logger.warning("! Failed to read action: " + action);
|
||||
Logger.warning(" > The sound \"" + soundName + "\" could not be found!");
|
||||
Logger.warning(" > Here's an example of an existing sound effect:");
|
||||
Logger.warning(" > ENTITY_ENDER_DRAGON_GROWL");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendActionbar(String action, UUID uuid, String command, String message) {
|
||||
Player player = Bukkit.getPlayer(uuid);
|
||||
|
||||
if (player == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
message = ResponseHandler.replaceArgsVariables(message, command);
|
||||
message = StringUtils.replace(message, "&", "§", "%player%", player.getName());
|
||||
message = PlaceholderReplacer.replace(player, message);
|
||||
|
||||
try {
|
||||
if (versionPackage == null) {
|
||||
versionPackage = Reflection.getVersionPackageName();
|
||||
}
|
||||
|
||||
Object entityPlayer = player.getClass().getMethod("getHandle").invoke(player);
|
||||
Constructor<?> constructor = (Objects.<Class<?>>requireNonNull(Class.forName("net.minecraft.server." + versionPackage + ".PacketPlayOutChat"))).getConstructor(Class.forName("net.minecraft.server." + versionPackage + ".IChatBaseComponent"), byte.class);
|
||||
Object iChatBaseComponent = (Objects.requireNonNull(Class.forName("net.minecraft.server." + versionPackage + ".IChatBaseComponent"))).getDeclaredClasses()[0].getMethod("a", String.class).invoke(null, "{\"text\":\"" + message + "\"}");
|
||||
Object actionbarPacket = constructor.newInstance(iChatBaseComponent, (byte) 2);
|
||||
Object playerConnection = entityPlayer.getClass().getField("playerConnection").get(entityPlayer);
|
||||
playerConnection.getClass().getMethod("sendPacket", Class.forName("net.minecraft.server." + versionPackage + ".Packet")).invoke(playerConnection, actionbarPacket);
|
||||
|
||||
} catch (ClassNotFoundException
|
||||
| NoSuchMethodException
|
||||
| IllegalAccessException
|
||||
| InvocationTargetException
|
||||
| NoSuchFieldException
|
||||
| InstantiationException exception) {
|
||||
|
||||
Logger.warning("! Failed to run action: " + action);
|
||||
Logger.warning(" > Actionbars are not supported in this server version!");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,12 @@
|
||||
package de.rayzs.pat.utils.response.action.impl;
|
||||
|
||||
import de.rayzs.pat.plugin.logger.Logger;
|
||||
import de.rayzs.pat.utils.message.MessageTranslator;
|
||||
import de.rayzs.pat.utils.message.MessageHelper;
|
||||
import de.rayzs.pat.utils.response.ResponseHandler;
|
||||
import de.rayzs.pat.utils.response.action.Action;
|
||||
import com.velocitypowered.api.proxy.Player;
|
||||
import de.rayzs.pat.plugin.VelocityLoader;
|
||||
import de.rayzs.pat.utils.StringUtils;
|
||||
import de.rayzs.pat.utils.sender.CommandSender;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
@@ -14,49 +14,48 @@ public class VelocityAction implements Action {
|
||||
|
||||
@Override
|
||||
public void executeConsoleCommand(String action, UUID uuid, String command, String message) {
|
||||
Optional<Player> optPlayer = VelocityLoader.getServer().getPlayer(uuid);
|
||||
final CommandSender sender = CommandSender.from(uuid);
|
||||
message = ResponseHandler.replaceArgsVariables(message, command);
|
||||
|
||||
if (optPlayer.isPresent()) {
|
||||
message = message.replace("%player%", optPlayer.get().getUsername());
|
||||
if (sender != null && sender.isPlayer()) {
|
||||
message = message.replace("%player%", sender.getName());
|
||||
}
|
||||
|
||||
VelocityLoader.getServer().getCommandManager().executeAsync(VelocityLoader.getServer().getConsoleCommandSource(), message);
|
||||
VelocityLoader.getServer().getCommandManager().executeAsync(
|
||||
VelocityLoader.getServer().getConsoleCommandSource(),
|
||||
message
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void executePlayerCommand(String action, UUID uuid, String command, String message) {
|
||||
Optional<Player> optPlayer = VelocityLoader.getServer().getPlayer(uuid);
|
||||
final CommandSender sender = CommandSender.from(uuid);
|
||||
|
||||
if (optPlayer.isEmpty()) {
|
||||
if (sender == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Player player = optPlayer.get();
|
||||
|
||||
message = message.replace("%player%", player.getUsername());
|
||||
message = message.replace("%player%", sender.getName());
|
||||
message = ResponseHandler.replaceArgsVariables(message, command);
|
||||
|
||||
VelocityLoader.getServer().getCommandManager().executeAsync(player, message);
|
||||
sender.execute(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendTitle(String action, UUID uuid, String command, String title, String subTitle, int fadeIn, int stay, int fadeOut) {
|
||||
Optional<Player> optPlayer = VelocityLoader.getServer().getPlayer(uuid);
|
||||
final CommandSender sender = CommandSender.from(uuid);
|
||||
|
||||
if (optPlayer.isEmpty()) {
|
||||
if (sender == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Player player = optPlayer.get();
|
||||
|
||||
title = ResponseHandler.replaceArgsVariables(title, command);
|
||||
subTitle = ResponseHandler.replaceArgsVariables(subTitle, command);
|
||||
|
||||
title = StringUtils.replace(title, "%player%", player.getUsername());
|
||||
subTitle = StringUtils.replace(subTitle, "%player%", player.getUsername());
|
||||
title = StringUtils.replace(title, "%player%", sender.getName());
|
||||
subTitle = StringUtils.replace(subTitle, "%player%", sender.getName());
|
||||
|
||||
MessageTranslator.sendTitle(player, title, subTitle, fadeIn, stay, fadeOut);
|
||||
MessageHelper.sendTitle(sender, title, subTitle, fadeIn, stay, fadeOut);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -65,16 +64,14 @@ public class VelocityAction implements Action {
|
||||
|
||||
@Override
|
||||
public void playSound(String action, UUID uuid, String soundName, float volume, float pitch) {
|
||||
Optional<Player> optPlayer = VelocityLoader.getServer().getPlayer(uuid);
|
||||
final CommandSender sender = CommandSender.from(uuid);
|
||||
|
||||
if (optPlayer.isEmpty()) {
|
||||
if (sender == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Player player = optPlayer.get();
|
||||
|
||||
try {
|
||||
MessageTranslator.playSound(player, soundName, volume, pitch);
|
||||
MessageHelper.playSound(sender, soundName, volume, pitch);
|
||||
} catch (Exception exception) {
|
||||
Logger.warning("! Failed to read action: " + action);
|
||||
Logger.warning(" > The sound \"" + soundName + "\" could not be found!");
|
||||
@@ -85,17 +82,15 @@ public class VelocityAction implements Action {
|
||||
|
||||
@Override
|
||||
public void sendActionbar(String action, UUID uuid, String command, String message) {
|
||||
Optional<Player> optPlayer = VelocityLoader.getServer().getPlayer(uuid);
|
||||
final CommandSender sender = CommandSender.from(uuid);
|
||||
|
||||
if (optPlayer.isEmpty()) {
|
||||
if (sender == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Player player = optPlayer.get();
|
||||
|
||||
message = ResponseHandler.replaceArgsVariables(message, command);
|
||||
message = StringUtils.replace(message, "%player%", player.getUsername());
|
||||
message = StringUtils.replace(message, "%player%", sender.getName());
|
||||
|
||||
MessageTranslator.sendActionbar(player, message);
|
||||
MessageHelper.sendActionbar(sender, message);
|
||||
}
|
||||
}
|
||||
@@ -51,5 +51,9 @@ public interface CommandSender {
|
||||
String getName();
|
||||
String getServerName();
|
||||
|
||||
void execute(String command);
|
||||
void sendTitle(String title, String subtitle, int fadeIn, int stay, int fadeOut);
|
||||
void sendActionbar(String message);
|
||||
|
||||
void sendMessage(String message);
|
||||
}
|
||||
@@ -1,13 +1,20 @@
|
||||
package de.rayzs.pat.utils.sender.impl;
|
||||
|
||||
import de.rayzs.pat.api.storage.Storage;
|
||||
import de.rayzs.pat.plugin.logger.Logger;
|
||||
import de.rayzs.pat.utils.Reflection;
|
||||
import de.rayzs.pat.utils.message.MessageTranslator;
|
||||
import de.rayzs.pat.utils.message.MessageHelper;
|
||||
import de.rayzs.pat.utils.message.replacer.PlaceholderReplacer;
|
||||
import de.rayzs.pat.utils.sender.CommandSenderAbstract;
|
||||
import net.md_5.bungee.api.ChatMessageType;
|
||||
import net.md_5.bungee.api.chat.TextComponent;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.Objects;
|
||||
import java.util.UUID;
|
||||
|
||||
public class BukkitSender extends CommandSenderAbstract {
|
||||
@@ -100,23 +107,95 @@ public class BukkitSender extends CommandSenderAbstract {
|
||||
|
||||
@Override
|
||||
public void sendMessage(String message) {
|
||||
if (MessageTranslator.isSupported()) {
|
||||
MessageTranslator.send(sender, message);
|
||||
if (MessageHelper.isSupported()) {
|
||||
MessageHelper.sendMessage(this, message);
|
||||
return;
|
||||
}
|
||||
|
||||
// To prevent color-code overlapping on Bukkit consoles.
|
||||
if (Reflection.isCraftbukkit() && isConsole()) {
|
||||
if (Reflection.isBukkit() && isConsole()) {
|
||||
String[] lines = message.split("\n");
|
||||
|
||||
for (String line : lines) {
|
||||
sender.sendMessage(MessageTranslator.replaceMessage(sender, line));
|
||||
sender.sendMessage(PlaceholderReplacer.applyPlaceholders(this, line));
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
sender.sendMessage(MessageTranslator.replaceMessage(sender, message));
|
||||
sender.sendMessage(PlaceholderReplacer.applyPlaceholders(this, message));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendTitle(String title, String subtitle, int fadeIn, int stay, int fadeOut) {
|
||||
if (isPlayer()) return;
|
||||
|
||||
if (MessageHelper.isSupported()) {
|
||||
MessageHelper.sendTitle(this, title, subtitle, 10, 10, 10);
|
||||
return;
|
||||
}
|
||||
|
||||
if (Reflection.isAfter(1, 11, 0)) {
|
||||
((Player) sender).sendTitle(
|
||||
PlaceholderReplacer.applyPlaceholders(this, title),
|
||||
PlaceholderReplacer.applyPlaceholders(this, subtitle),
|
||||
fadeIn, stay, fadeOut
|
||||
);
|
||||
} else {
|
||||
((Player) sender).sendTitle(
|
||||
PlaceholderReplacer.applyPlaceholders(this, title),
|
||||
PlaceholderReplacer.applyPlaceholders(this, subtitle)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(String command) {
|
||||
Bukkit.dispatchCommand(sender, command);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendActionbar(String message) {
|
||||
if (MessageHelper.isSupported()) {
|
||||
MessageHelper.sendActionbar(this, message);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (Reflection.isAtMost(1, 16)) {
|
||||
try {
|
||||
final Object entityPlayer = sender.getClass().getMethod("getHandle").invoke(sender);
|
||||
final Constructor<?> constructor = (Objects.<Class<?>> requireNonNull(Class.forName("net.minecraft.server." + Reflection.getVersionPackageName() + ".PacketPlayOutChat")))
|
||||
.getConstructor(
|
||||
Class.forName("net.minecraft.server." + Reflection.getVersionPackageName() + ".IChatBaseComponent"),
|
||||
byte.class
|
||||
);
|
||||
|
||||
final Object iChatBaseComponent = (Objects.requireNonNull(Class.forName("net.minecraft.server." + Reflection.getVersionPackageName() + ".IChatBaseComponent")))
|
||||
.getDeclaredClasses()[0]
|
||||
.getMethod("a", String.class)
|
||||
.invoke(null, "{\"text\":\"" + message + "\"}");
|
||||
|
||||
final Object actionbarPacket = constructor.newInstance(iChatBaseComponent, (byte) 2);
|
||||
final Object playerConnection = entityPlayer.getClass().getField("playerConnection").get(entityPlayer);
|
||||
|
||||
playerConnection.getClass().getMethod(
|
||||
"sendPacket",
|
||||
Class.forName("net.minecraft.server." + Reflection.getVersionPackageName() + ".Packet")
|
||||
).invoke(playerConnection, actionbarPacket);
|
||||
|
||||
return;
|
||||
|
||||
|
||||
} catch (ClassNotFoundException
|
||||
| NoSuchMethodException
|
||||
| IllegalAccessException
|
||||
| InvocationTargetException
|
||||
| NoSuchFieldException
|
||||
| InstantiationException ignored) { }
|
||||
}
|
||||
|
||||
Logger.warning("Actionbars are not supported in this server version!");
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,10 +1,14 @@
|
||||
package de.rayzs.pat.utils.sender.impl;
|
||||
|
||||
import de.rayzs.pat.api.storage.Storage;
|
||||
import de.rayzs.pat.utils.message.MessageTranslator;
|
||||
import de.rayzs.pat.plugin.logger.Logger;
|
||||
import de.rayzs.pat.utils.message.MessageHelper;
|
||||
import de.rayzs.pat.utils.message.replacer.PlaceholderReplacer;
|
||||
import de.rayzs.pat.utils.sender.CommandSenderAbstract;
|
||||
import net.md_5.bungee.api.ChatMessageType;
|
||||
import net.md_5.bungee.api.CommandSender;
|
||||
import net.md_5.bungee.api.ProxyServer;
|
||||
import net.md_5.bungee.api.chat.TextComponent;
|
||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||
|
||||
import java.util.UUID;
|
||||
@@ -102,12 +106,56 @@ public class BungeeSender extends CommandSenderAbstract {
|
||||
|
||||
@Override
|
||||
public void sendMessage(String message) {
|
||||
if (MessageTranslator.isSupported()) {
|
||||
MessageTranslator.send(sender, message);
|
||||
if (MessageHelper.isSupported()) {
|
||||
MessageHelper.sendMessage(this, message);
|
||||
return;
|
||||
}
|
||||
|
||||
sender.sendMessage(MessageTranslator.replaceMessage(sender, message));
|
||||
sender.sendMessage(PlaceholderReplacer.applyPlaceholders(this, message));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendTitle(String title, String subtitle, int fadeIn, int stay, int fadeOut) {
|
||||
if (MessageHelper.isSupported()) {
|
||||
MessageHelper.sendTitle(this, title, subtitle, fadeIn, stay, fadeOut);
|
||||
return;
|
||||
}
|
||||
|
||||
if (! (sender instanceof ProxiedPlayer player)) {
|
||||
return;
|
||||
}
|
||||
|
||||
ProxyServer.getInstance().createTitle()
|
||||
.title(TextComponent.fromLegacyText(PlaceholderReplacer.applyPlaceholders(this, title)))
|
||||
.subTitle(TextComponent.fromLegacyText(PlaceholderReplacer.applyPlaceholders(this, subtitle)))
|
||||
.fadeIn(fadeIn)
|
||||
.stay(stay)
|
||||
.fadeOut(fadeOut)
|
||||
.send(player);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendActionbar(String message) {
|
||||
if (MessageHelper.isSupported()) {
|
||||
MessageHelper.sendActionbar(this, message);
|
||||
return;
|
||||
}
|
||||
|
||||
if (! (sender instanceof ProxiedPlayer player)) {
|
||||
return;
|
||||
}
|
||||
|
||||
player.sendMessage(
|
||||
ChatMessageType.ACTION_BAR,
|
||||
TextComponent.fromLegacyText(
|
||||
PlaceholderReplacer.applyPlaceholders(this, message)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(String command) {
|
||||
ProxyServer.getInstance().getPluginManager().dispatchCommand(sender, command);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -4,7 +4,7 @@ import com.velocitypowered.api.command.CommandSource;
|
||||
import com.velocitypowered.api.proxy.Player;
|
||||
import de.rayzs.pat.api.storage.Storage;
|
||||
import de.rayzs.pat.plugin.VelocityLoader;
|
||||
import de.rayzs.pat.utils.message.MessageTranslator;
|
||||
import de.rayzs.pat.utils.message.MessageHelper;
|
||||
import de.rayzs.pat.utils.sender.CommandSenderAbstract;
|
||||
|
||||
import java.util.Optional;
|
||||
@@ -105,7 +105,22 @@ public class VelocitySender extends CommandSenderAbstract {
|
||||
|
||||
@Override
|
||||
public void sendMessage(String message) {
|
||||
MessageTranslator.send(sender, message);
|
||||
MessageHelper.sendMessage(this, message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendTitle(String title, String subtitle, int fadeIn, int stay, int fadeOut) {
|
||||
MessageHelper.sendTitle(this, title, subtitle, fadeIn, stay, fadeOut);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendActionbar(String message) {
|
||||
MessageHelper.sendActionbar(this, message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(String command) {
|
||||
VelocityLoader.getServer().getCommandManager().executeAsync(sender, command);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -6,4 +6,10 @@ author: Rayzs_YT
|
||||
version: 2.5.1
|
||||
main: de.rayzs.pat.plugin.BungeeLoader
|
||||
|
||||
softDepends: [LuckPerms, PAPIProxyBridge]
|
||||
softDepends: [LuckPerms, PAPIProxyBridge]
|
||||
|
||||
libraries:
|
||||
- net.kyori:adventure-platform-bungeecord:4.4.1
|
||||
- net.kyori:adventure-text-minimessage:5.2.0
|
||||
- net.kyori:adventure-api:5.2.0
|
||||
- net.kyori:adventure-text-serializer-legacy:5.2.0
|
||||
@@ -15,7 +15,7 @@
|
||||
# %pat_general_prefix% = Get the PAT prefix set in the config.yml.
|
||||
# %pat_general_user% = Get the name of the user who receives this message.
|
||||
# %pat_general_version_current% = Get current version name of PAT.
|
||||
# %pat_general_version_newest% = Get newest version name of PAT.
|
||||
# %pat_general_version_newest% = Get the newest version name of PAT.
|
||||
|
||||
# Placeholders of some of the messages in the config.yml:
|
||||
# %pat_message_unknowncommand% = Get the "unknown command"-message from the config.yml of PAT. [cancel-blocked-command]
|
||||
|
||||
@@ -10,6 +10,12 @@ main: de.rayzs.pat.plugin.BukkitLoader
|
||||
|
||||
softdepend: [PlaceholderAPI, LuckPerms, GroupManager, Skript, ViaVersion, ViaBackwards, ViaRewind]
|
||||
|
||||
libraries:
|
||||
- net.kyori:adventure-platform-bukkit:4.4.1
|
||||
- net.kyori:adventure-text-minimessage:5.2.0
|
||||
- net.kyori:adventure-api:5.2.0
|
||||
- net.kyori:adventure-text-serializer-legacy:5.2.0
|
||||
|
||||
commands:
|
||||
proantitab:
|
||||
aliases: [pat]
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"id": "proantitab",
|
||||
"name": "ProAntiTab",
|
||||
"version": "2.5.1",
|
||||
"description": "Hides more than just your plugins.",
|
||||
"url": "https://www.rayzs.de/products/proantitab/page",
|
||||
"authors": ["Rayzs_YT"],
|
||||
"main":"de.rayzs.pat.plugin.VelocityLoader",
|
||||
"dependencies": [
|
||||
{
|
||||
"id":"luckperms",
|
||||
"optional":true
|
||||
},
|
||||
{
|
||||
"id":"papiproxybridge",
|
||||
"optional":true
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,371 @@
|
||||
package de.rayzs.pat.utils;
|
||||
|
||||
import de.rayzs.pat.api.storage.Storage;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import de.rayzs.pat.utils.configuration.helper.MultipleMessagesHelper;
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.Mac;
|
||||
import javax.crypto.spec.GCMParameterSpec;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
class CommunicationPacketsSecurityTest {
|
||||
|
||||
private static final String TOKEN = "test-token-6d21af0b-e44e-4c94-9920-7ecbd96243e1";
|
||||
private static final UUID BACKEND_ID = UUID.fromString("28ef48c0-62cc-4f25-b2f0-6fb53d2dd61b");
|
||||
private static final UUID OTHER_BACKEND_ID = UUID.fromString("dfe05064-55c9-4b3b-a65f-d6beaeb0b9af");
|
||||
private static final String EXPECTED_HKDF_SALT = "ProAntiTab/plugin-messaging/v1";
|
||||
|
||||
private String previousToken;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
previousToken = Storage.TOKEN;
|
||||
Storage.TOKEN = TOKEN;
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
void tearDown() {
|
||||
Storage.TOKEN = previousToken;
|
||||
}
|
||||
|
||||
@Test
|
||||
void normalPacketRoundTripsWithMatchingBackendContext() {
|
||||
UUID playerId = UUID.fromString("7c9f9835-cf72-49c1-aaf0-e4c9853cf7fa");
|
||||
var original = new CommunicationPackets.Proxy2Backend.ExecutePlayerCommandPacket(
|
||||
playerId, "warp spawn"
|
||||
);
|
||||
|
||||
byte[] encoded = CommunicationPackets.preparePacket(original, BACKEND_ID);
|
||||
Object decoded = CommunicationPackets.readPacket(encoded, BACKEND_ID);
|
||||
|
||||
assertNotNull(encoded);
|
||||
assertEquals(original, decoded);
|
||||
assertTrue(CommunicationPackets.isP2BPacket(decoded));
|
||||
assertFalse(CommunicationPackets.isInitialPacket(decoded));
|
||||
}
|
||||
|
||||
@Test
|
||||
void initialHandshakePacketRoundTripsIndependentlyOfBackendContext() {
|
||||
var original = new CommunicationPackets.Backend2Proxy.IdentityRequestPacket(BACKEND_ID);
|
||||
|
||||
byte[] encoded = CommunicationPackets.preparePacket(original, BACKEND_ID);
|
||||
|
||||
assertNotNull(encoded);
|
||||
assertTrue(CommunicationPackets.isInitialPacket(encoded));
|
||||
assertEquals(original, CommunicationPackets.readPacket(encoded, OTHER_BACKEND_ID));
|
||||
}
|
||||
|
||||
@Test
|
||||
void samePlaintextProducesDifferentCiphertextBecauseNonceIsRandom() {
|
||||
var packet = new CommunicationPackets.Proxy2Backend.ConsoleMessagePacket("same message");
|
||||
|
||||
byte[] first = CommunicationPackets.preparePacket(packet, BACKEND_ID);
|
||||
byte[] second = CommunicationPackets.preparePacket(packet, BACKEND_ID);
|
||||
|
||||
assertNotNull(first);
|
||||
assertNotNull(second);
|
||||
assertFalse(Arrays.equals(first, second), "AES-GCM packets must use fresh nonces");
|
||||
assertEquals(packet, CommunicationPackets.readPacket(first, BACKEND_ID));
|
||||
assertEquals(packet, CommunicationPackets.readPacket(second, BACKEND_ID));
|
||||
}
|
||||
|
||||
@Test
|
||||
void tamperingWithCiphertextIsRejected() {
|
||||
var packet = new CommunicationPackets.Proxy2Backend.ExecuteConsoleCommandPacket("say secure");
|
||||
byte[] encoded = CommunicationPackets.preparePacket(packet, BACKEND_ID);
|
||||
assertNotNull(encoded);
|
||||
|
||||
byte[] tampered = encoded.clone();
|
||||
tampered[tampered.length - 1] ^= 0x01;
|
||||
|
||||
assertNull(CommunicationPackets.readPacket(tampered, BACKEND_ID));
|
||||
}
|
||||
|
||||
@Test
|
||||
void tamperingWithAuthenticatedHeaderIsRejected() {
|
||||
var packet = new CommunicationPackets.Proxy2Backend.KeepAliveResponsePacket();
|
||||
byte[] encoded = CommunicationPackets.preparePacket(packet, BACKEND_ID);
|
||||
assertNotNull(encoded);
|
||||
|
||||
byte[] tampered = encoded.clone();
|
||||
tampered[1] = 0; // claim this normal packet is an initial packet
|
||||
|
||||
assertNull(CommunicationPackets.readPacket(tampered, BACKEND_ID));
|
||||
}
|
||||
|
||||
@Test
|
||||
void wrongBackendUuidCannotDecryptNormalPacket() {
|
||||
var packet = new CommunicationPackets.Backend2Proxy.AnnouncePlayerPermissionChanges(UUID.randomUUID());
|
||||
byte[] encoded = CommunicationPackets.preparePacket(packet, BACKEND_ID);
|
||||
|
||||
assertNotNull(encoded);
|
||||
assertNull(CommunicationPackets.readPacket(encoded, OTHER_BACKEND_ID));
|
||||
assertEquals(packet, CommunicationPackets.readPacket(encoded, BACKEND_ID));
|
||||
}
|
||||
|
||||
@Test
|
||||
void wrongStorageTokenCannotDecryptPacket() {
|
||||
var packet = new CommunicationPackets.Proxy2Backend.NotificationPacket(
|
||||
UUID.randomUUID(), "help"
|
||||
);
|
||||
byte[] encoded = CommunicationPackets.preparePacket(packet, BACKEND_ID);
|
||||
assertNotNull(encoded);
|
||||
|
||||
Storage.TOKEN = "different-token-that-must-not-authenticate";
|
||||
assertNull(CommunicationPackets.readPacket(encoded, BACKEND_ID));
|
||||
}
|
||||
|
||||
@Test
|
||||
void truncatedAndInvalidFramesAreRejectedWithoutThrowing() {
|
||||
assertDoesNotThrow(() -> {
|
||||
assertNull(CommunicationPackets.readPacket(null, BACKEND_ID));
|
||||
assertNull(CommunicationPackets.readPacket(new byte[0], BACKEND_ID));
|
||||
assertNull(CommunicationPackets.readPacket(new byte[8], BACKEND_ID));
|
||||
});
|
||||
|
||||
var packet = new CommunicationPackets.Backend2Proxy.KeepAlivePacket();
|
||||
byte[] encoded = CommunicationPackets.preparePacket(packet, BACKEND_ID);
|
||||
assertNotNull(encoded);
|
||||
|
||||
for (int length : new int[]{1, 2, 5, 13, encoded.length - 1}) {
|
||||
byte[] truncated = Arrays.copyOf(encoded, length);
|
||||
assertDoesNotThrow(() -> assertNull(CommunicationPackets.readPacket(truncated, BACKEND_ID)));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void invalidProtocolVersionIsRejected() {
|
||||
var packet = new CommunicationPackets.Backend2Proxy.KeepAlivePacket();
|
||||
byte[] encoded = CommunicationPackets.preparePacket(packet, BACKEND_ID);
|
||||
assertNotNull(encoded);
|
||||
|
||||
byte[] wrongVersion = encoded.clone();
|
||||
wrongVersion[0] = (byte) (CommunicationPackets.PROTOCOL_VERSION + 1);
|
||||
|
||||
assertNull(CommunicationPackets.readPacket(wrongVersion, BACKEND_ID));
|
||||
}
|
||||
|
||||
@Test
|
||||
void blankTokenDisablesEncodingAndDecoding() {
|
||||
var packet = new CommunicationPackets.Backend2Proxy.KeepAlivePacket();
|
||||
byte[] valid = CommunicationPackets.preparePacket(packet, BACKEND_ID);
|
||||
assertNotNull(valid);
|
||||
|
||||
Storage.TOKEN = " ";
|
||||
assertNull(CommunicationPackets.preparePacket(packet, BACKEND_ID));
|
||||
assertNull(CommunicationPackets.readPacket(valid, BACKEND_ID));
|
||||
}
|
||||
|
||||
@Test
|
||||
void representativePacketTypesPreserveTheirPayloads() {
|
||||
UUID player = UUID.fromString("c112a6b7-82ec-4120-a4f6-f7c6d0953eef");
|
||||
Set<UUID> players = new HashSet<>(Set.of(
|
||||
player,
|
||||
UUID.fromString("f59bad95-cd4c-4fc2-a76b-834f38de2447")
|
||||
));
|
||||
|
||||
CommunicationPackets.PATPacket[] packets = {
|
||||
new CommunicationPackets.Proxy2Backend.UpdatePacket(null),
|
||||
new CommunicationPackets.Proxy2Backend.UpdatePacket(player),
|
||||
new CommunicationPackets.Proxy2Backend.IdentityPacket(BACKEND_ID, "survival"),
|
||||
new CommunicationPackets.Proxy2Backend.ExecuteConsoleCommandPacket("list"),
|
||||
new CommunicationPackets.Proxy2Backend.ConsoleMessagePacket("hello"),
|
||||
new CommunicationPackets.Backend2Proxy.IdentityResponsePacket(BACKEND_ID),
|
||||
new CommunicationPackets.Backend2Proxy.DataSyncReceivedPacket(),
|
||||
new CommunicationPackets.Backend2Proxy.AnnounceGroupPermissionChanges(players)
|
||||
};
|
||||
|
||||
for (CommunicationPackets.PATPacket packet : packets) {
|
||||
byte[] encoded = CommunicationPackets.preparePacket(packet, BACKEND_ID);
|
||||
assertNotNull(encoded, () -> "Failed to encode " + packet.getClass().getSimpleName());
|
||||
assertEquals(packet, CommunicationPackets.readPacket(encoded, BACKEND_ID),
|
||||
() -> "Round-trip mismatch for " + packet.getClass().getSimpleName());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void normalPacketRequiresBackendContext() {
|
||||
var packet = new CommunicationPackets.Backend2Proxy.KeepAlivePacket();
|
||||
|
||||
assertNull(CommunicationPackets.preparePacket(packet, null));
|
||||
|
||||
byte[] encoded = CommunicationPackets.preparePacket(packet, BACKEND_ID);
|
||||
assertNotNull(encoded);
|
||||
assertNull(CommunicationPackets.readPacket(encoded, null));
|
||||
}
|
||||
|
||||
private static CommunicationPackets.Proxy2Backend.DataSyncPacket sync(String prefix, List<String> lines) {
|
||||
return new CommunicationPackets.Proxy2Backend.DataSyncPacket(
|
||||
new CommunicationPackets.Proxy2Backend.DataSyncPacket.Messages(prefix),
|
||||
new CommunicationPackets.Proxy2Backend.DataSyncPacket.AutoLowerCase(true),
|
||||
new CommunicationPackets.Proxy2Backend.DataSyncPacket.UnknownCommand(true, new MultipleMessagesHelper(lines)));
|
||||
}
|
||||
|
||||
private static void assertRoundTrip(CommunicationPackets.PATPacket packet) {
|
||||
byte[] wire = CommunicationPackets.preparePacket(packet, BACKEND_ID);
|
||||
assertNotNull(wire, () -> "Encoding failed for " + packet.getClass().getSimpleName());
|
||||
Object decoded = CommunicationPackets.readPacket(wire, BACKEND_ID);
|
||||
if (packet instanceof CommunicationPackets.Proxy2Backend.DataSyncPacket original) {
|
||||
var actual = assertInstanceOf(CommunicationPackets.Proxy2Backend.DataSyncPacket.class, decoded);
|
||||
assertEquals(original.messages(), actual.messages());
|
||||
assertEquals(original.autoLowerCase(), actual.autoLowerCase());
|
||||
assertEquals(original.unknownCommand().enabled(), actual.unknownCommand().enabled());
|
||||
assertEquals(original.unknownCommand().message().getLines(), actual.unknownCommand().message().getLines());
|
||||
} else {
|
||||
assertEquals(packet, decoded);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void allFourteenPacketTypesRoundTrip() {
|
||||
UUID player = UUID.fromString("f5b80b7d-c1ad-48f0-b07b-4bd3e24fb8f2");
|
||||
CommunicationPackets.PATPacket[] packets = {
|
||||
new CommunicationPackets.Proxy2Backend.UpdatePacket(null),
|
||||
new CommunicationPackets.Proxy2Backend.IdentityPacket(BACKEND_ID, "survival"),
|
||||
new CommunicationPackets.Proxy2Backend.NotificationPacket(player, "help"),
|
||||
new CommunicationPackets.Proxy2Backend.ExecuteConsoleCommandPacket("list"),
|
||||
new CommunicationPackets.Proxy2Backend.ExecutePlayerCommandPacket(player, "spawn"),
|
||||
new CommunicationPackets.Proxy2Backend.ConsoleMessagePacket("hello"),
|
||||
new CommunicationPackets.Proxy2Backend.KeepAliveResponsePacket(),
|
||||
sync("prefix", List.of("one", "two", "three")),
|
||||
new CommunicationPackets.Backend2Proxy.IdentityRequestPacket(BACKEND_ID),
|
||||
new CommunicationPackets.Backend2Proxy.IdentityResponsePacket(BACKEND_ID),
|
||||
new CommunicationPackets.Backend2Proxy.DataSyncReceivedPacket(),
|
||||
new CommunicationPackets.Backend2Proxy.KeepAlivePacket(),
|
||||
new CommunicationPackets.Backend2Proxy.AnnouncePlayerPermissionChanges(player),
|
||||
new CommunicationPackets.Backend2Proxy.AnnounceGroupPermissionChanges(Set.of(player, BACKEND_ID))
|
||||
};
|
||||
assertEquals(14, packets.length);
|
||||
for (var packet : packets) assertRoundTrip(packet);
|
||||
}
|
||||
|
||||
@Test
|
||||
void maximumPlaintextAndWireSizeAreAcceptedAndNextByteRejected() {
|
||||
// 19 bytes of framing + 16,384 + 8,192 + 8,142 bytes of strings = 32,737 bytes.
|
||||
var maximum = sync("a".repeat(16384), List.of("b".repeat(8192), "c".repeat(8142)));
|
||||
byte[] wire = CommunicationPackets.preparePacket(maximum, BACKEND_ID);
|
||||
assertNotNull(wire);
|
||||
assertEquals(32_767, wire.length);
|
||||
assertRoundTrip(maximum);
|
||||
assertNull(CommunicationPackets.readPacket(Arrays.copyOf(wire, wire.length + 1), BACKEND_ID));
|
||||
|
||||
var overMaximum = sync("a".repeat(16384), List.of("b".repeat(8192), "c".repeat(8143)));
|
||||
assertNull(CommunicationPackets.preparePacket(overMaximum, BACKEND_ID));
|
||||
}
|
||||
|
||||
@Test
|
||||
void utf8StringsAreLimitedByTotalPacketBytes() {
|
||||
// 1-byte type + 4-byte length + UTF-8 bytes.
|
||||
assertRoundTrip(new CommunicationPackets.Proxy2Backend.ConsoleMessagePacket("é".repeat(16_366)));
|
||||
assertNull(CommunicationPackets.preparePacket(
|
||||
new CommunicationPackets.Proxy2Backend.ConsoleMessagePacket("é".repeat(16_367)), BACKEND_ID));
|
||||
}
|
||||
|
||||
@Test
|
||||
void collectionsAreLimitedByTotalPacketBytes() {
|
||||
// Each empty string still takes 4 bytes for its length prefix.
|
||||
assertRoundTrip(sync("", java.util.Collections.nCopies(8_181, "")));
|
||||
assertNull(CommunicationPackets.preparePacket(
|
||||
sync("", java.util.Collections.nCopies(8_182, "")), BACKEND_ID));
|
||||
|
||||
Set<UUID> ids = new HashSet<>();
|
||||
for (int i = 0; i < 2_045; i++) ids.add(new UUID(0, i));
|
||||
assertRoundTrip(new CommunicationPackets.Backend2Proxy.AnnounceGroupPermissionChanges(ids));
|
||||
ids.add(new UUID(0, 2_045));
|
||||
assertNull(CommunicationPackets.preparePacket(
|
||||
new CommunicationPackets.Backend2Proxy.AnnounceGroupPermissionChanges(ids), BACKEND_ID));
|
||||
}
|
||||
|
||||
// Independently encrypt arbitrary plaintext to exercise malformed authenticated codec input.
|
||||
private static byte[] authenticatedFrame(byte[] plaintext, boolean initial) throws Exception {
|
||||
Method derive = CommunicationPackets.class.getDeclaredMethod("deriveKey", String.class, UUID.class);
|
||||
derive.setAccessible(true);
|
||||
SecretKeySpec key = (SecretKeySpec) derive.invoke(null, TOKEN, initial ? null : BACKEND_ID);
|
||||
byte[] header = {CommunicationPackets.PROTOCOL_VERSION, (byte) (initial ? 0 : 1)};
|
||||
byte[] nonce = new byte[12]; // Deterministic nonce used only by isolated test frames.
|
||||
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
|
||||
cipher.init(Cipher.ENCRYPT_MODE, key, new GCMParameterSpec(128, nonce));
|
||||
cipher.updateAAD(header);
|
||||
byte[] ciphertext = cipher.doFinal(plaintext);
|
||||
byte[] frame = new byte[header.length + nonce.length + ciphertext.length];
|
||||
System.arraycopy(header, 0, frame, 0, 2);
|
||||
System.arraycopy(nonce, 0, frame, 2, 12);
|
||||
System.arraycopy(ciphertext, 0, frame, 14, ciphertext.length);
|
||||
return frame;
|
||||
}
|
||||
|
||||
private static byte[] plaintext(int type, int length) throws Exception {
|
||||
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
|
||||
DataOutputStream out = new DataOutputStream(bytes);
|
||||
out.writeByte(type);
|
||||
out.writeInt(length);
|
||||
return bytes.toByteArray();
|
||||
}
|
||||
|
||||
@Test
|
||||
void authenticatedMalformedPayloadsAreRejected() throws Exception {
|
||||
// Unknown packet type, trailing bytes, invalid/negative string lengths.
|
||||
byte[][] invalid = {
|
||||
{(byte) 127},
|
||||
{23, 1},
|
||||
plaintext(6, -1),
|
||||
plaintext(6, 32_738),
|
||||
plaintext(6, 10),
|
||||
plaintext(25, -1),
|
||||
plaintext(25, Integer.MAX_VALUE),
|
||||
plaintext(8, -1),
|
||||
plaintext(8, Integer.MAX_VALUE)
|
||||
};
|
||||
for (byte[] payload : invalid) {
|
||||
assertNull(CommunicationPackets.readPacket(authenticatedFrame(payload, false), BACKEND_ID),
|
||||
"Malformed authenticated packet accepted: " + Arrays.toString(payload));
|
||||
}
|
||||
// Initial flag must match decoded packet type, even with a valid GCM tag.
|
||||
assertNull(CommunicationPackets.readPacket(authenticatedFrame(new byte[]{23}, true), BACKEND_ID));
|
||||
assertNull(CommunicationPackets.readPacket(authenticatedFrame(new byte[]{20}, false), BACKEND_ID));
|
||||
}
|
||||
|
||||
@Test
|
||||
void hkdfMatchesIndependentExtractExpandComputation() throws Exception {
|
||||
Method derive = CommunicationPackets.class.getDeclaredMethod("deriveKey", String.class, UUID.class);
|
||||
derive.setAccessible(true);
|
||||
Mac mac = Mac.getInstance("HmacSHA256");
|
||||
mac.init(new SecretKeySpec(EXPECTED_HKDF_SALT.getBytes(StandardCharsets.UTF_8), "HmacSHA256"));
|
||||
byte[] prk = mac.doFinal(TOKEN.getBytes(StandardCharsets.UTF_8));
|
||||
for (UUID context : new UUID[]{null, BACKEND_ID}) {
|
||||
String info = context == null ? "initial" : "backend:" + context;
|
||||
mac.init(new SecretKeySpec(prk, "HmacSHA256"));
|
||||
mac.update(info.getBytes(StandardCharsets.UTF_8));
|
||||
mac.update((byte) 1);
|
||||
byte[] expected = mac.doFinal();
|
||||
SecretKeySpec actual = (SecretKeySpec) derive.invoke(null, TOKEN, context);
|
||||
assertArrayEquals(expected, actual.getEncoded());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void oversizedWirePacketIsRejectedBeforeDecryption() {
|
||||
// Default Velocity maximum payload size plus one byte.
|
||||
byte[] oversized = new byte[32_768];
|
||||
oversized[0] = CommunicationPackets.PROTOCOL_VERSION;
|
||||
oversized[1] = 1;
|
||||
|
||||
assertNull(CommunicationPackets.readPacket(oversized, BACKEND_ID));
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user