From dd72123d4b9409038095eb52f720ed3fe4e63342 Mon Sep 17 00:00:00 2001 From: Sekwah Date: Wed, 13 Nov 2024 11:02:01 +0000 Subject: [PATCH] feat: proxy tag (#451) --- .versionrc.js | 65 -------------- build.gradle | 2 + bungee/build.gradle | 11 +-- .../bungee/AdvancedPortalsBungeePlugin.java | 25 ++++++ .../bungee/BungeeInfoLogger.java | 28 ++++++ .../advancedportals/bungee/EventListener.java | 47 ++++++++++ .../container/BungeeProxyContainer.java | 38 +++++++++ .../container/BungeeProxyPlayerContainer.java | 33 +++++++ .../container/BungeeProxyServerContainer.java | 17 ++++ bungee/src/main/resources/bungee.yml | 4 + core/build.gradle | 35 +++++--- .../core/AdvancedPortalsCore.java | 11 ++- .../advancedportals/core/CoreListeners.java | 17 +++- .../advancedportals/core/ProxyMessages.java | 18 ++++ .../portal/ShowPortalSubCommand.java | 12 ++- .../advancedportals/core/network/Packet.java | 5 ++ .../core/network/ProxyCommandPacket.java | 30 +++++++ .../network/ProxyTransferDestiPacket.java | 38 +++++++++ .../core/network/ProxyTransferPacket.java | 31 +++++++ .../core/network/ServerDestiPacket.java | 31 +++++++ .../core/repository/ConfigRepository.java | 2 + .../repository/impl/ConfigRepositoryImpl.java | 5 ++ .../repository/impl/PortalRepositoryImpl.java | 8 ++ .../config/CommandPortalConfig.java | 1 + .../core/serializeddata/config/Config.java | 2 + .../advancedportals/core/tags/BungeeTag.java | 5 -- .../advancedportals/core/tags/CommandTag.java | 15 ++++ .../advancedportals/core/tags/DestiTag.java | 18 ++-- .../advancedportals/core/tags/NameTag.java | 6 -- .../core/tags/PortalEventTag.java | 6 -- .../advancedportals/core/tags/ProxyTag.java | 85 +++++++++++++++++++ .../advancedportals/core/warphandler/Tag.java | 9 +- .../advancedportals/core/BuildConstants.java | 5 ++ lang/src/main/resources/lang/de_DE.lang | 2 +- lang/src/main/resources/lang/en_GB.lang | 6 +- lang/src/main/resources/lang/fr_FR.lang | 4 +- lang/src/main/resources/lang/hu_HU.lang | 2 +- proxycore/build.gradle | 29 +++++++ .../proxycore/AdvancedPortalsProxyCore.java | 85 +++++++++++++++++++ .../connector/container/ProxyContainer.java | 8 ++ .../connector/container/ProxyJoinData.java | 18 ++++ .../container/ProxyPlayerContainer.java | 7 ++ .../container/ProxyServerContainer.java | 5 ++ settings.gradle | 1 + velocity/build.gradle | 7 +- .../AdvancedPortalsVelocityPlugin.java | 72 ++++++++++++++++ .../velocity/VelocityInfoLogger.java | 33 +++++++ .../velocity/connector/MinecraftToAnsi.java | 55 ++++++++++++ .../container/VelocityProxyContainer.java | 33 +++++++ .../VelocityProxyPlayerContainer.java | 36 ++++++++ .../VelocityProxyServerContainer.java | 17 ++++ version.txt | 2 +- 52 files changed, 954 insertions(+), 133 deletions(-) delete mode 100644 .versionrc.js create mode 100644 bungee/src/main/java/com/sekwah/advancedportals/bungee/AdvancedPortalsBungeePlugin.java create mode 100644 bungee/src/main/java/com/sekwah/advancedportals/bungee/BungeeInfoLogger.java create mode 100644 bungee/src/main/java/com/sekwah/advancedportals/bungee/EventListener.java create mode 100644 bungee/src/main/java/com/sekwah/advancedportals/bungee/connector/container/BungeeProxyContainer.java create mode 100644 bungee/src/main/java/com/sekwah/advancedportals/bungee/connector/container/BungeeProxyPlayerContainer.java create mode 100644 bungee/src/main/java/com/sekwah/advancedportals/bungee/connector/container/BungeeProxyServerContainer.java create mode 100644 bungee/src/main/resources/bungee.yml create mode 100644 core/src/main/java/com/sekwah/advancedportals/core/ProxyMessages.java create mode 100644 core/src/main/java/com/sekwah/advancedportals/core/network/Packet.java create mode 100644 core/src/main/java/com/sekwah/advancedportals/core/network/ProxyCommandPacket.java create mode 100644 core/src/main/java/com/sekwah/advancedportals/core/network/ProxyTransferDestiPacket.java create mode 100644 core/src/main/java/com/sekwah/advancedportals/core/network/ProxyTransferPacket.java create mode 100644 core/src/main/java/com/sekwah/advancedportals/core/network/ServerDestiPacket.java create mode 100644 core/src/main/java/com/sekwah/advancedportals/core/tags/ProxyTag.java create mode 100644 core/src/main/templates/com/sekwah/advancedportals/core/BuildConstants.java create mode 100644 proxycore/build.gradle create mode 100644 proxycore/src/main/java/com/sekwah/advancedportals/proxycore/AdvancedPortalsProxyCore.java create mode 100644 proxycore/src/main/java/com/sekwah/advancedportals/proxycore/connector/container/ProxyContainer.java create mode 100644 proxycore/src/main/java/com/sekwah/advancedportals/proxycore/connector/container/ProxyJoinData.java create mode 100644 proxycore/src/main/java/com/sekwah/advancedportals/proxycore/connector/container/ProxyPlayerContainer.java create mode 100644 proxycore/src/main/java/com/sekwah/advancedportals/proxycore/connector/container/ProxyServerContainer.java create mode 100644 velocity/src/main/java/com/sekwah/advancedportals/velocity/AdvancedPortalsVelocityPlugin.java create mode 100644 velocity/src/main/java/com/sekwah/advancedportals/velocity/VelocityInfoLogger.java create mode 100644 velocity/src/main/java/com/sekwah/advancedportals/velocity/connector/MinecraftToAnsi.java create mode 100644 velocity/src/main/java/com/sekwah/advancedportals/velocity/connector/container/VelocityProxyContainer.java create mode 100644 velocity/src/main/java/com/sekwah/advancedportals/velocity/connector/container/VelocityProxyPlayerContainer.java create mode 100644 velocity/src/main/java/com/sekwah/advancedportals/velocity/connector/container/VelocityProxyServerContainer.java diff --git a/.versionrc.js b/.versionrc.js deleted file mode 100644 index a5b60d29..00000000 --- a/.versionrc.js +++ /dev/null @@ -1,65 +0,0 @@ -let versionRegex = /(\nversion:\s)([0-9.-]+)/; -let velocityVersionRegex = /(\sversion\s=\s")([0-9.-]+)("\))/; - - -const ymlUpdater = { - updater: { - 'readVersion': (contents) => { - return versionRegex.exec(contents)[2]; - }, - 'writeVersion': (contents, version) => { - return contents.replace(versionRegex, `$1${version}`); - } - } -} - -const bungee = { - filename: 'src/main/resources/bungee.yml', - ...ymlUpdater, -} - -const spigotPlugin = { - filename: 'spigot/src/main/resources/plugin.yml', - ...ymlUpdater, -} - - -const gradleTracker = { - filename: 'gradle.properties', - updater: { - 'readVersion': (contents) => { - return versionRegex.exec(contents)[2]; - }, - 'writeVersion': (contents, version) => { - return contents.replace(versionRegex, `$1${version}`); - } - } -} - - -const velocity_plugin = { - filename: 'src/main/java/com/sekwah/advancedportals/velocity/AdvancedPortalsPlugin.java', - updater: { - 'readVersion': (contents) => { - return velocityVersionRegex.exec(contents)[2]; - }, - 'writeVersion': (contents, version) => { - return contents.replace(velocityVersionRegex, `$1${version}$3`); - } - } -} - -const files = [gradleTracker] // spigotPlugin, velocity_plugin, bungee - -module.exports = { - bumpFiles: files, - packageFiles: files, - // In case you need to force a version change (mostly due to change of scope of the update e.g. major now instead of patch) - //releaseAs: '1.0.0', - header:"# Changelog\n" + - "\n" + - "All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.\n" + - "\n" + - "For the release changelogs see [CHANGELOG.md](CHANGELOG.md) \n" + - "For the snapshot changelogs see [SNAPSHOT_CHANGELOG.md](SNAPSHOT_CHANGELOG.md)\n", -} diff --git a/build.gradle b/build.gradle index 39a66b05..c53514b2 100644 --- a/build.gradle +++ b/build.gradle @@ -67,10 +67,12 @@ buildscript { plugins { id 'dev.s7a.gradle.minecraft.server' version '1.1.0' + id 'org.jetbrains.gradle.plugin.idea-ext' version '1.1.7' } allprojects { apply plugin: 'java' + apply plugin: 'idea' tasks.withType(JavaCompile).configureEach { options.encoding = 'UTF-8' diff --git a/bungee/build.gradle b/bungee/build.gradle index 80e0b85e..23138236 100644 --- a/bungee/build.gradle +++ b/bungee/build.gradle @@ -17,17 +17,12 @@ repositories { // includeLibs just says to include the library in the final jar dependencies { - //includeLibs group: 'com.google.code.gson', name: 'gson', version:'2.8.2' - implementation group: 'com.google.code.gson', name: 'gson', version: '2.8.9' - //includeLibs group: 'com.google.inject', name: 'guice', version:'4.0' - implementation group: 'com.google.inject', name: 'guice', version:'4.0' - implementation group: 'com.google.guava', name: 'guava', version: '33.2.0-jre' - - // For spigot api - implementation "org.spigotmc:spigot-api:1.16.1-R0.1-SNAPSHOT" // For bungee api implementation "net.md-5:bungeecord-api:1.15-SNAPSHOT" + + implementation project(":proxycore") + implementation project(":core") } jar { diff --git a/bungee/src/main/java/com/sekwah/advancedportals/bungee/AdvancedPortalsBungeePlugin.java b/bungee/src/main/java/com/sekwah/advancedportals/bungee/AdvancedPortalsBungeePlugin.java new file mode 100644 index 00000000..8bf80095 --- /dev/null +++ b/bungee/src/main/java/com/sekwah/advancedportals/bungee/AdvancedPortalsBungeePlugin.java @@ -0,0 +1,25 @@ +package com.sekwah.advancedportals.bungee; + +import com.sekwah.advancedportals.bungee.connector.container.BungeeProxyContainer; +import com.sekwah.advancedportals.core.ProxyMessages; +import com.sekwah.advancedportals.proxycore.AdvancedPortalsProxyCore; +import net.md_5.bungee.api.plugin.Plugin; + +public class AdvancedPortalsBungeePlugin extends Plugin { + private AdvancedPortalsProxyCore proxyCore; + + @Override + public void onEnable() { + this.proxyCore = new AdvancedPortalsProxyCore(new BungeeInfoLogger(this), new BungeeProxyContainer(this)); + this.proxyCore.onEnable(); + + getProxy().registerChannel(ProxyMessages.CHANNEL_NAME); + + getProxy().getPluginManager().registerListener(this, new EventListener(this, this.proxyCore)); + } + + @Override + public void onDisable() { + this.proxyCore.onDisable(); + } +} diff --git a/bungee/src/main/java/com/sekwah/advancedportals/bungee/BungeeInfoLogger.java b/bungee/src/main/java/com/sekwah/advancedportals/bungee/BungeeInfoLogger.java new file mode 100644 index 00000000..58086f95 --- /dev/null +++ b/bungee/src/main/java/com/sekwah/advancedportals/bungee/BungeeInfoLogger.java @@ -0,0 +1,28 @@ +package com.sekwah.advancedportals.bungee; + +import com.sekwah.advancedportals.core.util.InfoLogger; + +import java.util.logging.Level; + +public class BungeeInfoLogger extends InfoLogger { + private final AdvancedPortalsBungeePlugin plugin; + + public BungeeInfoLogger(AdvancedPortalsBungeePlugin plugin) { + this.plugin = plugin; + } + + @Override + public void warning(String s) { + plugin.getLogger().warning(s); + } + + @Override + public void info(String s) { + plugin.getLogger().info(s); + } + + @Override + public void error(Exception e) { + plugin.getLogger().log(Level.SEVERE, e.getMessage(), e); + } +} diff --git a/bungee/src/main/java/com/sekwah/advancedportals/bungee/EventListener.java b/bungee/src/main/java/com/sekwah/advancedportals/bungee/EventListener.java new file mode 100644 index 00000000..605a3cce --- /dev/null +++ b/bungee/src/main/java/com/sekwah/advancedportals/bungee/EventListener.java @@ -0,0 +1,47 @@ +package com.sekwah.advancedportals.bungee; + +import com.sekwah.advancedportals.bungee.connector.container.BungeeProxyPlayerContainer; +import com.sekwah.advancedportals.bungee.connector.container.BungeeProxyServerContainer; +import com.sekwah.advancedportals.core.ProxyMessages; +import com.sekwah.advancedportals.proxycore.AdvancedPortalsProxyCore; +import net.md_5.bungee.api.connection.ProxiedPlayer; +import net.md_5.bungee.api.connection.Server; +import net.md_5.bungee.api.event.PlayerDisconnectEvent; +import net.md_5.bungee.api.event.PluginMessageEvent; +import net.md_5.bungee.api.event.ServerConnectedEvent; +import net.md_5.bungee.api.plugin.Listener; +import net.md_5.bungee.event.EventHandler; + +public class EventListener implements Listener { + + + private final AdvancedPortalsBungeePlugin plugin; + private final AdvancedPortalsProxyCore proxyCore; + + public EventListener(AdvancedPortalsBungeePlugin plugin, AdvancedPortalsProxyCore proxyCore) { + this.plugin = plugin; + this.proxyCore = proxyCore; + } + + @EventHandler + public void onMessageReceived(PluginMessageEvent event) { + if(!event.getTag().equalsIgnoreCase(ProxyMessages.CHANNEL_NAME)) return; + event.setCancelled(true); + + if(!(event.getSender() instanceof Server)) return; + + if(event.getReceiver() instanceof ProxiedPlayer player) { + this.proxyCore.incomingMessage(new BungeeProxyPlayerContainer(player), event.getData()); + } + } + + @EventHandler + public void onServerConnected(ServerConnectedEvent event) { + this.proxyCore.onServerConnect(new BungeeProxyServerContainer(event.getServer()), new BungeeProxyPlayerContainer(event.getPlayer())); + } + + @EventHandler + public void onDisconnect(PlayerDisconnectEvent event) { + this.proxyCore.onPlayerDisconnect(new BungeeProxyPlayerContainer(event.getPlayer())); + } +} diff --git a/bungee/src/main/java/com/sekwah/advancedportals/bungee/connector/container/BungeeProxyContainer.java b/bungee/src/main/java/com/sekwah/advancedportals/bungee/connector/container/BungeeProxyContainer.java new file mode 100644 index 00000000..4d745fc8 --- /dev/null +++ b/bungee/src/main/java/com/sekwah/advancedportals/bungee/connector/container/BungeeProxyContainer.java @@ -0,0 +1,38 @@ +package com.sekwah.advancedportals.bungee.connector.container; + +import com.sekwah.advancedportals.bungee.AdvancedPortalsBungeePlugin; +import com.sekwah.advancedportals.core.util.Lang; +import com.sekwah.advancedportals.proxycore.connector.container.ProxyContainer; +import com.sekwah.advancedportals.proxycore.connector.container.ProxyPlayerContainer; +import net.md_5.bungee.api.chat.TextComponent; + +public class BungeeProxyContainer implements ProxyContainer { + + private final AdvancedPortalsBungeePlugin plugin; + + public BungeeProxyContainer(AdvancedPortalsBungeePlugin plugin) { + this.plugin = plugin; + } + + @Override + public void invokeCommand(ProxyPlayerContainer proxyPlayer, String command) { + // Should never not be true but just to be safe + if(proxyPlayer instanceof BungeeProxyPlayerContainer playerContainer) { + plugin.getProxy().getPluginManager().dispatchCommand(playerContainer.getPlayer(), command); + } + } + + @Override + public void transferPlayer(ProxyPlayerContainer proxyPlayer, String serverName) { + // Should never not be true but just to be safe + if(proxyPlayer instanceof BungeeProxyPlayerContainer playerContainer) { + var serverInfo = plugin.getProxy().getServerInfo(serverName); + var player = playerContainer.getPlayer(); + if(serverInfo == null) { + player.sendMessage(new TextComponent(Lang.convertColors("&cCould not find server: &e") + serverName)); + return; + } + player.connect(serverInfo); + } + } +} diff --git a/bungee/src/main/java/com/sekwah/advancedportals/bungee/connector/container/BungeeProxyPlayerContainer.java b/bungee/src/main/java/com/sekwah/advancedportals/bungee/connector/container/BungeeProxyPlayerContainer.java new file mode 100644 index 00000000..edceafa1 --- /dev/null +++ b/bungee/src/main/java/com/sekwah/advancedportals/bungee/connector/container/BungeeProxyPlayerContainer.java @@ -0,0 +1,33 @@ +package com.sekwah.advancedportals.bungee.connector.container; + +import com.sekwah.advancedportals.core.ProxyMessages; +import com.sekwah.advancedportals.proxycore.connector.container.ProxyPlayerContainer; +import net.md_5.bungee.api.connection.ProxiedPlayer; + +public class BungeeProxyPlayerContainer implements ProxyPlayerContainer { + + private final ProxiedPlayer player; + + public BungeeProxyPlayerContainer(ProxiedPlayer player) { + this.player = player; + } + + public ProxiedPlayer getPlayer() { + return this.player; + } + + @Override + public String getUUID() { + return this.player.getUniqueId().toString(); + } + + @Override + public String getName() { + return this.player.getName(); + } + + public void sendServerPluginMessage(byte[] data) { + this.player.getServer().sendData(ProxyMessages.CHANNEL_NAME, data); + } + +} diff --git a/bungee/src/main/java/com/sekwah/advancedportals/bungee/connector/container/BungeeProxyServerContainer.java b/bungee/src/main/java/com/sekwah/advancedportals/bungee/connector/container/BungeeProxyServerContainer.java new file mode 100644 index 00000000..53473d71 --- /dev/null +++ b/bungee/src/main/java/com/sekwah/advancedportals/bungee/connector/container/BungeeProxyServerContainer.java @@ -0,0 +1,17 @@ +package com.sekwah.advancedportals.bungee.connector.container; + +import com.sekwah.advancedportals.proxycore.connector.container.ProxyServerContainer; +import net.md_5.bungee.api.connection.Server; + +public class BungeeProxyServerContainer implements ProxyServerContainer { + private final Server server; + + public BungeeProxyServerContainer(Server server) { + this.server = server; + } + + @Override + public String getServerName() { + return this.server.getInfo().getName(); + } +} diff --git a/bungee/src/main/resources/bungee.yml b/bungee/src/main/resources/bungee.yml new file mode 100644 index 00000000..fea8c275 --- /dev/null +++ b/bungee/src/main/resources/bungee.yml @@ -0,0 +1,4 @@ +main: com.sekwah.advancedportals.bungee.AdvancedPortalsBungeePlugin +name: AdvancedPortals +version: ${pluginVersion} +author: sekwah41 \ No newline at end of file diff --git a/core/build.gradle b/core/build.gradle index eb429d6b..28d03766 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -1,6 +1,9 @@ -apply plugin: 'maven-publish' -apply plugin: 'idea' -apply plugin: 'eclipse' + +plugins { + id 'maven-publish' + id 'idea' + id 'eclipse' +} configurations { // configuration that holds jars to copy into lib @@ -32,15 +35,19 @@ jar { } } -// Set SPIGOT_LOC to the location of your server and SPIGOT_JAR as the name of the jar file in the server you want to run -// DIReallyKnowWhatIAmDoingISwear is to remove the stupid pause spigot has at the start -tasks.register('runJar') { - doLast { - javaexec { - main "-jar" - args "${System.env.MC_SERVER_LOC}\\${System.env.MC_SERVER_JAR}.jar" - jvmArgs = ["-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005", "-DIReallyKnowWhatIAmDoingISwear=true"] - workingDir "${System.env.MC_SERVER_LOC}" - } - } +def templateSource = file('src/main/templates') +def templateDest = layout.buildDirectory.dir('generated/sources/templates') + +def generateTemplates = tasks.register('generateTemplates', Copy) { task -> + def props = [ + 'version': project.version + ] + task.inputs.properties props + + task.from templateSource + task.into templateDest + task.expand props } + +sourceSets.main.java.srcDir(generateTemplates.map { it.outputs }) + diff --git a/core/src/main/java/com/sekwah/advancedportals/core/AdvancedPortalsCore.java b/core/src/main/java/com/sekwah/advancedportals/core/AdvancedPortalsCore.java index 505bbb72..70e8638c 100644 --- a/core/src/main/java/com/sekwah/advancedportals/core/AdvancedPortalsCore.java +++ b/core/src/main/java/com/sekwah/advancedportals/core/AdvancedPortalsCore.java @@ -2,7 +2,6 @@ package com.sekwah.advancedportals.core; import com.google.inject.Inject; import com.google.inject.Injector; -import com.google.inject.spi.Message; import com.sekwah.advancedportals.core.commands.CommandWithSubCommands; import com.sekwah.advancedportals.core.commands.SubCommand; import com.sekwah.advancedportals.core.commands.subcommands.desti.*; @@ -12,7 +11,6 @@ import com.sekwah.advancedportals.core.connector.containers.ServerContainer; import com.sekwah.advancedportals.core.module.AdvancedPortalsModule; import com.sekwah.advancedportals.core.registry.TagRegistry; import com.sekwah.advancedportals.core.repository.ConfigRepository; -import com.sekwah.advancedportals.core.repository.IPlayerDataRepository; import com.sekwah.advancedportals.core.serializeddata.DataStorage; import com.sekwah.advancedportals.core.services.DestinationServices; import com.sekwah.advancedportals.core.services.PlayerDataServices; @@ -66,10 +64,6 @@ public class AdvancedPortalsCore { @Inject private GameScheduler gameScheduler; - // TEMP REMOVE THIS THIS IS JUST FOR DEV - @Inject - private IPlayerDataRepository tempDataRepository; - public AdvancedPortalsCore(String mcVersion, File dataStorageLoc, InfoLogger infoLogger, ServerContainer serverContainer) { @@ -126,6 +120,10 @@ public class AdvancedPortalsCore { private void registerChannels() { this.serverContainer.registerOutgoingChannel(BungeeTag.PACKET_CHANNEL); + if(this.configRepository.getEnableProxySupport()) { + this.serverContainer.registerOutgoingChannel(ProxyMessages.CHANNEL_NAME); + this.serverContainer.registerIncomingChannel(ProxyMessages.CHANNEL_NAME); + } } private void registerTags() { @@ -138,6 +136,7 @@ public class AdvancedPortalsCore { this.tagRegistry.registerTag(new PortalEventTag()); this.tagRegistry.registerTag(new MessageTag()); this.tagRegistry.registerTag(new BungeeTag()); + this.tagRegistry.registerTag(new ProxyTag()); } /** diff --git a/core/src/main/java/com/sekwah/advancedportals/core/CoreListeners.java b/core/src/main/java/com/sekwah/advancedportals/core/CoreListeners.java index fc38136f..8399fba8 100644 --- a/core/src/main/java/com/sekwah/advancedportals/core/CoreListeners.java +++ b/core/src/main/java/com/sekwah/advancedportals/core/CoreListeners.java @@ -1,15 +1,18 @@ package com.sekwah.advancedportals.core; +import com.google.common.io.ByteStreams; import com.google.inject.Inject; import com.sekwah.advancedportals.core.connector.containers.EntityContainer; import com.sekwah.advancedportals.core.connector.containers.PlayerContainer; import com.sekwah.advancedportals.core.connector.containers.WorldContainer; import com.sekwah.advancedportals.core.data.BlockAxis; import com.sekwah.advancedportals.core.data.Direction; +import com.sekwah.advancedportals.core.network.ServerDestiPacket; import com.sekwah.advancedportals.core.permissions.PortalPermissions; import com.sekwah.advancedportals.core.repository.ConfigRepository; import com.sekwah.advancedportals.core.serializeddata.BlockLocation; import com.sekwah.advancedportals.core.serializeddata.PlayerLocation; +import com.sekwah.advancedportals.core.services.DestinationServices; import com.sekwah.advancedportals.core.services.PlayerDataServices; import com.sekwah.advancedportals.core.services.PortalServices; import com.sekwah.advancedportals.core.util.GameScheduler; @@ -25,6 +28,9 @@ public class CoreListeners { @Inject private PortalServices portalServices; + @Inject + private DestinationServices destinationServices; + @Inject private ConfigRepository configRepository; @@ -56,7 +62,16 @@ public class CoreListeners { } public void incomingMessage(PlayerContainer player, String channel, byte[] message) { - // TODO implement proxy handling + var buffer = ByteStreams.newDataInput(message); + var messageType = buffer.readUTF(); + + switch (messageType) { + case ProxyMessages.SERVER_DESTI -> { + var serverDestiPacket = ServerDestiPacket.decode(buffer); + this.destinationServices.teleportToDestination(serverDestiPacket.getDestination(), player); + } + } + } public void tick() { diff --git a/core/src/main/java/com/sekwah/advancedportals/core/ProxyMessages.java b/core/src/main/java/com/sekwah/advancedportals/core/ProxyMessages.java new file mode 100644 index 00000000..9fdb4fbe --- /dev/null +++ b/core/src/main/java/com/sekwah/advancedportals/core/ProxyMessages.java @@ -0,0 +1,18 @@ +package com.sekwah.advancedportals.core; + +/** + * messages going to the proxy will start with proxy: messages going to the server will start with server: + */ +public class ProxyMessages { + + /** + * Could split by channel messages we will handle it ourselves + */ + public static final String CHANNEL_NAME = "advancedportals:message"; + + public static final String PROXY_TRANSFER_DESTI = "proxy:transfer_desti"; + public static final String PROXY_TRANSFER = "proxy:transfer"; + public static final String PROXY_COMMAND = "proxy:command"; + + public static final String SERVER_DESTI = "server:destination"; +} diff --git a/core/src/main/java/com/sekwah/advancedportals/core/commands/subcommands/portal/ShowPortalSubCommand.java b/core/src/main/java/com/sekwah/advancedportals/core/commands/subcommands/portal/ShowPortalSubCommand.java index e37e8b60..0e7c6c3f 100644 --- a/core/src/main/java/com/sekwah/advancedportals/core/commands/subcommands/portal/ShowPortalSubCommand.java +++ b/core/src/main/java/com/sekwah/advancedportals/core/commands/subcommands/portal/ShowPortalSubCommand.java @@ -25,7 +25,7 @@ import java.util.Objects; */ public class ShowPortalSubCommand implements SubCommand, SubCommand.SubCommandOnInit { - static final int SHOW_TICKS = 1010; + static final int SHOW_TICKS = 1050; boolean alternate_show_trigger = true; @@ -116,8 +116,14 @@ public class ShowPortalSubCommand player.getWorldName()) && tempData.getPos2().getWorldName().equals( player.getWorldName())) { - debugVisuals(player, tempData.getPos1(), tempData.getPos2(), - SELECTION_COLOR, SHOW_TICKS); + int widthX = Math.abs(tempData.getPos1().getPosX() + - tempData.getPos2().getPosX()); + int widthY = Math.abs(tempData.getPos1().getPosY() - tempData.getPos2().getPosY()); + int widthZ = Math.abs(tempData.getPos1().getPosZ() - tempData.getPos2().getPosZ()); + int totalBlocks = widthX * widthY * widthZ; + if (totalBlocks <= config.getMaxTriggerVisualisationSize()) + debugVisuals(player, tempData.getPos1(), tempData.getPos2(), + SELECTION_COLOR, SHOW_TICKS); } if (tempData.getPos1() != null diff --git a/core/src/main/java/com/sekwah/advancedportals/core/network/Packet.java b/core/src/main/java/com/sekwah/advancedportals/core/network/Packet.java new file mode 100644 index 00000000..019b4e64 --- /dev/null +++ b/core/src/main/java/com/sekwah/advancedportals/core/network/Packet.java @@ -0,0 +1,5 @@ +package com.sekwah.advancedportals.core.network; + +public interface Packet { + byte[] encode(); +} diff --git a/core/src/main/java/com/sekwah/advancedportals/core/network/ProxyCommandPacket.java b/core/src/main/java/com/sekwah/advancedportals/core/network/ProxyCommandPacket.java new file mode 100644 index 00000000..a9353868 --- /dev/null +++ b/core/src/main/java/com/sekwah/advancedportals/core/network/ProxyCommandPacket.java @@ -0,0 +1,30 @@ +package com.sekwah.advancedportals.core.network; + +import com.google.common.io.ByteArrayDataInput; +import com.google.common.io.ByteArrayDataOutput; +import com.google.common.io.ByteStreams; +import com.sekwah.advancedportals.core.ProxyMessages; + +public class ProxyCommandPacket implements Packet { + + private final String command; + + public ProxyCommandPacket(String command) { + this.command = command; + } + + public byte[] encode() { + ByteArrayDataOutput buffer = ByteStreams.newDataOutput(); + buffer.writeUTF(ProxyMessages.PROXY_COMMAND); + buffer.writeUTF(this.command); + return buffer.toByteArray(); + } + + public static ProxyCommandPacket decode(ByteArrayDataInput buffer) { + return new ProxyCommandPacket(buffer.readUTF()); + } + + public String getCommand() { + return command; + } +} diff --git a/core/src/main/java/com/sekwah/advancedportals/core/network/ProxyTransferDestiPacket.java b/core/src/main/java/com/sekwah/advancedportals/core/network/ProxyTransferDestiPacket.java new file mode 100644 index 00000000..6c04860b --- /dev/null +++ b/core/src/main/java/com/sekwah/advancedportals/core/network/ProxyTransferDestiPacket.java @@ -0,0 +1,38 @@ +package com.sekwah.advancedportals.core.network; + +import com.google.common.io.ByteArrayDataInput; +import com.google.common.io.ByteArrayDataOutput; +import com.google.common.io.ByteStreams; +import com.sekwah.advancedportals.core.ProxyMessages; + +public class ProxyTransferDestiPacket implements Packet { + + private final String serverName; + private final String destination; + + public ProxyTransferDestiPacket(String serverName, String destination) { + this.serverName = serverName; + this.destination = destination; + } + + public byte[] encode() { + ByteArrayDataOutput buffer = ByteStreams.newDataOutput(); + buffer.writeUTF(ProxyMessages.PROXY_TRANSFER_DESTI); + buffer.writeUTF(this.serverName); + buffer.writeUTF(this.destination); + return buffer.toByteArray(); + + } + + public static ProxyTransferDestiPacket decode(ByteArrayDataInput buffer) { + return new ProxyTransferDestiPacket(buffer.readUTF(), buffer.readUTF()); + } + + public String getServerName() { + return serverName; + } + + public String getDestination() { + return destination; + } +} diff --git a/core/src/main/java/com/sekwah/advancedportals/core/network/ProxyTransferPacket.java b/core/src/main/java/com/sekwah/advancedportals/core/network/ProxyTransferPacket.java new file mode 100644 index 00000000..417d15fd --- /dev/null +++ b/core/src/main/java/com/sekwah/advancedportals/core/network/ProxyTransferPacket.java @@ -0,0 +1,31 @@ +package com.sekwah.advancedportals.core.network; + +import com.google.common.io.ByteArrayDataInput; +import com.google.common.io.ByteArrayDataOutput; +import com.google.common.io.ByteStreams; +import com.sekwah.advancedportals.core.ProxyMessages; + +public class ProxyTransferPacket implements Packet { + + private final String serverName; + + public ProxyTransferPacket(String serverName) { + this.serverName = serverName; + } + + public byte[] encode() { + ByteArrayDataOutput buffer = ByteStreams.newDataOutput(); + buffer.writeUTF(ProxyMessages.PROXY_TRANSFER); + buffer.writeUTF(this.serverName); + return buffer.toByteArray(); + + } + + public static ProxyTransferPacket decode(ByteArrayDataInput buffer) { + return new ProxyTransferPacket(buffer.readUTF()); + } + + public String getServerName() { + return serverName; + } +} diff --git a/core/src/main/java/com/sekwah/advancedportals/core/network/ServerDestiPacket.java b/core/src/main/java/com/sekwah/advancedportals/core/network/ServerDestiPacket.java new file mode 100644 index 00000000..02f1cd85 --- /dev/null +++ b/core/src/main/java/com/sekwah/advancedportals/core/network/ServerDestiPacket.java @@ -0,0 +1,31 @@ +package com.sekwah.advancedportals.core.network; + +import com.google.common.io.ByteArrayDataInput; +import com.google.common.io.ByteArrayDataOutput; +import com.google.common.io.ByteStreams; +import com.sekwah.advancedportals.core.ProxyMessages; + +public class ServerDestiPacket implements Packet { + + private final String destination; + + public ServerDestiPacket(String destination) { + this.destination = destination; + } + + public byte[] encode() { + ByteArrayDataOutput buffer = ByteStreams.newDataOutput(); + buffer.writeUTF(ProxyMessages.SERVER_DESTI); + buffer.writeUTF(this.destination); + return buffer.toByteArray(); + + } + + public static ServerDestiPacket decode(ByteArrayDataInput buffer) { + return new ServerDestiPacket(buffer.readUTF()); + } + + public String getDestination() { + return destination; + } +} diff --git a/core/src/main/java/com/sekwah/advancedportals/core/repository/ConfigRepository.java b/core/src/main/java/com/sekwah/advancedportals/core/repository/ConfigRepository.java index be8a1e45..2f2bf385 100644 --- a/core/src/main/java/com/sekwah/advancedportals/core/repository/ConfigRepository.java +++ b/core/src/main/java/com/sekwah/advancedportals/core/repository/ConfigRepository.java @@ -45,4 +45,6 @@ public interface ConfigRepository { boolean warpMessageInChat(); String getWarpParticles(); + + boolean getEnableProxySupport(); } diff --git a/core/src/main/java/com/sekwah/advancedportals/core/repository/impl/ConfigRepositoryImpl.java b/core/src/main/java/com/sekwah/advancedportals/core/repository/impl/ConfigRepositoryImpl.java index 425b82b2..50d23fa2 100644 --- a/core/src/main/java/com/sekwah/advancedportals/core/repository/impl/ConfigRepositoryImpl.java +++ b/core/src/main/java/com/sekwah/advancedportals/core/repository/impl/ConfigRepositoryImpl.java @@ -95,6 +95,11 @@ public class ConfigRepositoryImpl implements ConfigRepository { return this.config.warpParticles; } + @Override + public boolean getEnableProxySupport() { + return this.config.enableProxySupport; + } + @Override public void loadConfig(DataStorage dataStorage) { this.dataStorage = dataStorage; diff --git a/core/src/main/java/com/sekwah/advancedportals/core/repository/impl/PortalRepositoryImpl.java b/core/src/main/java/com/sekwah/advancedportals/core/repository/impl/PortalRepositoryImpl.java index eb030798..13778ddf 100644 --- a/core/src/main/java/com/sekwah/advancedportals/core/repository/impl/PortalRepositoryImpl.java +++ b/core/src/main/java/com/sekwah/advancedportals/core/repository/impl/PortalRepositoryImpl.java @@ -65,6 +65,14 @@ public class PortalRepositoryImpl implements IPortalRepository { for (String fileName : allFiles) { AdvancedPortal portal = dataStorage.loadFile( AdvancedPortal.class, fileLocation + fileName); + + if (portal != null) { + AdvancedPortalsCore.getInstance() + .getModule() + .getInjector() + .injectMembers(portal); + } + // Forces the name tag to be up-to-date on load String[] name = portal.getArgValues(NameTag.TAG_NAME); if (name != null && name.length > 0) { diff --git a/core/src/main/java/com/sekwah/advancedportals/core/serializeddata/config/CommandPortalConfig.java b/core/src/main/java/com/sekwah/advancedportals/core/serializeddata/config/CommandPortalConfig.java index ac6ee47e..372fcaa5 100644 --- a/core/src/main/java/com/sekwah/advancedportals/core/serializeddata/config/CommandPortalConfig.java +++ b/core/src/main/java/com/sekwah/advancedportals/core/serializeddata/config/CommandPortalConfig.java @@ -4,5 +4,6 @@ public class CommandPortalConfig { public boolean op = true; public boolean console = true; public boolean permsWildcard = true; + public boolean proxy = true; public boolean enabled = true; } diff --git a/core/src/main/java/com/sekwah/advancedportals/core/serializeddata/config/Config.java b/core/src/main/java/com/sekwah/advancedportals/core/serializeddata/config/Config.java index a6442b67..bd321a01 100644 --- a/core/src/main/java/com/sekwah/advancedportals/core/serializeddata/config/Config.java +++ b/core/src/main/java/com/sekwah/advancedportals/core/serializeddata/config/Config.java @@ -39,4 +39,6 @@ public class Config { public boolean warpMessageInChat = false; public CommandPortalConfig commandPortals = new CommandPortalConfig(); + + public boolean enableProxySupport = false; } diff --git a/core/src/main/java/com/sekwah/advancedportals/core/tags/BungeeTag.java b/core/src/main/java/com/sekwah/advancedportals/core/tags/BungeeTag.java index ac2e54bd..f713e200 100644 --- a/core/src/main/java/com/sekwah/advancedportals/core/tags/BungeeTag.java +++ b/core/src/main/java/com/sekwah/advancedportals/core/tags/BungeeTag.java @@ -2,11 +2,8 @@ package com.sekwah.advancedportals.core.tags; import com.google.common.io.ByteArrayDataOutput; import com.google.common.io.ByteStreams; -import com.google.inject.Inject; import com.sekwah.advancedportals.core.connector.containers.PlayerContainer; import com.sekwah.advancedportals.core.registry.TagTarget; -import com.sekwah.advancedportals.core.repository.ConfigRepository; -import com.sekwah.advancedportals.core.util.FriendlyDataOutput; import com.sekwah.advancedportals.core.util.Lang; import com.sekwah.advancedportals.core.warphandler.ActivationData; import com.sekwah.advancedportals.core.warphandler.Tag; @@ -16,8 +13,6 @@ import java.util.Random; public class BungeeTag implements Tag.Activation { public static final String PACKET_CHANNEL = "BungeeCord"; - @Inject - ConfigRepository configRepository; public static String TAG_NAME = "bungee"; diff --git a/core/src/main/java/com/sekwah/advancedportals/core/tags/CommandTag.java b/core/src/main/java/com/sekwah/advancedportals/core/tags/CommandTag.java index 458ba03e..a320a59e 100644 --- a/core/src/main/java/com/sekwah/advancedportals/core/tags/CommandTag.java +++ b/core/src/main/java/com/sekwah/advancedportals/core/tags/CommandTag.java @@ -1,7 +1,10 @@ package com.sekwah.advancedportals.core.tags; import com.google.inject.Inject; +import com.sekwah.advancedportals.core.ProxyMessages; import com.sekwah.advancedportals.core.connector.containers.PlayerContainer; +import com.sekwah.advancedportals.core.network.ProxyCommandPacket; +import com.sekwah.advancedportals.core.network.ProxyTransferPacket; import com.sekwah.advancedportals.core.registry.TagTarget; import com.sekwah.advancedportals.core.repository.ConfigRepository; import com.sekwah.advancedportals.core.util.Lang; @@ -84,6 +87,14 @@ public class CommandTag implements Tag.Activation, Tag.Split, Tag.Creation { return false; } break; + case '%': + if (!commandPortals.proxy || !configRepository.getEnableProxySupport()) { + player.sendMessage( + Lang.getNegativePrefix() + + Lang.translate("tag.command.proxy.disabled")); + return false; + } + break; default: break; } @@ -116,6 +127,10 @@ public class CommandTag implements Tag.Activation, Tag.Split, Tag.Creation { player.getUUID(), formattedCommand.substring(1), CommandLevel.PERMISSION_WILDCARD); break; + case '%': + var packet = new ProxyCommandPacket(formattedCommand.substring(1)); + player.sendPacket(ProxyMessages.CHANNEL_NAME, packet.encode()); + break; default: player.getServer().dispatchCommand(player.getUUID(), formattedCommand, diff --git a/core/src/main/java/com/sekwah/advancedportals/core/tags/DestiTag.java b/core/src/main/java/com/sekwah/advancedportals/core/tags/DestiTag.java index 774f0895..9237272e 100644 --- a/core/src/main/java/com/sekwah/advancedportals/core/tags/DestiTag.java +++ b/core/src/main/java/com/sekwah/advancedportals/core/tags/DestiTag.java @@ -67,6 +67,10 @@ public class DestiTag implements Tag.Activation, Tag.AutoComplete, Tag.Split { activeData.setMetadata(TAG_NAME, selectedArg); + if(activeData.getMetadata(ProxyTag.TAG_NAME) != null) { + return true; + } + if(destinationServices.getDestination(selectedArg) == null) { player.sendMessage(Lang.getNegativePrefix() + Lang.translateInsertVariables("desti.error.notfound", selectedArg)); return false; @@ -92,6 +96,10 @@ public class DestiTag implements Tag.Activation, Tag.AutoComplete, Tag.Split { @Override public void postActivated(TagTarget target, PlayerContainer player, ActivationData activationData, String[] argData) { + if(activationData.getMetadata(ProxyTag.TAG_NAME) != null) { + return; + } + var selectedArg = activationData.getMetadata(TAG_NAME); Destination destination = destinationServices.getDestination(selectedArg); if (destination != null) { @@ -112,6 +120,10 @@ public class DestiTag implements Tag.Activation, Tag.AutoComplete, Tag.Split { @Override public boolean activated(TagTarget target, PlayerContainer player, ActivationData activationData, String[] argData) { + if(activationData.getMetadata(ProxyTag.TAG_NAME) != null) { + return true; + } + var selectedArg = activationData.getMetadata(TAG_NAME); Destination destination = destinationServices.getDestination(selectedArg); @@ -149,10 +161,4 @@ public class DestiTag implements Tag.Activation, Tag.AutoComplete, Tag.Split { public List autoComplete(String argData) { return destinationServices.getDestinationNames(); } - - @Nullable - @Override - public String splitString() { - return ","; - } } diff --git a/core/src/main/java/com/sekwah/advancedportals/core/tags/NameTag.java b/core/src/main/java/com/sekwah/advancedportals/core/tags/NameTag.java index 718795ac..7706d0af 100644 --- a/core/src/main/java/com/sekwah/advancedportals/core/tags/NameTag.java +++ b/core/src/main/java/com/sekwah/advancedportals/core/tags/NameTag.java @@ -48,12 +48,6 @@ public class NameTag implements Tag.AutoComplete, Tag.Creation { return null; } - @Nullable - @Override - public String splitString() { - return null; - } - @Override public boolean created(TagTarget target, PlayerContainer player, String[] argData) { diff --git a/core/src/main/java/com/sekwah/advancedportals/core/tags/PortalEventTag.java b/core/src/main/java/com/sekwah/advancedportals/core/tags/PortalEventTag.java index 25c17fcf..29362cf0 100644 --- a/core/src/main/java/com/sekwah/advancedportals/core/tags/PortalEventTag.java +++ b/core/src/main/java/com/sekwah/advancedportals/core/tags/PortalEventTag.java @@ -80,12 +80,6 @@ public class PortalEventTag implements Tag.Activation, Tag.AutoComplete, Tag.Den return List.of("true", "false"); } - @Nullable - @Override - public String splitString() { - return ""; - } - @Override public Behaviour getDenyBehavior() { return Behaviour.SILENT; diff --git a/core/src/main/java/com/sekwah/advancedportals/core/tags/ProxyTag.java b/core/src/main/java/com/sekwah/advancedportals/core/tags/ProxyTag.java new file mode 100644 index 00000000..f0004824 --- /dev/null +++ b/core/src/main/java/com/sekwah/advancedportals/core/tags/ProxyTag.java @@ -0,0 +1,85 @@ +package com.sekwah.advancedportals.core.tags; + +import com.google.common.io.ByteArrayDataOutput; +import com.google.common.io.ByteStreams; +import com.google.inject.Inject; +import com.sekwah.advancedportals.core.ProxyMessages; +import com.sekwah.advancedportals.core.connector.containers.PlayerContainer; +import com.sekwah.advancedportals.core.network.ProxyTransferDestiPacket; +import com.sekwah.advancedportals.core.network.ProxyTransferPacket; +import com.sekwah.advancedportals.core.registry.TagTarget; +import com.sekwah.advancedportals.core.repository.ConfigRepository; +import com.sekwah.advancedportals.core.util.Lang; +import com.sekwah.advancedportals.core.warphandler.ActivationData; +import com.sekwah.advancedportals.core.warphandler.Tag; + +import javax.annotation.Nullable; +import java.util.Random; + +public class ProxyTag implements Tag.Activation, Tag.OrderPriority, Tag.Split { + + @Inject + ConfigRepository configRepository; + + public static String TAG_NAME = "proxy"; + + private final TagType[] tagTypes = + new TagType[] {TagType.PORTAL}; + + private final Random random = new Random(); + + @Override + public TagType[] getTagTypes() { + return tagTypes; + } + + @Override + public String getName() { + return TAG_NAME; + } + + @Override + public String[] getAliases() { + return null; + } + + @Override + public String description() { + return Lang.translate("tag.proxy.description"); + } + + @Override + public boolean preActivated(TagTarget target, PlayerContainer player, ActivationData activeData, String[] argData) { + String selectedArg = argData[random.nextInt(argData.length)]; + activeData.setMetadata(TAG_NAME, selectedArg); + return true; + } + + @Override + public void postActivated(TagTarget target, PlayerContainer player, ActivationData activationData, String[] argData) { + + } + + @Override + public boolean activated(TagTarget target, PlayerContainer player, ActivationData activeData, String[] argData) { + + if(!this.configRepository.getEnableProxySupport()) { + player.sendMessage(Lang.getNegativePrefix() + Lang.translate("tag.proxy.notenabled")); + return false; + } + + String selectedArg = argData[random.nextInt(argData.length)]; + + var desti = activeData.getMetadata(DestiTag.TAG_NAME); + + var packet = desti == null ? new ProxyTransferPacket(selectedArg) : new ProxyTransferDestiPacket(selectedArg, desti); + player.sendPacket(ProxyMessages.CHANNEL_NAME, packet.encode()); + activeData.setWarpStatus(ActivationData.WarpedStatus.WARPED); + return true; + } + + @Override + public Priority getPriority() { + return Priority.HIGHEST; + } +} diff --git a/core/src/main/java/com/sekwah/advancedportals/core/warphandler/Tag.java b/core/src/main/java/com/sekwah/advancedportals/core/warphandler/Tag.java index 1b0883b0..0e7d1171 100644 --- a/core/src/main/java/com/sekwah/advancedportals/core/warphandler/Tag.java +++ b/core/src/main/java/com/sekwah/advancedportals/core/warphandler/Tag.java @@ -29,7 +29,7 @@ public interface Tag { */ enum TagType { PORTAL, DESTINATION } - enum Priority { LOWEST, LOW, NORMAL, HIGH, HIGHEST } + enum Priority { HIGHEST, HIGH, NORMAL, LOW, LOWEST } /** * Used to flag where the auto complete should show more or less info. @@ -65,9 +65,6 @@ public interface Tag { */ @Nullable List autoComplete(String argData); - - @Nullable - String splitString(); } interface Split extends Tag { @@ -78,7 +75,9 @@ public interface Tag { * @return null if the tag does not support splitting */ @Nullable - String splitString(); + default String splitString() { + return ","; + } } /** diff --git a/core/src/main/templates/com/sekwah/advancedportals/core/BuildConstants.java b/core/src/main/templates/com/sekwah/advancedportals/core/BuildConstants.java new file mode 100644 index 00000000..03a9c4d6 --- /dev/null +++ b/core/src/main/templates/com/sekwah/advancedportals/core/BuildConstants.java @@ -0,0 +1,5 @@ +package com.sekwah.advancedportals.core; + +public class BuildConstants { + public static final String VERSION = "${version}"; +} \ No newline at end of file diff --git a/lang/src/main/resources/lang/de_DE.lang b/lang/src/main/resources/lang/de_DE.lang index 4c26065e..67240437 100644 --- a/lang/src/main/resources/lang/de_DE.lang +++ b/lang/src/main/resources/lang/de_DE.lang @@ -56,7 +56,7 @@ command.help.invalidhelp= &e%1$s&c ist keine gültige Seitennummer oder Sub-Comm command.reload.help=Ladet die Portal-Dateien neu command.reload.detailedhelp=Lade alle Portal-Dateien von den Dateien im Dateiordner neu. -command.reload.reloaded= Alle Advanced Portals Dateien wurden neugeladet +command.reload.reloaded= Alle Advanced Portals-Daten wurden neu geladen. Einige Konfigurationswerte erfordern möglicherweise einen vollständigen Serverneustart oder ein Plugin-Reload, um wirksam zu werden. command.create.help=Erstellt Portale command.create.error= Beim Portal erstellen ist ein Fehler aufgetreten: diff --git a/lang/src/main/resources/lang/en_GB.lang b/lang/src/main/resources/lang/en_GB.lang index 4f14b30e..6b23cfef 100644 --- a/lang/src/main/resources/lang/en_GB.lang +++ b/lang/src/main/resources/lang/en_GB.lang @@ -54,7 +54,7 @@ command.help.invalidhelp= Sorry but &e%1$s&c is not a valid page number or sub c command.reload.help=Reloads portal data command.reload.detailedhelp=Reloads all portal data from files in the data folder -command.reload.reloaded= All Advanced Portals data reloaded +command.reload.reloaded= All Advanced Portals data reloaded. Some config values may need a full server restart or a plugin reload to take effect. command.create.help=Creates portals command.create.error= There was a problem making the portal. @@ -192,3 +192,7 @@ tag.command.disabled= Command portals are &edisabled &con this server. Please co tag.command.op.disabled= Op command portals are &edisabled &con this server. Please contact a server admin if this is an issue. tag.command.console.disabled= Console command portals are &edisabled &con this server. Please contact a server admin if this is an issue. tag.command.permswildcard.disabled= Wildcard &e*&c permission command portals are &edisabled &con this server. Please contact a server admin if this is an issue. +tag.command.proxy.disabled= Proxy command portals are &edisabled &con this server. Please contact a server admin if this is an issue. + +tag.proxy.notenabled= Proxy portals are currently &edisabled &con this server. Please contact a server admin to enable them. +tag.proxy.description= Sets the server destination of the portal. \ No newline at end of file diff --git a/lang/src/main/resources/lang/fr_FR.lang b/lang/src/main/resources/lang/fr_FR.lang index 0aff3d96..d1e4c75e 100644 --- a/lang/src/main/resources/lang/fr_FR.lang +++ b/lang/src/main/resources/lang/fr_FR.lang @@ -37,7 +37,7 @@ translatedata.translationsoutdated=Certaines des traductions du fichier de tradu translatedata.replacecommand= Utilisez &e/portal transupdate&c pour copier un nouveau fichier par défaut de traduction &een_GB&c. translatedata.replaced= Un nouveau fichier &een_GB&a a bien été enregistré. -messageprefix.positive=&c[&7AdvancedPortals&c] +messageprefix.positive=&a[&7AdvancedPortals&a] messageprefix.negative=&c[&7AdvancedPortals&c] logger.pluginenable=Advanced portals have been enabled! @@ -53,7 +53,7 @@ command.help.invalidhelp= Désolé mais &e%1$s&c n'est pas une page ou sous comm command.reload.help=Recharge les fichiers command.reload.detailedhelp=Recharge toutes les données du portail à partir des fichiers du dossier de données. -command.reload.reloaded= Tous les fichiers ont bien été rechargés. +command.reload.reloaded= Toutes les données d'Advanced Portals ont été rechargées. Certaines valeurs de configuration peuvent nécessiter un redémarrage complet du serveur ou un rechargement du plugin pour prendre effet. command.create.help=Crée un portail command.create.error= Une erreur est survenue en créant le portail: diff --git a/lang/src/main/resources/lang/hu_HU.lang b/lang/src/main/resources/lang/hu_HU.lang index a4da968b..3da48647 100644 --- a/lang/src/main/resources/lang/hu_HU.lang +++ b/lang/src/main/resources/lang/hu_HU.lang @@ -53,7 +53,7 @@ command.help.invalidhelp= Sajnálom, de &e%1$s&c nem érvényes oldalszám vagy command.reload.help=Portál adat újratöltése command.reload.detailedhelp=Újratölt minden portáladatot az adatmappában található fájlokból -command.reload.reloaded= Minden Advanced Portals adat újratöltve +command.reload.reloaded= Minden Advanced Portals adat újratöltve. Egyes konfigurációs értékek teljes szerverújraindítást vagy a plugin újratöltését igényelhetik a hatályba lépéshez. command.create.help=Portál létrehozása command.create.error= Hiba történt a portál létrehozásában: diff --git a/proxycore/build.gradle b/proxycore/build.gradle new file mode 100644 index 00000000..bf896d0a --- /dev/null +++ b/proxycore/build.gradle @@ -0,0 +1,29 @@ +apply plugin: 'maven-publish' +apply plugin: 'idea' +apply plugin: 'eclipse' + +configurations { + // configuration that holds jars to copy into lib + includeLibs +} + +repositories { + + maven { url "https://repo.maven.apache.org/maven2" } + maven { url "https://hub.spigotmc.org/nexus/content/repositories/snapshots/" } + maven { url "https://oss.sonatype.org/content/repositories/snapshots/" } +} + +// includeLibs just says to include the library in the final jar +dependencies { + // This is here just for referencing the proxy message strings + implementation project(":core") + implementation group: 'com.google.guava', name: 'guava', version: '33.2.0-jre' +} + +jar { + from configurations.includeLibs.collect { + it.isDirectory() ? it : zipTree(it) + } +} + diff --git a/proxycore/src/main/java/com/sekwah/advancedportals/proxycore/AdvancedPortalsProxyCore.java b/proxycore/src/main/java/com/sekwah/advancedportals/proxycore/AdvancedPortalsProxyCore.java new file mode 100644 index 00000000..cc880e2f --- /dev/null +++ b/proxycore/src/main/java/com/sekwah/advancedportals/proxycore/AdvancedPortalsProxyCore.java @@ -0,0 +1,85 @@ +package com.sekwah.advancedportals.proxycore; + +import com.google.common.io.ByteStreams; +import com.sekwah.advancedportals.core.ProxyMessages; +import com.sekwah.advancedportals.core.network.ProxyCommandPacket; +import com.sekwah.advancedportals.core.network.ProxyTransferDestiPacket; +import com.sekwah.advancedportals.core.network.ProxyTransferPacket; +import com.sekwah.advancedportals.core.network.ServerDestiPacket; +import com.sekwah.advancedportals.core.util.InfoLogger; +import com.sekwah.advancedportals.core.util.Lang; +import com.sekwah.advancedportals.proxycore.connector.container.ProxyContainer; +import com.sekwah.advancedportals.proxycore.connector.container.ProxyJoinData; +import com.sekwah.advancedportals.proxycore.connector.container.ProxyPlayerContainer; +import com.sekwah.advancedportals.proxycore.connector.container.ProxyServerContainer; + +import java.util.HashMap; + +public class AdvancedPortalsProxyCore { + + private final InfoLogger logger; + private final ProxyContainer proxyContainer; + + public HashMap playerJoinMap = new HashMap<>(); + + public AdvancedPortalsProxyCore(InfoLogger logger, ProxyContainer proxyContainer) { + this.logger = logger; + this.proxyContainer = proxyContainer; + } + + public void onEnable() { + this.logger.info(Lang.convertColors("&aSuccessfully enabled!")); + } + + public void onDisable() { + this.logger.info(Lang.convertColors("&cDisabling plugin!")); + } + + public void onServerConnect(ProxyServerContainer server, ProxyPlayerContainer player) { + if(this.playerJoinMap.containsKey(player.getUUID())) { + var joinData = this.playerJoinMap.get(player.getUUID()); + if(joinData.isExpired()) return; + player.sendServerPluginMessage(new ServerDestiPacket(joinData.destination).encode()); + this.playerJoinMap.remove(player.getUUID()); + } + } + + public void onPlayerDisconnect(ProxyPlayerContainer player) { + this.playerJoinMap.remove(player.getUUID()); + } + + /** + * Messages coming on the ProxyMessages.CHANNEL_NAME from the server, others will be filtered out before now. + * @param player + * @param message + */ + public void incomingMessage(ProxyPlayerContainer player, byte[] message) { + + var buffer = ByteStreams.newDataInput(message); + var messageType = buffer.readUTF(); + + // Might be a bit overboard for some as they'll only have one value, but try to keep the decode behavior with + // the encode behavior in the packets + switch (messageType) { + case ProxyMessages.PROXY_TRANSFER -> { + var transferPacket = ProxyTransferPacket.decode(buffer); + this.logger.info("Transfer request for " + player.getName() + " to " + transferPacket.getServerName()); + this.proxyContainer.transferPlayer(player, transferPacket.getServerName()); + } + case ProxyMessages.PROXY_COMMAND -> { + var commandPacket = ProxyCommandPacket.decode(buffer); + this.logger.info("Command request for " + player.getName() + " to run /" + commandPacket.getCommand()); + this.proxyContainer.invokeCommand(player, commandPacket.getCommand()); + } + case ProxyMessages.PROXY_TRANSFER_DESTI -> { + var transferDestiPacket = ProxyTransferDestiPacket.decode(buffer); + this.proxyContainer.transferPlayer(player, transferDestiPacket.getServerName()); + this.playerJoinMap.put(player.getUUID(), new ProxyJoinData(transferDestiPacket.getDestination(), transferDestiPacket.getServerName())); + } + default -> { + this.logger.info("Unknown message type: " + messageType); + } + } + + } +} diff --git a/proxycore/src/main/java/com/sekwah/advancedportals/proxycore/connector/container/ProxyContainer.java b/proxycore/src/main/java/com/sekwah/advancedportals/proxycore/connector/container/ProxyContainer.java new file mode 100644 index 00000000..29b3d555 --- /dev/null +++ b/proxycore/src/main/java/com/sekwah/advancedportals/proxycore/connector/container/ProxyContainer.java @@ -0,0 +1,8 @@ +package com.sekwah.advancedportals.proxycore.connector.container; + +public interface ProxyContainer { + void invokeCommand(ProxyPlayerContainer proxyPlayer, String command); + + void transferPlayer(ProxyPlayerContainer proxyPlayer, String serverName); + +} diff --git a/proxycore/src/main/java/com/sekwah/advancedportals/proxycore/connector/container/ProxyJoinData.java b/proxycore/src/main/java/com/sekwah/advancedportals/proxycore/connector/container/ProxyJoinData.java new file mode 100644 index 00000000..f8dbfd09 --- /dev/null +++ b/proxycore/src/main/java/com/sekwah/advancedportals/proxycore/connector/container/ProxyJoinData.java @@ -0,0 +1,18 @@ +package com.sekwah.advancedportals.proxycore.connector.container; + +public class ProxyJoinData { + + public final String destination; + public final String serverName; + public final long joinTime; + + public ProxyJoinData(String destination, String serverName) { + this.destination = destination; + this.serverName = serverName; + this.joinTime = System.currentTimeMillis(); + } + + public boolean isExpired() { + return System.currentTimeMillis() - this.joinTime > 1000 * 15; // 15 seconds + } +} diff --git a/proxycore/src/main/java/com/sekwah/advancedportals/proxycore/connector/container/ProxyPlayerContainer.java b/proxycore/src/main/java/com/sekwah/advancedportals/proxycore/connector/container/ProxyPlayerContainer.java new file mode 100644 index 00000000..878773d1 --- /dev/null +++ b/proxycore/src/main/java/com/sekwah/advancedportals/proxycore/connector/container/ProxyPlayerContainer.java @@ -0,0 +1,7 @@ +package com.sekwah.advancedportals.proxycore.connector.container; + +public interface ProxyPlayerContainer { + String getUUID(); + String getName(); + void sendServerPluginMessage(byte[] data); +} diff --git a/proxycore/src/main/java/com/sekwah/advancedportals/proxycore/connector/container/ProxyServerContainer.java b/proxycore/src/main/java/com/sekwah/advancedportals/proxycore/connector/container/ProxyServerContainer.java new file mode 100644 index 00000000..b90fdc13 --- /dev/null +++ b/proxycore/src/main/java/com/sekwah/advancedportals/proxycore/connector/container/ProxyServerContainer.java @@ -0,0 +1,5 @@ +package com.sekwah.advancedportals.proxycore.connector.container; + +public interface ProxyServerContainer { + String getServerName(); +} diff --git a/settings.gradle b/settings.gradle index 803feaad..4a36b19d 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,6 +1,7 @@ rootProject.name = "Advanced-Portals" // Core modules include 'core' +include 'proxycore' include 'lang' // Implementations diff --git a/velocity/build.gradle b/velocity/build.gradle index a7ec0fa0..8f0a91ef 100644 --- a/velocity/build.gradle +++ b/velocity/build.gradle @@ -7,12 +7,15 @@ configurations { repositories { maven { url "https://repo.maven.apache.org/maven2" } - maven { url 'https://papermc.io/repo/repository/maven-public/' } - maven { url "https://nexus.velocitypowered.com/repository/maven-public/" } + maven { + name 'papermc' + url 'https://repo.papermc.io/repository/maven-public/' + } } // includeLibs just says to include the library in the final jar dependencies { + implementation project(":proxycore") implementation project(":core") implementation("com.velocitypowered:velocity-api:3.1.0") diff --git a/velocity/src/main/java/com/sekwah/advancedportals/velocity/AdvancedPortalsVelocityPlugin.java b/velocity/src/main/java/com/sekwah/advancedportals/velocity/AdvancedPortalsVelocityPlugin.java new file mode 100644 index 00000000..7fcf2d16 --- /dev/null +++ b/velocity/src/main/java/com/sekwah/advancedportals/velocity/AdvancedPortalsVelocityPlugin.java @@ -0,0 +1,72 @@ +package com.sekwah.advancedportals.velocity; + +import com.google.inject.Inject; +import com.sekwah.advancedportals.core.BuildConstants; +import com.sekwah.advancedportals.core.ProxyMessages; +import com.sekwah.advancedportals.proxycore.AdvancedPortalsProxyCore; +import com.sekwah.advancedportals.velocity.connector.container.VelocityProxyContainer; +import com.sekwah.advancedportals.velocity.connector.container.VelocityProxyPlayerContainer; +import com.sekwah.advancedportals.velocity.connector.container.VelocityProxyServerContainer; +import com.velocitypowered.api.event.Subscribe; +import com.velocitypowered.api.event.connection.DisconnectEvent; +import com.velocitypowered.api.event.connection.PluginMessageEvent; +import com.velocitypowered.api.event.player.ServerPostConnectEvent; +import com.velocitypowered.api.event.proxy.ProxyInitializeEvent; +import com.velocitypowered.api.proxy.ProxyServer; +import com.velocitypowered.api.plugin.Plugin; +import com.velocitypowered.api.proxy.ServerConnection; +import org.slf4j.Logger; +import com.velocitypowered.api.proxy.messages.LegacyChannelIdentifier; + +@Plugin(authors = {"sekwah41"} ,id = "advancedportals", name = "Advanced Portals", + url = "https://www.spigotmc.org/resources/advanced-portals.14356/", + version = BuildConstants.VERSION) +public class AdvancedPortalsVelocityPlugin { + + private AdvancedPortalsProxyCore proxyCore; + + private final Logger logger; + private final ProxyServer proxy; + + private LegacyChannelIdentifier AP_CHANNEL; + + @Inject + public AdvancedPortalsVelocityPlugin(ProxyServer proxy, Logger logger) { + this.proxy = proxy; + this.logger = logger; + this.proxyCore = new AdvancedPortalsProxyCore(new VelocityInfoLogger(this.logger, this.proxy), new VelocityProxyContainer(this.proxy)); + this.proxyCore.onEnable(); + } + + @Subscribe + public void onProxyInitialize(ProxyInitializeEvent event) { + AP_CHANNEL = new LegacyChannelIdentifier(ProxyMessages.CHANNEL_NAME); + + proxy.getChannelRegistrar().register(AP_CHANNEL); + } + + @Subscribe + public void onPluginMessage(PluginMessageEvent event) { + if (event.getIdentifier().equals(AP_CHANNEL)) { + if(event.getSource() instanceof ServerConnection serverConnection) { + this.proxyCore.incomingMessage(new VelocityProxyPlayerContainer(serverConnection.getPlayer(), AP_CHANNEL), event.getData()); + } + // So that client packets don't make it through to the servers, always trigger on this channel. + event.setResult(PluginMessageEvent.ForwardResult.handled()); + } + } + + + @Subscribe + public void postJoinEvent(ServerPostConnectEvent event) { + event.getPlayer().getCurrentServer().ifPresent(serverConnection -> { + this.proxyCore.onServerConnect(new VelocityProxyServerContainer(serverConnection.getServer()), new VelocityProxyPlayerContainer(event.getPlayer(), AP_CHANNEL)); + }); + } + + @Subscribe + public void onDisconnect(DisconnectEvent event) { + this.proxyCore.onPlayerDisconnect(new VelocityProxyPlayerContainer(event.getPlayer(), AP_CHANNEL)); + } + +} diff --git a/velocity/src/main/java/com/sekwah/advancedportals/velocity/VelocityInfoLogger.java b/velocity/src/main/java/com/sekwah/advancedportals/velocity/VelocityInfoLogger.java new file mode 100644 index 00000000..64150640 --- /dev/null +++ b/velocity/src/main/java/com/sekwah/advancedportals/velocity/VelocityInfoLogger.java @@ -0,0 +1,33 @@ +package com.sekwah.advancedportals.velocity; +import com.sekwah.advancedportals.core.util.InfoLogger; +import com.sekwah.advancedportals.velocity.connector.MinecraftToAnsi; +import com.velocitypowered.api.proxy.ProxyServer; +import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; +import org.slf4j.Logger; + +public class VelocityInfoLogger extends InfoLogger { + + private final Logger logger; + private final ProxyServer proxy; + private final LegacyComponentSerializer serializer = LegacyComponentSerializer.builder().character('&').hexCharacter('#').hexColors().build(); + + public VelocityInfoLogger(Logger logger, ProxyServer proxy) { + this.logger = logger; + this.proxy = proxy; + } + + @Override + public void warning(String s) { + logger.warn(MinecraftToAnsi.convert(s)); + } + + @Override + public void info(String s) { + logger.info(MinecraftToAnsi.convert(s)); + } + + @Override + public void error(Exception e) { + logger.error(MinecraftToAnsi.convert("\u00A7c" + e.getMessage()), e); + } +} diff --git a/velocity/src/main/java/com/sekwah/advancedportals/velocity/connector/MinecraftToAnsi.java b/velocity/src/main/java/com/sekwah/advancedportals/velocity/connector/MinecraftToAnsi.java new file mode 100644 index 00000000..822c5d4e --- /dev/null +++ b/velocity/src/main/java/com/sekwah/advancedportals/velocity/connector/MinecraftToAnsi.java @@ -0,0 +1,55 @@ +package com.sekwah.advancedportals.velocity.connector; + +import java.util.HashMap; +import java.util.Map; + +/** + * I believe later versions of velocity have some component handlers for this, and I could just send it to the server as components + * but ive decided to throw this in for now just to use the plugin logger. Also, to try to clone the bungee behavior as close as possible. + */ +public class MinecraftToAnsi { + + private static final Map minecraftToAnsiMap = new HashMap<>(); + + static { + minecraftToAnsiMap.put('0', "\u001B[30m"); // Black + minecraftToAnsiMap.put('1', "\u001B[34m"); // Dark Blue + minecraftToAnsiMap.put('2', "\u001B[32m"); // Dark Green + minecraftToAnsiMap.put('3', "\u001B[36m"); // Dark Aqua + minecraftToAnsiMap.put('4', "\u001B[31m"); // Dark Red + minecraftToAnsiMap.put('5', "\u001B[35m"); // Dark Purple + minecraftToAnsiMap.put('6', "\u001B[33m"); // Gold + minecraftToAnsiMap.put('7', "\u001B[37m"); // Gray + minecraftToAnsiMap.put('8', "\u001B[90m"); // Dark Gray + minecraftToAnsiMap.put('9', "\u001B[94m"); // Blue + minecraftToAnsiMap.put('a', "\u001B[92m"); // Green + minecraftToAnsiMap.put('b', "\u001B[96m"); // Aqua + minecraftToAnsiMap.put('c', "\u001B[91m"); // Red + minecraftToAnsiMap.put('d', "\u001B[95m"); // Light Purple + minecraftToAnsiMap.put('e', "\u001B[93m"); // Yellow + minecraftToAnsiMap.put('f', "\u001B[97m"); // White + minecraftToAnsiMap.put('k', "\u001B[5m"); // Obfuscated (Blinking) + minecraftToAnsiMap.put('l', "\u001B[1m"); // Bold + minecraftToAnsiMap.put('m', "\u001B[9m"); // Strikethrough + minecraftToAnsiMap.put('n', "\u001B[4m"); // Underline + minecraftToAnsiMap.put('o', "\u001B[3m"); // Italic + minecraftToAnsiMap.put('r', "\u001B[0m"); // Reset + } + + public static String convert(String text) { + StringBuilder result = new StringBuilder(); + for (int i = 0; i < text.length(); i++) { + if (text.charAt(i) == '\u00A7' && i + 1 < text.length()) { + char code = Character.toLowerCase(text.charAt(i + 1)); + String ansiCode = minecraftToAnsiMap.getOrDefault(code, ""); + result.append(ansiCode); + i++; + } else { + result.append(text.charAt(i)); + } + } + + result.append("\u001B[0m"); + return result.toString(); + } +} diff --git a/velocity/src/main/java/com/sekwah/advancedportals/velocity/connector/container/VelocityProxyContainer.java b/velocity/src/main/java/com/sekwah/advancedportals/velocity/connector/container/VelocityProxyContainer.java new file mode 100644 index 00000000..1cd38957 --- /dev/null +++ b/velocity/src/main/java/com/sekwah/advancedportals/velocity/connector/container/VelocityProxyContainer.java @@ -0,0 +1,33 @@ +package com.sekwah.advancedportals.velocity.connector.container; + +import com.sekwah.advancedportals.proxycore.connector.container.ProxyContainer; +import com.sekwah.advancedportals.proxycore.connector.container.ProxyPlayerContainer; +import com.velocitypowered.api.proxy.ProxyServer; +import net.kyori.adventure.text.Component; + +public class VelocityProxyContainer implements ProxyContainer { + private final ProxyServer proxy; + + public VelocityProxyContainer(ProxyServer proxy) { + this.proxy = proxy; + } + + @Override + public void invokeCommand(ProxyPlayerContainer proxyPlayer, String command) { + if(proxyPlayer instanceof VelocityProxyPlayerContainer playerContainer) { + this.proxy.getCommandManager().executeAsync(playerContainer.getPlayer(), command); + } + } + + @Override + public void transferPlayer(ProxyPlayerContainer proxyPlayer, String serverName) { + if(proxyPlayer instanceof VelocityProxyPlayerContainer playerContainer) { + this.proxy.getServer(serverName).ifPresentOrElse( + server -> { + playerContainer.getPlayer().createConnectionRequest(server).fireAndForget(); + }, + () -> playerContainer.getPlayer().sendMessage(Component.text("Could not find server: " + serverName)) + ); + } + } +} diff --git a/velocity/src/main/java/com/sekwah/advancedportals/velocity/connector/container/VelocityProxyPlayerContainer.java b/velocity/src/main/java/com/sekwah/advancedportals/velocity/connector/container/VelocityProxyPlayerContainer.java new file mode 100644 index 00000000..fe80844c --- /dev/null +++ b/velocity/src/main/java/com/sekwah/advancedportals/velocity/connector/container/VelocityProxyPlayerContainer.java @@ -0,0 +1,36 @@ +package com.sekwah.advancedportals.velocity.connector.container; + +import com.sekwah.advancedportals.proxycore.connector.container.ProxyPlayerContainer; +import com.velocitypowered.api.proxy.Player; +import com.velocitypowered.api.proxy.messages.LegacyChannelIdentifier; +import net.kyori.adventure.text.Component; + +public class VelocityProxyPlayerContainer implements ProxyPlayerContainer { + + private final Player player; + private final LegacyChannelIdentifier channel; + + public VelocityProxyPlayerContainer(Player player, LegacyChannelIdentifier channel) { + this.player = player; + this.channel = channel; + } + + @Override + public String getUUID() { + return player.getUniqueId().toString(); + } + + @Override + public String getName() { + return player.getUsername(); + } + + @Override + public void sendServerPluginMessage(byte[] data) { + player.getCurrentServer().ifPresent(serverConnection -> serverConnection.sendPluginMessage(channel, data)); + } + + public Player getPlayer() { + return this.player; + } +} diff --git a/velocity/src/main/java/com/sekwah/advancedportals/velocity/connector/container/VelocityProxyServerContainer.java b/velocity/src/main/java/com/sekwah/advancedportals/velocity/connector/container/VelocityProxyServerContainer.java new file mode 100644 index 00000000..8c8d2447 --- /dev/null +++ b/velocity/src/main/java/com/sekwah/advancedportals/velocity/connector/container/VelocityProxyServerContainer.java @@ -0,0 +1,17 @@ +package com.sekwah.advancedportals.velocity.connector.container; + +import com.sekwah.advancedportals.proxycore.connector.container.ProxyServerContainer; +import com.velocitypowered.api.proxy.server.RegisteredServer; + +public class VelocityProxyServerContainer implements ProxyServerContainer { + private final RegisteredServer server; + + public VelocityProxyServerContainer(RegisteredServer server) { + this.server = server; + } + + @Override + public String getServerName() { + return this.server.getServerInfo().getName(); + } +} diff --git a/version.txt b/version.txt index 2003b639..3eefcb9d 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -0.9.2 +1.0.0