diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml index 3390df5..fa8dbe3 100644 --- a/.github/workflows/gradle.yml +++ b/.github/workflows/gradle.yml @@ -16,8 +16,8 @@ jobs: java-package: jdk - name: Grant execute permission for gradlew run: chmod +x gradlew - - name: Build with Gradle - run: ./gradlew clean build + - name: Build with Gradle, using shadowJar + run: ./gradlew clean shadowJar - name: Upload artifact uses: actions/upload-artifact@v2 with: diff --git a/README.md b/README.md index a2f67c5..188cfd2 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,6 @@ on server start: set address of connection to "127.0.0.1" # Use this IP if the Bungeecord is on the same machine set port of connection to 20000 # This port as to be opened if the specified client is not hosted on the same machine as the server set password of connection to "Strong password" # Complete your password here, this has to be the same as the one in the Bungeecord config - set name of connection to "hub" # Name has to be unique, if the same name is already connected, the connection will end start new connection with last created connection # Sending connection request to the server wait 30 seconds # Waiting 30 seconds between 2 connection tries, it's recommended to not decrease this value ``` diff --git a/build.gradle b/build.gradle index 94ee262..eb26f70 100644 --- a/build.gradle +++ b/build.gradle @@ -1,33 +1,34 @@ import org.apache.tools.ant.filters.ReplaceTokens plugins { + id 'com.github.johnrengelman.shadow' version '7.0.0' id 'java' } group 'fr.zorg' -version '1.0.3' +version '1.1.0' -def mcVersion = '1.16' -def subVersion = '.5' +def mcVersion = '1.17' +def subVersion = '' repositories { mavenCentral() - jcenter() + maven { url = 'https://jitpack.io' } maven { url = 'https://hub.spigotmc.org/nexus/content/repositories/snapshots/' } maven { url = 'https://oss.sonatype.org/content/repositories/snapshots' } - maven { url = 'https://jitpack.io' } maven { url = 'https://repo.destroystokyo.com/repository/maven-public/' } } dependencies { compileOnly group: 'org.spigotmc', name: 'spigot-api', version: mcVersion + subVersion + '-R0.1-SNAPSHOT' compileOnly group: 'net.md-5', name: 'bungeecord-api', version: mcVersion + '-R0.1-SNAPSHOT' - implementation group: 'org.jetbrains', name: 'annotations', version: '16.0.2' - implementation (group: 'com.github.SkriptLang', name: 'Skript', version: '2.5.3') { + compileOnly group: 'org.jetbrains', name: 'annotations', version: '16.0.2' + compileOnly (group: 'com.github.SkriptLang', name: 'Skript', version: '2.6-alpha1') { exclude group: 'com.sk89q.worldguard', module: 'worldguard-legacy' exclude group: 'net.milkbowl.vault', module: 'Vault' } - compile group: 'commons-io', name: 'commons-io', version: '2.8.0' + implementation group: 'commons-io', name: 'commons-io', version: '2.8.0' + implementation group: 'com.github.rockaport', name:'alice', version: '0.9.0' } [compileJava, compileTestJava]*.options*.encoding = 'UTF-8' @@ -38,8 +39,12 @@ processResources { ] } -jar { - from { - configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } +configurations { + implementation { + canBeResolved = true } } + +shadowJar { + archiveName("BungeeSK.jar") +} \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 2a56324..0f80bbf 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.8.2-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.0.2-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/src/main/java/fr/zorg/bungeesk/bukkit/BungeeSK.java b/src/main/java/fr/zorg/bungeesk/bukkit/BungeeSK.java index d147c41..c3fe741 100644 --- a/src/main/java/fr/zorg/bungeesk/bukkit/BungeeSK.java +++ b/src/main/java/fr/zorg/bungeesk/bukkit/BungeeSK.java @@ -1,26 +1,28 @@ package fr.zorg.bungeesk.bukkit; -import java.io.IOException; -import java.util.logging.Level; -import java.util.logging.Logger; - +import ch.njol.skript.Skript; +import ch.njol.skript.SkriptAddon; +import com.rockaport.alice.AliceContext; import fr.zorg.bungeesk.bukkit.sockets.ConnectionClient; -import fr.zorg.bungeesk.bukkit.updater.Commands; -import fr.zorg.bungeesk.bukkit.updater.Updater; import fr.zorg.bungeesk.bukkit.utils.Metrics; +import fr.zorg.bungeesk.common.encryption.GlobalEncryption; import org.bukkit.plugin.java.JavaPlugin; -import ch.njol.skript.Skript; -import ch.njol.skript.SkriptAddon; +import java.io.IOException; +import java.util.logging.Level; +import java.util.logging.Logger; public class BungeeSK extends JavaPlugin { private Metrics metrics; private static Logger logger; + private static GlobalEncryption encryption; @Override public void onEnable() { this.metrics = new Metrics(this, 10655); + encryption = new GlobalEncryption(AliceContext.Algorithm.AES, 10); + logger = getLogger(); final SkriptAddon addon = Skript.registerAddon(this); try { @@ -28,16 +30,13 @@ public void onEnable() { } catch (IOException e) { e.printStackTrace(); } - Updater.get().register(new Commands()); this.metrics.addCustomChart(new Metrics.SimplePie("skript_version", () -> Skript.getVersion().toString())); } @Override public void onDisable() { - Updater.get().stop(); - if(ConnectionClient.get() != null) { - getLogger().info("Disconnecting from connection " + ConnectionClient.get().getAddress() + ":" + ConnectionClient.get().getPort()); + if (isClientConnected()) { ConnectionClient.get().disconnect(); } } @@ -47,7 +46,6 @@ public static BungeeSK getInstance() { } - public static boolean isClientConnected() { if (ConnectionClient.get() != null && ConnectionClient.get().isConnected()) { return true; @@ -56,4 +54,7 @@ public static boolean isClientConnected() { return false; } + public static GlobalEncryption getEncryption() { + return encryption; + } } diff --git a/src/main/java/fr/zorg/bungeesk/bukkit/skript/Types.java b/src/main/java/fr/zorg/bungeesk/bukkit/skript/Types.java index cd6516d..fe2a13e 100644 --- a/src/main/java/fr/zorg/bungeesk/bukkit/skript/Types.java +++ b/src/main/java/fr/zorg/bungeesk/bukkit/skript/Types.java @@ -7,6 +7,7 @@ import ch.njol.skript.registrations.Classes; import fr.zorg.bungeesk.bukkit.sockets.ClientSettings; import fr.zorg.bungeesk.bukkit.utils.BungeePlayer; +import fr.zorg.bungeesk.bukkit.utils.BungeeServer; public class Types { @@ -62,12 +63,42 @@ public BungeePlayer parse(final String id, final ParseContext context) { @Override public String toString(final BungeePlayer player, final int arg1) { - return player.getPlayer(); + return player.getName(); } @Override public String toVariableNameString(final BungeePlayer player) { - return player.getPlayer(); + return player.getName(); + } + + })); + + Classes.registerClass(new ClassInfo<>(BungeeServer.class, "bungeeserver") + .defaultExpression(new EventValueExpression<>(BungeeServer.class)) + .user("bungeeserver") + .name("Bungee player") + .description("Represents a player on the network") + .since("1.1.0") + .parser(new Parser() { + + @Override + public String getVariableNamePattern() { + return ".+"; + } + + @Override + public BungeeServer parse(final String id, final ParseContext context) { + return null; + } + + @Override + public String toString(final BungeeServer server, final int arg1) { + return server.getName(); + } + + @Override + public String toVariableNameString(final BungeeServer server) { + return server.getName(); } })); diff --git a/src/main/java/fr/zorg/bungeesk/bukkit/skript/conditions/CondBungeePlayerConnected.java b/src/main/java/fr/zorg/bungeesk/bukkit/skript/conditions/CondBungeePlayerConnected.java index 03a8aae..aaa2f81 100644 --- a/src/main/java/fr/zorg/bungeesk/bukkit/skript/conditions/CondBungeePlayerConnected.java +++ b/src/main/java/fr/zorg/bungeesk/bukkit/skript/conditions/CondBungeePlayerConnected.java @@ -9,22 +9,17 @@ import ch.njol.skript.lang.Expression; import ch.njol.skript.lang.SkriptParser; import ch.njol.util.Kleenean; +import com.google.gson.JsonObject; import fr.zorg.bungeesk.bukkit.BungeeSK; import fr.zorg.bungeesk.bukkit.sockets.ConnectionClient; import fr.zorg.bungeesk.bukkit.utils.BungeePlayer; import org.bukkit.event.Event; import org.jetbrains.annotations.Nullable; -import java.util.LinkedList; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; - @Name("Is bungee player connected") @Description("Checks if a bungee player is connected") @Since("1.0.0") -@Examples("broadcast \"God is connected !\" if bungeeplayer \"Zorg\" is connected") +@Examples("broadcast \"Zorg is connected !\" if bungee player named \"Zorg\" is connected") public class CondBungeePlayerConnected extends Condition { static { @@ -46,11 +41,14 @@ public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelaye @Override public boolean check(Event e) { if (BungeeSK.isClientConnected()) { - String result = ConnectionClient.get().future("ISCONNECTEDµ" + player.getSingle(e).getData()); - if (negate) { - return (result.equals("FALSE")); - } - return (result.equals("TRUE")); + if (player.getSingle(e) == null) + return negate; + + final JsonObject result = ConnectionClient.get().future("expressionGetPlayerConnectionState", + "playerUniqueId", player.getSingle(e).getUuid()); + if (negate) + return (result.get("error").getAsBoolean()); + return !(result.get("error").getAsBoolean()); } return false; } diff --git a/src/main/java/fr/zorg/bungeesk/bukkit/skript/effects/EffBroadcastMessageToNetwork.java b/src/main/java/fr/zorg/bungeesk/bukkit/skript/effects/EffBroadcastMessageToNetwork.java new file mode 100644 index 0000000..bdb8d08 --- /dev/null +++ b/src/main/java/fr/zorg/bungeesk/bukkit/skript/effects/EffBroadcastMessageToNetwork.java @@ -0,0 +1,47 @@ +package fr.zorg.bungeesk.bukkit.skript.effects; + +import ch.njol.skript.Skript; +import ch.njol.skript.doc.Description; +import ch.njol.skript.doc.Examples; +import ch.njol.skript.doc.Name; +import ch.njol.skript.doc.Since; +import ch.njol.skript.lang.Effect; +import ch.njol.skript.lang.Expression; +import ch.njol.skript.lang.SkriptParser; +import ch.njol.util.Kleenean; +import fr.zorg.bungeesk.bukkit.BungeeSK; +import fr.zorg.bungeesk.bukkit.sockets.ConnectionClient; +import org.bukkit.event.Event; + +@Name("Broadcast message to the network") +@Description("Broadcast message to the network, like the /alert command does but with more personalization (the messages will not appear in the spigot consoles)") +@Examples("broadcast \"&6Hello everyone\" to network") +@Since("1.1.0") +public class EffBroadcastMessageToNetwork extends Effect { + + static { + Skript.registerEffect(EffBroadcastMessageToNetwork.class, + "broadcast %string% to [the] network"); + } + + private Expression message; + + @Override + public boolean init(Expression[] exprs, int pattern, Kleenean kleenean, SkriptParser.ParseResult parseResult) { + this.message = (Expression) exprs[0]; + return true; + } + + @Override + protected void execute(Event e) { + if (BungeeSK.isClientConnected()) { + ConnectionClient.get().write(true, "effectBroadcastMessageToNetwork", + "message", this.message.getSingle(e)); + } + } + + @Override + public String toString(Event e, boolean debug) { + return "broadcast message " + this.message.toString(e, debug) + " into the whole bungeecord network"; + } +} diff --git a/src/main/java/fr/zorg/bungeesk/bukkit/skript/effects/EffBroadcastMessageToServer.java b/src/main/java/fr/zorg/bungeesk/bukkit/skript/effects/EffBroadcastMessageToServer.java index 941fbd3..ad7e1f3 100644 --- a/src/main/java/fr/zorg/bungeesk/bukkit/skript/effects/EffBroadcastMessageToServer.java +++ b/src/main/java/fr/zorg/bungeesk/bukkit/skript/effects/EffBroadcastMessageToServer.java @@ -11,34 +11,41 @@ import ch.njol.util.Kleenean; import fr.zorg.bungeesk.bukkit.BungeeSK; import fr.zorg.bungeesk.bukkit.sockets.ConnectionClient; +import fr.zorg.bungeesk.bukkit.utils.BungeeServer; import org.bukkit.event.Event; import org.jetbrains.annotations.Nullable; @Name("Broadcast message to server") @Description("Broadcasts a message to a server in the network") -@Examples("broadcast \"&aHello world !\" to server \"hub\"") -@Since("1.0.3") +@Examples("broadcast \"&aHello world !\" to bungee server named \"hub\"") +@Since("1.0.3 - 1.1.0: Usage of BungeeServer type") public class EffBroadcastMessageToServer extends Effect { static { Skript.registerEffect(EffBroadcastMessageToServer.class, - "broadcast %string% to server %string%"); + "broadcast %string% to %bungeeserver%"); } private Expression message; - private Expression server; + private Expression server; @Override public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, SkriptParser.ParseResult parseResult) { - message = (Expression) exprs[0]; - server = (Expression) exprs[1]; + this.message = (Expression) exprs[0]; + this.server = (Expression) exprs[1]; return true; } @Override protected void execute(Event e) { if (BungeeSK.isClientConnected()) { - ConnectionClient.get().write("BROADCASTTOSERVµ" + server.getSingle(e) + "µ" + message.getSingle(e)); + + if (this.server.getSingle(e) == null) + return; + + ConnectionClient.get().write(true, "effectBroadcastMessageToServer", + "server", this.server.getSingle(e).getAddress() + ":" + this.server.getSingle(e).getPort(), + "message", message.getSingle(e)); } } diff --git a/src/main/java/fr/zorg/bungeesk/bukkit/skript/effects/EffExecuteCommand.java b/src/main/java/fr/zorg/bungeesk/bukkit/skript/effects/EffExecuteCommand.java index 650bb57..fb4e409 100644 --- a/src/main/java/fr/zorg/bungeesk/bukkit/skript/effects/EffExecuteCommand.java +++ b/src/main/java/fr/zorg/bungeesk/bukkit/skript/effects/EffExecuteCommand.java @@ -11,57 +11,65 @@ import ch.njol.util.Kleenean; import fr.zorg.bungeesk.bukkit.BungeeSK; import fr.zorg.bungeesk.bukkit.sockets.ConnectionClient; +import fr.zorg.bungeesk.bukkit.utils.BungeeServer; import org.bukkit.event.Event; import org.jetbrains.annotations.Nullable; @Name("Execute console command") @Description("Make bungee or spigot execute command") -@Since("1.0.0") -@Examples({"make bungee console execute command \"alert This is an alert !\"", - "make server \"hub\" console execute command \"say Hi everyone !\""}) +@Since("1.0.0 - 1.1.0: Usage of BungeeServer type") +@Examples({"make bungee execute console command \"alert This is an alert !\"", + "make bungee server named \"hub\" execute console command \"say Hi everyone !\""}) public class EffExecuteCommand extends Effect { static { Skript.registerEffect(EffExecuteCommand.class, - "make bungee console execute command %string%", - "make server %string% console execute command %string%", - "make all servers console execute command %string%" - + "make bungee[cord] [server] execute console command %string%", + "make %bungeeserver% execute console command %string%", + "make all servers execute console command %string%" ); } private Expression command; - private Expression server; + private Expression server; private int pattern; @Override public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, SkriptParser.ParseResult parseResult) { - command = (Expression) exprs[0]; this.pattern = matchedPattern; + if (this.pattern == 1) { - command = (Expression) exprs[1]; - server = (Expression) exprs[0]; - } + this.command = (Expression) exprs[1]; + this.server = (Expression) exprs[0]; + } else + this.command = (Expression) exprs[0]; + return true; } @Override protected void execute(Event e) { if (BungeeSK.isClientConnected()) { - String server = null; + String toSend = null; switch (this.pattern) { case 0: - server = "Bungee"; + toSend = "bungeecord"; break; - case 1: - server = this.server.getSingle(e); + case 1: { + if (this.server.getSingle(e) == null) + return; + toSend = this.server.getSingle(e).getAddress() + ":" + this.server.getSingle(e).getPort(); break; + } case 2: - server = "All"; + toSend = "all"; break; } - ConnectionClient.get().write("EffExecuteCommandµ" + server + "µ" + command.getSingle(e)); + + ConnectionClient.get().write(true, "effectExecuteCommand", + "server", toSend, + "command", this.command.getSingle(e)); } } diff --git a/src/main/java/fr/zorg/bungeesk/bukkit/skript/effects/EffKickBungeePlayer.java b/src/main/java/fr/zorg/bungeesk/bukkit/skript/effects/EffKickBungeePlayer.java new file mode 100644 index 0000000..2e362ab --- /dev/null +++ b/src/main/java/fr/zorg/bungeesk/bukkit/skript/effects/EffKickBungeePlayer.java @@ -0,0 +1,55 @@ +package fr.zorg.bungeesk.bukkit.skript.effects; + +import ch.njol.skript.Skript; +import ch.njol.skript.doc.Description; +import ch.njol.skript.doc.Examples; +import ch.njol.skript.doc.Name; +import ch.njol.skript.doc.Since; +import ch.njol.skript.lang.Effect; +import ch.njol.skript.lang.Expression; +import ch.njol.skript.lang.SkriptParser; +import ch.njol.util.Kleenean; +import fr.zorg.bungeesk.bukkit.BungeeSK; +import fr.zorg.bungeesk.bukkit.sockets.ConnectionClient; +import fr.zorg.bungeesk.bukkit.utils.BungeePlayer; +import org.bukkit.event.Event; + +@Name("Kick bungee player") +@Description("Kicks a player on the network from the network") +@Examples("kick bungee player named \"Zorg_btw\" from bungeecord due to \"&6Spamming in the chat is not good :'(\"") +@Since("1.1.0") +public class EffKickBungeePlayer extends Effect { + + static { + Skript.registerEffect(EffKickBungeePlayer.class, + "kick %bungeeplayer% from bungeecord [(due to|because of) %-string%]"); + } + + private Expression player; + private Expression reason; + + @Override + public boolean init(Expression[] exprs, int pattern, Kleenean kleenean, SkriptParser.ParseResult parseResult) { + this.player = (Expression) exprs[0]; + this.reason = (Expression) exprs[1]; + return true; + } + + @Override + protected void execute(Event e) { + if (BungeeSK.isClientConnected()) { + if (this.player.getSingle(e) == null) + return; + System.out.println("this.reason.getSingle(e) = " + this.reason.getSingle(e)); + ConnectionClient.get().write(true, "effectKickBungeePlayer", + "playerUniqueId", this.player.getSingle(e).getUuid(), + "reason", (this.reason == null ? "NONE" : this.reason.getSingle(e))); + } + } + + @Override + public String toString(Event event, boolean b) { + return "kicks bungee player with uuid " + this.player.toString(event, b); + } + +} \ No newline at end of file diff --git a/src/main/java/fr/zorg/bungeesk/bukkit/skript/effects/EffMakeBungeePlayerExecuteCommand.java b/src/main/java/fr/zorg/bungeesk/bukkit/skript/effects/EffMakeBungeePlayerExecuteCommand.java new file mode 100644 index 0000000..76d5da0 --- /dev/null +++ b/src/main/java/fr/zorg/bungeesk/bukkit/skript/effects/EffMakeBungeePlayerExecuteCommand.java @@ -0,0 +1,56 @@ +package fr.zorg.bungeesk.bukkit.skript.effects; + +import ch.njol.skript.Skript; +import ch.njol.skript.doc.Description; +import ch.njol.skript.doc.Examples; +import ch.njol.skript.doc.Name; +import ch.njol.skript.doc.Since; +import ch.njol.skript.lang.Effect; +import ch.njol.skript.lang.Expression; +import ch.njol.skript.lang.SkriptParser; +import ch.njol.util.Kleenean; +import fr.zorg.bungeesk.bukkit.BungeeSK; +import fr.zorg.bungeesk.bukkit.sockets.ConnectionClient; +import fr.zorg.bungeesk.bukkit.utils.BungeePlayer; +import org.bukkit.event.Event; + +@Name("Make BungeePlayer execute command") +@Description("Make a player on the bungeecord execute a specific command") +@Examples("make bungee player named \"Zorg_btw\" execute command \"say What's up people !\"") +@Since("1.1.0") +public class EffMakeBungeePlayerExecuteCommand extends Effect { + + static { + Skript.registerEffect(EffMakeBungeePlayerExecuteCommand.class, + "make %bungeeplayer% execute command %string%"); + } + + private Expression player; + private Expression message; + + @Override + public boolean init(Expression[] exprs, int pattern, Kleenean kleenean, SkriptParser.ParseResult parseResult) { + this.player = (Expression) exprs[0]; + this.message = (Expression) exprs[1]; + return true; + } + + @Override + protected void execute(Event e) { + if (BungeeSK.isClientConnected()) { + if (this.player.getSingle(e) == null) + return; + + ConnectionClient.get().write(true, "effectMakeBungeePlayerExecuteCommand", + "playerUniqueId", this.player.getSingle(e).getUuid(), + "command", this.message.getSingle(e)); + } + + } + + @Override + public String toString(Event e, boolean debug) { + return "make bungee player " + this.player.toString(e, debug) + " execute command " + this.message.toString(e, debug); + } + +} diff --git a/src/main/java/fr/zorg/bungeesk/bukkit/skript/effects/EffRetrieveScripts.java b/src/main/java/fr/zorg/bungeesk/bukkit/skript/effects/EffRetrieveScripts.java index 7b304c3..e79a276 100644 --- a/src/main/java/fr/zorg/bungeesk/bukkit/skript/effects/EffRetrieveScripts.java +++ b/src/main/java/fr/zorg/bungeesk/bukkit/skript/effects/EffRetrieveScripts.java @@ -32,7 +32,7 @@ public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelaye @Override protected void execute(Event e) { if (BungeeSK.isClientConnected()) { - ConnectionClient.get().write("RETRIEVE_SKRIPTSµ"); + ConnectionClient.get().write(true, "sendFilesRequest"); } } diff --git a/src/main/java/fr/zorg/bungeesk/bukkit/skript/effects/EffSendActionBar.java b/src/main/java/fr/zorg/bungeesk/bukkit/skript/effects/EffSendActionBar.java new file mode 100644 index 0000000..9fc5988 --- /dev/null +++ b/src/main/java/fr/zorg/bungeesk/bukkit/skript/effects/EffSendActionBar.java @@ -0,0 +1,55 @@ +package fr.zorg.bungeesk.bukkit.skript.effects; + +import ch.njol.skript.Skript; +import ch.njol.skript.doc.Description; +import ch.njol.skript.doc.Examples; +import ch.njol.skript.doc.Name; +import ch.njol.skript.doc.Since; +import ch.njol.skript.lang.Effect; +import ch.njol.skript.lang.Expression; +import ch.njol.skript.lang.SkriptParser; +import ch.njol.util.Kleenean; +import fr.zorg.bungeesk.bukkit.BungeeSK; +import fr.zorg.bungeesk.bukkit.sockets.ConnectionClient; +import fr.zorg.bungeesk.bukkit.utils.BungeePlayer; +import org.bukkit.event.Event; + +@Name("Send action bar message") +@Description("Send an action bar message to a player on the bungeecord network") +@Examples("send (bungee player named \"Notch\") action bar \"&6Welcome ! :)\"") +@Since("1.1.0") +public class EffSendActionBar extends Effect { + + static { + Skript.registerEffect(EffSendActionBar.class, + "send %bungeeplayer% action bar [message] %string%"); + } + + private Expression player; + private Expression message; + + @Override + public boolean init(Expression[] exprs, int pattern, Kleenean kleenean, SkriptParser.ParseResult parseResult) { + this.player = (Expression) exprs[0]; + this.message = (Expression) exprs[1]; + return true; + } + @Override + protected void execute(Event e) { + if (BungeeSK.isClientConnected()) { + + if (this.player.getSingle(e) == null) + return; + + ConnectionClient.get().write(true, "effectSendActionBar", + "playerUuid", this.player.getSingle(e).getUuid(), + "message", this.message.getSingle(e)); + } + } + + @Override + public String toString(Event e, boolean debug) { + return "send action bar message " + this.message.toString(e, debug) + " to bungee player " + this.player.toString(e, debug); + } + +} diff --git a/src/main/java/fr/zorg/bungeesk/bukkit/skript/effects/EffSendBungeePlayerToServer.java b/src/main/java/fr/zorg/bungeesk/bukkit/skript/effects/EffSendBungeePlayerToServer.java index c59eed9..ab99bb3 100644 --- a/src/main/java/fr/zorg/bungeesk/bukkit/skript/effects/EffSendBungeePlayerToServer.java +++ b/src/main/java/fr/zorg/bungeesk/bukkit/skript/effects/EffSendBungeePlayerToServer.java @@ -12,34 +12,41 @@ import fr.zorg.bungeesk.bukkit.BungeeSK; import fr.zorg.bungeesk.bukkit.sockets.ConnectionClient; import fr.zorg.bungeesk.bukkit.utils.BungeePlayer; +import fr.zorg.bungeesk.bukkit.utils.BungeeServer; import org.bukkit.event.Event; import org.jetbrains.annotations.Nullable; @Name("Send bungee player to server") @Description("Send a player on the network to a specific server") -@Examples("send bungee player \"Zorg_btw\" to server \"lobby2\"") -@Since("1.0.0") +@Examples("send bungee player named \"Zorg_btw\" to bungee server named \"lobby2\"") +@Since("1.0.0 - 1.1.0: Usage of BungeeServer type") public class EffSendBungeePlayerToServer extends Effect { static { Skript.registerEffect(EffSendBungeePlayerToServer.class, - "send %bungeeplayer% to server %string%"); + "send %bungeeplayer% to %bungeeserver%"); } private Expression player; - private Expression server; + private Expression server; @Override public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, SkriptParser.ParseResult parseResult) { - player = (Expression) exprs[0]; - server = (Expression) exprs[1]; + this.player = (Expression) exprs[0]; + this.server = (Expression) exprs[1]; return true; } @Override protected void execute(Event e) { if (BungeeSK.isClientConnected()) { - ConnectionClient.get().write("SENDTOSERVµ" + player.getSingle(e).getData() + "^" + server.getSingle(e)); + if (this.player.getSingle(e) == null) + return; + + ConnectionClient.get().write(true, "effectSendBungeePlayerToServer", + "playerUniqueId", this.player.getSingle(e).getUuid(), + "serverAddress", this.server.getSingle(e).getAddress(), + "serverPort", String.valueOf(this.server.getSingle(e).getPort())); } } diff --git a/src/main/java/fr/zorg/bungeesk/bukkit/skript/effects/EffSendCustomBungeeMessage.java b/src/main/java/fr/zorg/bungeesk/bukkit/skript/effects/EffSendCustomBungeeMessage.java new file mode 100644 index 0000000..5d3208d --- /dev/null +++ b/src/main/java/fr/zorg/bungeesk/bukkit/skript/effects/EffSendCustomBungeeMessage.java @@ -0,0 +1,55 @@ +package fr.zorg.bungeesk.bukkit.skript.effects; + +import ch.njol.skript.Skript; +import ch.njol.skript.doc.Description; +import ch.njol.skript.doc.Examples; +import ch.njol.skript.doc.Name; +import ch.njol.skript.doc.Since; +import ch.njol.skript.lang.Effect; +import ch.njol.skript.lang.Expression; +import ch.njol.skript.lang.SkriptParser; +import ch.njol.util.Kleenean; +import fr.zorg.bungeesk.bukkit.BungeeSK; +import fr.zorg.bungeesk.bukkit.sockets.ConnectionClient; +import fr.zorg.bungeesk.bukkit.utils.BungeeServer; +import org.bukkit.event.Event; + +@Name("Send custom bungee message to a server") +@Description("Sends a custom bungee message in string form to one or more servers") +@Examples("send custom message \"This is an example\" to bungee server named \"lobby2\"") +@Since("1.1.0") +public class EffSendCustomBungeeMessage extends Effect { + + static { + Skript.registerEffect(EffSendCustomBungeeMessage.class, + "send custom message %string% to %bungeeservers%"); + } + + private Expression message; + private Expression servers; + + @Override + public boolean init(Expression[] exprs, int pattern, Kleenean kleenean, SkriptParser.ParseResult parseResult) { + this.message = (Expression) exprs[0]; + this.servers = (Expression) exprs[1]; + return true; + } + + @Override + protected void execute(Event e) { + if (BungeeSK.isClientConnected()) { + for (final BungeeServer server : servers.getArray(e)) { + ConnectionClient.get().write(true, "effectSendBungeeCustomMessage", + "serverAddress", server.getAddress(), + "serverPort", String.valueOf(server.getPort()), + "message", this.message.getSingle(e)); + } + } + } + + @Override + public String toString(Event e, boolean debug) { + return null; + } + +} diff --git a/src/main/java/fr/zorg/bungeesk/bukkit/skript/effects/EffSendMessage.java b/src/main/java/fr/zorg/bungeesk/bukkit/skript/effects/EffSendMessage.java index e13e6e9..aacb1f1 100644 --- a/src/main/java/fr/zorg/bungeesk/bukkit/skript/effects/EffSendMessage.java +++ b/src/main/java/fr/zorg/bungeesk/bukkit/skript/effects/EffSendMessage.java @@ -5,19 +5,19 @@ import ch.njol.skript.doc.Examples; import ch.njol.skript.doc.Name; import ch.njol.skript.doc.Since; -import fr.zorg.bungeesk.bukkit.BungeeSK; -import org.jetbrains.annotations.Nullable; -import fr.zorg.bungeesk.bukkit.sockets.ConnectionClient; -import org.bukkit.event.Event; +import ch.njol.skript.lang.Effect; +import ch.njol.skript.lang.Expression; import ch.njol.skript.lang.SkriptParser; import ch.njol.util.Kleenean; +import fr.zorg.bungeesk.bukkit.BungeeSK; +import fr.zorg.bungeesk.bukkit.sockets.ConnectionClient; import fr.zorg.bungeesk.bukkit.utils.BungeePlayer; -import ch.njol.skript.lang.Expression; -import ch.njol.skript.lang.Effect; +import org.bukkit.event.Event; +import org.jetbrains.annotations.Nullable; @Name("Send message to bungee player") @Description("Send a message to a bungee player on the network") -@Examples("send bungee message \"&6Hello !\" to bungee player \"Zorg_btw\"") +@Examples("send bungee message \"&6Hello !\" to bungee player named \"Zorg_btw\"") @Since("1.0.0") public class EffSendMessage extends Effect { @@ -36,7 +36,12 @@ public boolean init(final Expression[] exprs, final int matchedPattern, final protected void execute(final Event e) { if (BungeeSK.isClientConnected()) { - ConnectionClient.get().write("SENDPLAYERMESSAGEµ" + player.getSingle(e).getData() + "^" + message.getSingle(e)); + if (this.player.getSingle(e) == null) + return; + + ConnectionClient.get().write(true, "effectSendMessageToBungeePlayer", + "playerUniqueId", this.player.getSingle(e).getUuid(), + "message", this.message.getSingle(e)); } } diff --git a/src/main/java/fr/zorg/bungeesk/bukkit/skript/effects/EffSendTitle.java b/src/main/java/fr/zorg/bungeesk/bukkit/skript/effects/EffSendTitle.java new file mode 100644 index 0000000..df94694 --- /dev/null +++ b/src/main/java/fr/zorg/bungeesk/bukkit/skript/effects/EffSendTitle.java @@ -0,0 +1,74 @@ +package fr.zorg.bungeesk.bukkit.skript.effects; + +import ch.njol.skript.Skript; +import ch.njol.skript.doc.Description; +import ch.njol.skript.doc.Examples; +import ch.njol.skript.doc.Name; +import ch.njol.skript.doc.Since; +import ch.njol.skript.lang.Effect; +import ch.njol.skript.lang.Expression; +import ch.njol.skript.lang.SkriptParser; +import ch.njol.skript.util.Timespan; +import ch.njol.util.Kleenean; +import fr.zorg.bungeesk.bukkit.BungeeSK; +import fr.zorg.bungeesk.bukkit.sockets.ConnectionClient; +import fr.zorg.bungeesk.bukkit.utils.BungeePlayer; +import org.bukkit.event.Event; + +@Name("Send Bungeecord title to bungee player") +@Description("Send a Bungeecord title to a player on the network") +@Examples("send bungeecord title \"&cHey you !\" with subtitle \"&6How are you ? :)\" for 3 seconds to bungee player named \"Notch\" with fade-in 10 ticks and fade-out 2 seconds") +@Since("1.1.0") +public class EffSendTitle extends Effect { + + static { + Skript.registerEffect(EffSendTitle.class, + "send bungeecord title %string% [with subtitle %-string%] [for %-timespan%] to %bungeeplayer% [with fade-in %-timespan%] [(and|with) fade-out %timespan%]"); + } + + private Expression title; + private Expression subTitle; + private Expression time; + private Expression player; + private Expression fadeIn; + private Expression fadeOut; + + @Override + public boolean init(Expression[] exprs, int pattern, Kleenean kleenean, SkriptParser.ParseResult parseResult) { + this.title = (Expression) exprs[0]; + this.subTitle = (Expression) exprs[1]; + this.time = (Expression) exprs[2]; + this.player = (Expression) exprs[3]; + this.fadeIn = (Expression) exprs[4]; + this.fadeOut = (Expression) exprs[5]; + return true; + } + + @Override + protected void execute(Event e) { + if (BungeeSK.isClientConnected()) { + if (this.player.getSingle(e) == null) + return; + + final String title = this.title == null ? "NONE" : this.title.getSingle(e); + final String subTitle = this.subTitle == null ? "NONE" : this.subTitle.getSingle(e); + final String time = this.time == null ? "NONE" : String.valueOf(this.time.getSingle(e).getTicks_i()); + final String fadeIn = this.fadeIn == null ? "NONE" : String.valueOf(this.fadeIn.getSingle(e).getTicks_i()); + final String fadeOut = this.fadeOut == null ? "NONE" : String.valueOf(this.fadeOut.getSingle(e).getTicks_i()); + + ConnectionClient.get().write(true, "effectSendBungeePlayerTitle", + "playerUuid", this.player.getSingle(e).getUuid(), + "title", title, + "subTitle", subTitle, + "time", time, + "fadeIn", fadeIn, + "fadeOut", fadeOut); + } + } + + @Override + public String toString(Event e, boolean debug) { + return null; + } + +} diff --git a/src/main/java/fr/zorg/bungeesk/bukkit/skript/effects/EffStartConnection.java b/src/main/java/fr/zorg/bungeesk/bukkit/skript/effects/EffStartConnection.java index ffcd6fd..ddfc1b9 100644 --- a/src/main/java/fr/zorg/bungeesk/bukkit/skript/effects/EffStartConnection.java +++ b/src/main/java/fr/zorg/bungeesk/bukkit/skript/effects/EffStartConnection.java @@ -21,12 +21,11 @@ "\t\tset address of connection to \"127.0.0.1\"\n" + "\t\tset port of connection to 100\n" + "\t\tset password of connection to \"abcd\"\n" + - "\t\tset name of connection to \"server1\"\n" + "\tstart new connection with connection") public class EffStartConnection extends Effect { - static { + static { Skript.registerEffect(EffStartConnection.class, "start new connection with %bungeeconn%"); } diff --git a/src/main/java/fr/zorg/bungeesk/bukkit/skript/events/EvtBungeeMessageReceive.java b/src/main/java/fr/zorg/bungeesk/bukkit/skript/events/EvtBungeeMessageReceive.java new file mode 100644 index 0000000..ce5c9de --- /dev/null +++ b/src/main/java/fr/zorg/bungeesk/bukkit/skript/events/EvtBungeeMessageReceive.java @@ -0,0 +1,36 @@ +package fr.zorg.bungeesk.bukkit.skript.events; + +import ch.njol.skript.Skript; +import ch.njol.skript.lang.util.SimpleEvent; +import ch.njol.skript.registrations.EventValues; +import ch.njol.skript.util.Getter; +import fr.zorg.bungeesk.bukkit.skript.events.bukkit.BungeeMessageReceiveEvent; +import fr.zorg.bungeesk.bukkit.utils.BungeeServer; +import org.jetbrains.annotations.Nullable; + +public class EvtBungeeMessageReceive { + + static { + Skript.registerEvent("bungee message receive", SimpleEvent.class, BungeeMessageReceiveEvent.class, + "bungee [custom] message receive") + .description("When a bungee message is received") + .examples("on bungee message receive:", "\tset {_server} to event-bungeeserver", "\tset {_message} to event-string") + .since("1.1.0"); + + EventValues.registerEventValue(BungeeMessageReceiveEvent.class, BungeeServer.class, new Getter() { + @Nullable + @Override + public BungeeServer get(BungeeMessageReceiveEvent e) { + return e.getFrom(); + } + }, 0); + + EventValues.registerEventValue(BungeeMessageReceiveEvent.class, String.class, new Getter() { + @Nullable + @Override + public String get(BungeeMessageReceiveEvent e) { + return e.getMessage(); + } + }, 0); + } +} diff --git a/src/main/java/fr/zorg/bungeesk/bukkit/skript/events/EvtServerSwitch.java b/src/main/java/fr/zorg/bungeesk/bukkit/skript/events/EvtServerSwitch.java index 01a382f..7fd43e5 100644 --- a/src/main/java/fr/zorg/bungeesk/bukkit/skript/events/EvtServerSwitch.java +++ b/src/main/java/fr/zorg/bungeesk/bukkit/skript/events/EvtServerSwitch.java @@ -6,6 +6,7 @@ import ch.njol.skript.util.Getter; import fr.zorg.bungeesk.bukkit.skript.events.bukkit.ServerSwitchEvent; import fr.zorg.bungeesk.bukkit.utils.BungeePlayer; +import fr.zorg.bungeesk.bukkit.utils.BungeeServer; import org.jetbrains.annotations.Nullable; public class EvtServerSwitch { @@ -26,10 +27,10 @@ public BungeePlayer get(ServerSwitchEvent e) { } }, 0); - EventValues.registerEventValue(ServerSwitchEvent.class, String.class, new Getter() { + EventValues.registerEventValue(ServerSwitchEvent.class, BungeeServer.class, new Getter() { @Nullable @Override - public String get(ServerSwitchEvent e) { + public BungeeServer get(ServerSwitchEvent e) { return e.getServer(); } }, 0); diff --git a/src/main/java/fr/zorg/bungeesk/bukkit/skript/events/bukkit/BungeeMessageReceiveEvent.java b/src/main/java/fr/zorg/bungeesk/bukkit/skript/events/bukkit/BungeeMessageReceiveEvent.java new file mode 100644 index 0000000..7830cc9 --- /dev/null +++ b/src/main/java/fr/zorg/bungeesk/bukkit/skript/events/bukkit/BungeeMessageReceiveEvent.java @@ -0,0 +1,35 @@ +package fr.zorg.bungeesk.bukkit.skript.events.bukkit; + +import fr.zorg.bungeesk.bukkit.utils.BungeeServer; +import org.bukkit.event.Event; +import org.bukkit.event.HandlerList; + +public class BungeeMessageReceiveEvent extends Event { + + public static final HandlerList handlers = new HandlerList(); + private final BungeeServer from; + private final String message; + + public BungeeMessageReceiveEvent(final BungeeServer from, final String message) { + this.from = from; + this.message = message; + } + + public static HandlerList getHandlerList() { + return handlers; + } + + @Override + public HandlerList getHandlers() { + return handlers; + } + + public BungeeServer getFrom() { + return this.from; + } + + public String getMessage() { + return this.message; + } + +} diff --git a/src/main/java/fr/zorg/bungeesk/bukkit/skript/events/bukkit/ClientConnectEvent.java b/src/main/java/fr/zorg/bungeesk/bukkit/skript/events/bukkit/ClientConnectEvent.java index dcb0064..6c18c0a 100644 --- a/src/main/java/fr/zorg/bungeesk/bukkit/skript/events/bukkit/ClientConnectEvent.java +++ b/src/main/java/fr/zorg/bungeesk/bukkit/skript/events/bukkit/ClientConnectEvent.java @@ -7,7 +7,8 @@ public class ClientConnectEvent extends Event { public static final HandlerList handlers = new HandlerList(); - public ClientConnectEvent() { } + public ClientConnectEvent() { + } public static HandlerList getHandlerList() { return handlers; diff --git a/src/main/java/fr/zorg/bungeesk/bukkit/skript/events/bukkit/ClientDisconnectEvent.java b/src/main/java/fr/zorg/bungeesk/bukkit/skript/events/bukkit/ClientDisconnectEvent.java index c7fae4f..27426fa 100644 --- a/src/main/java/fr/zorg/bungeesk/bukkit/skript/events/bukkit/ClientDisconnectEvent.java +++ b/src/main/java/fr/zorg/bungeesk/bukkit/skript/events/bukkit/ClientDisconnectEvent.java @@ -7,7 +7,8 @@ public class ClientDisconnectEvent extends Event { public static final HandlerList handlers = new HandlerList(); - public ClientDisconnectEvent() { } + public ClientDisconnectEvent() { + } public static HandlerList getHandlerList() { return handlers; diff --git a/src/main/java/fr/zorg/bungeesk/bukkit/skript/events/bukkit/ServerSwitchEvent.java b/src/main/java/fr/zorg/bungeesk/bukkit/skript/events/bukkit/ServerSwitchEvent.java index eec068b..3c1bcb5 100644 --- a/src/main/java/fr/zorg/bungeesk/bukkit/skript/events/bukkit/ServerSwitchEvent.java +++ b/src/main/java/fr/zorg/bungeesk/bukkit/skript/events/bukkit/ServerSwitchEvent.java @@ -1,6 +1,7 @@ package fr.zorg.bungeesk.bukkit.skript.events.bukkit; import fr.zorg.bungeesk.bukkit.utils.BungeePlayer; +import fr.zorg.bungeesk.bukkit.utils.BungeeServer; import org.bukkit.event.Event; import org.bukkit.event.HandlerList; @@ -8,9 +9,9 @@ public class ServerSwitchEvent extends Event { public static final HandlerList handlers = new HandlerList(); private final BungeePlayer player; - private final String server; + private final BungeeServer server; - public ServerSwitchEvent(BungeePlayer player, String server) { + public ServerSwitchEvent(BungeePlayer player, BungeeServer server) { this.player = player; this.server = server; } @@ -28,7 +29,7 @@ public BungeePlayer getPlayer() { return this.player; } - public String getServer() { + public BungeeServer getServer() { return this.server; } } diff --git a/src/main/java/fr/zorg/bungeesk/bukkit/skript/expressions/ExprAllBungeeServers.java b/src/main/java/fr/zorg/bungeesk/bukkit/skript/expressions/ExprAllBungeeServers.java deleted file mode 100644 index 360fa72..0000000 --- a/src/main/java/fr/zorg/bungeesk/bukkit/skript/expressions/ExprAllBungeeServers.java +++ /dev/null @@ -1,59 +0,0 @@ -package fr.zorg.bungeesk.bukkit.skript.expressions; - -import ch.njol.skript.Skript; -import ch.njol.skript.doc.Description; -import ch.njol.skript.doc.Examples; -import ch.njol.skript.doc.Name; -import ch.njol.skript.doc.Since; -import ch.njol.skript.lang.Expression; -import ch.njol.skript.lang.ExpressionType; -import ch.njol.skript.lang.SkriptParser; -import ch.njol.skript.lang.util.SimpleExpression; -import ch.njol.util.Kleenean; -import fr.zorg.bungeesk.bukkit.BungeeSK; -import fr.zorg.bungeesk.bukkit.sockets.ConnectionClient; -import org.bukkit.event.Event; -import org.jetbrains.annotations.Nullable; - -@Name("All of the bungee servers") -@Description("Returns every server connected") -@Examples("loop all bungee servers:\n" + - "\tsend \"%loop-value%\"") -@Since("1.0.0") -public class ExprAllBungeeServers extends SimpleExpression { - - static { - Skript.registerExpression(ExprAllBungeeServers.class, String.class, ExpressionType.SIMPLE, - "[(all [[of] the]|the)] [bungee] servers"); - } - - @Override - public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, SkriptParser.ParseResult parseResult) { - return true; - } - - @Override - protected @Nullable String[] get(Event e) { - if (BungeeSK.isClientConnected()) { - final String result = ConnectionClient.get().future("ALLBUNGEESERVERSµ"); - return result.split("\\^"); - } - return new String[0]; - } - - @Override - public boolean isSingle() { - return false; - } - - @Override - public Class getReturnType() { - return String.class; - } - - @Override - public String toString(@Nullable Event e, boolean debug) { - return "all bungee servers"; - } - -} diff --git a/src/main/java/fr/zorg/bungeesk/bukkit/skript/expressions/ExprClientRealName.java b/src/main/java/fr/zorg/bungeesk/bukkit/skript/expressions/ExprClientRealName.java deleted file mode 100644 index 5184180..0000000 --- a/src/main/java/fr/zorg/bungeesk/bukkit/skript/expressions/ExprClientRealName.java +++ /dev/null @@ -1,62 +0,0 @@ -package fr.zorg.bungeesk.bukkit.skript.expressions; - -import ch.njol.skript.Skript; -import ch.njol.skript.doc.Description; -import ch.njol.skript.doc.Examples; -import ch.njol.skript.doc.Name; -import ch.njol.skript.doc.Since; -import ch.njol.skript.lang.Expression; -import ch.njol.skript.lang.ExpressionType; -import ch.njol.skript.lang.SkriptParser; -import ch.njol.skript.lang.util.SimpleExpression; -import ch.njol.util.Kleenean; -import fr.zorg.bungeesk.bukkit.BungeeSK; -import fr.zorg.bungeesk.bukkit.sockets.ConnectionClient; -import org.bukkit.event.Event; -import org.jetbrains.annotations.Nullable; - -@Name("Client real name") -@Description("Returns the client's name in the Bungeecord proxy configuration") -@Examples("set {_name} to real name of this client") -@Since("1.0.2") -public class ExprClientRealName extends SimpleExpression { - - static { - Skript.registerExpression(ExprClientRealName.class, - String.class, - ExpressionType.SIMPLE, - "real name of this client", - "this client's real name"); - } - - @Override - public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, SkriptParser.ParseResult parseResult) { - return true; - } - - @Nullable - @Override - protected String[] get(Event e) { - if (BungeeSK.isClientConnected()) { - final String result = ConnectionClient.get().future("CLIENTREALNAMEµ" + BungeeSK.getInstance().getServer().getIp() + ":" + BungeeSK.getInstance().getServer().getPort()); - return new String[] { result }; - } - return new String[0]; - } - - @Override - public boolean isSingle() { - return true; - } - - @Override - public Class getReturnType() { - return String.class; - } - - @Override - public String toString(@Nullable Event e, boolean debug) { - return "client's real name on the bungeecord"; - } - -} diff --git a/src/main/java/fr/zorg/bungeesk/bukkit/skript/expressions/ExprGlobalVariables.java b/src/main/java/fr/zorg/bungeesk/bukkit/skript/expressions/ExprGlobalVariables.java new file mode 100644 index 0000000..d02c767 --- /dev/null +++ b/src/main/java/fr/zorg/bungeesk/bukkit/skript/expressions/ExprGlobalVariables.java @@ -0,0 +1,93 @@ +package fr.zorg.bungeesk.bukkit.skript.expressions; + +import ch.njol.skript.Skript; +import ch.njol.skript.classes.Changer; +import ch.njol.skript.doc.Description; +import ch.njol.skript.doc.Examples; +import ch.njol.skript.doc.Name; +import ch.njol.skript.doc.Since; +import ch.njol.skript.lang.Expression; +import ch.njol.skript.lang.ExpressionType; +import ch.njol.skript.lang.SkriptParser; +import ch.njol.skript.lang.util.SimpleExpression; +import ch.njol.util.Kleenean; +import ch.njol.util.coll.CollectionUtils; +import com.google.gson.JsonObject; +import fr.zorg.bungeesk.bukkit.BungeeSK; +import fr.zorg.bungeesk.bukkit.sockets.ConnectionClient; +import org.bukkit.event.Event; + +@Name("Global variables stored on the Bungeecord") +@Description("Set, get and delete a global variable stored on the Bungeecord. The variable can only be a String") +@Examples("set global variable \"rank.%player%\" to \"Admin\"\n" + + "set {_rank} to global variable \"rank.%player%\"") +@Since("1.1.0") +public class ExprGlobalVariables extends SimpleExpression { + + static { + Skript.registerExpression(ExprGlobalVariables.class, String.class, ExpressionType.SIMPLE, "global variable [named] %string%"); + } + + private Expression varName; + + @Override + public boolean init(Expression[] exprs, int pattern, Kleenean kleenean, SkriptParser.ParseResult parseResult) { + this.varName = (Expression) exprs[0]; + return true; + } + + @Override + protected String[] get(Event e) { + if (BungeeSK.isClientConnected()) { + final JsonObject result = ConnectionClient.get().future("getGlobalVariable", + "varName", this.varName.getSingle(e)); + if (result.get("value").getAsString().equalsIgnoreCase("NONE")) + return new String[0]; + return new String[] { result.get("value").getAsString() }; + } + return new String[0]; + } + + @Override + public boolean isSingle() { + return true; + } + + @Override + public Class getReturnType() { + return String.class; + } + + @Override + public String toString(Event e, boolean debug) { + return "global variable named " + this.varName.toString(e, debug); + } + + @Override + public Class[] acceptChange(Changer.ChangeMode mode) { + if (mode == Changer.ChangeMode.SET || mode == Changer.ChangeMode.DELETE) + return CollectionUtils.array(String.class); + return null; + } + + @Override + public void change(Event e, Object[] delta, Changer.ChangeMode mode) { + if (BungeeSK.isClientConnected()) { + switch (mode) { + case SET: { + if (delta == null) + return; + ConnectionClient.get().write(true, "setGlobalVariable", + "varName", this.varName.getSingle(e), + "value", String.valueOf(delta[0])); + break; + } + case DELETE: { + ConnectionClient.get().write(true, "deleteGlobalVariable", + "varName", this.varName.getSingle(e)); + break; + } + } + } + } +} diff --git a/src/main/java/fr/zorg/bungeesk/bukkit/skript/expressions/bungeeplayer/ExprAllBungeePlayers.java b/src/main/java/fr/zorg/bungeesk/bukkit/skript/expressions/bungeeplayer/ExprAllBungeePlayers.java index 23bdd5a..ef15b17 100644 --- a/src/main/java/fr/zorg/bungeesk/bukkit/skript/expressions/bungeeplayer/ExprAllBungeePlayers.java +++ b/src/main/java/fr/zorg/bungeesk/bukkit/skript/expressions/bungeeplayer/ExprAllBungeePlayers.java @@ -10,6 +10,7 @@ import ch.njol.skript.lang.SkriptParser; import ch.njol.skript.lang.util.SimpleExpression; import ch.njol.util.Kleenean; +import com.google.gson.JsonObject; import fr.zorg.bungeesk.bukkit.BungeeSK; import fr.zorg.bungeesk.bukkit.sockets.ConnectionClient; import fr.zorg.bungeesk.bukkit.utils.BungeePlayer; @@ -39,15 +40,15 @@ public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelaye @Override protected @Nullable BungeePlayer[] get(Event e) { if (BungeeSK.isClientConnected()) { - String result = ConnectionClient.get().future("ALLBUNGEEPLAYERSµ"); + final JsonObject result = ConnectionClient.get().future("expressionGetAllBungeePlayers"); + + if (result.get("error").getAsBoolean()) + return new BungeePlayer[0]; List players = new ArrayList<>(); - if (result.equals("NONE^")) return new BungeePlayer[0]; - for (String player : result.split("\\^")) { - String name = player.split("\\$")[0]; - String uuid = player.split("\\$")[1]; - players.add(new BungeePlayer(name, uuid)); - } + result.get("players").getAsJsonArray().forEach(player -> { + players.add(new BungeePlayer(player.getAsJsonObject().get("name").getAsString(), player.getAsJsonObject().get("uniqueId").getAsString())); + }); return players.toArray(new BungeePlayer[0]); } return new BungeePlayer[0]; diff --git a/src/main/java/fr/zorg/bungeesk/bukkit/skript/expressions/ExprAllPlayersOnServer.java b/src/main/java/fr/zorg/bungeesk/bukkit/skript/expressions/bungeeplayer/ExprAllPlayersOnServer.java similarity index 57% rename from src/main/java/fr/zorg/bungeesk/bukkit/skript/expressions/ExprAllPlayersOnServer.java rename to src/main/java/fr/zorg/bungeesk/bukkit/skript/expressions/bungeeplayer/ExprAllPlayersOnServer.java index 9dabe5b..6c60bc1 100644 --- a/src/main/java/fr/zorg/bungeesk/bukkit/skript/expressions/ExprAllPlayersOnServer.java +++ b/src/main/java/fr/zorg/bungeesk/bukkit/skript/expressions/bungeeplayer/ExprAllPlayersOnServer.java @@ -1,4 +1,4 @@ -package fr.zorg.bungeesk.bukkit.skript.expressions; +package fr.zorg.bungeesk.bukkit.skript.expressions.bungeeplayer; import ch.njol.skript.Skript; import ch.njol.skript.doc.Description; @@ -10,20 +10,20 @@ import ch.njol.skript.lang.SkriptParser; import ch.njol.skript.lang.util.SimpleExpression; import ch.njol.util.Kleenean; +import com.google.gson.JsonObject; import fr.zorg.bungeesk.bukkit.BungeeSK; import fr.zorg.bungeesk.bukkit.sockets.ConnectionClient; import fr.zorg.bungeesk.bukkit.utils.BungeePlayer; +import fr.zorg.bungeesk.bukkit.utils.BungeeServer; import org.bukkit.event.Event; import org.jetbrains.annotations.Nullable; import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; import java.util.List; @Name("All of the bungee players on specific server") @Description("Returns every bungee player on a specific server") -@Examples("loop all bungee players on server \"lobby\":\n" + +@Examples("loop all bungee players on bungee server named \"lobby\":\n" + "\tsend \"%loop-bungeeplayer%\"") @Since("1.0.2") public class ExprAllPlayersOnServer extends SimpleExpression { @@ -32,14 +32,14 @@ public class ExprAllPlayersOnServer extends SimpleExpression { Skript.registerExpression(ExprAllPlayersOnServer.class, BungeePlayer.class, ExpressionType.SIMPLE, - "[(all [[of] the]|the)] bungee players on server %string%"); + "[(all [[of] the]|the)] bungee players on %bungeeserver%"); } - private Expression server; + private Expression server; @Override public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, SkriptParser.ParseResult parseResult) { - server = (Expression) exprs[0]; + this.server = (Expression) exprs[0]; return true; } @@ -47,15 +47,23 @@ public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelaye @Override protected BungeePlayer[] get(Event e) { if (BungeeSK.isClientConnected()) { - String result = ConnectionClient.get().future("ALLBUNGEEPLAYERSONSERVERµ" + server.getSingle(e)); - result = result.replace(server.getSingle(e), ""); + + if (server.getSingle(e) == null) + return new BungeePlayer[0]; + + final JsonObject result = ConnectionClient.get().future("expressionGetAllPlayersOnServer", + "address", this.server.getSingle(e).getAddress(), + "port", String.valueOf(this.server.getSingle(e).getPort())); + + if (result.get("error").getAsBoolean()) + return new BungeePlayer[0]; + List players = new ArrayList<>(); - if (result.equals("^NONE")) return new BungeePlayer[0]; - for (String player : result.replaceFirst("\\^", "").split("\\^")) { - String name = player.split("\\$")[0]; - String uuid = player.split("\\$")[1]; - players.add(new BungeePlayer(name, uuid)); - } + result.get("players").getAsJsonArray().forEach(player -> { + System.out.println("player.getAsJsonObject().get(\"name\").getAsString() = " + player.getAsJsonObject().get("name").getAsString()); + players.add(new BungeePlayer(player.getAsJsonObject().get("name").getAsString(), player.getAsJsonObject().get("uniqueId").getAsString())); + }); + return players.toArray(new BungeePlayer[0]); } return new BungeePlayer[0]; @@ -73,7 +81,7 @@ public Class getReturnType() { @Override public String toString(@Nullable Event e, boolean debug) { - return "every bungee player connected on server " + server.toString(e, debug); + return "every bungee player connected on server " + this.server.toString(e, debug); } } diff --git a/src/main/java/fr/zorg/bungeesk/bukkit/skript/expressions/bungeeplayer/ExprBungeePlayerFromString.java b/src/main/java/fr/zorg/bungeesk/bukkit/skript/expressions/bungeeplayer/ExprBungeePlayerFromName.java similarity index 61% rename from src/main/java/fr/zorg/bungeesk/bukkit/skript/expressions/bungeeplayer/ExprBungeePlayerFromString.java rename to src/main/java/fr/zorg/bungeesk/bukkit/skript/expressions/bungeeplayer/ExprBungeePlayerFromName.java index 22feb62..2db0d5a 100644 --- a/src/main/java/fr/zorg/bungeesk/bukkit/skript/expressions/bungeeplayer/ExprBungeePlayerFromString.java +++ b/src/main/java/fr/zorg/bungeesk/bukkit/skript/expressions/bungeeplayer/ExprBungeePlayerFromName.java @@ -10,45 +10,44 @@ import ch.njol.skript.lang.SkriptParser; import ch.njol.skript.lang.util.SimpleExpression; import ch.njol.util.Kleenean; +import com.google.gson.JsonObject; import fr.zorg.bungeesk.bukkit.BungeeSK; import fr.zorg.bungeesk.bukkit.sockets.ConnectionClient; import fr.zorg.bungeesk.bukkit.utils.BungeePlayer; import org.bukkit.event.Event; import org.jetbrains.annotations.Nullable; -import java.util.LinkedList; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; - -@Name("Bungee player from string") +@Name("Bungee player from name") @Description("Get bungee player from his name") -@Examples("set {_player} to bungee player \"Zorg\"") -@Since("1.0.0") -public class ExprBungeePlayerFromString extends SimpleExpression { +@Examples("set {_player} to bungee player named \"Zorg\"") +@Since("1.0.0, 1.1.0: Add of 'named'") +public class ExprBungeePlayerFromName extends SimpleExpression { static { - Skript.registerExpression(ExprBungeePlayerFromString.class, + Skript.registerExpression(ExprBungeePlayerFromName.class, BungeePlayer.class, ExpressionType.SIMPLE, - "bungee[ ]player %string%"); + "bungee[ ]player (with name|named) %string%"); } private Expression player; @Override public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, SkriptParser.ParseResult parseResult) { - player = (Expression) exprs[0]; + this.player = (Expression) exprs[0]; return true; } @Override protected BungeePlayer[] get(Event e) { if (BungeeSK.isClientConnected()) { - String result = ConnectionClient.get().future("GETPLAYERµ" + player.getSingle(e)); - if (result.split("\\$")[1].equals("NONE")) return null; - return new BungeePlayer[] { new BungeePlayer(result.split("\\$")[0], result.split("\\$")[1]) }; + final JsonObject result = ConnectionClient.get().future("expressionGetBungeePlayerFromName", + "name", this.player.getSingle(e)); + + if (result.get("error").getAsBoolean()) + return new BungeePlayer[0]; + + return new BungeePlayer[]{new BungeePlayer(result.get("name").getAsString(), result.get("uniqueId").getAsString())}; } return new BungeePlayer[0]; } @@ -65,7 +64,7 @@ public Class getReturnType() { @Override public String toString(@Nullable Event e, boolean debug) { - return "bungee player " + player.toString(e, debug); + return "bungee player named " + this.player.toString(e, debug); } } diff --git a/src/main/java/fr/zorg/bungeesk/bukkit/skript/expressions/bungeeplayer/ExprBungeePlayerFromUuid.java b/src/main/java/fr/zorg/bungeesk/bukkit/skript/expressions/bungeeplayer/ExprBungeePlayerFromUuid.java new file mode 100644 index 0000000..42e1a30 --- /dev/null +++ b/src/main/java/fr/zorg/bungeesk/bukkit/skript/expressions/bungeeplayer/ExprBungeePlayerFromUuid.java @@ -0,0 +1,70 @@ +package fr.zorg.bungeesk.bukkit.skript.expressions.bungeeplayer; + +import ch.njol.skript.Skript; +import ch.njol.skript.doc.Description; +import ch.njol.skript.doc.Examples; +import ch.njol.skript.doc.Name; +import ch.njol.skript.doc.Since; +import ch.njol.skript.lang.Expression; +import ch.njol.skript.lang.ExpressionType; +import ch.njol.skript.lang.SkriptParser; +import ch.njol.skript.lang.util.SimpleExpression; +import ch.njol.util.Kleenean; +import com.google.gson.JsonObject; +import fr.zorg.bungeesk.bukkit.BungeeSK; +import fr.zorg.bungeesk.bukkit.sockets.ConnectionClient; +import fr.zorg.bungeesk.bukkit.utils.BungeePlayer; +import org.bukkit.event.Event; +import org.jetbrains.annotations.Nullable; + +@Name("Bungee player from uuid") +@Description("Get bungee player from his uuid") +@Examples("set {_player} to bungee player with uuid \"06c80842-1780-4c51-97bf-d37759bc4ed1\"") +@Since("1.1.0") +public class ExprBungeePlayerFromUuid extends SimpleExpression { + + static { + Skript.registerExpression(ExprBungeePlayerFromUuid.class, + BungeePlayer.class, + ExpressionType.SIMPLE, + "bungee[ ]player with uuid %string%"); + } + + private Expression uuid; + + @Override + public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, SkriptParser.ParseResult parseResult) { + this.uuid = (Expression) exprs[0]; + return true; + } + + @Override + protected BungeePlayer[] get(Event e) { + if (BungeeSK.isClientConnected()) { + final JsonObject result = ConnectionClient.get().future("expressionGetBungeePlayerFromUUID", + "uniqueId", this.uuid.getSingle(e)); + + if (result.get("error").getAsBoolean()) + return new BungeePlayer[0]; + + return new BungeePlayer[]{new BungeePlayer(result.get("name").getAsString(), result.get("uniqueId").getAsString())}; + } + return new BungeePlayer[0]; + } + + @Override + public boolean isSingle() { + return true; + } + + @Override + public Class getReturnType() { + return BungeePlayer.class; + } + + @Override + public String toString(@Nullable Event e, boolean debug) { + return "bungee player with uuid " + this.uuid.toString(e, debug); + } + +} diff --git a/src/main/java/fr/zorg/bungeesk/bukkit/skript/expressions/bungeeplayer/ExprBungeePlayerIP.java b/src/main/java/fr/zorg/bungeesk/bukkit/skript/expressions/bungeeplayer/ExprBungeePlayerIP.java new file mode 100644 index 0000000..30c93a8 --- /dev/null +++ b/src/main/java/fr/zorg/bungeesk/bukkit/skript/expressions/bungeeplayer/ExprBungeePlayerIP.java @@ -0,0 +1,62 @@ +package fr.zorg.bungeesk.bukkit.skript.expressions.bungeeplayer; + +import ch.njol.skript.classes.Changer; +import ch.njol.skript.doc.Description; +import ch.njol.skript.doc.Examples; +import ch.njol.skript.doc.Name; +import ch.njol.skript.doc.Since; +import ch.njol.skript.expressions.base.SimplePropertyExpression; +import com.google.gson.JsonObject; +import fr.zorg.bungeesk.bukkit.BungeeSK; +import fr.zorg.bungeesk.bukkit.sockets.ConnectionClient; +import fr.zorg.bungeesk.bukkit.utils.BungeePlayer; +import org.bukkit.event.Event; +import org.jetbrains.annotations.Nullable; + +@Name("IP address of BungeePlayer") +@Description("Gets the IP address of a BungeePlayer") +@Examples("send (bungee player named \"Zorg_btw\")'s ip") +@Since("1.1.0") +public class ExprBungeePlayerIP extends SimplePropertyExpression { + + static { + register(ExprBungeePlayerIP.class, + String.class, + "ip [address]", + "bungeeplayer"); + } + + @Nullable + @Override + public String convert(BungeePlayer player) { + if (BungeeSK.isClientConnected()) { + if (player == null) + return null; + + final JsonObject result = ConnectionClient.get().future("expressionGetBungeePlayerIP", + "playerUniqueId", player.getUuid()); + + if (result.get("error").getAsBoolean()) + return null; + + return result.get("address").getAsString(); + } + return null; + } + + @Override + public void change(Event e, @Nullable Object[] delta, Changer.ChangeMode mode) { + return; + } + + @Override + public Class getReturnType() { + return String.class; + } + + @Override + protected String getPropertyName() { + return "bungee player's ip address"; + } + +} diff --git a/src/main/java/fr/zorg/bungeesk/bukkit/skript/expressions/bungeeplayer/ExprBungeePlayerServer.java b/src/main/java/fr/zorg/bungeesk/bukkit/skript/expressions/bungeeplayer/ExprBungeePlayerServer.java index 17b865e..5a75928 100644 --- a/src/main/java/fr/zorg/bungeesk/bukkit/skript/expressions/bungeeplayer/ExprBungeePlayerServer.java +++ b/src/main/java/fr/zorg/bungeesk/bukkit/skript/expressions/bungeeplayer/ExprBungeePlayerServer.java @@ -6,40 +6,48 @@ import ch.njol.skript.doc.Name; import ch.njol.skript.doc.Since; import ch.njol.skript.expressions.base.SimplePropertyExpression; +import com.google.gson.JsonObject; import fr.zorg.bungeesk.bukkit.BungeeSK; import fr.zorg.bungeesk.bukkit.sockets.ConnectionClient; import fr.zorg.bungeesk.bukkit.utils.BungeePlayer; +import fr.zorg.bungeesk.bukkit.utils.BungeeServer; import org.bukkit.event.Event; import org.jetbrains.annotations.Nullable; -import java.util.LinkedList; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; - @Name("Server of bungee player") @Description("Get the server of a player on the network. " + - "NOTE: Server can be get only 2 ticks or more after the bungee playar join event") + "NOTE: Server can be get only 2 ticks or more after the bungee player join event") @Examples("set {_server} to event-bungeeplayer's server\n") -@Since("1.0.0") -public class ExprBungeePlayerServer extends SimplePropertyExpression { +@Since("1.0.0, 1.1.0: Returns BungeeServer") +public class ExprBungeePlayerServer extends SimplePropertyExpression { static { register(ExprBungeePlayerServer.class, - String.class, + BungeeServer.class, "server", "bungeeplayer"); } @Nullable @Override - public String convert(BungeePlayer player) { + public BungeeServer convert(BungeePlayer player) { if (BungeeSK.isClientConnected()) { - String result = ConnectionClient.get().future("PLAYERSERVERµ" + player.getData()); + if (player == null) + return null; + + final JsonObject result = ConnectionClient.get().future("expressionGetServerOfBungeePlayer", + "uniqueId", player.getUuid()); + + if (result.get("error").getAsBoolean()) + return null; + + final JsonObject jsonObject = result.get("server").getAsJsonObject(); - if (result.equals("NONE")) return null; - return result; + return new BungeeServer( + jsonObject.get("address").getAsString(), + jsonObject.get("port").getAsInt(), + jsonObject.get("name").getAsString(), + jsonObject.get("motd").getAsString()); } return null; } @@ -50,8 +58,8 @@ public void change(Event e, @Nullable Object[] delta, Changer.ChangeMode mode) { } @Override - public Class getReturnType() { - return String.class; + public Class getReturnType() { + return BungeeServer.class; } @Override diff --git a/src/main/java/fr/zorg/bungeesk/bukkit/skript/expressions/bungeeserver/ExprAddressOfBungeeServer.java b/src/main/java/fr/zorg/bungeesk/bukkit/skript/expressions/bungeeserver/ExprAddressOfBungeeServer.java new file mode 100644 index 0000000..6ee0344 --- /dev/null +++ b/src/main/java/fr/zorg/bungeesk/bukkit/skript/expressions/bungeeserver/ExprAddressOfBungeeServer.java @@ -0,0 +1,46 @@ +package fr.zorg.bungeesk.bukkit.skript.expressions.bungeeserver; + +import ch.njol.skript.classes.Changer; +import ch.njol.skript.doc.Description; +import ch.njol.skript.doc.Examples; +import ch.njol.skript.doc.Name; +import ch.njol.skript.doc.Since; +import ch.njol.skript.expressions.base.SimplePropertyExpression; +import fr.zorg.bungeesk.bukkit.utils.BungeeServer; +import org.bukkit.event.Event; +import org.jetbrains.annotations.Nullable; + +@Name("Bungee address of bungee server") +@Description("Get the address of a server precised in the Bungeecord config") +@Examples("broadcast bungee address of bungee server named \"lobby\"") +@Since("1.1.0") +public class ExprAddressOfBungeeServer extends SimplePropertyExpression { + + static { + register(ExprAddressOfBungeeServer.class, + String.class, + "bungee address", + "bungeeserver"); + } + + @Nullable + @Override + public String convert(BungeeServer server) { + return server == null ? null : server.getAddress(); + } + + @Override + public void change(Event e, @Nullable Object[] delta, Changer.ChangeMode mode) { + return; + } + + @Override + public Class getReturnType() { + return String.class; + } + + @Override + protected String getPropertyName() { + return "bungee server's address"; + } +} diff --git a/src/main/java/fr/zorg/bungeesk/bukkit/skript/expressions/bungeeserver/ExprAllBungeeServers.java b/src/main/java/fr/zorg/bungeesk/bukkit/skript/expressions/bungeeserver/ExprAllBungeeServers.java new file mode 100644 index 0000000..6c1270a --- /dev/null +++ b/src/main/java/fr/zorg/bungeesk/bukkit/skript/expressions/bungeeserver/ExprAllBungeeServers.java @@ -0,0 +1,70 @@ +package fr.zorg.bungeesk.bukkit.skript.expressions.bungeeserver; + +import ch.njol.skript.Skript; +import ch.njol.skript.doc.Description; +import ch.njol.skript.doc.Examples; +import ch.njol.skript.doc.Name; +import ch.njol.skript.doc.Since; +import ch.njol.skript.lang.Expression; +import ch.njol.skript.lang.ExpressionType; +import ch.njol.skript.lang.SkriptParser; +import ch.njol.skript.lang.util.SimpleExpression; +import ch.njol.util.Kleenean; +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; +import fr.zorg.bungeesk.bukkit.BungeeSK; +import fr.zorg.bungeesk.bukkit.sockets.ConnectionClient; +import fr.zorg.bungeesk.bukkit.utils.BungeeServer; +import org.bukkit.event.Event; +import org.jetbrains.annotations.Nullable; + +@Name("All of the bungee servers") +@Description("Returns every server in the bungeecord config") +@Examples("loop all bungee servers:\n" + + "\tsend \"%loop-bungeeserver%\"") +@Since("1.0.0, 1.1.0: Returns BungeeServer") +public class ExprAllBungeeServers extends SimpleExpression { + + static { + Skript.registerExpression(ExprAllBungeeServers.class, BungeeServer.class, + ExpressionType.SIMPLE, "[(all [[of] the]|the)] [bungee] servers"); + } + + @Override + public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, SkriptParser.ParseResult parseResult) { + return true; + } + + @Override + protected @Nullable BungeeServer[] get(Event e) { + if (BungeeSK.isClientConnected()) { + final JsonArray result = ConnectionClient.get().future("expressionGetAllBungeeServers").get("servers").getAsJsonArray(); + BungeeServer[] servers = new BungeeServer[result.size()]; + for (int i = 0; i < result.size(); i++) { + final JsonObject serverData = result.get(i).getAsJsonObject(); + servers[i] = new BungeeServer(serverData.get("address").getAsString(), + serverData.get("port").getAsInt(), + serverData.get("name").getAsString(), + serverData.get("motd").getAsString()); + } + return servers; + } + return new BungeeServer[0]; + } + + @Override + public boolean isSingle() { + return false; + } + + @Override + public Class getReturnType() { + return BungeeServer.class; + } + + @Override + public String toString(@Nullable Event e, boolean debug) { + return "all bungee servers"; + } + +} diff --git a/src/main/java/fr/zorg/bungeesk/bukkit/skript/expressions/bungeeserver/ExprBungeeServerFromAddress.java b/src/main/java/fr/zorg/bungeesk/bukkit/skript/expressions/bungeeserver/ExprBungeeServerFromAddress.java new file mode 100644 index 0000000..64ecdc7 --- /dev/null +++ b/src/main/java/fr/zorg/bungeesk/bukkit/skript/expressions/bungeeserver/ExprBungeeServerFromAddress.java @@ -0,0 +1,76 @@ +package fr.zorg.bungeesk.bukkit.skript.expressions.bungeeserver; + +import ch.njol.skript.Skript; +import ch.njol.skript.doc.Description; +import ch.njol.skript.doc.Examples; +import ch.njol.skript.doc.Name; +import ch.njol.skript.doc.Since; +import ch.njol.skript.lang.Expression; +import ch.njol.skript.lang.ExpressionType; +import ch.njol.skript.lang.SkriptParser; +import ch.njol.skript.lang.util.SimpleExpression; +import ch.njol.util.Kleenean; +import com.google.gson.JsonObject; +import fr.zorg.bungeesk.bukkit.BungeeSK; +import fr.zorg.bungeesk.bukkit.sockets.ConnectionClient; +import fr.zorg.bungeesk.bukkit.utils.BungeeServer; +import org.bukkit.event.Event; +import org.jetbrains.annotations.Nullable; + +@Name("Get a bungee server from its address and port") +@Description("Get one of the servers precised in the Bungeecord config whose address and port match") +@Examples("set {_server} to bungee server with address \"127.0.0.1\" and port 25566") +@Since("1.1.0") +public class ExprBungeeServerFromAddress extends SimpleExpression { + + static { + Skript.registerExpression(ExprBungeeServerFromAddress.class, + BungeeServer.class, + ExpressionType.SIMPLE, + "bungee[ ]server with address %string% and port %integer%"); + } + + private Expression address; + private Expression port; + + @Override + public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, SkriptParser.ParseResult parseResult) { + this.address = (Expression) exprs[0]; + this.port = (Expression) exprs[1]; + return true; + } + + @Override + protected BungeeServer[] get(Event e) { + if (BungeeSK.isClientConnected()) { + final JsonObject result = ConnectionClient.get().future("expressionGetBungeeServerFromAddress", + "address", this.address.getSingle(e), + "port", String.valueOf(this.port.getSingle(e))); + + if (result.get("error").getAsBoolean() || result == null) { + return new BungeeServer[0]; + } + + return new BungeeServer[]{new BungeeServer(result.get("address").getAsString(), + result.get("port").getAsInt(), + result.get("name").getAsString(), + result.get("motd").getAsString())}; + } + return new BungeeServer[0]; + } + + @Override + public boolean isSingle() { + return true; + } + + @Override + public Class getReturnType() { + return BungeeServer.class; + } + + @Override + public String toString(@Nullable Event e, boolean debug) { + return "bungee server with address " + this.address.toString(e, debug) + " and port " + this.port.toString(e, debug); + } +} diff --git a/src/main/java/fr/zorg/bungeesk/bukkit/skript/expressions/bungeeserver/ExprBungeeServerFromName.java b/src/main/java/fr/zorg/bungeesk/bukkit/skript/expressions/bungeeserver/ExprBungeeServerFromName.java new file mode 100644 index 0000000..f88b031 --- /dev/null +++ b/src/main/java/fr/zorg/bungeesk/bukkit/skript/expressions/bungeeserver/ExprBungeeServerFromName.java @@ -0,0 +1,72 @@ +package fr.zorg.bungeesk.bukkit.skript.expressions.bungeeserver; + +import ch.njol.skript.Skript; +import ch.njol.skript.doc.Description; +import ch.njol.skript.doc.Examples; +import ch.njol.skript.doc.Name; +import ch.njol.skript.doc.Since; +import ch.njol.skript.lang.Expression; +import ch.njol.skript.lang.ExpressionType; +import ch.njol.skript.lang.SkriptParser; +import ch.njol.skript.lang.util.SimpleExpression; +import ch.njol.util.Kleenean; +import com.google.gson.JsonObject; +import fr.zorg.bungeesk.bukkit.BungeeSK; +import fr.zorg.bungeesk.bukkit.sockets.ConnectionClient; +import fr.zorg.bungeesk.bukkit.utils.BungeeServer; +import org.bukkit.event.Event; +import org.jetbrains.annotations.Nullable; + +@Name("Bungee server from its name") +@Description("Get bungee server from its name") +@Examples("set {_player} to bungee server named \"Hub\"") +@Since("1.1.0") +public class ExprBungeeServerFromName extends SimpleExpression { + + static { + Skript.registerExpression(ExprBungeeServerFromName.class, + BungeeServer.class, + ExpressionType.SIMPLE, + "bungee[ ]server (with name|named) %string%"); + } + + private Expression name; + + @Override + public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, SkriptParser.ParseResult parseResult) { + this.name = (Expression) exprs[0]; + return true; + } + + @Override + protected BungeeServer[] get(Event e) { + if (BungeeSK.isClientConnected()) { + final JsonObject result = ConnectionClient.get().future("expressionGetBungeeServerFromName", "name", this.name.getSingle(e)); + + if (result.get("error").getAsBoolean()) { + return new BungeeServer[0]; + } + return new BungeeServer[]{new BungeeServer(result.get("address").getAsString(), + result.get("port").getAsInt(), + result.get("name").getAsString(), + result.get("motd").getAsString())}; + } + return new BungeeServer[0]; + } + + @Override + public boolean isSingle() { + return true; + } + + @Override + public Class getReturnType() { + return BungeeServer.class; + } + + @Override + public String toString(@Nullable Event e, boolean debug) { + return "bungee server with name " + this.name.toString(e, debug); + } + +} diff --git a/src/main/java/fr/zorg/bungeesk/bukkit/skript/expressions/bungeeserver/ExprMOTDOfBungeeServer.java b/src/main/java/fr/zorg/bungeesk/bukkit/skript/expressions/bungeeserver/ExprMOTDOfBungeeServer.java new file mode 100644 index 0000000..67ea5ff --- /dev/null +++ b/src/main/java/fr/zorg/bungeesk/bukkit/skript/expressions/bungeeserver/ExprMOTDOfBungeeServer.java @@ -0,0 +1,46 @@ +package fr.zorg.bungeesk.bukkit.skript.expressions.bungeeserver; + +import ch.njol.skript.classes.Changer; +import ch.njol.skript.doc.Description; +import ch.njol.skript.doc.Examples; +import ch.njol.skript.doc.Name; +import ch.njol.skript.doc.Since; +import ch.njol.skript.expressions.base.SimplePropertyExpression; +import fr.zorg.bungeesk.bukkit.utils.BungeeServer; +import org.bukkit.event.Event; +import org.jetbrains.annotations.Nullable; + +@Name("Bungee motd of bungee server") +@Description("Get the MOTD of a server precised in the Bungeecord config") +@Examples("broadcast bungee motd of bungee server named \"lobby\"") +@Since("1.1.0") +public class ExprMOTDOfBungeeServer extends SimplePropertyExpression { + + static { + register(ExprMOTDOfBungeeServer.class, + String.class, + "bungee motd", + "bungeeserver"); + } + + @Nullable + @Override + public String convert(BungeeServer server) { + return server == null ? null : server.getMotd(); + } + + @Override + public void change(Event e, @Nullable Object[] delta, Changer.ChangeMode mode) { + return; + } + + @Override + public Class getReturnType() { + return String.class; + } + + @Override + protected String getPropertyName() { + return "bungee server's motd"; + } +} diff --git a/src/main/java/fr/zorg/bungeesk/bukkit/skript/expressions/bungeeserver/ExprNameOfBungeeServer.java b/src/main/java/fr/zorg/bungeesk/bukkit/skript/expressions/bungeeserver/ExprNameOfBungeeServer.java new file mode 100644 index 0000000..8a68597 --- /dev/null +++ b/src/main/java/fr/zorg/bungeesk/bukkit/skript/expressions/bungeeserver/ExprNameOfBungeeServer.java @@ -0,0 +1,47 @@ +package fr.zorg.bungeesk.bukkit.skript.expressions.bungeeserver; + +import ch.njol.skript.classes.Changer; +import ch.njol.skript.doc.Description; +import ch.njol.skript.doc.Examples; +import ch.njol.skript.doc.Name; +import ch.njol.skript.doc.Since; +import ch.njol.skript.expressions.base.SimplePropertyExpression; +import fr.zorg.bungeesk.bukkit.utils.BungeeServer; +import org.bukkit.event.Event; +import org.jetbrains.annotations.Nullable; + +@Name("Bungee name of bungee server") +@Description("Get the name of a server precised in the Bungeecord config") +@Examples("broadcast bungee name of bungee server named \"lobby\"") +@Since("1.1.0") +public class ExprNameOfBungeeServer extends SimplePropertyExpression { + + static { + register(ExprNameOfBungeeServer.class, + String.class, + "bungee name", + "bungeeserver"); + } + + @Nullable + @Override + public String convert(BungeeServer server) { + return server == null ? null : server.getName(); + } + + @Override + public void change(Event e, @Nullable Object[] delta, Changer.ChangeMode mode) { + return; + } + + @Override + public Class getReturnType() { + return String.class; + } + + @Override + protected String getPropertyName() { + return "bungee server's name"; + } + +} diff --git a/src/main/java/fr/zorg/bungeesk/bukkit/skript/expressions/bungeeserver/ExprPortOfBungeeServer.java b/src/main/java/fr/zorg/bungeesk/bukkit/skript/expressions/bungeeserver/ExprPortOfBungeeServer.java new file mode 100644 index 0000000..ef0f12f --- /dev/null +++ b/src/main/java/fr/zorg/bungeesk/bukkit/skript/expressions/bungeeserver/ExprPortOfBungeeServer.java @@ -0,0 +1,46 @@ +package fr.zorg.bungeesk.bukkit.skript.expressions.bungeeserver; + +import ch.njol.skript.classes.Changer; +import ch.njol.skript.doc.Description; +import ch.njol.skript.doc.Examples; +import ch.njol.skript.doc.Name; +import ch.njol.skript.doc.Since; +import ch.njol.skript.expressions.base.SimplePropertyExpression; +import fr.zorg.bungeesk.bukkit.utils.BungeeServer; +import org.bukkit.event.Event; +import org.jetbrains.annotations.Nullable; + +@Name("Bungee port of bungee server") +@Description("Get the port of a server precised in the Bungeecord config") +@Examples("broadcast bungee port of bungee server named \"lobby\"") +@Since("1.1.0") +public class ExprPortOfBungeeServer extends SimplePropertyExpression { + + static { + register(ExprPortOfBungeeServer.class, + Long.class, + "bungee port", + "bungeeserver"); + } + + @Nullable + @Override + public Long convert(BungeeServer server) { + return server == null ? null : (long) server.getPort(); + } + + @Override + public void change(Event e, @Nullable Object[] delta, Changer.ChangeMode mode) { + return; + } + + @Override + public Class getReturnType() { + return Long.class; + } + + @Override + protected String getPropertyName() { + return "bungee server's port"; + } +} diff --git a/src/main/java/fr/zorg/bungeesk/bukkit/skript/expressions/client/ExprAddress.java b/src/main/java/fr/zorg/bungeesk/bukkit/skript/expressions/client/ExprAddress.java index bf77f14..0a15a2e 100644 --- a/src/main/java/fr/zorg/bungeesk/bukkit/skript/expressions/client/ExprAddress.java +++ b/src/main/java/fr/zorg/bungeesk/bukkit/skript/expressions/client/ExprAddress.java @@ -1,5 +1,6 @@ package fr.zorg.bungeesk.bukkit.skript.expressions.client; +import ch.njol.skript.classes.Changer.ChangeMode; import ch.njol.skript.doc.Description; import ch.njol.skript.doc.Examples; import ch.njol.skript.doc.Name; @@ -8,7 +9,6 @@ import ch.njol.util.coll.CollectionUtils; import fr.zorg.bungeesk.bukkit.sockets.ClientSettings; import org.bukkit.event.Event; -import ch.njol.skript.classes.Changer.ChangeMode; import org.jetbrains.annotations.Nullable; @Name("Address of connection") @@ -21,7 +21,8 @@ public class ExprAddress extends SimplePropertyExpression { diff --git a/src/main/java/fr/zorg/bungeesk/bukkit/skript/expressions/client/ExprName.java b/src/main/java/fr/zorg/bungeesk/bukkit/skript/expressions/client/ExprName.java deleted file mode 100644 index c9c80fe..0000000 --- a/src/main/java/fr/zorg/bungeesk/bukkit/skript/expressions/client/ExprName.java +++ /dev/null @@ -1,58 +0,0 @@ -package fr.zorg.bungeesk.bukkit.skript.expressions.client; - -import ch.njol.skript.classes.Changer.ChangeMode; -import ch.njol.skript.doc.Description; -import ch.njol.skript.doc.Examples; -import ch.njol.skript.doc.Name; -import ch.njol.skript.doc.Since; -import ch.njol.skript.expressions.base.SimplePropertyExpression; -import ch.njol.util.coll.CollectionUtils; -import fr.zorg.bungeesk.bukkit.sockets.ClientSettings; -import org.bukkit.event.Event; -import org.jetbrains.annotations.Nullable; - -@Name("Name of server for a connection") -@Description("Set the name of the server for a connection") -@Since("1.0.0") -@Examples("set name of {_connection} to \"hub\"") -public class ExprName extends SimplePropertyExpression { - - static { - register(ExprName.class, - String.class, - "name", - "bungeeconn"); - } - - - @Nullable - @Override - public String convert(ClientSettings clientsettings) { - return clientsettings.getAddress(); - } - - @Override - public Class[] acceptChange(ChangeMode mode) { - if (mode == ChangeMode.SET) { - return CollectionUtils.array(String.class); - } - return CollectionUtils.array(); - } - - @Override - public void change(Event e, Object[] delta, ChangeMode mode) { - for (ClientSettings clientSettings : getExpr().getArray(e)) { - clientSettings.setName((String) delta[0]); - } - } - - @Override - public Class getReturnType() { - return String.class; - } - - @Override - protected String getPropertyName() { - return "name"; - } -} diff --git a/src/main/java/fr/zorg/bungeesk/bukkit/skript/expressions/client/ExprPassword.java b/src/main/java/fr/zorg/bungeesk/bukkit/skript/expressions/client/ExprPassword.java index 4830291..42385f3 100644 --- a/src/main/java/fr/zorg/bungeesk/bukkit/skript/expressions/client/ExprPassword.java +++ b/src/main/java/fr/zorg/bungeesk/bukkit/skript/expressions/client/ExprPassword.java @@ -7,16 +7,12 @@ import ch.njol.skript.doc.Since; import ch.njol.skript.expressions.base.SimplePropertyExpression; import ch.njol.util.coll.CollectionUtils; -import fr.zorg.bungeesk.bukkit.BungeeSK; import fr.zorg.bungeesk.bukkit.sockets.ClientSettings; import org.bukkit.event.Event; import org.jetbrains.annotations.Nullable; -import java.util.logging.Level; - @Name("Password of connection") -@Description("Set the password to connect to a bungeecord server." + - "NOTE: The password must not contain the 'µ' character") +@Description("Set the password to connect to a bungeecord server.") @Since("1.0.0") @Examples("set password of {_connection} to \"abdc123\"") public class ExprPassword extends SimplePropertyExpression { diff --git a/src/main/java/fr/zorg/bungeesk/bukkit/skript/expressions/eventvalues/ExprPastServer.java b/src/main/java/fr/zorg/bungeesk/bukkit/skript/expressions/eventvalues/ExprPastServer.java index 8ce453d..1ef5963 100644 --- a/src/main/java/fr/zorg/bungeesk/bukkit/skript/expressions/eventvalues/ExprPastServer.java +++ b/src/main/java/fr/zorg/bungeesk/bukkit/skript/expressions/eventvalues/ExprPastServer.java @@ -2,21 +2,30 @@ import ch.njol.skript.ScriptLoader; import ch.njol.skript.Skript; -import ch.njol.skript.SkriptAddon; +import ch.njol.skript.doc.Description; +import ch.njol.skript.doc.Examples; +import ch.njol.skript.doc.Name; +import ch.njol.skript.doc.Since; import ch.njol.skript.lang.Expression; import ch.njol.skript.lang.ExpressionType; import ch.njol.skript.lang.SkriptParser; import ch.njol.skript.lang.util.SimpleExpression; import ch.njol.util.Kleenean; import fr.zorg.bungeesk.bukkit.skript.events.bukkit.ServerSwitchEvent; +import fr.zorg.bungeesk.bukkit.utils.BungeeServer; import org.bukkit.event.Event; import org.jetbrains.annotations.Nullable; -public class ExprPastServer extends SimpleExpression { +@Name("Server switch event past server") +@Description("Gets the server where the player was from in a server switch event") +@Examples("on server switch:\n" + + "\tbroadcast \"The player was in the %past-server% server !\"") +@Since("1.0.0 - 1.1.0: Returns bungee server") +public class ExprPastServer extends SimpleExpression { static { Skript.registerExpression(ExprPastServer.class, - String.class, + BungeeServer.class, ExpressionType.SIMPLE, "past-server"); } @@ -32,8 +41,8 @@ public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelaye @Nullable @Override - protected String[] get(Event e) { - return new String[] { ((ServerSwitchEvent) e).getServer() }; + protected BungeeServer[] get(Event e) { + return new BungeeServer[]{((ServerSwitchEvent) e).getServer()}; } @Override @@ -42,13 +51,13 @@ public boolean isSingle() { } @Override - public Class getReturnType() { - return String.class; + public Class getReturnType() { + return BungeeServer.class; } @Override public String toString(@Nullable Event e, boolean debug) { - return "past server of " + ((ServerSwitchEvent) e).getPlayer().getPlayer(); + return "past server of " + ((ServerSwitchEvent) e).getPlayer().getName(); } } diff --git a/src/main/java/fr/zorg/bungeesk/bukkit/skript/scopes/ScopeConnectToServer.java b/src/main/java/fr/zorg/bungeesk/bukkit/skript/scopes/ScopeConnectToServer.java index 2a3a2da..9dea60b 100644 --- a/src/main/java/fr/zorg/bungeesk/bukkit/skript/scopes/ScopeConnectToServer.java +++ b/src/main/java/fr/zorg/bungeesk/bukkit/skript/scopes/ScopeConnectToServer.java @@ -23,7 +23,6 @@ "\t\tset address of connection to \"127.0.0.1\"\n" + "\t\tset port of connection to 100\n" + "\t\tset password of connection to \"abcd\"\n" + - "\t\tset name of connection to \"server1\"\n" + "\tstart new connection with connection") public class ScopeConnectToServer extends EffectSection { diff --git a/src/main/java/fr/zorg/bungeesk/bukkit/sockets/ClientSettings.java b/src/main/java/fr/zorg/bungeesk/bukkit/sockets/ClientSettings.java index 0f06926..223b94f 100644 --- a/src/main/java/fr/zorg/bungeesk/bukkit/sockets/ClientSettings.java +++ b/src/main/java/fr/zorg/bungeesk/bukkit/sockets/ClientSettings.java @@ -4,7 +4,6 @@ public final class ClientSettings { private String address; private Long port; - private String name; private String password; public String getAddress() { @@ -23,14 +22,6 @@ public void setPort(final Long port) { this.port = port; } - public String getName() { - return this.name; - } - - public void setName(final String name) { - this.name = name; - } - public String getPassword() { return this.password; } diff --git a/src/main/java/fr/zorg/bungeesk/bukkit/sockets/ConnectionClient.java b/src/main/java/fr/zorg/bungeesk/bukkit/sockets/ConnectionClient.java index 05c5727..deffcf1 100644 --- a/src/main/java/fr/zorg/bungeesk/bukkit/sockets/ConnectionClient.java +++ b/src/main/java/fr/zorg/bungeesk/bukkit/sockets/ConnectionClient.java @@ -1,13 +1,14 @@ package fr.zorg.bungeesk.bukkit.sockets; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; import fr.zorg.bungeesk.bukkit.BungeeSK; import fr.zorg.bungeesk.bukkit.skript.events.bukkit.*; -import fr.zorg.bungeesk.bukkit.updater.Commands; -import fr.zorg.bungeesk.bukkit.updater.Updater; import fr.zorg.bungeesk.bukkit.utils.BungeePlayer; -import fr.zorg.bungeesk.common.encryption.AESEncryption; -import fr.zorg.bungeesk.common.utils.Utils; -import org.apache.commons.io.FileUtils; +import fr.zorg.bungeesk.bukkit.utils.BungeeServer; +import fr.zorg.bungeesk.common.encryption.GlobalEncryption; import org.bukkit.Bukkit; import org.bukkit.event.Event; import org.jetbrains.annotations.Nullable; @@ -15,7 +16,9 @@ import java.io.*; import java.net.Socket; import java.nio.charset.StandardCharsets; -import java.util.*; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; @@ -35,16 +38,11 @@ public static ConnectionClient generateConnection(final ClientSettings settings) if (instance != null) { instance.disconnect(); - try { - instance.finalize(); - instance = null; - } catch (final Throwable throwable) { - throwable.printStackTrace(); - } + instance = null; } try { final Socket socket = new Socket(settings.getAddress(), settings.getPort().intValue()); - instance = new ConnectionClient(socket, settings.getName(), settings.getPassword()); + instance = new ConnectionClient(socket, settings.getPassword()); } catch (Exception e) { BungeeSK.getInstance().getLogger().log(Level.SEVERE, "BungeeSK couldn't find server with this address/port !"); } @@ -55,18 +53,23 @@ public static ConnectionClient generateConnection(final ClientSettings settings) private final Thread readThread; private final BufferedReader reader; private final PrintWriter writer; + private final String address; + private final String password; + private final static Gson gson = new GsonBuilder().create(); - private final Map>> toComplete; + private final Map> toComplete; - private final AESEncryption encryption; + private final GlobalEncryption encryption; - private ConnectionClient(final Socket socket, final String name, final String password) throws IOException { + private ConnectionClient(final Socket socket, final String password) throws IOException { this.socket = socket; this.reader = new BufferedReader(new InputStreamReader(socket.getInputStream(), StandardCharsets.UTF_8)); this.writer = new PrintWriter(socket.getOutputStream(), true); this.toComplete = new HashMap<>(); - this.encryption = new AESEncryption(password, BungeeSK.getInstance().getLogger()); - this.write("name=" + name + "µpassword=" + password); + this.address = socket.getInetAddress().toString() + ":" + BungeeSK.getInstance().getServer().getPort(); + this.password = password; + this.encryption = BungeeSK.getEncryption(); + this.write(true, "connectionRequest", "address", this.address.substring(1), "password", this.password); this.readThread = new Thread(this::read); this.readThread.setDaemon(true); this.readThread.start(); @@ -82,121 +85,123 @@ public void read() { break; } - final String data = this.encryption.decrypt(Utils.getMessage(rawData)); - final String[] separateDatas = data.split("µ"); - - final String header = separateDatas[0]; - final List received = new ArrayList<>(Arrays.asList(separateDatas).subList(1, separateDatas.length)); - switch (header.toUpperCase()) { - case "ALREADY_CONNECTED": { - BungeeSK.getInstance().getLogger().log(Level.WARNING, "§6Trying to connect to §c" - + this.socket.getInetAddress().getHostAddress() - + " §6and returned failure: §cServer already connected under this name !"); - this.disconnect(); - break; - } - case "WRONG_PASSWORD": { - BungeeSK.getInstance().getLogger().log(Level.WARNING, "§6Trying to connect to §c" - + this.socket.getInetAddress().getHostAddress() - + " §6and returned failure: §cWrong password !"); - this.disconnect(); - break; - } - case "DISCONNECT": { - this.disconnect(); - break; - } - case "CONNECTED_SUCCESSFULLY": { - final Event event = new ClientConnectEvent(); - Bukkit.getScheduler().runTask(BungeeSK.getInstance(), () -> Bukkit.getPluginManager().callEvent(event)); + final String data = this.encryption.decrypt(rawData, this.password); + + final JsonObject jsonObject = new JsonParser().parse(data).getAsJsonObject(); + final String action = jsonObject.get("action").getAsString(); + final JsonObject args = jsonObject.get("args").getAsJsonObject(); + + + switch (action) { + + // Connection + + case "connectionInformation": { + if (args.get("status").getAsString().equals("wrongPassword")) { + this.forceDisconnect(); + BungeeSK.getInstance().getLogger().log(Level.WARNING, "§6Trying to connect to §c" + + this.socket.getInetAddress().getHostAddress() + + " §6and returned failure: §cWrong password !"); + } else if (args.get("status").getAsString().equals("alreadyConnected")) { + BungeeSK.getInstance().getLogger().log(Level.WARNING, "§6Trying to connect to §c" + + this.socket.getInetAddress().getHostAddress() + + " §6and returned failure: §cServer already connected under this address !"); + this.forceDisconnect(); + } else if (args.get("status").getAsString().equals("disconnect")) { + this.disconnect(); + } else if (args.get("status").getAsString().equals("connected")) { + Bukkit.getScheduler().runTask(BungeeSK.getInstance(), () -> Bukkit.getPluginManager().callEvent(new ClientConnectEvent())); + } break; } - case "SEND_SKRIPTS": { - final String[] flux = received.get(0).split("™"); + + // Global scripts + + case "sendFiles": { final File folder = new File("plugins/Skript/scripts/BungeeSK"); if (!folder.exists()) folder.mkdirs(); - String file = null; - byte[] content; - File skript; - for (final String line : flux) { - if (line.equals("endFile")) { - file = null; - } else if (file == null && line.startsWith("newFile:")) { - file = line.substring(8); - } else if (file != null) { - try { - content = Utils.fromBase64(line); - skript = new File(folder, file); - if (skript.exists()) - skript.delete(); - skript.createNewFile(); - FileUtils.writeByteArrayToFile(skript, content); - } catch (Exception e) { - e.printStackTrace(); - } - } else if (line.equals("END_SKRIPTS")) - break; - } + + args.entrySet().forEach(fileArg -> { + try { + File file = new File(folder, fileArg.getKey()); + if (file.exists()) + file.delete(); + file.createNewFile(); + BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(file)); + fileArg.getValue().getAsJsonArray().forEach(jsonElement -> { + try { + bufferedWriter.write(jsonElement.getAsString()); + bufferedWriter.newLine(); + } catch (IOException e) { + e.printStackTrace(); + } + }); + bufferedWriter.close(); + } catch (IOException e) { + e.printStackTrace(); + } + + }); break; } - case "CONSOLECOMMAND": { - Updater.get().getByClass(Commands.class).addCommandToSend(Bukkit.getConsoleSender(), separateDatas[1]); + + // Executables + + case "executeConsoleCommand": { + Bukkit.getScheduler().runTask(BungeeSK.getInstance(), + () -> Bukkit.dispatchCommand(BungeeSK.getInstance().getServer().getConsoleSender(), args.get("command").getAsString())); break; } - case "LOGINEVENT": { - final Event event = new BungeePlayerJoinEvent(new BungeePlayer(separateDatas[1], separateDatas[2])); - Bukkit.getScheduler().runTask(BungeeSK.getInstance(), () -> Bukkit.getPluginManager().callEvent(event)); + + case "broadcastMessage": { + Bukkit.getScheduler().runTask(BungeeSK.getInstance(), + () -> Bukkit.broadcastMessage(args.get("message").getAsString())); break; } - case "LEAVEEVENT": { - final Event event = new BungeePlayerLeaveEvent(new BungeePlayer(separateDatas[1], separateDatas[2])); + + case "customBungeeMessage": { + final JsonObject serverInfos = args.get("fromServer").getAsJsonObject(); + final BungeeServer server = new BungeeServer(serverInfos.get("address").getAsString(), + serverInfos.get("port").getAsInt(), + serverInfos.get("name").getAsString(), + serverInfos.get("motd").getAsString()); + final Event event = new BungeeMessageReceiveEvent(server, args.get("message").getAsString()); Bukkit.getScheduler().runTask(BungeeSK.getInstance(), () -> Bukkit.getPluginManager().callEvent(event)); break; } - case "ALLBUNGEEPLAYERS": { - this.putFuture("ALLBUNGEEPLAYERSµ", separateDatas[1] + "^"); - break; - } - case "PLAYERSERVER": { - final String[] dataArray = separateDatas[1].split("\\^"); - this.putFuture("PLAYERSERVERµ" + dataArray[0], dataArray[1]); - break; - } - case "GETPLAYER": { - final String player = separateDatas[1].split("\\$")[0]; - this.putFuture("GETPLAYERµ" + player, separateDatas[1]); - break; - } - case "ISCONNECTED": { - final String[] dataArray = separateDatas[1].split("\\^"); - this.putFuture("ISCONNECTEDµ" + dataArray[0], dataArray[1]); + // Futures + + case "futureResponse": { + final UUID uuid = UUID.fromString(args.get("uuid").getAsString()); + this.completeFuture(uuid, args.get("response").getAsJsonObject()); break; } - case "SERVERSWITCHEVENT": { - final String[] dataArray = separateDatas[1].split("\\^"); - final BungeePlayer bungeePlayer = new BungeePlayer(dataArray[0].split("\\$")[0], dataArray[0].split("\\$")[1]); - final Event event = new ServerSwitchEvent(bungeePlayer, dataArray[1]); + // Events + + case "eventBungeePlayerConnect": { + final Event event = new BungeePlayerJoinEvent(new BungeePlayer(args.get("name").getAsString(), args.get("uniqueId").getAsString())); Bukkit.getScheduler().runTask(BungeeSK.getInstance(), () -> Bukkit.getPluginManager().callEvent(event)); break; } - case "ALLBUNGEESERVERS": { - this.putFuture("ALLBUNGEESERVERSµ", separateDatas[1]); - break; - } - case "CLIENTREALNAME": { - this.putFuture("CLIENTREALNAMEµ" + separateDatas[1].split("\\^")[0], separateDatas[1].split("\\^")[1]); - break; - } - case "ALLBUNGEEPLAYERSONSERVER": { - final String server = separateDatas[1].split("\\^")[0]; - this.putFuture("ALLBUNGEEPLAYERSONSERVERµ" + server, separateDatas[1]); + case "eventBungeePlayerDisconnect": { + final Event event = new BungeePlayerLeaveEvent(new BungeePlayer(args.get("name").getAsString(), args.get("uniqueId").getAsString())); + Bukkit.getScheduler().runTask(BungeeSK.getInstance(), () -> Bukkit.getPluginManager().callEvent(event)); break; } - case "BROADCAST": { - Bukkit.getScheduler().runTask(BungeeSK.getInstance(), () -> Bukkit.broadcastMessage(separateDatas[1])); + case "eventBungeePlayerServerSwitch": { + final BungeePlayer player = new BungeePlayer(args.get("player").getAsJsonObject().get("name").getAsString(), + args.get("player").getAsJsonObject().get("uniqueId").getAsString()); + final JsonObject serverObj = args.get("server").getAsJsonObject(); + final BungeeServer server = new BungeeServer(serverObj.get("address").getAsString(), + serverObj.get("port").getAsInt(), + serverObj.get("name").getAsString(), + serverObj.get("motd").getAsString()); + + final Event event = new ServerSwitchEvent(player, server); + Bukkit.getScheduler().runTask(BungeeSK.getInstance(), () -> Bukkit.getPluginManager().callEvent(event)); break; } } @@ -209,7 +214,7 @@ public void read() { public void disconnect() { try { - this.writer.println(Arrays.toString("DISCONNECT".getBytes(StandardCharsets.UTF_8))); + this.write(false, "connectionInformation", "status", "disconnect"); Bukkit.getScheduler().runTask(BungeeSK.getInstance(), () -> Bukkit.getPluginManager().callEvent(new ClientDisconnectEvent())); } catch (final Exception ignored) { } @@ -219,10 +224,10 @@ public void disconnect() { public void forceDisconnect() { try { if (!this.socket.isClosed()) { - this.socket.close(); this.reader.close(); this.writer.close(); this.readThread.interrupt(); + this.socket.close(); } } catch (IOException e) { e.printStackTrace(); @@ -233,43 +238,81 @@ public boolean isConnected() { return this.socket != null && this.socket.isConnected() && !this.socket.isClosed(); } - public void write(final String message) { - this.writer.println(Arrays.toString(this.encryption.encrypt(message).getBytes(StandardCharsets.UTF_8))); + public void write(final boolean encryption, final String action, final String... args) { + final Map map = new HashMap<>(); + map.put("action", action); + final Map argsMap = new HashMap<>(); + for (int i = 0; i < args.length; i = i + 2) { + argsMap.put(args[i], args[i + 1]); + } + map.put("args", argsMap); + + if (encryption) { + final String toSend = this.encryption.encrypt(gson.toJson(map), this.password); + this.writer.println(toSend); + return; + } + this.writer.println(gson.toJson(map)); + } + + public void writeRaw(final boolean encryption, final String action, final Map argsMap) { + final Map map = new HashMap<>(); + map.put("action", action); + map.put("args", argsMap); + + if (encryption) { + this.writer.println(this.encryption.encrypt(gson.toJson(map), this.password)); + return; + } + this.writer.println(gson.toJson(map)); } - public Map>> getToComplete() { + public Map> getToComplete() { return this.toComplete; } - public void putFuture(final String key, final String value) { - LinkedList> future = this.toComplete.get(key); - if (future != null && future.size() > 0) { - future.poll().complete(value); - if (future.size() == 0) this.toComplete.remove(key, future); + public void completeFuture(final UUID uuid, final JsonObject toComplete) { + CompletableFuture future = this.toComplete.get(uuid); + if (future != null) { + future.complete(toComplete); + this.toComplete.remove(uuid); } } - public String future(final String value) { - LinkedList> futureList = new LinkedList<>(); - if (this.toComplete.containsKey(value)) futureList = this.toComplete.get(value); - final CompletableFuture future = new CompletableFuture<>(); - futureList.add(future); - this.toComplete.put(value, futureList); - this.write(value); - String result; + public JsonObject future(final String action, final String... args) { + final UUID randomUUID = UUID.randomUUID(); // Using a random UUID here to prevent from mixing between 2 actions at the same time + CompletableFuture future = new CompletableFuture<>(); + this.toComplete.put(randomUUID, future); + + Map map = new HashMap<>(); + + map.put("action", action); + map.put("uuid", randomUUID.toString()); + if (args != null) + for (int i = 0; i < args.length; i = i + 2) + map.put(args[i], args[i + 1]); + + this.writeRaw(true, "futureGet", map); + + JsonObject jsonObject; try { - result = future.get(1, TimeUnit.SECONDS); + jsonObject = future.get(1, TimeUnit.SECONDS); } catch (InterruptedException | ExecutionException | TimeoutException e) { + BungeeSK.getInstance().getLogger().log(Level.WARNING, "An error occurred during the get of something !"); return null; } - return result; + return jsonObject; } public String getAddress() { - return this.socket.getInetAddress().getHostAddress(); + return this.address; } public int getPort() { return this.socket.getPort(); } + + public static Gson getGson() { + return gson; + } } diff --git a/src/main/java/fr/zorg/bungeesk/bukkit/updater/Commands.java b/src/main/java/fr/zorg/bungeesk/bukkit/updater/Commands.java deleted file mode 100644 index 641ecba..0000000 --- a/src/main/java/fr/zorg/bungeesk/bukkit/updater/Commands.java +++ /dev/null @@ -1,34 +0,0 @@ -package fr.zorg.bungeesk.bukkit.updater; - -import fr.zorg.bungeesk.common.updater.Scheduler; -import fr.zorg.bungeesk.common.utils.Pair; -import org.bukkit.Bukkit; -import org.bukkit.command.CommandSender; - -import java.util.LinkedList; - -public class Commands implements Scheduler { - - private final LinkedList> commandToSend; - - public Commands() { - this.commandToSend = new LinkedList<>(); - } - - @Override - public void run() { - synchronized (this.commandToSend) { - Pair toExecute; - while ((toExecute = this.commandToSend.poll()) != null) { - Bukkit.dispatchCommand(toExecute.getFirstValue(), toExecute.getSecondValue()); - } - } - } - - public void addCommandToSend(final CommandSender sender, final String command) { - synchronized (this.commandToSend) { - this.commandToSend.add(Pair.from(sender, command)); - } - } - -} diff --git a/src/main/java/fr/zorg/bungeesk/bukkit/updater/Updater.java b/src/main/java/fr/zorg/bungeesk/bukkit/updater/Updater.java deleted file mode 100644 index e13b110..0000000 --- a/src/main/java/fr/zorg/bungeesk/bukkit/updater/Updater.java +++ /dev/null @@ -1,56 +0,0 @@ -package fr.zorg.bungeesk.bukkit.updater; - -import fr.zorg.bungeesk.bukkit.BungeeSK; -import fr.zorg.bungeesk.common.updater.Scheduler; -import org.bukkit.scheduler.BukkitRunnable; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -public class Updater extends BukkitRunnable { - - private static Updater instance; - - public static Updater get() { - if (instance == null) - instance = new Updater(); - return instance; - } - - private final List toUpdate; - - private Updater() { - this.toUpdate = new ArrayList<>(); - this.runTaskTimer(BungeeSK.getInstance(), 0L, 1L); - } - - @Override - public void run() { - this.toUpdate.forEach(Scheduler::run); - } - - public void stop() { - if (this.isCancelled()) - return; - this.cancel(); - } - - public T getByClass(Class clazz) { - for (final Scheduler scheduler : this.toUpdate) { - if (scheduler.getClass().equals(clazz)) - return (T) scheduler; - } - return null; - } - - - public void register(final Scheduler... schedulers) { - Arrays.stream(schedulers).filter(scheduler -> !this.toUpdate.contains(scheduler)).forEach(this.toUpdate::add); - } - - public void unregister(final Scheduler... schedulers) { - Arrays.stream(schedulers).filter(this.toUpdate::contains).forEach(this.toUpdate::remove); - } - -} diff --git a/src/main/java/fr/zorg/bungeesk/bukkit/utils/BukkitUtils.java b/src/main/java/fr/zorg/bungeesk/bukkit/utils/BukkitUtils.java deleted file mode 100644 index 476851b..0000000 --- a/src/main/java/fr/zorg/bungeesk/bukkit/utils/BukkitUtils.java +++ /dev/null @@ -1,15 +0,0 @@ -package fr.zorg.bungeesk.bukkit.utils; - -import org.bukkit.configuration.file.YamlConfiguration; - -public class BukkitUtils { - - public static boolean addDefault(final YamlConfiguration config, final String path, final Object o) { - if (config.get(path) == null) { - config.set(path, o); - return true; - } - return false; - } - -} diff --git a/src/main/java/fr/zorg/bungeesk/bukkit/utils/BungeePlayer.java b/src/main/java/fr/zorg/bungeesk/bukkit/utils/BungeePlayer.java index ec0abfd..33da767 100644 --- a/src/main/java/fr/zorg/bungeesk/bukkit/utils/BungeePlayer.java +++ b/src/main/java/fr/zorg/bungeesk/bukkit/utils/BungeePlayer.java @@ -2,24 +2,20 @@ public class BungeePlayer { - private final String player; + private final String name; private final String uuid; - public BungeePlayer(String player, String uuid) { - this.player = player; + public BungeePlayer(final String name, final String uuid) { + this.name = name; this.uuid = uuid; } - public String getPlayer() { - return this.player; + public String getName() { + return this.name; } public String getUuid() { return this.uuid; } - public String getData() { - return this.player + "$" + this.uuid; - } - } diff --git a/src/main/java/fr/zorg/bungeesk/bukkit/utils/BungeeServer.java b/src/main/java/fr/zorg/bungeesk/bukkit/utils/BungeeServer.java new file mode 100644 index 0000000..279bdea --- /dev/null +++ b/src/main/java/fr/zorg/bungeesk/bukkit/utils/BungeeServer.java @@ -0,0 +1,33 @@ +package fr.zorg.bungeesk.bukkit.utils; + +public class BungeeServer { + + private final String address; + private final int port; + private final String name; + private final String motd; + + public BungeeServer(final String address, final int port, final String name, final String motd) { + this.address = address; + this.port = port; + this.name = name; + this.motd = motd; + } + + public String getAddress() { + return this.address; + } + + public int getPort() { + return this.port; + } + + public String getName() { + return this.name; + } + + public String getMotd() { + return this.motd; + } + +} diff --git a/src/main/java/fr/zorg/bungeesk/bukkit/utils/EffectSection.java b/src/main/java/fr/zorg/bungeesk/bukkit/utils/EffectSection.java index f65900f..e03bd9a 100644 --- a/src/main/java/fr/zorg/bungeesk/bukkit/utils/EffectSection.java +++ b/src/main/java/fr/zorg/bungeesk/bukkit/utils/EffectSection.java @@ -5,6 +5,7 @@ import ch.njol.skript.config.Node; import ch.njol.skript.config.SectionNode; import ch.njol.skript.lang.*; +import ch.njol.skript.lang.parser.ParserInstance; import ch.njol.skript.log.*; import ch.njol.util.Kleenean; import ch.njol.util.StringUtils; @@ -163,13 +164,14 @@ public TriggerItem walk(Event event) { */ public void loadSection(String name, boolean setNext, Class... events) { if (section != null && name != null && events != null && events.length > 0) { - String previousName = ScriptLoader.getCurrentEventName(); - Class[] previousEvents = ScriptLoader.getCurrentEvents(); - Kleenean previousDelay = ScriptLoader.hasDelayBefore; - ScriptLoader.setCurrentEvent(name, events); + final ParserInstance instance = ParserInstance.get(); + String previousName = instance.getCurrentEventName(); + Class[] previousEvents = instance.getCurrentEvents(); + Kleenean previousDelay = instance.getHasDelayBefore(); + instance.setCurrentEvent(name, events); loadSection(setNext); - ScriptLoader.setCurrentEvent(previousName, previousEvents); - ScriptLoader.hasDelayBefore = previousDelay; + instance.setCurrentEvent(previousName, previousEvents); + instance.setHasDelayBefore(previousDelay); } } @@ -231,4 +233,4 @@ public boolean checkIfCondition() { public SectionNode getSectionNode() { return section; } -} \ No newline at end of file +} diff --git a/src/main/java/fr/zorg/bungeesk/bukkit/utils/Metrics.java b/src/main/java/fr/zorg/bungeesk/bukkit/utils/Metrics.java index b37a307..dcc12fb 100644 --- a/src/main/java/fr/zorg/bungeesk/bukkit/utils/Metrics.java +++ b/src/main/java/fr/zorg/bungeesk/bukkit/utils/Metrics.java @@ -1,21 +1,17 @@ package fr.zorg.bungeesk.bukkit.utils; -import java.io.BufferedReader; -import java.io.ByteArrayOutputStream; -import java.io.DataOutputStream; -import java.io.File; -import java.io.IOException; -import java.io.InputStreamReader; +import org.bukkit.Bukkit; +import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.entity.Player; +import org.bukkit.plugin.Plugin; +import org.bukkit.plugin.java.JavaPlugin; + +import javax.net.ssl.HttpsURLConnection; +import java.io.*; import java.lang.reflect.Method; import java.net.URL; import java.nio.charset.StandardCharsets; -import java.util.Arrays; -import java.util.Collection; -import java.util.HashSet; -import java.util.Map; -import java.util.Objects; -import java.util.Set; -import java.util.UUID; +import java.util.*; import java.util.concurrent.Callable; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; @@ -26,12 +22,6 @@ import java.util.logging.Level; import java.util.stream.Collectors; import java.util.zip.GZIPOutputStream; -import javax.net.ssl.HttpsURLConnection; -import org.bukkit.Bukkit; -import org.bukkit.configuration.file.YamlConfiguration; -import org.bukkit.entity.Player; -import org.bukkit.plugin.Plugin; -import org.bukkit.plugin.java.JavaPlugin; public class Metrics { @@ -42,9 +32,9 @@ public class Metrics { /** * Creates a new Metrics instance. * - * @param plugin Your plugin instance. + * @param plugin Your plugin instance. * @param serviceId The id of the service. It can be found at What is my plugin id? + * href="https://bstats.org/what-is-my-plugin-id">What is my plugin id? */ public Metrics(JavaPlugin plugin, int serviceId) { this.plugin = plugin; @@ -138,7 +128,9 @@ private int getPlayerAmount() { public static class MetricsBase { - /** The version of the Metrics class. */ + /** + * The version of the Metrics class. + */ public static final String METRICS_VERSION = "2.2.1"; private static final ScheduledExecutorService scheduler = @@ -177,23 +169,23 @@ public static class MetricsBase { /** * Creates a new MetricsBase class instance. * - * @param platform The platform of the service. - * @param serviceId The id of the service. - * @param serverUuid The server uuid. - * @param enabled Whether or not data sending is enabled. - * @param appendPlatformDataConsumer A consumer that receives a {@code JsonObjectBuilder} and - * appends all platform-specific data. - * @param appendServiceDataConsumer A consumer that receives a {@code JsonObjectBuilder} and - * appends all service-specific data. - * @param submitTaskConsumer A consumer that takes a runnable with the submit task. This can be - * used to delegate the data collection to a another thread to prevent errors caused by - * concurrency. Can be {@code null}. + * @param platform The platform of the service. + * @param serviceId The id of the service. + * @param serverUuid The server uuid. + * @param enabled Whether or not data sending is enabled. + * @param appendPlatformDataConsumer A consumer that receives a {@code JsonObjectBuilder} and + * appends all platform-specific data. + * @param appendServiceDataConsumer A consumer that receives a {@code JsonObjectBuilder} and + * appends all service-specific data. + * @param submitTaskConsumer A consumer that takes a runnable with the submit task. This can be + * used to delegate the data collection to a another thread to prevent errors caused by + * concurrency. Can be {@code null}. * @param checkServiceEnabledSupplier A supplier to check if the service is still enabled. - * @param errorLogger A consumer that accepts log message and an error. - * @param infoLogger A consumer that accepts info log messages. - * @param logErrors Whether or not errors should be logged. - * @param logSentData Whether or not the sent data should be logged. - * @param logResponseStatusText Whether or not the response status text should be logged. + * @param errorLogger A consumer that accepts log message and an error. + * @param infoLogger A consumer that accepts info log messages. + * @param logErrors Whether or not errors should be logged. + * @param logSentData Whether or not the sent data should be logged. + * @param logResponseStatusText Whether or not the response status text should be logged. */ public MetricsBase( String platform, @@ -322,7 +314,9 @@ private void sendData(JsonObjectBuilder.JsonObject data) throws Exception { } } - /** Checks that the class was properly relocated. */ + /** + * Checks that the class was properly relocated. + */ private void checkRelocation() { // You can use the property to disable the check in your test environment if (System.getProperty("bstats.relocatecheck") == null @@ -330,9 +324,9 @@ private void checkRelocation() { // Maven's Relocate is clever and changes strings, too. So we have to use this little // "trick" ... :D final String defaultPackage = - new String(new byte[] {'o', 'r', 'g', '.', 'b', 's', 't', 'a', 't', 's'}); + new String(new byte[]{'o', 'r', 'g', '.', 'b', 's', 't', 'a', 't', 's'}); final String examplePackage = - new String(new byte[] {'y', 'o', 'u', 'r', '.', 'p', 'a', 'c', 'k', 'a', 'g', 'e'}); + new String(new byte[]{'y', 'o', 'u', 'r', '.', 'p', 'a', 'c', 'k', 'a', 'g', 'e'}); // We want to make sure no one just copy & pastes the example and uses the wrong package // names if (MetricsBase.class.getPackage().getName().startsWith(defaultPackage) @@ -367,7 +361,7 @@ public static class AdvancedBarChart extends CustomChart { /** * Class constructor. * - * @param chartId The id of the chart. + * @param chartId The id of the chart. * @param callable The callable which is used to request the chart data. */ public AdvancedBarChart(String chartId, Callable> callable) { @@ -407,7 +401,7 @@ public static class SimpleBarChart extends CustomChart { /** * Class constructor. * - * @param chartId The id of the chart. + * @param chartId The id of the chart. * @param callable The callable which is used to request the chart data. */ public SimpleBarChart(String chartId, Callable> callable) { @@ -424,7 +418,7 @@ protected JsonObjectBuilder.JsonObject getChartData() throws Exception { return null; } for (Map.Entry entry : map.entrySet()) { - valuesBuilder.appendField(entry.getKey(), new int[] {entry.getValue()}); + valuesBuilder.appendField(entry.getKey(), new int[]{entry.getValue()}); } return new JsonObjectBuilder().appendField("values", valuesBuilder.build()).build(); } @@ -437,7 +431,7 @@ public static class MultiLineChart extends CustomChart { /** * Class constructor. * - * @param chartId The id of the chart. + * @param chartId The id of the chart. * @param callable The callable which is used to request the chart data. */ public MultiLineChart(String chartId, Callable> callable) { @@ -477,7 +471,7 @@ public static class AdvancedPie extends CustomChart { /** * Class constructor. * - * @param chartId The id of the chart. + * @param chartId The id of the chart. * @param callable The callable which is used to request the chart data. */ public AdvancedPie(String chartId, Callable> callable) { @@ -551,7 +545,7 @@ public static class SingleLineChart extends CustomChart { /** * Class constructor. * - * @param chartId The id of the chart. + * @param chartId The id of the chart. * @param callable The callable which is used to request the chart data. */ public SingleLineChart(String chartId, Callable callable) { @@ -577,7 +571,7 @@ public static class SimplePie extends CustomChart { /** * Class constructor. * - * @param chartId The id of the chart. + * @param chartId The id of the chart. * @param callable The callable which is used to request the chart data. */ public SimplePie(String chartId, Callable callable) { @@ -603,7 +597,7 @@ public static class DrilldownPie extends CustomChart { /** * Class constructor. * - * @param chartId The id of the chart. + * @param chartId The id of the chart. * @param callable The callable which is used to request the chart data. */ public DrilldownPie(String chartId, Callable>> callable) { @@ -670,7 +664,7 @@ public JsonObjectBuilder appendNull(String key) { /** * Appends a string field to the JSON. * - * @param key The key of the field. + * @param key The key of the field. * @param value The value of the field. * @return A reference to this object. */ @@ -685,7 +679,7 @@ public JsonObjectBuilder appendField(String key, String value) { /** * Appends an integer field to the JSON. * - * @param key The key of the field. + * @param key The key of the field. * @param value The value of the field. * @return A reference to this object. */ @@ -697,7 +691,7 @@ public JsonObjectBuilder appendField(String key, int value) { /** * Appends an object to the JSON. * - * @param key The key of the field. + * @param key The key of the field. * @param object The object. * @return A reference to this object. */ @@ -712,7 +706,7 @@ public JsonObjectBuilder appendField(String key, JsonObject object) { /** * Appends a string array to the JSON. * - * @param key The key of the field. + * @param key The key of the field. * @param values The string array. * @return A reference to this object. */ @@ -731,7 +725,7 @@ public JsonObjectBuilder appendField(String key, String[] values) { /** * Appends an integer array to the JSON. * - * @param key The key of the field. + * @param key The key of the field. * @param values The integer array. * @return A reference to this object. */ @@ -748,7 +742,7 @@ public JsonObjectBuilder appendField(String key, int[] values) { /** * Appends an object array to the JSON. * - * @param key The key of the field. + * @param key The key of the field. * @param values The integer array. * @return A reference to this object. */ @@ -765,7 +759,7 @@ public JsonObjectBuilder appendField(String key, JsonObject[] values) { /** * Appends a field to the object. * - * @param key The key of the field. + * @param key The key of the field. * @param escapedValue The escaped value of the field. */ private void appendFieldUnescaped(String key, String escapedValue) { diff --git a/src/main/java/fr/zorg/bungeesk/bungee/BungeeSK.java b/src/main/java/fr/zorg/bungeesk/bungee/BungeeSK.java index 725021e..e7a5003 100644 --- a/src/main/java/fr/zorg/bungeesk/bungee/BungeeSK.java +++ b/src/main/java/fr/zorg/bungeesk/bungee/BungeeSK.java @@ -1,34 +1,41 @@ package fr.zorg.bungeesk.bungee; +import com.rockaport.alice.AliceContext; import fr.zorg.bungeesk.bungee.listeners.LeaveEvent; import fr.zorg.bungeesk.bungee.listeners.LoginEvent; import fr.zorg.bungeesk.bungee.listeners.ServSwitchEvent; import fr.zorg.bungeesk.bungee.sockets.Server; import fr.zorg.bungeesk.bungee.storage.BungeeConfig; -import fr.zorg.bungeesk.common.utils.Utils; +import fr.zorg.bungeesk.bungee.storage.GlobalVariables; +import fr.zorg.bungeesk.bungee.utils.Metrics; +import fr.zorg.bungeesk.common.encryption.GlobalEncryption; import net.md_5.bungee.api.ChatColor; import net.md_5.bungee.api.plugin.Plugin; import net.md_5.bungee.api.plugin.PluginManager; -import org.apache.commons.io.FileUtils; import java.io.*; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.nio.file.Paths; import java.util.ArrayList; -import java.util.Arrays; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.logging.Level; public class BungeeSK extends Plugin { public static BungeeSK instance; + private static GlobalEncryption encryption; private Server server; private PluginManager pm; + private Metrics metrics; + private GlobalVariables globalVariables; @Override public void onEnable() { instance = this; + + this.metrics = new Metrics(this, 11146); + + encryption = new GlobalEncryption(AliceContext.Algorithm.AES, 10); pm = getProxy().getPluginManager(); this.getLogger().log(Level.INFO, ChatColor.GOLD + "BungeeSK has been successfully started !"); @@ -46,6 +53,7 @@ public void onEnable() { } catch (IOException e) { e.printStackTrace(); } + this.globalVariables = new GlobalVariables(); } @Override @@ -53,22 +61,30 @@ public void onDisable() { this.server.disconnect(); } - public List filesToString() { + public Map filesToString() { final File folder = new File(this.getDataFolder().getAbsolutePath(), "common-skript"); if (!folder.exists()) - return new ArrayList<>(); + return new HashMap<>(); final FilenameFilter filter = (dir, name) -> !name.replaceAll("--", "").startsWith("-") && name.endsWith(".sk"); - final ArrayList list = new ArrayList<>(); + final Map map = new HashMap<>(); for (final File file : folder.listFiles(filter)) { - list.add("newFile:" + file.getName()); try { - list.add(Utils.toBase64(FileUtils.readFileToByteArray(file))); - } catch (IOException ignored) { - + FileReader fr = new FileReader(file); + BufferedReader br = new BufferedReader(fr); + List lines = new ArrayList<>(); + int i = 0; + String line; + while ((line = br.readLine()) != null) { + lines.add(line); + i++; + } + fr.close(); + map.put(file.getName(), lines.toArray(new String[0])); + } catch (IOException e) { + e.printStackTrace(); } - list.add("endFile"); } - return list; + return map; } public static BungeeSK getInstance() { @@ -79,4 +95,8 @@ public Server getServer() { return this.server; } + public static GlobalEncryption getEncryption() { + return encryption; + } + } diff --git a/src/main/java/fr/zorg/bungeesk/bungee/listeners/LeaveEvent.java b/src/main/java/fr/zorg/bungeesk/bungee/listeners/LeaveEvent.java index ed826c1..e1eb509 100644 --- a/src/main/java/fr/zorg/bungeesk/bungee/listeners/LeaveEvent.java +++ b/src/main/java/fr/zorg/bungeesk/bungee/listeners/LeaveEvent.java @@ -9,9 +9,9 @@ public class LeaveEvent implements Listener { @EventHandler public void onLeave(PlayerDisconnectEvent e) { - String[] data = {e.getPlayer().getName(), - e.getPlayer().getUniqueId().toString()}; - BungeeSK.getInstance().getServer().writeAll("LeaveEventµ" + String.join("µ", data)); + BungeeSK.getInstance().getServer().writeAll(true, "eventBungeePlayerDisconnect", + "name", e.getPlayer().getName(), + "uniqueId", e.getPlayer().getUniqueId().toString()); } } diff --git a/src/main/java/fr/zorg/bungeesk/bungee/listeners/LoginEvent.java b/src/main/java/fr/zorg/bungeesk/bungee/listeners/LoginEvent.java index b8e2ff9..b33a64d 100644 --- a/src/main/java/fr/zorg/bungeesk/bungee/listeners/LoginEvent.java +++ b/src/main/java/fr/zorg/bungeesk/bungee/listeners/LoginEvent.java @@ -9,9 +9,9 @@ public class LoginEvent implements Listener { @EventHandler public void onLogin(PostLoginEvent e) { - String[] data = {e.getPlayer().getName(), - e.getPlayer().getUniqueId().toString()}; - BungeeSK.getInstance().getServer().writeAll("LoginEventµ" + String.join("µ", data)); + BungeeSK.getInstance().getServer().writeAll(true, "eventBungeePlayerConnect", + "name", e.getPlayer().getName(), + "uniqueId", e.getPlayer().getUniqueId().toString()); } } diff --git a/src/main/java/fr/zorg/bungeesk/bungee/listeners/ServSwitchEvent.java b/src/main/java/fr/zorg/bungeesk/bungee/listeners/ServSwitchEvent.java index 6be8137..e6f572a 100644 --- a/src/main/java/fr/zorg/bungeesk/bungee/listeners/ServSwitchEvent.java +++ b/src/main/java/fr/zorg/bungeesk/bungee/listeners/ServSwitchEvent.java @@ -1,20 +1,37 @@ package fr.zorg.bungeesk.bungee.listeners; import fr.zorg.bungeesk.bungee.BungeeSK; +import net.md_5.bungee.api.config.ServerInfo; import net.md_5.bungee.api.event.ServerSwitchEvent; import net.md_5.bungee.api.plugin.Listener; import net.md_5.bungee.event.EventHandler; +import java.util.HashMap; +import java.util.Map; + public class ServSwitchEvent implements Listener { @EventHandler public void onSwitch(ServerSwitchEvent e) { - final StringBuilder builder = new StringBuilder().append("SERVERSWITCHEVENTµ"); if (e.getFrom() == null) return; - builder.append(e.getPlayer().toString()).append("$"); - builder.append(e.getPlayer().getUniqueId().toString()).append("^"); - builder.append(e.getFrom().getName()); - BungeeSK.getInstance().getServer().writeAll(builder.toString()); + + + final ServerInfo server = e.getFrom(); + Map serverMap = new HashMap<>(); + serverMap.put("name", server.getName()); + serverMap.put("address", server.getAddress().getAddress().getHostAddress()); + serverMap.put("port", String.valueOf(server.getAddress().getPort())); + serverMap.put("motd", server.getMotd()); + + Map playerMap = new HashMap<>(); + playerMap.put("name", e.getPlayer().getName()); + playerMap.put("uniqueId", e.getPlayer().getUniqueId().toString()); + + Map> map = new HashMap<>(); + map.put("server", serverMap); + map.put("player", playerMap); + + BungeeSK.getInstance().getServer().writeRawAll(true, "eventBungeePlayerServerSwitch", map); } } diff --git a/src/main/java/fr/zorg/bungeesk/bungee/sockets/ClientServer.java b/src/main/java/fr/zorg/bungeesk/bungee/sockets/ClientServer.java index 5d6414f..2b227af 100644 --- a/src/main/java/fr/zorg/bungeesk/bungee/sockets/ClientServer.java +++ b/src/main/java/fr/zorg/bungeesk/bungee/sockets/ClientServer.java @@ -1,37 +1,40 @@ package fr.zorg.bungeesk.bungee.sockets; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; import fr.zorg.bungeesk.bungee.BungeeSK; import fr.zorg.bungeesk.bungee.storage.BungeeConfig; -import fr.zorg.bungeesk.common.utils.Utils; +import fr.zorg.bungeesk.bungee.storage.GlobalVariables; +import fr.zorg.bungeesk.bungee.utils.BungeeUtils; +import fr.zorg.bungeesk.common.encryption.GlobalEncryption; +import net.md_5.bungee.api.ChatColor; +import net.md_5.bungee.api.ChatMessageType; +import net.md_5.bungee.api.Title; import net.md_5.bungee.api.chat.TextComponent; import net.md_5.bungee.api.config.ServerInfo; import net.md_5.bungee.api.connection.ProxiedPlayer; -import org.jetbrains.annotations.Nullable; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; -import java.net.InetSocketAddress; import java.net.Socket; -import java.net.SocketAddress; import java.nio.charset.StandardCharsets; import java.util.*; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; import java.util.logging.Level; public final class ClientServer { private final Socket socket; - private String name; + private String address; private final Thread readThread; private final BufferedReader reader; private final PrintWriter writer; - private final Map>> toComplete; - + private final GlobalEncryption encryption; + private final static Gson gson = new GsonBuilder().create(); + private final String password; private boolean identified; @@ -40,7 +43,8 @@ public ClientServer(final Socket socket) throws IOException { this.identified = false; this.reader = new BufferedReader(new InputStreamReader(this.socket.getInputStream(), StandardCharsets.UTF_8)); this.writer = new PrintWriter(this.socket.getOutputStream(), true); - this.toComplete = new HashMap<>(); + this.encryption = BungeeSK.getEncryption(); + this.password = BungeeConfig.get().getPassword(); this.readThread = new Thread(this::read); this.readThread.setDaemon(true); @@ -52,49 +56,45 @@ public void read() { reader: while (this.isConnected()) { String rawData = reader.readLine(); - if (rawData == null) continue; - final Server server = BungeeSK.getInstance().getServer(); - if (this.name == null) { - final String data = BungeeSK.getInstance().getServer().encryption.decrypt(Utils.getMessage(rawData), false); - if (!server.isClient(socket)) { - if (!data.contains("µ")) { - this.disconnect(); - break; - } - String[] datas = data.split("µ"); - if (datas.length != 2) { - this.disconnect(); - break; - } - if (datas[0].startsWith("name=")) - this.name = datas[0].substring(5); - else { - this.disconnect(); - break; - } - if (server.getClient(this.name).isPresent()) { - this.disconnect(); - break; - } - String password; - if (datas[1].startsWith("password=")) - password = datas[1].substring(9); - else { + if (rawData == null) + continue; + + + final String data = this.encryption.decrypt(rawData, this.password); + + if (data.equals("wrongPassword")) { + this.disconnect(); + break reader; + } + + final JsonParser jsonParser = new JsonParser(); + final JsonObject jsonObject = jsonParser.parse(data).getAsJsonObject(); + + final String action = jsonObject.get("action").getAsString(); + final Server serv = BungeeSK.getInstance().getServer(); + final JsonObject args = jsonObject.get("args").getAsJsonObject(); + + if (this.address == null) { + if (!serv.isClient(socket)) { + this.address = args.get("address").getAsString(); + + if (serv.isClient(this.address)) { this.disconnect(); break; } - if (!server.isPassword(password)) { + + if (!serv.isPassword(args.get("password").getAsString())) { this.disconnect(); break; } this.identified = true; - server.addClient(this); - BungeeSK.getInstance().getLogger().log(Level.INFO, "§6New server connected under name §a" - + this.name - + " §6with adress §a" - + this.socket.getInetAddress().getHostAddress()); - this.write("CONNECTED_SUCCESSFULLYµ"); + serv.addClient(this); + + BungeeSK.getInstance().getLogger().log(Level.INFO, "§6New server connected under address §a" + + this.address); + + this.write(true, "connectionInformation", "status", "connected"); if (BungeeConfig.get().isSendFilesAutoEnabled()) this.sendFiles(); @@ -106,162 +106,373 @@ public void read() { continue; } - final String data = BungeeSK.getInstance().getServer().encryption.decrypt(Utils.getMessage(rawData)); - final String[] separateDatas = data.split("µ"); - - final String header = separateDatas[0]; - String args = null; - if (separateDatas.length > 1) - args = separateDatas[1]; - - switch (header.toUpperCase()) { - case "DISCONNECT": { - BungeeSK.getInstance().getLogger().info("§6A server has been disconnected: §a" + - this.getName() + - " §6(§a" + - this.getSocket().getInetAddress().getHostAddress() + - "§6)" - ); - this.forceDisconnect(); + + switch (action) { + + // Connection management + + case "connectionInformation": { + if (args.get("status").getAsString().equals("disconnect")) { + BungeeSK.getInstance().getLogger().log(Level.INFO, "§6Server disconnected under address §c" + this.address); + this.forceDisconnect(); + } break reader; } - case "RETRIEVE_SKRIPTS": { + //Global scripts + + case "sendFilesRequest": { this.sendFiles(); break; } - case "EFFEXECUTECOMMAND": { - if (args.equalsIgnoreCase("bungee")) - BungeeSK.getInstance().getProxy().getPluginManager().dispatchCommand(BungeeSK.getInstance().getProxy().getConsole(), separateDatas[2]); - else if (args.equalsIgnoreCase("all")) - server.writeAll("CONSOLECOMMANDµ" + separateDatas[2]); - else - server.getClient(args).get().write("CONSOLECOMMANDµ" + separateDatas[2]); + // Global variables + + case "setGlobalVariable": { + GlobalVariables.get().setVar(args.get("varName").getAsString(), args.get("value").getAsString()); break; } - case "ALLBUNGEEPLAYERS": { - if (BungeeSK.getInstance().getProxy().getPlayers().size() < 1) { - this.write("ALLBUNGEEPLAYERSµNONE"); - break; - } - final StringBuilder builder = new StringBuilder("ALLBUNGEEPLAYERSµ"); - final Object lastPlayer = BungeeSK.getInstance().getProxy().getPlayers().toArray()[BungeeSK.getInstance().getProxy().getPlayers().size() - 1]; - for (final ProxiedPlayer player : BungeeSK.getInstance().getProxy().getPlayers()) { - builder.append(player.getName()).append("$").append(player.getUniqueId().toString()); - if (!player.equals(lastPlayer)) builder.append("^"); + case "deleteGlobalVariable": { + System.out.println("aabbccdd"); + System.out.println("args.get(\"varName\").getAsString() = " + args.get("varName").getAsString()); + GlobalVariables.get().deleteVar(args.get("varName").getAsString()); + break; + } + + // Effects + + case "effectExecuteCommand": { + final String server = args.get("server").getAsString(); + final String command = args.get("command").getAsString(); + if (server.equals("bungeecord")) + BungeeSK.getInstance().getProxy().getPluginManager().dispatchCommand(BungeeSK.getInstance().getProxy().getConsole(), command); + + else if (server.equals("all")) + serv.writeAll(true, "executeConsoleCommand", "command", command); + + else if (serv.getClient(args.get("server").getAsString()).isPresent()) + serv.getClient(args.get("server").getAsString()).get().write(true, "executeConsoleCommand", "command", command); + + break; + } + + case "effectBroadcastMessageToServer": { + final String server = args.get("server").getAsString(); + final String message = args.get("message").getAsString(); + if (serv.getClient(server).isPresent()) { + serv.getClient(server).get().write(true, "broadcastMessage", + "message", message); } - this.write(builder.toString()); break; } - case "PLAYERSERVER": { - final net.md_5.bungee.api.connection.Server playerServer = BungeeSK.getInstance().getProxy().getPlayer(UUID.fromString(args.split("\\$")[1])).getServer(); - if (playerServer == null) { - this.write("PLAYERSERVERµ" + args + "^NONE"); + case "effectSendBungeePlayerToServer": { + final ProxiedPlayer player = BungeeSK.getInstance().getProxy().getPlayer(UUID.fromString(args.get("playerUniqueId").getAsString())); + final Optional optionalServer = BungeeUtils.findServer(args.get("serverAddress").getAsString(), args.get("serverPort").getAsInt()); + + if (player == null || !(player.isConnected()) || !(optionalServer.isPresent())) break; - } - this.write("PLAYERSERVERµ" + args + "^" + playerServer.getInfo().getName()); + + player.connect(optionalServer.get()); break; } - case "ISCONNECTED": { - final ProxiedPlayer player = BungeeSK.getInstance().getProxy().getPlayer(UUID.fromString(args.split("\\$")[1])); - if (player != null && player.isConnected()) { - this.write("ISCONNECTEDµ" + args + "^TRUE"); + case "effectSendMessageToBungeePlayer": { + final ProxiedPlayer player = BungeeSK.getInstance().getProxy().getPlayer(UUID.fromString(args.get("playerUniqueId").getAsString())); + + if (player == null || !(player.isConnected())) break; - } - this.write("ISCONNECTEDµ" + args + "^FALSE"); + + player.sendMessage(TextComponent.fromLegacyText(args.get("message").getAsString())); break; } - case "GETPLAYER": { - final ProxiedPlayer player = BungeeSK.getInstance().getProxy().getPlayer(args); - if (player != null && player.getUniqueId() != null) { - this.write("GETPLAYERµ" + args + "$" + player.getUniqueId().toString()); + + case "effectMakeBungeePlayerExecuteCommand": { + final ProxiedPlayer player = BungeeSK.getInstance().getProxy().getPlayer(UUID.fromString(args.get("playerUniqueId").getAsString())); + + if (player == null || !(player.isConnected())) break; - } - this.write("GETPLAYERµ" + args + "$NONE"); + + String command = args.get("command").getAsString(); + + if (!command.startsWith("/")) + command = "/" + command; + player.chat(command); break; } - case "SENDPLAYERMESSAGE": { - final String message = args.split("\\^")[1]; - final ProxiedPlayer player = BungeeSK.getInstance().getProxy().getPlayer(UUID.fromString(args.split("\\^")[0].split("\\$")[1])); - if (player != null && player.isConnected()) - player.sendMessage(TextComponent.fromLegacyText(message)); + + case "effectKickBungeePlayer": { + final ProxiedPlayer player = BungeeSK.getInstance().getProxy().getPlayer(UUID.fromString(args.get("playerUniqueId").getAsString())); + + if (player == null || !(player.isConnected())) + break; + + final String reason = args.get("reason").getAsString(); + if (reason.equalsIgnoreCase("NONE")) { + player.disconnect(); + break; + } + player.disconnect(TextComponent.fromLegacyText(ChatColor.translateAlternateColorCodes('&', reason))); break; } - case "SENDTOSERV": { - final String[] dataArray = args.split("\\^"); - final ProxiedPlayer player = BungeeSK.getInstance().getProxy().getPlayer(UUID.fromString(dataArray[0].split("\\$")[1])); - if (player != null && player.isConnected()) { - final ServerInfo toSend = BungeeSK.getInstance().getProxy().getServerInfo(dataArray[1]); - if (toSend != null) - player.connect(toSend); + + case "effectSendBungeeCustomMessage": { + final String server = args.get("serverAddress").getAsString() + ":" + args.get("serverPort").getAsInt(); + + final Optional optionnalServer = BungeeUtils.findServer(this.address.split(":")[0], Integer.parseInt(this.address.split(":")[1])); + + if (serv.getClient(server).isPresent() && optionnalServer.isPresent()) { + Map map = new HashMap<>(); + map.put("message", args.get("message").getAsString()); + map.put("fromServer", BungeeUtils.getBungeeServer(optionnalServer.get())); + + serv.getClient(server).get().writeRaw(true, "customBungeeMessage", map); } break; } - case "ALLBUNGEESERVERS": { - final Map servers = BungeeSK.getInstance().getProxy().getServers(); - final StringBuilder builder = new StringBuilder("ALLBUNGEESERVERSµ"); - servers.forEach((s, serverInfo) -> builder.append(s).append("^")); - this.write(builder.toString()); + + case "effectBroadcastMessageToNetwork": { + final String message = args.get("message").getAsString(); + + BungeeSK.getInstance().getProxy().broadcast(TextComponent.fromLegacyText(ChatColor.translateAlternateColorCodes('&', message))); break; } - case "CLIENTREALNAME": { - final SocketAddress address = new InetSocketAddress(args.split(":")[0], Integer.parseInt(args.split(":")[1])); - final String finalArgs = args; - BungeeSK.getInstance().getProxy().getServers().forEach((s, serverInfo) -> { - if (serverInfo.getSocketAddress().equals(address)) - this.write("CLIENTREALNAMEµ" + finalArgs + "^" + s); - }); + + case "effectSendActionBar": { + final ProxiedPlayer player = BungeeSK.getInstance().getProxy().getPlayer(UUID.fromString(args.get("playerUuid").getAsString())); + + if (player == null || !(player.isConnected())) { + break; + } + + player.sendMessage(ChatMessageType.ACTION_BAR, TextComponent.fromLegacyText(ChatColor.translateAlternateColorCodes('&', args.get("message").getAsString()))); break; } - case "ALLBUNGEEPLAYERSONSERVER": { - final ServerInfo bungeeServ = BungeeSK.getInstance().getProxy().getServerInfo(args); - if (bungeeServ == null || bungeeServ.getPlayers().toArray().length == 0) { - this.write("ALLBUNGEEPLAYERSONSERVERµ" + args + "^NONE"); + + case "effectSendBungeePlayerTitle": { + final ProxiedPlayer player = BungeeSK.getInstance().getProxy().getPlayer(UUID.fromString(args.get("playerUuid").getAsString())); + + if (player == null || !(player.isConnected())) { break; } - final StringBuilder builder = new StringBuilder("ALLBUNGEEPLAYERSONSERVERµ" + args + "^"); - final Object lastPlayer = bungeeServ.getPlayers().toArray()[bungeeServ.getPlayers().size() - 1]; - for (final ProxiedPlayer player : bungeeServ.getPlayers()) { - builder.append(player.getName()).append("$").append(player.getUniqueId().toString()); - if (!player.equals(lastPlayer)) builder.append("^"); + + final Title title = BungeeSK.getInstance().getProxy().createTitle(); + if (!args.get("title").getAsString().equalsIgnoreCase("NONE")) { + title.title(TextComponent.fromLegacyText(args.get("title").getAsString())); + } + if (!args.get("subTitle").getAsString().equalsIgnoreCase("NONE")) { + title.subTitle(TextComponent.fromLegacyText(args.get("subTitle").getAsString())); } - this.write(builder.toString()); + if (!args.get("time").getAsString().equalsIgnoreCase("NONE")) { + title.stay(args.get("time").getAsInt()); + } + if (!args.get("fadeIn").getAsString().equalsIgnoreCase("NONE")) { + title.fadeIn(args.get("fadeIn").getAsInt()); + } + if (!args.get("fadeOut").getAsString().equalsIgnoreCase("NONE")) { + title.fadeOut(args.get("fadeOut").getAsInt()); + } + + + title.send(player); break; } - case "BROADCASTTOSERV": { - if (!server.getClient(separateDatas[1]).isPresent()) break; - server.getClient(separateDatas[1]).get().write("BROADCASTµ" + separateDatas[2]); + + // Futures + + case "futureGet": { + final String uuid = args.get("uuid").getAsString(); + final String localAction = args.get("action").getAsString(); + Map toSend = new HashMap<>(); + toSend.put("uuid", uuid); + Map argsMap = new HashMap<>(); + boolean error = false; + switch (localAction) { + case "expressionGetBungeeServerFromName": { + ServerInfo server = BungeeSK.getInstance().getProxy().getServerInfo(args.get("name").getAsString()); + + if (server == null) { + error = true; + break; + } + + argsMap.put("name", server.getName()); + argsMap.put("address", server.getAddress().getAddress().getHostAddress()); + argsMap.put("port", String.valueOf(server.getAddress().getPort())); + argsMap.put("motd", server.getMotd()); + + break; + } + + case "expressionGetBungeeServerFromAddress": { + final Optional optionalServer = BungeeUtils.findServer(args.get("address").getAsString(), args.get("port").getAsInt()); + + if (!(optionalServer.isPresent())) { + error = true; + break; + } + + final ServerInfo server = optionalServer.get(); + + argsMap.put("name", server.getName()); + argsMap.put("address", server.getAddress().getAddress().getHostAddress()); + argsMap.put("port", String.valueOf(server.getAddress().getPort())); + argsMap.put("motd", server.getMotd()); + + break; + } + + case "expressionGetAllBungeeServers": { + if (BungeeSK.getInstance().getProxy().getServers().values().size() == 0) { + error = true; + break; + } + + List> serverInfos = new ArrayList<>(); + for (ServerInfo server : BungeeSK.getInstance().getProxy().getServers().values()) { + Map serverInfo = new HashMap<>(); + serverInfo.put("name", server.getName()); + serverInfo.put("address", server.getAddress().getAddress().getHostAddress()); + serverInfo.put("port", String.valueOf(server.getAddress().getPort())); + serverInfo.put("motd", server.getMotd()); + serverInfos.add(serverInfo); + } + argsMap.put("servers", serverInfos); + break; + } + + case "expressionGetBungeePlayerFromName": { + final ProxiedPlayer player = BungeeSK.getInstance().getProxy().getPlayer(args.get("name").getAsString()); + + if (player == null) { + error = true; + break; + } + + argsMap.put("name", player.getName()); + argsMap.put("uniqueId", player.getUniqueId().toString()); + + break; + } + + case "expressionGetBungeePlayerFromUUID": { + final ProxiedPlayer player = BungeeSK.getInstance().getProxy().getPlayer(UUID.fromString(args.get("uniqueId").getAsString())); + + if (player == null) { + error = true; + break; + } + + argsMap.put("name", player.getName()); + argsMap.put("uniqueId", player.getUniqueId().toString()); + + break; + } + + case "expressionGetAllBungeePlayers": { + if (BungeeSK.getInstance().getProxy().getPlayers().size() == 0) { + error = true; + break; + } + + List> players = new ArrayList<>(); + BungeeSK.getInstance().getProxy().getPlayers().forEach(player -> { + Map playerData = new HashMap<>(); + playerData.put("name", player.getName()); + playerData.put("uniqueId", player.getUniqueId().toString()); + players.add(playerData); + }); + argsMap.put("players", players); + break; + } + case "expressionGetServerOfBungeePlayer": { + final ProxiedPlayer player = BungeeSK.getInstance().getProxy().getPlayer(UUID.fromString(args.get("uniqueId").getAsString())); + + if (player == null) { + error = true; + break; + } + + final Map bungeeServ = BungeeUtils.getBungeeServer(player.getServer().getInfo()); + + argsMap.put("server", bungeeServ); + break; + } + case "expressionGetAllPlayersOnServer": { + final Optional optionalServer = BungeeUtils.findServer(args.get("address").getAsString(), args.get("port").getAsInt()); + + if (!(optionalServer.isPresent())) { + error = true; + break; + } + + final ServerInfo server = optionalServer.get(); + + List> players = new ArrayList<>(); + server.getPlayers().forEach(player -> { + Map playerData = new HashMap<>(); + playerData.put("name", player.getName()); + playerData.put("uniqueId", player.getUniqueId().toString()); + players.add(playerData); + }); + + argsMap.put("players", players); + break; + } + case "expressionGetPlayerConnectionState": { + final ProxiedPlayer player = BungeeSK.getInstance().getProxy().getPlayer(UUID.fromString(args.get("playerUniqueId").getAsString())); + + if (player == null || !(player.isConnected())) { + error = true; + break; + } + } + case "expressionGetBungeePlayerIP": { + final ProxiedPlayer player = BungeeSK.getInstance().getProxy().getPlayer(UUID.fromString(args.get("playerUniqueId").getAsString())); + + if (player == null || !(player.isConnected())) { + error = true; + break; + } + + argsMap.put("address", player.getAddress().getAddress().getHostAddress()); + break; + } + case "getGlobalVariable": { + argsMap.put("varName", args.get("varName").getAsString()); + argsMap.put("value", GlobalVariables.get().getVar(args.get("varName").getAsString())); + break; + } + } + argsMap.put("error", error); + toSend.put("response", argsMap); + this.writeRaw(true, "futureResponse", toSend); break; } } } } catch (IOException e) { + e.printStackTrace(); this.forceDisconnect(); } } private void sendFiles() { - final List result = BungeeSK.getInstance().filesToString(); - result.add("END_SKRIPTS"); - final String toString = String.join("™", result.toArray(new String[0])); - this.write("SEND_SKRIPTSµ" + toString); + final Map files = BungeeSK.getInstance().filesToString(); + this.writeRaw(true, "sendFiles", files); } public void disconnect() { - try { - if (!this.identified) { - if (this.name != null) { - this.writer.println(Arrays.toString("ALREADY_CONNECTED".getBytes(StandardCharsets.UTF_8))); - } else - this.writer.println(Arrays.toString("WRONG_PASSWORD".getBytes(StandardCharsets.UTF_8))); - } else - this.write("DISCONNECT"); - } catch (final Exception ignored) { + if (!this.identified) { + if (this.address != null) { + this.write(false, "connectionInformation", "status", "alreadyConnected"); + } else { + this.write(false, "connectionInformation", "status", "wrongPassword"); + } + } else { + this.write(false, "connectionInformation", "status", "disconnect"); } this.forceDisconnect(); } @@ -269,10 +480,10 @@ public void disconnect() { public void forceDisconnect() { if (!this.socket.isClosed()) { try { - this.socket.close(); this.reader.close(); this.writer.close(); this.readThread.interrupt(); + this.socket.close(); BungeeSK.getInstance().getServer().removeClient(this); } catch (IOException e) { e.printStackTrace(); @@ -284,48 +495,44 @@ public Socket getSocket() { return this.socket; } - public void write(final String message) { - this.writer.println(Arrays.toString(BungeeSK.getInstance().getServer().encryption.encrypt(message).getBytes(StandardCharsets.UTF_8))); - } - @Nullable - public String getName() { - return this.name; + public void write(final boolean encryption, final String action, final String... args) { + final Map map = new HashMap<>(); + map.put("action", action); + final Map argsMap = new HashMap<>(); + for (int i = 0; i < args.length; i = i + 2) { + argsMap.put(args[i], args[i + 1]); + } + map.put("args", argsMap); + if (encryption) { + this.writer.println(this.encryption.encrypt(gson.toJson(map), this.password)); + return; + } + this.writer.println(gson.toJson(map)); } - public boolean isConnected() { - return this.socket != null && this.socket.isConnected() && !this.socket.isClosed(); + public void writeRaw(final boolean encryption, final String action, final Map argsMap) { + final Map map = new HashMap<>(); + map.put("action", action); + map.put("args", argsMap); + if (encryption) { + this.writer.println(this.encryption.encrypt(gson.toJson(map), this.password)); + return; + } + this.writer.println(gson.toJson(map)); } - public Map>> getToComplete() { - return this.toComplete; + public String getAddress() { + return this.address; } - public void putFuture(final String key, final String value) { - LinkedList> future = this.toComplete.get(key); - if (future != null && future.size() > 0) { - future.poll().complete(value); - if (future.size() == 0) this.toComplete.remove(key, future); - } + public boolean isConnected() { + return this.socket != null && this.socket.isConnected() && !this.socket.isClosed(); } - public String future(final String value) { - LinkedList> futureList = new LinkedList<>(); - if (this.toComplete.containsKey(value)) futureList = this.toComplete.get(value); - final CompletableFuture future = new CompletableFuture<>(); - futureList.add(future); - this.toComplete.put(value, futureList); - this.write(value); - String result; - try { - result = future.get(1, TimeUnit.SECONDS); - } catch (InterruptedException | ExecutionException | TimeoutException e) { - return null; - } - return result; + public static Gson getGson() { + return gson; } - - } diff --git a/src/main/java/fr/zorg/bungeesk/bungee/sockets/Server.java b/src/main/java/fr/zorg/bungeesk/bungee/sockets/Server.java index e0dd6be..795b7a7 100644 --- a/src/main/java/fr/zorg/bungeesk/bungee/sockets/Server.java +++ b/src/main/java/fr/zorg/bungeesk/bungee/sockets/Server.java @@ -1,14 +1,15 @@ package fr.zorg.bungeesk.bungee.sockets; -import fr.zorg.bungeesk.bungee.BungeeSK; import fr.zorg.bungeesk.bungee.storage.BungeeConfig; -import fr.zorg.bungeesk.common.encryption.AESEncryption; import fr.zorg.bungeesk.common.utils.Utils; import java.io.IOException; import java.net.ServerSocket; import java.net.Socket; -import java.util.*; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Optional; public final class Server { @@ -17,13 +18,11 @@ public final class Server { private final ServerSocket servSocket; private final Thread waitingConnection; - final AESEncryption encryption; public Server(final int port, final String passwd) throws IOException { this.password = passwd; this.clients = new ArrayList<>(); this.servSocket = new ServerSocket(port); - this.encryption = new AESEncryption(passwd, BungeeSK.getInstance().getLogger()); this.waitingConnection = new Thread(this::waitForConn); this.waitingConnection.setDaemon(true); @@ -61,6 +60,10 @@ public boolean isClient(final Socket socket) { return this.clients.stream().anyMatch(client -> client.getSocket().equals(socket)); } + public boolean isClient(final String address) { + return this.clients.stream().anyMatch(client -> client.getAddress().equals(address)); + } + public void removeClient(final ClientServer client) { this.clients.remove(client); } @@ -75,20 +78,24 @@ public void addClient(final ClientServer client) { this.clients.add(client); } - public Optional getClient(final String name) { - return this.clients.stream().filter(client -> name.equalsIgnoreCase(client.getName())).findFirst(); + public Optional getClient(final String address) { + return this.clients.stream().filter(client -> client.getAddress().equalsIgnoreCase(address)).findFirst(); } public void write(final String message, ClientServer... clients) { if (clients == null || clients.length == 0) clients = this.clients.toArray(new ClientServer[0]); for (final ClientServer client : clients) { - client.write(message); + client.write(true, message); } } - public void writeAll(final String message) { - this.clients.forEach(((ClientServer client) -> client.write(message))); + public void writeAll(final boolean encryption, final String action, final String... args) { + this.clients.forEach(client -> client.write(encryption, action, args)); + } + + public void writeRawAll(final boolean encryption, final String action, final Map argsMap) { + this.clients.forEach(client -> client.writeRaw(encryption, action, argsMap)); } public List getClients() { diff --git a/src/main/java/fr/zorg/bungeesk/bungee/storage/BungeeConfig.java b/src/main/java/fr/zorg/bungeesk/bungee/storage/BungeeConfig.java index f928688..9f23062 100644 --- a/src/main/java/fr/zorg/bungeesk/bungee/storage/BungeeConfig.java +++ b/src/main/java/fr/zorg/bungeesk/bungee/storage/BungeeConfig.java @@ -7,15 +7,14 @@ import net.md_5.bungee.config.ConfigurationProvider; import net.md_5.bungee.config.YamlConfiguration; -import java.io.*; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.nio.file.Files; -import java.util.ArrayList; -import java.util.Arrays; import java.util.Collections; import java.util.List; -import java.util.logging.Level; public class BungeeConfig { @@ -28,7 +27,7 @@ public static BungeeConfig get() { } private int port = 20000; - private String password = Utils.randomString(10); + private String password = Utils.randomString(16); private boolean sendFilesAuto = false; private boolean whitelistIp = true; private List authorizedIp = Collections.singletonList("127.0.0.1"); @@ -42,7 +41,8 @@ private BungeeConfig() { public void load() { this.file = new File(BungeeSK.getInstance().getDataFolder(), "config.yml"); - if (!BungeeSK.getInstance().getDataFolder().exists()) BungeeSK.getInstance().getDataFolder().mkdir(); + if (!BungeeSK.getInstance().getDataFolder().exists()) + BungeeSK.getInstance().getDataFolder().mkdir(); if (!this.file.exists()) { try (final InputStream in = BungeeSK.getInstance().getResourceAsStream("config.yml")) { Files.copy(in, this.file.toPath()); diff --git a/src/main/java/fr/zorg/bungeesk/bungee/storage/GlobalVariables.java b/src/main/java/fr/zorg/bungeesk/bungee/storage/GlobalVariables.java new file mode 100644 index 0000000..d0153cf --- /dev/null +++ b/src/main/java/fr/zorg/bungeesk/bungee/storage/GlobalVariables.java @@ -0,0 +1,62 @@ +package fr.zorg.bungeesk.bungee.storage; + +import com.google.gson.*; +import fr.zorg.bungeesk.bungee.BungeeSK; +import org.apache.commons.io.FileUtils; + +import java.io.*; + +public class GlobalVariables { + + private static GlobalVariables instance; + private File variablesFile = new File(BungeeSK.getInstance().getDataFolder().getAbsolutePath(), "variables.json"); + private JsonObject globalVariables; + private Gson gson = new GsonBuilder().setPrettyPrinting().create(); + + public GlobalVariables() { + instance = this; + + + try { + if (!this.variablesFile.exists()) + FileUtils.copyInputStreamToFile(BungeeSK.getInstance().getResourceAsStream("variables.json"), this.variablesFile); + this.globalVariables = new JsonParser().parse(new BufferedReader(new FileReader(this.variablesFile))).getAsJsonObject(); + } catch (IOException ex) { + ex.printStackTrace(); + } + } + + public static GlobalVariables get() { + return instance; + } + + public void setVar(final String name, final String value) { + if (this.globalVariables.has(name)) + this.globalVariables.remove("name"); + this.globalVariables.addProperty(name, value); + this.saveConfig(); + } + + public void deleteVar(final String name) { + this.globalVariables.remove(name); + this.saveConfig(); + } + + public String getVar(final String name) { + if (this.globalVariables.has(name)) { + return this.globalVariables.get(name).getAsString(); + } + return "NONE"; + } + + private void saveConfig() { + try { + BufferedWriter bw = new BufferedWriter(new FileWriter(this.variablesFile)); + this.gson.toJson(this.globalVariables, bw); + bw.close(); + } catch (IOException ex) { + ex.printStackTrace(); + } + } + +} diff --git a/src/main/java/fr/zorg/bungeesk/bungee/utils/BungeeUtils.java b/src/main/java/fr/zorg/bungeesk/bungee/utils/BungeeUtils.java index 43c347f..a5c69ec 100644 --- a/src/main/java/fr/zorg/bungeesk/bungee/utils/BungeeUtils.java +++ b/src/main/java/fr/zorg/bungeesk/bungee/utils/BungeeUtils.java @@ -1,7 +1,14 @@ package fr.zorg.bungeesk.bungee.utils; +import fr.zorg.bungeesk.bungee.BungeeSK; +import fr.zorg.bungeesk.bungee.sockets.Server; +import net.md_5.bungee.api.config.ServerInfo; import net.md_5.bungee.config.Configuration; +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; + public class BungeeUtils { public static boolean addDefault(final Configuration config, final String path, final Object o) { @@ -12,4 +19,21 @@ public static boolean addDefault(final Configuration config, final String path, return false; } + public static Optional findServer(final String address, final int port) { + return BungeeSK.getInstance().getProxy().getServers().values().stream().filter( + server -> (server.getAddress().getAddress().getHostAddress().equalsIgnoreCase(address) + && server.getAddress().getPort() == port)).findFirst(); + } + + public static Map getBungeeServer(final ServerInfo server) { + Map infos = new HashMap<>(); + + infos.put("name", server.getName()); + infos.put("address", server.getAddress().getAddress().getHostAddress()); + infos.put("port", String.valueOf(server.getAddress().getPort())); + infos.put("motd", server.getMotd()); + + return infos; + } + } diff --git a/src/main/java/fr/zorg/bungeesk/bungee/utils/Metrics.java b/src/main/java/fr/zorg/bungeesk/bungee/utils/Metrics.java new file mode 100644 index 0000000..606e4f7 --- /dev/null +++ b/src/main/java/fr/zorg/bungeesk/bungee/utils/Metrics.java @@ -0,0 +1,852 @@ +package fr.zorg.bungeesk.bungee.utils; + +import net.md_5.bungee.api.plugin.Plugin; +import net.md_5.bungee.config.Configuration; +import net.md_5.bungee.config.ConfigurationProvider; +import net.md_5.bungee.config.YamlConfiguration; + +import javax.net.ssl.HttpsURLConnection; +import java.io.*; +import java.net.URL; +import java.nio.charset.StandardCharsets; +import java.util.*; +import java.util.concurrent.Callable; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; +import java.util.function.BiConsumer; +import java.util.function.Consumer; +import java.util.function.Supplier; +import java.util.logging.Level; +import java.util.stream.Collectors; +import java.util.zip.GZIPOutputStream; + +public class Metrics { + + private final Plugin plugin; + + private final MetricsBase metricsBase; + + private boolean enabled; + + private String serverUUID; + + private boolean logErrors = false; + + private boolean logSentData; + + private boolean logResponseStatusText; + + /** + * Creates a new Metrics instance. + * + * @param plugin Your plugin instance. + * @param serviceId The id of the service. It can be found at What is my plugin id? + */ + public Metrics(Plugin plugin, int serviceId) { + this.plugin = plugin; + try { + loadConfig(); + } catch (IOException e) { + // Failed to load configuration + plugin.getLogger().log(Level.WARNING, "Failed to load bStats config!", e); + metricsBase = null; + return; + } + metricsBase = + new MetricsBase( + "bungeecord", + serverUUID, + serviceId, + enabled, + this::appendPlatformData, + this::appendServiceData, + null, + () -> true, + (message, error) -> this.plugin.getLogger().log(Level.WARNING, message, error), + (message) -> this.plugin.getLogger().log(Level.INFO, message), + logErrors, + logSentData, + logResponseStatusText); + } + + /** + * Loads the bStats configuration. + */ + private void loadConfig() throws IOException { + File bStatsFolder = new File(plugin.getDataFolder().getParentFile(), "bStats"); + bStatsFolder.mkdirs(); + File configFile = new File(bStatsFolder, "config.yml"); + if (!configFile.exists()) { + writeFile( + configFile, + "# bStats (https://bStats.org) collects some basic information for plugin authors, like how", + "# many people use their plugin and their total player count. It's recommended to keep bStats", + "# enabled, but if you're not comfortable with this, you can turn this setting off. There is no", + "# performance penalty associated with having metrics enabled, and data sent to bStats is fully", + "# anonymous.", + "enabled: true", + "serverUuid: \"" + UUID.randomUUID() + "\"", + "logFailedRequests: false", + "logSentData: false", + "logResponseStatusText: false"); + } + Configuration configuration = + ConfigurationProvider.getProvider(YamlConfiguration.class).load(configFile); + // Load configuration + enabled = configuration.getBoolean("enabled", true); + serverUUID = configuration.getString("serverUuid"); + logErrors = configuration.getBoolean("logFailedRequests", false); + logSentData = configuration.getBoolean("logSentData", false); + logResponseStatusText = configuration.getBoolean("logResponseStatusText", false); + } + + private void writeFile(File file, String... lines) throws IOException { + try (BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(file))) { + for (String line : lines) { + bufferedWriter.write(line); + bufferedWriter.newLine(); + } + } + } + + /** + * Adds a custom chart. + * + * @param chart The chart to add. + */ + public void addCustomChart(CustomChart chart) { + metricsBase.addCustomChart(chart); + } + + private void appendPlatformData(JsonObjectBuilder builder) { + builder.appendField("playerAmount", plugin.getProxy().getOnlineCount()); + builder.appendField("managedServers", plugin.getProxy().getServers().size()); + builder.appendField("onlineMode", plugin.getProxy().getConfig().isOnlineMode() ? 1 : 0); + builder.appendField("bungeecordVersion", plugin.getProxy().getVersion()); + builder.appendField("javaVersion", System.getProperty("java.version")); + builder.appendField("osName", System.getProperty("os.name")); + builder.appendField("osArch", System.getProperty("os.arch")); + builder.appendField("osVersion", System.getProperty("os.version")); + builder.appendField("coreCount", Runtime.getRuntime().availableProcessors()); + } + + private void appendServiceData(JsonObjectBuilder builder) { + builder.appendField("pluginVersion", plugin.getDescription().getVersion()); + } + + public static class MetricsBase { + + /** + * The version of the Metrics class. + */ + public static final String METRICS_VERSION = "2.2.1"; + + private static final ScheduledExecutorService scheduler = + Executors.newScheduledThreadPool(1, task -> new Thread(task, "bStats-Metrics")); + + private static final String REPORT_URL = "https://bStats.org/api/v2/data/%s"; + + private final String platform; + + private final String serverUuid; + + private final int serviceId; + + private final Consumer appendPlatformDataConsumer; + + private final Consumer appendServiceDataConsumer; + + private final Consumer submitTaskConsumer; + + private final Supplier checkServiceEnabledSupplier; + + private final BiConsumer errorLogger; + + private final Consumer infoLogger; + + private final boolean logErrors; + + private final boolean logSentData; + + private final boolean logResponseStatusText; + + private final Set customCharts = new HashSet<>(); + + private final boolean enabled; + + /** + * Creates a new MetricsBase class instance. + * + * @param platform The platform of the service. + * @param serviceId The id of the service. + * @param serverUuid The server uuid. + * @param enabled Whether or not data sending is enabled. + * @param appendPlatformDataConsumer A consumer that receives a {@code JsonObjectBuilder} and + * appends all platform-specific data. + * @param appendServiceDataConsumer A consumer that receives a {@code JsonObjectBuilder} and + * appends all service-specific data. + * @param submitTaskConsumer A consumer that takes a runnable with the submit task. This can be + * used to delegate the data collection to a another thread to prevent errors caused by + * concurrency. Can be {@code null}. + * @param checkServiceEnabledSupplier A supplier to check if the service is still enabled. + * @param errorLogger A consumer that accepts log message and an error. + * @param infoLogger A consumer that accepts info log messages. + * @param logErrors Whether or not errors should be logged. + * @param logSentData Whether or not the sent data should be logged. + * @param logResponseStatusText Whether or not the response status text should be logged. + */ + public MetricsBase( + String platform, + String serverUuid, + int serviceId, + boolean enabled, + Consumer appendPlatformDataConsumer, + Consumer appendServiceDataConsumer, + Consumer submitTaskConsumer, + Supplier checkServiceEnabledSupplier, + BiConsumer errorLogger, + Consumer infoLogger, + boolean logErrors, + boolean logSentData, + boolean logResponseStatusText) { + this.platform = platform; + this.serverUuid = serverUuid; + this.serviceId = serviceId; + this.enabled = enabled; + this.appendPlatformDataConsumer = appendPlatformDataConsumer; + this.appendServiceDataConsumer = appendServiceDataConsumer; + this.submitTaskConsumer = submitTaskConsumer; + this.checkServiceEnabledSupplier = checkServiceEnabledSupplier; + this.errorLogger = errorLogger; + this.infoLogger = infoLogger; + this.logErrors = logErrors; + this.logSentData = logSentData; + this.logResponseStatusText = logResponseStatusText; + checkRelocation(); + if (enabled) { + startSubmitting(); + } + } + + public void addCustomChart(CustomChart chart) { + this.customCharts.add(chart); + } + + private void startSubmitting() { + final Runnable submitTask = + () -> { + if (!enabled || !checkServiceEnabledSupplier.get()) { + // Submitting data or service is disabled + scheduler.shutdown(); + return; + } + if (submitTaskConsumer != null) { + submitTaskConsumer.accept(this::submitData); + } else { + this.submitData(); + } + }; + // Many servers tend to restart at a fixed time at xx:00 which causes an uneven distribution + // of requests on the + // bStats backend. To circumvent this problem, we introduce some randomness into the initial + // and second delay. + // WARNING: You must not modify and part of this Metrics class, including the submit delay or + // frequency! + // WARNING: Modifying this code will get your plugin banned on bStats. Just don't do it! + long initialDelay = (long) (1000 * 60 * (3 + Math.random() * 3)); + long secondDelay = (long) (1000 * 60 * (Math.random() * 30)); + scheduler.schedule(submitTask, initialDelay, TimeUnit.MILLISECONDS); + scheduler.scheduleAtFixedRate( + submitTask, initialDelay + secondDelay, 1000 * 60 * 30, TimeUnit.MILLISECONDS); + } + + private void submitData() { + final JsonObjectBuilder baseJsonBuilder = new JsonObjectBuilder(); + appendPlatformDataConsumer.accept(baseJsonBuilder); + final JsonObjectBuilder serviceJsonBuilder = new JsonObjectBuilder(); + appendServiceDataConsumer.accept(serviceJsonBuilder); + JsonObjectBuilder.JsonObject[] chartData = + customCharts.stream() + .map(customChart -> customChart.getRequestJsonObject(errorLogger, logErrors)) + .filter(Objects::nonNull) + .toArray(JsonObjectBuilder.JsonObject[]::new); + serviceJsonBuilder.appendField("id", serviceId); + serviceJsonBuilder.appendField("customCharts", chartData); + baseJsonBuilder.appendField("service", serviceJsonBuilder.build()); + baseJsonBuilder.appendField("serverUUID", serverUuid); + baseJsonBuilder.appendField("metricsVersion", METRICS_VERSION); + JsonObjectBuilder.JsonObject data = baseJsonBuilder.build(); + scheduler.execute( + () -> { + try { + // Send the data + sendData(data); + } catch (Exception e) { + // Something went wrong! :( + if (logErrors) { + errorLogger.accept("Could not submit bStats metrics data", e); + } + } + }); + } + + private void sendData(JsonObjectBuilder.JsonObject data) throws Exception { + if (logSentData) { + infoLogger.accept("Sent bStats metrics data: " + data.toString()); + } + String url = String.format(REPORT_URL, platform); + HttpsURLConnection connection = (HttpsURLConnection) new URL(url).openConnection(); + // Compress the data to save bandwidth + byte[] compressedData = compress(data.toString()); + connection.setRequestMethod("POST"); + connection.addRequestProperty("Accept", "application/json"); + connection.addRequestProperty("Connection", "close"); + connection.addRequestProperty("Content-Encoding", "gzip"); + connection.addRequestProperty("Content-Length", String.valueOf(compressedData.length)); + connection.setRequestProperty("Content-Type", "application/json"); + connection.setRequestProperty("User-Agent", "Metrics-Service/1"); + connection.setDoOutput(true); + try (DataOutputStream outputStream = new DataOutputStream(connection.getOutputStream())) { + outputStream.write(compressedData); + } + StringBuilder builder = new StringBuilder(); + try (BufferedReader bufferedReader = + new BufferedReader(new InputStreamReader(connection.getInputStream()))) { + String line; + while ((line = bufferedReader.readLine()) != null) { + builder.append(line); + } + } + if (logResponseStatusText) { + infoLogger.accept("Sent data to bStats and received response: " + builder); + } + } + + /** + * Checks that the class was properly relocated. + */ + private void checkRelocation() { + // You can use the property to disable the check in your test environment + if (System.getProperty("bstats.relocatecheck") == null + || !System.getProperty("bstats.relocatecheck").equals("false")) { + // Maven's Relocate is clever and changes strings, too. So we have to use this little + // "trick" ... :D + final String defaultPackage = + new String(new byte[]{'o', 'r', 'g', '.', 'b', 's', 't', 'a', 't', 's'}); + final String examplePackage = + new String(new byte[]{'y', 'o', 'u', 'r', '.', 'p', 'a', 'c', 'k', 'a', 'g', 'e'}); + // We want to make sure no one just copy & pastes the example and uses the wrong package + // names + if (MetricsBase.class.getPackage().getName().startsWith(defaultPackage) + || MetricsBase.class.getPackage().getName().startsWith(examplePackage)) { + throw new IllegalStateException("bStats Metrics class has not been relocated correctly!"); + } + } + } + + /** + * Gzips the given string. + * + * @param str The string to gzip. + * @return The gzipped string. + */ + private static byte[] compress(final String str) throws IOException { + if (str == null) { + return null; + } + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + try (GZIPOutputStream gzip = new GZIPOutputStream(outputStream)) { + gzip.write(str.getBytes(StandardCharsets.UTF_8)); + } + return outputStream.toByteArray(); + } + } + + public static class AdvancedBarChart extends CustomChart { + + private final Callable> callable; + + /** + * Class constructor. + * + * @param chartId The id of the chart. + * @param callable The callable which is used to request the chart data. + */ + public AdvancedBarChart(String chartId, Callable> callable) { + super(chartId); + this.callable = callable; + } + + @Override + protected JsonObjectBuilder.JsonObject getChartData() throws Exception { + JsonObjectBuilder valuesBuilder = new JsonObjectBuilder(); + Map map = callable.call(); + if (map == null || map.isEmpty()) { + // Null = skip the chart + return null; + } + boolean allSkipped = true; + for (Map.Entry entry : map.entrySet()) { + if (entry.getValue().length == 0) { + // Skip this invalid + continue; + } + allSkipped = false; + valuesBuilder.appendField(entry.getKey(), entry.getValue()); + } + if (allSkipped) { + // Null = skip the chart + return null; + } + return new JsonObjectBuilder().appendField("values", valuesBuilder.build()).build(); + } + } + + public static class SimpleBarChart extends CustomChart { + + private final Callable> callable; + + /** + * Class constructor. + * + * @param chartId The id of the chart. + * @param callable The callable which is used to request the chart data. + */ + public SimpleBarChart(String chartId, Callable> callable) { + super(chartId); + this.callable = callable; + } + + @Override + protected JsonObjectBuilder.JsonObject getChartData() throws Exception { + JsonObjectBuilder valuesBuilder = new JsonObjectBuilder(); + Map map = callable.call(); + if (map == null || map.isEmpty()) { + // Null = skip the chart + return null; + } + for (Map.Entry entry : map.entrySet()) { + valuesBuilder.appendField(entry.getKey(), new int[]{entry.getValue()}); + } + return new JsonObjectBuilder().appendField("values", valuesBuilder.build()).build(); + } + } + + public static class MultiLineChart extends CustomChart { + + private final Callable> callable; + + /** + * Class constructor. + * + * @param chartId The id of the chart. + * @param callable The callable which is used to request the chart data. + */ + public MultiLineChart(String chartId, Callable> callable) { + super(chartId); + this.callable = callable; + } + + @Override + protected JsonObjectBuilder.JsonObject getChartData() throws Exception { + JsonObjectBuilder valuesBuilder = new JsonObjectBuilder(); + Map map = callable.call(); + if (map == null || map.isEmpty()) { + // Null = skip the chart + return null; + } + boolean allSkipped = true; + for (Map.Entry entry : map.entrySet()) { + if (entry.getValue() == 0) { + // Skip this invalid + continue; + } + allSkipped = false; + valuesBuilder.appendField(entry.getKey(), entry.getValue()); + } + if (allSkipped) { + // Null = skip the chart + return null; + } + return new JsonObjectBuilder().appendField("values", valuesBuilder.build()).build(); + } + } + + public static class AdvancedPie extends CustomChart { + + private final Callable> callable; + + /** + * Class constructor. + * + * @param chartId The id of the chart. + * @param callable The callable which is used to request the chart data. + */ + public AdvancedPie(String chartId, Callable> callable) { + super(chartId); + this.callable = callable; + } + + @Override + protected JsonObjectBuilder.JsonObject getChartData() throws Exception { + JsonObjectBuilder valuesBuilder = new JsonObjectBuilder(); + Map map = callable.call(); + if (map == null || map.isEmpty()) { + // Null = skip the chart + return null; + } + boolean allSkipped = true; + for (Map.Entry entry : map.entrySet()) { + if (entry.getValue() == 0) { + // Skip this invalid + continue; + } + allSkipped = false; + valuesBuilder.appendField(entry.getKey(), entry.getValue()); + } + if (allSkipped) { + // Null = skip the chart + return null; + } + return new JsonObjectBuilder().appendField("values", valuesBuilder.build()).build(); + } + } + + public abstract static class CustomChart { + + private final String chartId; + + protected CustomChart(String chartId) { + if (chartId == null) { + throw new IllegalArgumentException("chartId must not be null"); + } + this.chartId = chartId; + } + + public JsonObjectBuilder.JsonObject getRequestJsonObject( + BiConsumer errorLogger, boolean logErrors) { + JsonObjectBuilder builder = new JsonObjectBuilder(); + builder.appendField("chartId", chartId); + try { + JsonObjectBuilder.JsonObject data = getChartData(); + if (data == null) { + // If the data is null we don't send the chart. + return null; + } + builder.appendField("data", data); + } catch (Throwable t) { + if (logErrors) { + errorLogger.accept("Failed to get data for custom chart with id " + chartId, t); + } + return null; + } + return builder.build(); + } + + protected abstract JsonObjectBuilder.JsonObject getChartData() throws Exception; + } + + public static class SingleLineChart extends CustomChart { + + private final Callable callable; + + /** + * Class constructor. + * + * @param chartId The id of the chart. + * @param callable The callable which is used to request the chart data. + */ + public SingleLineChart(String chartId, Callable callable) { + super(chartId); + this.callable = callable; + } + + @Override + protected JsonObjectBuilder.JsonObject getChartData() throws Exception { + int value = callable.call(); + if (value == 0) { + // Null = skip the chart + return null; + } + return new JsonObjectBuilder().appendField("value", value).build(); + } + } + + public static class SimplePie extends CustomChart { + + private final Callable callable; + + /** + * Class constructor. + * + * @param chartId The id of the chart. + * @param callable The callable which is used to request the chart data. + */ + public SimplePie(String chartId, Callable callable) { + super(chartId); + this.callable = callable; + } + + @Override + protected JsonObjectBuilder.JsonObject getChartData() throws Exception { + String value = callable.call(); + if (value == null || value.isEmpty()) { + // Null = skip the chart + return null; + } + return new JsonObjectBuilder().appendField("value", value).build(); + } + } + + public static class DrilldownPie extends CustomChart { + + private final Callable>> callable; + + /** + * Class constructor. + * + * @param chartId The id of the chart. + * @param callable The callable which is used to request the chart data. + */ + public DrilldownPie(String chartId, Callable>> callable) { + super(chartId); + this.callable = callable; + } + + @Override + public JsonObjectBuilder.JsonObject getChartData() throws Exception { + JsonObjectBuilder valuesBuilder = new JsonObjectBuilder(); + Map> map = callable.call(); + if (map == null || map.isEmpty()) { + // Null = skip the chart + return null; + } + boolean reallyAllSkipped = true; + for (Map.Entry> entryValues : map.entrySet()) { + JsonObjectBuilder valueBuilder = new JsonObjectBuilder(); + boolean allSkipped = true; + for (Map.Entry valueEntry : map.get(entryValues.getKey()).entrySet()) { + valueBuilder.appendField(valueEntry.getKey(), valueEntry.getValue()); + allSkipped = false; + } + if (!allSkipped) { + reallyAllSkipped = false; + valuesBuilder.appendField(entryValues.getKey(), valueBuilder.build()); + } + } + if (reallyAllSkipped) { + // Null = skip the chart + return null; + } + return new JsonObjectBuilder().appendField("values", valuesBuilder.build()).build(); + } + } + + /** + * An extremely simple JSON builder. + * + *

While this class is neither feature-rich nor the most performant one, it's sufficient enough + * for its use-case. + */ + public static class JsonObjectBuilder { + + private StringBuilder builder = new StringBuilder(); + + private boolean hasAtLeastOneField = false; + + public JsonObjectBuilder() { + builder.append("{"); + } + + /** + * Appends a null field to the JSON. + * + * @param key The key of the field. + * @return A reference to this object. + */ + public JsonObjectBuilder appendNull(String key) { + appendFieldUnescaped(key, "null"); + return this; + } + + /** + * Appends a string field to the JSON. + * + * @param key The key of the field. + * @param value The value of the field. + * @return A reference to this object. + */ + public JsonObjectBuilder appendField(String key, String value) { + if (value == null) { + throw new IllegalArgumentException("JSON value must not be null"); + } + appendFieldUnescaped(key, "\"" + escape(value) + "\""); + return this; + } + + /** + * Appends an integer field to the JSON. + * + * @param key The key of the field. + * @param value The value of the field. + * @return A reference to this object. + */ + public JsonObjectBuilder appendField(String key, int value) { + appendFieldUnescaped(key, String.valueOf(value)); + return this; + } + + /** + * Appends an object to the JSON. + * + * @param key The key of the field. + * @param object The object. + * @return A reference to this object. + */ + public JsonObjectBuilder appendField(String key, JsonObject object) { + if (object == null) { + throw new IllegalArgumentException("JSON object must not be null"); + } + appendFieldUnescaped(key, object.toString()); + return this; + } + + /** + * Appends a string array to the JSON. + * + * @param key The key of the field. + * @param values The string array. + * @return A reference to this object. + */ + public JsonObjectBuilder appendField(String key, String[] values) { + if (values == null) { + throw new IllegalArgumentException("JSON values must not be null"); + } + String escapedValues = + Arrays.stream(values) + .map(value -> "\"" + escape(value) + "\"") + .collect(Collectors.joining(",")); + appendFieldUnescaped(key, "[" + escapedValues + "]"); + return this; + } + + /** + * Appends an integer array to the JSON. + * + * @param key The key of the field. + * @param values The integer array. + * @return A reference to this object. + */ + public JsonObjectBuilder appendField(String key, int[] values) { + if (values == null) { + throw new IllegalArgumentException("JSON values must not be null"); + } + String escapedValues = + Arrays.stream(values).mapToObj(String::valueOf).collect(Collectors.joining(",")); + appendFieldUnescaped(key, "[" + escapedValues + "]"); + return this; + } + + /** + * Appends an object array to the JSON. + * + * @param key The key of the field. + * @param values The integer array. + * @return A reference to this object. + */ + public JsonObjectBuilder appendField(String key, JsonObject[] values) { + if (values == null) { + throw new IllegalArgumentException("JSON values must not be null"); + } + String escapedValues = + Arrays.stream(values).map(JsonObject::toString).collect(Collectors.joining(",")); + appendFieldUnescaped(key, "[" + escapedValues + "]"); + return this; + } + + /** + * Appends a field to the object. + * + * @param key The key of the field. + * @param escapedValue The escaped value of the field. + */ + private void appendFieldUnescaped(String key, String escapedValue) { + if (builder == null) { + throw new IllegalStateException("JSON has already been built"); + } + if (key == null) { + throw new IllegalArgumentException("JSON key must not be null"); + } + if (hasAtLeastOneField) { + builder.append(","); + } + builder.append("\"").append(escape(key)).append("\":").append(escapedValue); + hasAtLeastOneField = true; + } + + /** + * Builds the JSON string and invalidates this builder. + * + * @return The built JSON string. + */ + public JsonObject build() { + if (builder == null) { + throw new IllegalStateException("JSON has already been built"); + } + JsonObject object = new JsonObject(builder.append("}").toString()); + builder = null; + return object; + } + + /** + * Escapes the given string like stated in https://www.ietf.org/rfc/rfc4627.txt. + * + *

This method escapes only the necessary characters '"', '\'. and '\u0000' - '\u001F'. + * Compact escapes are not used (e.g., '\n' is escaped as "\u000a" and not as "\n"). + * + * @param value The value to escape. + * @return The escaped value. + */ + private static String escape(String value) { + final StringBuilder builder = new StringBuilder(); + for (int i = 0; i < value.length(); i++) { + char c = value.charAt(i); + if (c == '"') { + builder.append("\\\""); + } else if (c == '\\') { + builder.append("\\\\"); + } else if (c <= '\u000F') { + builder.append("\\u000").append(Integer.toHexString(c)); + } else if (c <= '\u001F') { + builder.append("\\u00").append(Integer.toHexString(c)); + } else { + builder.append(c); + } + } + return builder.toString(); + } + + /** + * A super simple representation of a JSON object. + * + *

This class only exists to make methods of the {@link JsonObjectBuilder} type-safe and not + * allow a raw string inputs for methods like {@link JsonObjectBuilder#appendField(String, + * JsonObject)}. + */ + public static class JsonObject { + + private final String value; + + private JsonObject(String value) { + this.value = value; + } + + @Override + public String toString() { + return value; + } + } + } +} \ No newline at end of file diff --git a/src/main/java/fr/zorg/bungeesk/common/encryption/AESEncryption.java b/src/main/java/fr/zorg/bungeesk/common/encryption/AESEncryption.java deleted file mode 100644 index cc3179e..0000000 --- a/src/main/java/fr/zorg/bungeesk/common/encryption/AESEncryption.java +++ /dev/null @@ -1,74 +0,0 @@ -package fr.zorg.bungeesk.common.encryption; - -import javax.crypto.BadPaddingException; -import javax.crypto.Cipher; -import javax.crypto.IllegalBlockSizeException; -import javax.crypto.NoSuchPaddingException; -import javax.crypto.spec.SecretKeySpec; -import java.nio.charset.StandardCharsets; -import java.security.InvalidKeyException; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.util.Arrays; -import java.util.Base64; -import java.util.logging.Level; -import java.util.logging.Logger; - -public class AESEncryption { - - private Cipher encrypt; - private Cipher decrypt; - - private final Logger logger; - - public AESEncryption(final String key, final Logger logger) { - this.logger = logger; - try { - byte[] byteKey = key.getBytes(StandardCharsets.UTF_8); - byteKey = MessageDigest.getInstance("SHA-1").digest(byteKey); - byteKey = Arrays.copyOf(byteKey, 16); - - final SecretKeySpec secretKey = new SecretKeySpec(byteKey, "AES"); - this.encrypt = Cipher.getInstance("AES/ECB/PKCS5Padding"); - this.encrypt.init(Cipher.ENCRYPT_MODE, secretKey); - this.decrypt = Cipher.getInstance("AES/ECB/PKCS5Padding"); - this.decrypt.init(Cipher.DECRYPT_MODE, secretKey); - } catch (NoSuchAlgorithmException | InvalidKeyException | NoSuchPaddingException e) { - this.logger.log(Level.SEVERE, "Ooops, something went wrong. Can't initialize encryption method.", e); - } - } - - public String encrypt(final String message) { - if (this.encrypt == null) { - this.logger.log(Level.WARNING, "The Cypher is null. Can't encrypt the following message: " + message + ". A blank message will be send instead."); - return ""; - } - try { - return Base64.getEncoder().encodeToString(this.encrypt.doFinal(message.getBytes(StandardCharsets.UTF_8))); - } catch (IllegalArgumentException | IllegalBlockSizeException | BadPaddingException e) { - this.logger.log(Level.SEVERE, "Ooops, something went wrong. Can't encrypt the following message: " + message + ". A blank message will be send instead.", e); - } - return ""; - } - - public String decrypt(final String message) { - return this.decrypt(message, true); - } - - public String decrypt(final String message, final boolean sendError) { - if (message.equals("ALREADY_CONNECTED") || message.equals("WRONG_PASSWORD") || message.equals("DISCONNECT")) - return message; - if (this.decrypt == null) { - if (sendError) - this.logger.log(Level.WARNING, "The Cypher is null. Can't decrypt the following message: " + message + ". The raw message will be send instead."); - return message; - } - try { - return new String(this.decrypt.doFinal(Base64.getDecoder().decode(message)), StandardCharsets.UTF_8); - } catch (IllegalArgumentException | IllegalBlockSizeException | BadPaddingException e) { - if (sendError) - this.logger.log(Level.SEVERE, "Ooops, something went wrong. Can't decrypt the following message: " + message); - } - return message; - } -} diff --git a/src/main/java/fr/zorg/bungeesk/common/encryption/GlobalEncryption.java b/src/main/java/fr/zorg/bungeesk/common/encryption/GlobalEncryption.java new file mode 100644 index 0000000..93949bf --- /dev/null +++ b/src/main/java/fr/zorg/bungeesk/common/encryption/GlobalEncryption.java @@ -0,0 +1,44 @@ +package fr.zorg.bungeesk.common.encryption; + +import com.rockaport.alice.Alice; +import com.rockaport.alice.AliceContext; +import com.rockaport.alice.AliceContextBuilder; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.security.GeneralSecurityException; +import java.util.Base64; + +public class GlobalEncryption { + + private final Alice alice; + + public GlobalEncryption(final AliceContext.Algorithm algorithm, final int iterations) { + this.alice = new Alice(new AliceContextBuilder() + .setAlgorithm(algorithm) + .setIterations(iterations) + .build()); + } + + public String decrypt(final String toDecrypt, final String password) { + if (toDecrypt.equals("{\"args\":{\"status\":\"wrongPassword\"},\"action\":\"connectionInformation\"}") + || toDecrypt.equals("{\"args\":{\"status\":\"alreadyConnected\"},\"action\":\"connectionInformation\"}") + || toDecrypt.equals("{\"args\":{\"status\":\"disconnect\"},\"action\":\"connectionInformation\"}")) + return toDecrypt; + try { + return new String(this.alice.decrypt(Base64.getDecoder().decode(toDecrypt), password.toCharArray()), StandardCharsets.UTF_8); + } catch (GeneralSecurityException ex) { + return "wrongPassword"; + } + } + + public String encrypt(final String toEncrypt, final String password) { + try { + return Base64.getEncoder().encodeToString(this.alice.encrypt(toEncrypt.getBytes(StandardCharsets.UTF_8), password.toCharArray())); + } catch (GeneralSecurityException | IOException e) { + e.printStackTrace(); + return ""; + } + } + +} diff --git a/src/main/java/fr/zorg/bungeesk/common/utils/Utils.java b/src/main/java/fr/zorg/bungeesk/common/utils/Utils.java index cc15df1..49ed668 100644 --- a/src/main/java/fr/zorg/bungeesk/common/utils/Utils.java +++ b/src/main/java/fr/zorg/bungeesk/common/utils/Utils.java @@ -1,9 +1,5 @@ package fr.zorg.bungeesk.common.utils; -import com.google.gson.JsonArray; -import com.google.gson.JsonParser; - -import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Base64; import java.util.List; @@ -41,16 +37,4 @@ public static String toBase64(final byte[] input) { return Base64.getEncoder().encodeToString(input); } - public static byte[] fromBase64(final String input) { - return Base64.getDecoder().decode(input); - } - - public static String getMessage(final String message) { - final JsonArray array = new JsonParser().parse(message).getAsJsonArray(); - final byte[] bytes = new byte[array.size()]; - for (int index = 0; index < array.size(); index++) { - bytes[index] = array.get(index).getAsByte(); - } - return new String(bytes, StandardCharsets.UTF_8); - } } diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index b6ce7f9..369db58 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -1,7 +1,7 @@ name: BungeeSK -authors: [Zorg, BakaAless] +authors: [ Zorg, BakaAless ] main: fr.zorg.bungeesk.bukkit.BungeeSK website: https://github.com/ZorgBtw/BungeeSK version: @version@ api-version: 1.13 -softdepend: [Skript] \ No newline at end of file +softdepend: [ Skript ] \ No newline at end of file diff --git a/src/main/resources/variables.json b/src/main/resources/variables.json new file mode 100644 index 0000000..9e26dfe --- /dev/null +++ b/src/main/resources/variables.json @@ -0,0 +1 @@ +{} \ No newline at end of file