1
0
mirror of https://github.com/GeyserMC/Floodgate.git synced 2025-12-19 14:59:20 +00:00

Initial version of a universal platform

This commit is contained in:
Tim203
2022-09-02 11:39:44 +02:00
parent bc1a98c31a
commit 1a9d07c5c9
40 changed files with 1399 additions and 142 deletions

View File

@@ -28,7 +28,6 @@ object Versions {
const val cumulusVersion = "1.1"
const val eventsVersion = "1.0-SNAPSHOT"
const val configUtilsVersion = "1.0-SNAPSHOT"
const val spigotVersion = "1.13-R0.1-SNAPSHOT"
const val fastutilVersion = "8.5.3"
const val guiceVersion = "5.1.0"
const val nettyVersion = "4.1.49.Final"
@@ -39,4 +38,9 @@ object Versions {
const val javaWebsocketVersion = "1.5.2"
const val checkerQual = "3.19.0"
// Platform versions
const val velocityVersion = "3.1.1"
const val bungeeCommit = "ff5727c"
const val spigotVersion = "1.13-R0.1-SNAPSHOT"
}

View File

@@ -16,7 +16,8 @@ val deployProjects = setOf(
projects.core,
projects.bungee,
projects.spigot,
projects.velocity
projects.velocity,
projects.universal
).map { it.dependencyProject }
//todo re-add checkstyle when we switch back to 2 space indention

View File

@@ -1,4 +1,3 @@
var bungeeCommit = "ff5727c"
var gsonVersion = "2.8.0"
var guavaVersion = "21.0"
@@ -14,7 +13,7 @@ relocate("cloud.commandframework")
relocate("io.leangen.geantyref")
// these dependencies are already present on the platform
provided("com.github.SpigotMC.BungeeCord", "bungeecord-proxy", bungeeCommit)
provided("com.github.SpigotMC.BungeeCord", "bungeecord-proxy", Versions.bungeeCommit)
provided("com.google.code.gson", "gson", gsonVersion)
provided("com.google.guava", "guava", guavaVersion)
provided("org.yaml", "snakeyaml", Versions.snakeyamlVersion)

View File

@@ -0,0 +1,63 @@
/*
* Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Floodgate
*/
package org.geysermc.floodgate;
import com.google.inject.Module;
import net.md_5.bungee.api.plugin.Plugin;
import org.geysermc.floodgate.module.BungeeAddonModule;
import org.geysermc.floodgate.module.BungeeListenerModule;
import org.geysermc.floodgate.module.BungeePlatformModule;
import org.geysermc.floodgate.module.CommandModule;
import org.geysermc.floodgate.module.PluginMessageModule;
import org.geysermc.floodgate.module.ProxyCommonModule;
import org.geysermc.floodgate.util.ReflectionUtils;
public class BungeePlatform extends FloodgatePlatform {
private final Plugin plugin;
public BungeePlatform(Plugin floodgatePlugin) {
this.plugin = floodgatePlugin;
ReflectionUtils.setPrefix("net.md_5.bungee");
}
@Override
protected Module[] loadStageModules() {
return new Module[]{
new ProxyCommonModule(plugin.getDataFolder().toPath()),
new BungeePlatformModule(plugin)
};
}
@Override
protected Module[] postEnableStageModules() {
return new Module[]{
new CommandModule(),
new BungeeListenerModule(),
new BungeeAddonModule(),
new PluginMessageModule()
};
}
}

View File

@@ -25,48 +25,20 @@
package org.geysermc.floodgate;
import com.google.inject.Guice;
import com.google.inject.Injector;
import net.md_5.bungee.api.plugin.Plugin;
import org.geysermc.floodgate.api.logger.FloodgateLogger;
import org.geysermc.floodgate.module.BungeeAddonModule;
import org.geysermc.floodgate.module.BungeeListenerModule;
import org.geysermc.floodgate.module.BungeePlatformModule;
import org.geysermc.floodgate.module.CommandModule;
import org.geysermc.floodgate.module.PluginMessageModule;
import org.geysermc.floodgate.module.ProxyCommonModule;
import org.geysermc.floodgate.util.ReflectionUtils;
public final class BungeePlugin extends Plugin {
private FloodgatePlatform platform;
private BungeePlatform platform;
@Override
public void onLoad() {
ReflectionUtils.setPrefix("net.md_5.bungee");
long ctm = System.currentTimeMillis();
Injector injector = Guice.createInjector(
new ProxyCommonModule(getDataFolder().toPath()),
new BungeePlatformModule(this)
);
// Bungeecord doesn't have a build-in function to disable plugins,
// so there is no need to have a custom Platform class like Spigot
platform = injector.getInstance(FloodgatePlatform.class);
long endCtm = System.currentTimeMillis();
injector.getInstance(FloodgateLogger.class)
.translatedInfo("floodgate.core.finish", endCtm - ctm);
platform = new BungeePlatform(this);
platform.load();
}
@Override
public void onEnable() {
platform.enable(
new CommandModule(),
new BungeeListenerModule(),
new BungeeAddonModule(),
new PluginMessageModule()
);
platform.enable();
}
@Override

View File

@@ -29,12 +29,12 @@ import com.google.inject.Inject;
import lombok.RequiredArgsConstructor;
import net.md_5.bungee.api.ProxyServer;
import net.md_5.bungee.api.plugin.Listener;
import org.geysermc.floodgate.BungeePlugin;
import net.md_5.bungee.api.plugin.Plugin;
import org.geysermc.floodgate.platform.listener.ListenerRegistration;
@RequiredArgsConstructor(onConstructor = @__(@Inject))
public final class BungeeListenerRegistration implements ListenerRegistration<Listener> {
private final BungeePlugin plugin;
private final Plugin plugin;
@Override
public void register(Listener listener) {

View File

@@ -38,7 +38,6 @@ import lombok.RequiredArgsConstructor;
import net.md_5.bungee.api.CommandSender;
import net.md_5.bungee.api.plugin.Listener;
import net.md_5.bungee.api.plugin.Plugin;
import org.geysermc.floodgate.BungeePlugin;
import org.geysermc.floodgate.api.FloodgateApi;
import org.geysermc.floodgate.api.logger.FloodgateLogger;
import org.geysermc.floodgate.inject.CommonPlatformInjector;
@@ -63,7 +62,7 @@ import org.geysermc.floodgate.util.LanguageManager;
@RequiredArgsConstructor
public final class BungeePlatformModule extends AbstractModule {
private final BungeePlugin plugin;
private final Plugin plugin;
@Override
protected void configure() {

View File

@@ -25,39 +25,62 @@
package org.geysermc.floodgate;
import com.google.inject.Guice;
import com.google.inject.Inject;
import com.google.inject.Injector;
import com.google.inject.Module;
import java.util.UUID;
import lombok.AccessLevel;
import lombok.Getter;
import org.geysermc.floodgate.api.FloodgateApi;
import org.geysermc.floodgate.api.InstanceHolder;
import org.geysermc.floodgate.api.handshake.HandshakeHandlers;
import org.geysermc.floodgate.api.inject.PlatformInjector;
import org.geysermc.floodgate.api.link.PlayerLink;
import org.geysermc.floodgate.api.logger.FloodgateLogger;
import org.geysermc.floodgate.api.packet.PacketHandlers;
import org.geysermc.floodgate.config.FloodgateConfig;
import org.geysermc.floodgate.event.EventBus;
import org.geysermc.floodgate.event.PostEnableEvent;
import org.geysermc.floodgate.event.ShutdownEvent;
import org.geysermc.floodgate.module.PostInitializeModule;
import org.geysermc.floodgate.module.PostEnableModules;
public class FloodgatePlatform {
@Getter(AccessLevel.PROTECTED)
public abstract class FloodgatePlatform {
private static final UUID KEY = UUID.randomUUID();
@Inject private PlatformInjector injector;
private PlatformInjector injector;
@Inject private FloodgateConfig config;
private FloodgateConfig config;
@Inject private Injector guice;
@Inject
public void init(
FloodgateApi api,
PlayerLink link,
PacketHandlers packetHandlers,
HandshakeHandlers handshakeHandlers) {
InstanceHolder.set(api, link, this.injector, packetHandlers, handshakeHandlers, KEY);
public void load() {
long startTime = System.currentTimeMillis();
guice = guice != null ?
guice.createChildInjector(loadStageModules()) :
Guice.createInjector(loadStageModules());
config = guice.getInstance(FloodgateConfig.class);
injector = guice.getInstance(PlatformInjector.class);
InstanceHolder.set(
guice.getInstance(FloodgateApi.class),
guice.getInstance(PlayerLink.class),
injector,
guice.getInstance(PacketHandlers.class),
guice.getInstance(HandshakeHandlers.class),
KEY
);
long endTime = System.currentTimeMillis();
guice.getInstance(FloodgateLogger.class)
.translatedInfo("floodgate.core.finish", endTime - startTime);
}
public void enable(Module... postInitializeModules) throws RuntimeException {
protected abstract Module[] loadStageModules();
public void enable() throws RuntimeException {
if (injector == null) {
throw new RuntimeException("Failed to find the platform injector!");
}
@@ -68,11 +91,13 @@ public class FloodgatePlatform {
throw new RuntimeException("Failed to inject the packet listener!", exception);
}
this.guice = guice.createChildInjector(new PostInitializeModule(postInitializeModules));
this.guice = guice.createChildInjector(new PostEnableModules(postEnableStageModules()));
guice.getInstance(EventBus.class).fire(new PostEnableEvent());
}
protected abstract Module[] postEnableStageModules();
public void disable() {
guice.getInstance(EventBus.class).fire(new ShutdownEvent());

View File

@@ -30,7 +30,7 @@ import com.google.inject.Module;
import lombok.RequiredArgsConstructor;
@RequiredArgsConstructor
public final class PostInitializeModule extends AbstractModule {
public final class PostEnableModules extends AbstractModule {
private final Module[] postInitializeModules;
@Override

View File

@@ -68,6 +68,7 @@ include(":core")
include(":bungee")
include(":spigot")
include(":velocity")
include(":universal")
include(":sqlite")
include(":mysql")
include(":mongo")

View File

@@ -0,0 +1,84 @@
/*
* Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Floodgate
*/
package org.geysermc.floodgate;
import com.google.inject.Module;
import org.bukkit.plugin.java.JavaPlugin;
import org.geysermc.floodgate.api.handshake.HandshakeHandlers;
import org.geysermc.floodgate.module.PaperListenerModule;
import org.geysermc.floodgate.module.PluginMessageModule;
import org.geysermc.floodgate.module.ServerCommonModule;
import org.geysermc.floodgate.module.SpigotAddonModule;
import org.geysermc.floodgate.module.SpigotCommandModule;
import org.geysermc.floodgate.module.SpigotListenerModule;
import org.geysermc.floodgate.module.SpigotPlatformModule;
import org.geysermc.floodgate.util.ReflectionUtils;
import org.geysermc.floodgate.util.SpigotHandshakeHandler;
import org.geysermc.floodgate.util.SpigotProtocolSupportHandler;
import org.geysermc.floodgate.util.SpigotProtocolSupportListener;
public class SpigotPlatform extends FloodgatePlatform {
private final JavaPlugin plugin;
public SpigotPlatform(JavaPlugin floodgatePlugin) {
this.plugin = floodgatePlugin;
}
@Override
protected Module[] loadStageModules() {
return new Module[]{
new ServerCommonModule(plugin.getDataFolder().toPath()),
new SpigotPlatformModule(plugin)
};
}
@Override
protected Module[] postEnableStageModules() {
boolean usePaperListener = ReflectionUtils.getClassSilently(
"com.destroystokyo.paper.event.profile.PreFillProfileEvent") != null;
return new Module[]{
new SpigotCommandModule(plugin),
new SpigotAddonModule(),
new PluginMessageModule(),
(usePaperListener ? new PaperListenerModule() : new SpigotListenerModule())
};
}
@Override
public void enable() throws RuntimeException {
super.enable();
getGuice().getInstance(HandshakeHandlers.class)
.addHandshakeHandler(getGuice().getInstance(SpigotHandshakeHandler.class));
// add ProtocolSupport support (hack)
if (plugin.getServer().getPluginManager().getPlugin("ProtocolSupport") != null) {
getGuice().getInstance(SpigotProtocolSupportHandler.class);
SpigotProtocolSupportListener.registerHack(plugin);
}
}
}

View File

@@ -25,68 +25,26 @@
package org.geysermc.floodgate;
import com.google.inject.Guice;
import com.google.inject.Injector;
import org.bukkit.Bukkit;
import org.bukkit.plugin.java.JavaPlugin;
import org.geysermc.floodgate.api.handshake.HandshakeHandlers;
import org.geysermc.floodgate.api.logger.FloodgateLogger;
import org.geysermc.floodgate.module.PaperListenerModule;
import org.geysermc.floodgate.module.PluginMessageModule;
import org.geysermc.floodgate.module.ServerCommonModule;
import org.geysermc.floodgate.module.SpigotAddonModule;
import org.geysermc.floodgate.module.SpigotCommandModule;
import org.geysermc.floodgate.module.SpigotListenerModule;
import org.geysermc.floodgate.module.SpigotPlatformModule;
import org.geysermc.floodgate.util.ReflectionUtils;
import org.geysermc.floodgate.util.SpigotHandshakeHandler;
import org.geysermc.floodgate.util.SpigotProtocolSupportHandler;
import org.geysermc.floodgate.util.SpigotProtocolSupportListener;
public final class SpigotPlugin extends JavaPlugin {
private FloodgatePlatform platform;
private Injector injector;
@Override
public void onLoad() {
long ctm = System.currentTimeMillis();
injector = Guice.createInjector(
new ServerCommonModule(getDataFolder().toPath()),
new SpigotPlatformModule(this)
);
platform = injector.getInstance(FloodgatePlatform.class);
long endCtm = System.currentTimeMillis();
injector.getInstance(FloodgateLogger.class)
.translatedInfo("floodgate.core.finish", endCtm - ctm);
platform = new SpigotPlatform(this);
platform.load();
}
@Override
public void onEnable() {
boolean usePaperListener = ReflectionUtils.getClassSilently(
"com.destroystokyo.paper.event.profile.PreFillProfileEvent") != null;
try {
platform.enable(
new SpigotCommandModule(this),
new SpigotAddonModule(),
new PluginMessageModule(),
(usePaperListener ? new PaperListenerModule() : new SpigotListenerModule())
);
platform.enable();
} catch (Exception exception) {
Bukkit.getPluginManager().disablePlugin(this);
throw exception;
}
injector.getInstance(HandshakeHandlers.class)
.addHandshakeHandler(injector.getInstance(SpigotHandshakeHandler.class));
// add ProtocolSupport support (hack)
if (getServer().getPluginManager().getPlugin("ProtocolSupport") != null) {
injector.getInstance(SpigotProtocolSupportHandler.class);
SpigotProtocolSupportListener.registerHack(this);
}
}
@Override

View File

@@ -36,7 +36,7 @@ import org.bukkit.Bukkit;
import org.bukkit.command.CommandSender;
import org.bukkit.permissions.PermissionDefault;
import org.bukkit.plugin.PluginManager;
import org.geysermc.floodgate.SpigotPlugin;
import org.bukkit.plugin.java.JavaPlugin;
import org.geysermc.floodgate.command.util.Permission;
import org.geysermc.floodgate.platform.command.CommandUtil;
import org.geysermc.floodgate.player.FloodgateCommandPreprocessor;
@@ -44,7 +44,7 @@ import org.geysermc.floodgate.player.UserAudience;
@RequiredArgsConstructor
public final class SpigotCommandModule extends CommandModule {
private final SpigotPlugin plugin;
private final JavaPlugin plugin;
@Override
protected void configure() {

View File

@@ -34,7 +34,6 @@ import java.util.logging.Logger;
import lombok.RequiredArgsConstructor;
import org.bukkit.event.Listener;
import org.bukkit.plugin.java.JavaPlugin;
import org.geysermc.floodgate.SpigotPlugin;
import org.geysermc.floodgate.api.FloodgateApi;
import org.geysermc.floodgate.api.logger.FloodgateLogger;
import org.geysermc.floodgate.inject.CommonPlatformInjector;
@@ -57,7 +56,7 @@ import org.geysermc.floodgate.util.SpigotVersionSpecificMethods;
@RequiredArgsConstructor
public final class SpigotPlatformModule extends AbstractModule {
private final SpigotPlugin plugin;
private final JavaPlugin plugin;
@Override
protected void configure() {

View File

@@ -31,7 +31,7 @@ import com.mojang.authlib.properties.Property;
import com.mojang.authlib.properties.PropertyMap;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.geysermc.floodgate.SpigotPlugin;
import org.bukkit.plugin.java.JavaPlugin;
import org.geysermc.floodgate.api.player.FloodgatePlayer;
import org.geysermc.floodgate.skin.SkinApplier;
import org.geysermc.floodgate.skin.SkinData;
@@ -41,11 +41,11 @@ import org.geysermc.floodgate.util.SpigotVersionSpecificMethods;
public final class SpigotSkinApplier implements SkinApplier {
private final SpigotVersionSpecificMethods versionSpecificMethods;
private final SpigotPlugin plugin;
private final JavaPlugin plugin;
public SpigotSkinApplier(
SpigotVersionSpecificMethods versionSpecificMethods,
SpigotPlugin plugin) {
JavaPlugin plugin) {
this.versionSpecificMethods = versionSpecificMethods;
this.plugin = plugin;
}

View File

@@ -27,7 +27,7 @@ package org.geysermc.floodgate.util;
import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin;
import org.geysermc.floodgate.SpigotPlugin;
import org.bukkit.plugin.java.JavaPlugin;
public final class SpigotVersionSpecificMethods {
private static final boolean NEW_GET_LOCALE;
@@ -41,9 +41,9 @@ public final class SpigotVersionSpecificMethods {
);
}
private final SpigotPlugin plugin;
private final JavaPlugin plugin;
public SpigotVersionSpecificMethods(SpigotPlugin plugin) {
public SpigotVersionSpecificMethods(JavaPlugin plugin) {
this.plugin = plugin;
}

4
universal/.editorconfig Normal file
View File

@@ -0,0 +1,4 @@
[*]
indent_size = 2
tab_width = 2
ij_continuation_indent_size = 4

View File

@@ -0,0 +1,18 @@
import net.kyori.blossom.BlossomExtension
plugins {
id("net.kyori.blossom")
}
provided("com.github.SpigotMC.BungeeCord", "bungeecord-proxy", Versions.bungeeCommit)
provided("com.destroystokyo.paper", "paper-api", Versions.spigotVersion)
provided("com.velocitypowered", "velocity-api", Versions.velocityVersion)
// todo use an isolated class loader in the future
provided("com.google.code.gson", "gson", "2.8.5")
configure<BlossomExtension> {
val constantsFile = "src/main/java/org/geysermc/floodgate/universal/util/Constants.java"
replaceToken("\${branch}", branchName(), constantsFile)
}

View File

@@ -0,0 +1,113 @@
/*
* Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Floodgate
*/
package org.geysermc.floodgate.universal;
import java.nio.file.Files;
import java.nio.file.Path;
import org.geysermc.floodgate.universal.downloader.FloodgateDownloader;
import org.geysermc.floodgate.universal.holder.FloodgateHolder;
import org.geysermc.floodgate.universal.loader.FloodgateLoader;
import org.geysermc.floodgate.universal.loader.FloodgateLoader.LoadResult;
import org.geysermc.floodgate.universal.util.Constants;
import org.geysermc.floodgate.universal.util.Messages;
import org.geysermc.floodgate.universal.util.UniversalLogger;
import org.geysermc.floodgate.universal.version.FloodgateVersion;
import org.geysermc.floodgate.universal.version.FloodgateVersion.VersionResult;
public class UniversalLoader {
private final String platformName;
private final Path dataDirectory;
private final UniversalLogger logger;
private VersionResult currentVersion;
public UniversalLoader(String platformName, Path dataDirectory, UniversalLogger logger) {
this.platformName = platformName;
this.dataDirectory = dataDirectory;
this.logger = logger;
}
public FloodgateHolder start() throws Exception {
LoadResult result = checkDownloadAndLoad();
return new FloodgateHolder(result);
}
private LoadResult checkDownloadAndLoad() throws Exception {
currentVersion = FloodgateVersion.currentVersion(dataDirectory);
boolean cachedPluginFound =
Files.exists(Constants.cachedPluginPath(dataDirectory, platformName));
if (currentVersion == null) {
logger.info(Messages.NOT_CACHED);
return downloadAndLoad();
}
if (Constants.shouldCheck(dataDirectory)) {
logger.info(cachedPluginFound ? Messages.CHECKING : Messages.NOT_CACHED);
return downloadAndLoad();
}
if (!cachedPluginFound) {
logger.warn(Messages.FOUND_BUT_NOT_CACHED);
return downloadAndLoad(null, currentVersion);
}
logger.info(Messages.FOUND_NO_CHECKING);
return load();
}
private LoadResult downloadAndLoad() throws Exception {
VersionResult latestVersion = FloodgateVersion.retrieveLatestVersion(platformName);
return downloadAndLoad(currentVersion, latestVersion);
}
private LoadResult downloadAndLoad(VersionResult currentVersion, VersionResult latestVersion)
throws Exception {
boolean cachedPluginFound = currentVersion != null &&
Files.exists(Constants.cachedPluginPath(dataDirectory, platformName));
if (cachedPluginFound && currentVersion.equals(latestVersion)) {
logger.info(Messages.ON_LATEST);
return load();
}
logger.info(String.format(Messages.DOWNLOADING_NOW, latestVersion.versionIdentifier));
FloodgateDownloader.download(dataDirectory, platformName, latestVersion.downloadUrl);
FloodgateVersion.writeVersion(dataDirectory, latestVersion);
logger.info(String.format(Messages.DOWNLOADED_LATEST, latestVersion.versionIdentifier));
return load();
}
private LoadResult load() throws Exception {
logger.info(String.format(Messages.LOADING_NOW, platformName));
return FloodgateLoader.load(dataDirectory, platformName);
}
}

View File

@@ -0,0 +1,59 @@
/*
* Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Floodgate
*/
package org.geysermc.floodgate.universal.downloader;
import java.io.IOException;
import java.nio.file.Path;
import org.geysermc.floodgate.universal.util.Constants;
import org.geysermc.floodgate.universal.util.FileUtils;
import org.geysermc.floodgate.universal.util.HttpClient;
import org.geysermc.floodgate.universal.util.HttpClient.HttpResponse;
public class FloodgateDownloader {
public static void download(Path dataDirectory, String platformName, String downloadUrl) {
try {
HttpResponse<byte[]> response = HttpClient.getInstance().getRawData(downloadUrl);
if (!response.isCodeOk()) {
throw new RuntimeException(String.format(
"Got an invalid response code (%s) while downloading Floodgate for %s",
response.getHttpCode(), platformName
));
}
FileUtils.writeToPath(
Constants.cachedPluginPath(dataDirectory, platformName),
response.getResponse()
);
} catch (IOException exception) {
throw new RuntimeException(
"Something went wrong while downloading Floodgate for " + platformName,
exception
);
}
}
}

View File

@@ -0,0 +1,71 @@
/*
* Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Floodgate
*/
package org.geysermc.floodgate.universal.holder;
import java.lang.reflect.InvocationTargetException;
import org.geysermc.floodgate.universal.loader.FloodgateLoader.LoadResult;
import org.geysermc.floodgate.universal.loader.LoaderUtils;
public class FloodgateHolder {
private final LoadResult loadResult;
private Object platformInstance;
public FloodgateHolder(LoadResult loadResult) {
this.loadResult = loadResult;
}
public void init(Class<?>[] argumentTypes, Object... argumentValues)
throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
platformInstance = loadResult.pluginClass
.getConstructor(argumentTypes)
.newInstance(argumentValues);
}
public void load() {
LoaderUtils.invokeLoad(platformInstance);
}
public void enable() {
LoaderUtils.invokeEnable(platformInstance);
}
public void disable() {
LoaderUtils.invokeDisable(platformInstance);
closeClassLoader();
}
public void closeClassLoader() {
try {
loadResult.classLoader.close();
} catch (Exception exception) {
throw new RuntimeException(exception);
}
}
public Class<?> platformClass() {
return loadResult.pluginClass;
}
}

View File

@@ -0,0 +1,57 @@
/*
* Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Floodgate
*/
package org.geysermc.floodgate.universal.loader;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.file.Path;
import org.geysermc.floodgate.universal.util.Constants;
public class FloodgateLoader {
public static final class LoadResult {
public final URLClassLoader classLoader;
public final Class<?> pluginClass;
public LoadResult(URLClassLoader classLoader, Class<?> pluginClass) {
this.classLoader = classLoader;
this.pluginClass = pluginClass;
}
}
public static LoadResult load(Path dataDirectory, String platformName) throws Exception {
URL pluginUrl = Constants.cachedPluginPath(dataDirectory, platformName).toUri().toURL();
URLClassLoader loader = new URLClassLoader(
new URL[]{pluginUrl},
FloodgateLoader.class.getClassLoader()
);
String mainClassName = Character.toUpperCase(platformName.charAt(0)) +
platformName.substring(1) + "Platform";
return new LoadResult(loader, loader.loadClass("org.geysermc.floodgate." + mainClassName));
}
}

View File

@@ -0,0 +1,54 @@
/*
* Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Floodgate
*/
package org.geysermc.floodgate.universal.loader;
import java.lang.reflect.InvocationTargetException;
public class LoaderUtils {
public static void invokeLoad(Object floodgatePlatform) {
try {
floodgatePlatform.getClass().getMethod("load").invoke(floodgatePlatform);
} catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException exception) {
throw new RuntimeException(exception);
}
}
public static void invokeEnable(Object floodgatePlatform) {
try {
floodgatePlatform.getClass().getMethod("enable").invoke(floodgatePlatform);
} catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException exception) {
throw new RuntimeException(exception);
}
}
public static void invokeDisable(Object floodgatePlatform) {
try {
floodgatePlatform.getClass().getMethod("disable").invoke(floodgatePlatform);
} catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException exception) {
throw new RuntimeException(exception);
}
}
}

View File

@@ -0,0 +1,53 @@
/*
* Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Floodgate
*/
package org.geysermc.floodgate.universal.logger;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.geysermc.floodgate.universal.util.UniversalLogger;
public class JavaUtilLogger implements UniversalLogger {
private final Logger logger;
public JavaUtilLogger(Logger logger) {
this.logger = logger;
}
@Override
public void info(String message) {
logger.info(message);
}
@Override
public void warn(String message) {
logger.warning(message);
}
@Override
public void error(String message, Throwable throwable) {
logger.log(Level.SEVERE, message, throwable);
}
}

View File

@@ -0,0 +1,51 @@
/*
* Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Floodgate
*/
package org.geysermc.floodgate.universal.logger;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import org.geysermc.floodgate.universal.util.UniversalLogger;
import org.slf4j.Logger;
@Singleton
public class Slf4jLogger implements UniversalLogger {
@Inject private Logger logger;
@Override
public void info(String message) {
logger.info(message);
}
@Override
public void warn(String message) {
logger.warn(message);
}
@Override
public void error(String message, Throwable throwable) {
logger.error(message, throwable);
}
}

View File

@@ -0,0 +1,58 @@
/*
* Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Floodgate
*/
package org.geysermc.floodgate.universal.platform;
import net.md_5.bungee.api.plugin.Plugin;
import org.geysermc.floodgate.universal.UniversalLoader;
import org.geysermc.floodgate.universal.holder.FloodgateHolder;
import org.geysermc.floodgate.universal.logger.JavaUtilLogger;
import org.geysermc.floodgate.universal.util.UniversalLogger;
public class FloodgateBungee extends Plugin {
private FloodgateHolder holder;
@Override
public void onLoad() {
UniversalLogger logger = new JavaUtilLogger(getLogger());
try {
holder = new UniversalLoader("bungee", getDataFolder().toPath(), logger).start();
holder.init(new Class[]{Plugin.class}, this);
holder.load();
} catch (Exception exception) {
throw new RuntimeException("Failed to load Floodgate", exception);
}
}
@Override
public void onEnable() {
holder.enable();
}
@Override
public void onDisable() {
holder.disable();
}
}

View File

@@ -0,0 +1,58 @@
/*
* Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Floodgate
*/
package org.geysermc.floodgate.universal.platform;
import org.bukkit.plugin.java.JavaPlugin;
import org.geysermc.floodgate.universal.UniversalLoader;
import org.geysermc.floodgate.universal.holder.FloodgateHolder;
import org.geysermc.floodgate.universal.logger.JavaUtilLogger;
import org.geysermc.floodgate.universal.util.UniversalLogger;
public class FloodgateSpigot extends JavaPlugin {
private FloodgateHolder holder;
@Override
public void onLoad() {
UniversalLogger logger = new JavaUtilLogger(getLogger());
try {
holder = new UniversalLoader("spigot", getDataFolder().toPath(), logger).start();
holder.init(new Class[]{JavaPlugin.class}, this);
holder.load();
} catch (Exception exception) {
throw new RuntimeException("Failed to load Floodgate", exception);
}
}
@Override
public void onEnable() {
holder.enable();
}
@Override
public void onDisable() {
holder.disable();
}
}

View File

@@ -0,0 +1,56 @@
/*
* Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Floodgate
*/
package org.geysermc.floodgate.universal.platform;
import com.google.inject.Inject;
import com.google.inject.Injector;
import com.velocitypowered.api.event.Subscribe;
import com.velocitypowered.api.event.proxy.ProxyShutdownEvent;
import com.velocitypowered.api.plugin.annotation.DataDirectory;
import java.nio.file.Path;
import org.geysermc.floodgate.universal.UniversalLoader;
import org.geysermc.floodgate.universal.holder.FloodgateHolder;
import org.geysermc.floodgate.universal.logger.Slf4jLogger;
public final class FloodgateVelocity {
private FloodgateHolder holder;
@Inject
public FloodgateVelocity(
@DataDirectory Path dataDirectory,
Slf4jLogger logger,
Injector guice
) throws Exception {
holder = new UniversalLoader("velocity", dataDirectory, logger).start();
// make a child injector so that we're able to do things like reloading in the future
guice.createChildInjector().getInstance(holder.platformClass());
}
@Subscribe
public void onProxyShutdown(ProxyShutdownEvent event) throws Exception {
holder.closeClassLoader();
}
}

View File

@@ -0,0 +1,54 @@
/*
* Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Floodgate
*/
package org.geysermc.floodgate.universal.util;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
public final class Constants {
public static final String GIT_BRANCH = "${branch}";
public static final Path CACHE_PATH = Paths.get("cache");
public static final String PLUGIN_VERSION_FILE_NAME = "plugin_version.json";
public static final String PLUGIN_NAME_FORMAT = "floodgate-%s.jar";
public static Path cachedPluginPath(Path dataDirectory, String platformName) {
return dataDirectory
.resolve(CACHE_PATH)
.resolve(String.format(PLUGIN_NAME_FORMAT, platformName));
}
public static Path cachedPluginVersionPath(Path dataDirectory) {
return dataDirectory
.resolve(CACHE_PATH)
.resolve(PLUGIN_VERSION_FILE_NAME);
}
public static boolean shouldCheck(Path dataDirectory) {
return Files.notExists(dataDirectory.resolve(".no_version_check"));
}
}

View File

@@ -0,0 +1,46 @@
/*
* Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Floodgate
*/
package org.geysermc.floodgate.universal.util;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
public class FileUtils {
public static void writeToPath(Path path, byte[] data) {
try {
Files.createDirectories(path.getParent());
} catch (IOException exception) {
throw new IllegalStateException("Failed to create directories for " + path, exception);
}
try {
Files.write(path, data);
} catch (IOException exception) {
throw new IllegalStateException("Failed to write to path", exception);
}
}
}

View File

@@ -0,0 +1,182 @@
/*
* Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Floodgate
*/
package org.geysermc.floodgate.universal.util;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.SocketTimeoutException;
import java.net.URL;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Getter;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
// Mostly copied from the HttpClient class in the core module
public class HttpClient {
private static final String USER_AGENT = "GeyserMC/Floodgate-Universal";
private static final HttpClient INSTANCE = new HttpClient();
private final Gson gson = new Gson();
public static HttpClient getInstance() {
return INSTANCE;
}
public DefaultHttpResponse get(String urlString) {
return readDefaultResponse(request(urlString));
}
public <T> HttpResponse<T> get(String urlString, Class<T> clazz) {
return readResponse(request(urlString), clazz);
}
public HttpResponse<byte[]> getRawData(String urlString) throws IOException {
HttpURLConnection connection = request(urlString);
try (InputStream inputStream = connection.getInputStream()) {
int responseCode = connection.getResponseCode();
byte[] buffer = new byte[8196];
int len;
try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
while ((len = inputStream.read(buffer, 0, buffer.length)) != -1) {
outputStream.write(buffer, 0, len);
}
return new HttpResponse<>(responseCode, outputStream.toByteArray());
}
} catch (SocketTimeoutException | NullPointerException exception) {
return new HttpResponse<>(-1, null);
}
}
private HttpURLConnection request(String urlString) {
HttpURLConnection connection;
try {
URL url = new URL(urlString.replace(" ", "%20")); // Encode spaces correctly
connection = (HttpURLConnection) url.openConnection();
} catch (Exception exception) {
throw new RuntimeException("Failed to create connection", exception);
}
try {
connection.setRequestMethod("GET");
connection.setUseCaches(false);
connection.setRequestProperty("User-Agent", USER_AGENT);
connection.setConnectTimeout(3000);
connection.setReadTimeout(5000);
} catch (Exception exception) {
throw new RuntimeException("Failed to create request", exception);
}
return connection;
}
@NonNull
private <T> HttpResponse<T> readResponse(HttpURLConnection connection, Class<T> clazz) {
InputStreamReader streamReader = createReader(connection);
if (streamReader == null) {
return new HttpResponse<>(-1, null);
}
try {
int responseCode = connection.getResponseCode();
T response = gson.fromJson(streamReader, clazz);
return new HttpResponse<>(responseCode, response);
} catch (Exception ignored) {
return new HttpResponse<>(-1, null);
} finally {
try {
streamReader.close();
} catch (Exception ignored) {
}
}
}
@NonNull
private DefaultHttpResponse readDefaultResponse(HttpURLConnection connection) {
InputStreamReader streamReader = createReader(connection);
if (streamReader == null) {
return new DefaultHttpResponse(-1, null);
}
try {
int responseCode = connection.getResponseCode();
JsonObject response = gson.fromJson(streamReader, JsonObject.class);
return new DefaultHttpResponse(responseCode, response);
} catch (Exception exception) {
throw new RuntimeException("Failed to read response", exception);
} finally {
try {
streamReader.close();
} catch (Exception ignored) {
}
}
}
@Nullable
private InputStreamReader createReader(HttpURLConnection connection) {
InputStream stream;
try {
stream = connection.getInputStream();
} catch (Exception exception) {
try {
stream = connection.getErrorStream();
} catch (Exception exception1) {
throw new RuntimeException("Both the input and the error stream failed?!");
}
}
// it's null for example when it couldn't connect to the server
if (stream != null) {
return new InputStreamReader(stream);
}
return null;
}
@Getter
@AllArgsConstructor(access = AccessLevel.PRIVATE)
public static class HttpResponse<T> {
private final int httpCode;
private final T response;
public boolean isCodeOk() {
return httpCode >= 200 && httpCode < 300;
}
}
public static final class DefaultHttpResponse extends HttpResponse<JsonObject> {
DefaultHttpResponse(int httpCode, JsonObject response) {
super(httpCode, response);
}
}
}

View File

@@ -0,0 +1,40 @@
/*
* Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Floodgate
*/
package org.geysermc.floodgate.universal.util;
public final class Messages {
public static final String LOADING_NOW = "Loading Floodgate for %s now";
public static final String DOWNLOADING_NOW = "Downloading Floodgate version %s now";
public static final String NOT_CACHED = "Plugin has not been cached";
public static final String CHECKING = "Checking for newer Floodgate versions";
public static final String FOUND_BUT_NOT_CACHED = "Plugin info was found but not cached";
public static final String FOUND_NO_CHECKING = "A version of Floodgate has been cached and checking for updates has been disabled";
public static final String ON_LATEST = "We're on the latest version of Floodgate";
public static final String DOWNLOADED_LATEST = "Floodgate version %s has been downloaded";
}

View File

@@ -0,0 +1,34 @@
/*
* Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Floodgate
*/
package org.geysermc.floodgate.universal.util;
public interface UniversalLogger {
void info(String message);
void warn(String message);
void error(String message, Throwable throwable);
}

View File

@@ -0,0 +1,93 @@
/*
* Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Floodgate
*/
package org.geysermc.floodgate.universal.version;
import com.google.gson.Gson;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import java.io.Reader;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import org.geysermc.floodgate.universal.util.Constants;
import org.geysermc.floodgate.universal.util.FileUtils;
import org.geysermc.floodgate.universal.util.HttpClient;
public final class FloodgateVersion {
private static final Gson GSON = new Gson();
public static final class VersionResult {
public final String versionIdentifier;
public final String downloadUrl;
public VersionResult(String versionIdentifier, String downloadUrl) {
this.versionIdentifier = versionIdentifier;
this.downloadUrl = downloadUrl;
}
@Override
public boolean equals(Object obj) {
return obj instanceof VersionResult && versionIdentifier != null &&
versionIdentifier.equals(((VersionResult) obj).versionIdentifier);
}
}
public static VersionResult currentVersion(Path dataDirectory) throws Exception {
Path pluginVersionPath = Constants.cachedPluginVersionPath(dataDirectory);
if (!Files.exists(pluginVersionPath)) {
return null;
}
Reader reader = Files.newBufferedReader(pluginVersionPath);
return GSON.fromJson(reader, VersionResult.class);
}
public static VersionResult retrieveLatestVersion(String platformName) {
String fullName = String.format(Constants.PLUGIN_NAME_FORMAT, platformName);
JsonObject buildInfo = HttpClient.getInstance().get(String.format(
"https://ci.opencollab.dev/job/GeyserMC/job/Floodgate/job/%s/lastSuccessfulBuild/api/json",
Constants.GIT_BRANCH
)).getResponse();
String downloadUrl = buildInfo.get("url").getAsString() + "artifact/";
for (JsonElement artifactElement : buildInfo.getAsJsonArray("artifacts")) {
JsonObject artifact = artifactElement.getAsJsonObject();
if (artifact.get("fileName").getAsString().equals(fullName)) {
downloadUrl += artifact.get("relativePath").getAsString();
break;
}
}
return new VersionResult(buildInfo.get("number").getAsString(), downloadUrl);
}
public static void writeVersion(Path dataDirectory, VersionResult downloadedVersion) {
FileUtils.writeToPath(
Constants.cachedPluginVersionPath(dataDirectory),
GSON.toJson(downloadedVersion).getBytes(StandardCharsets.UTF_8)
);
}
}

View File

@@ -0,0 +1,5 @@
name: ${name}
description: ${description}
version: ${version}
author: ${author}
main: org.geysermc.floodgate.universal.platform.FloodgateBungee

View File

@@ -0,0 +1,7 @@
name: ${name}
description: ${description}
version: ${version}
author: ${author}
website: ${url}
main: org.geysermc.floodgate.universal.platform.FloodgateSpigot
api-version: 1.13

View File

@@ -0,0 +1 @@
{"id": "${id}", "name": "${name}", "version": "${version}", "description": "${description}", "url": "$url}", "authors": ["${author}"], "main": "org.geysermc.floodgate.universal.platform.FloodgateVelocity"}

View File

@@ -1,4 +1,3 @@
var velocityVersion = "3.1.1"
var log4jVersion = "2.11.2"
var gsonVersion = "2.8.8"
var guavaVersion = "25.1-jre"
@@ -18,5 +17,5 @@ provided("com.google.code.gson", "gson", gsonVersion)
provided("com.google.guava", "guava", guavaVersion)
provided("com.google.inject", "guice", Versions.guiceVersion)
provided("org.yaml", "snakeyaml", Versions.snakeyamlVersion) // included in Configurate
provided("com.velocitypowered", "velocity-api", velocityVersion)
provided("com.velocitypowered", "velocity-api", Versions.velocityVersion)
provided("org.apache.logging.log4j", "log4j-core", log4jVersion)

View File

@@ -0,0 +1,65 @@
/*
* Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Floodgate
*/
package org.geysermc.floodgate;
import com.google.inject.Inject;
import com.google.inject.Module;
import com.velocitypowered.api.plugin.annotation.DataDirectory;
import java.nio.file.Path;
import org.geysermc.floodgate.module.CommandModule;
import org.geysermc.floodgate.module.PluginMessageModule;
import org.geysermc.floodgate.module.ProxyCommonModule;
import org.geysermc.floodgate.module.VelocityAddonModule;
import org.geysermc.floodgate.module.VelocityListenerModule;
import org.geysermc.floodgate.module.VelocityPlatformModule;
import org.geysermc.floodgate.util.ReflectionUtils;
public class VelocityPlatform extends FloodgatePlatform {
@Inject
private @DataDirectory Path dataDirectory;
public VelocityPlatform() {
ReflectionUtils.setPrefix("com.velocitypowered.proxy");
}
@Override
protected Module[] loadStageModules() {
return new Module[]{
new ProxyCommonModule(dataDirectory),
new VelocityPlatformModule(getGuice())
};
}
@Override
protected Module[] postEnableStageModules() {
return new Module[]{
new CommandModule(),
new VelocityListenerModule(),
new VelocityAddonModule(),
new PluginMessageModule()
};
}
}

View File

@@ -30,45 +30,19 @@ import com.google.inject.Injector;
import com.velocitypowered.api.event.Subscribe;
import com.velocitypowered.api.event.proxy.ProxyInitializeEvent;
import com.velocitypowered.api.event.proxy.ProxyShutdownEvent;
import com.velocitypowered.api.plugin.annotation.DataDirectory;
import java.nio.file.Path;
import org.geysermc.floodgate.api.logger.FloodgateLogger;
import org.geysermc.floodgate.module.CommandModule;
import org.geysermc.floodgate.module.PluginMessageModule;
import org.geysermc.floodgate.module.ProxyCommonModule;
import org.geysermc.floodgate.module.VelocityAddonModule;
import org.geysermc.floodgate.module.VelocityListenerModule;
import org.geysermc.floodgate.module.VelocityPlatformModule;
import org.geysermc.floodgate.util.ReflectionUtils;
public final class VelocityPlugin {
private final FloodgatePlatform platform;
private final VelocityPlatform platform;
@Inject
public VelocityPlugin(@DataDirectory Path dataDirectory, Injector guice) {
ReflectionUtils.setPrefix("com.velocitypowered.proxy");
long ctm = System.currentTimeMillis();
Injector injector = guice.createChildInjector(
new ProxyCommonModule(dataDirectory),
new VelocityPlatformModule(guice)
);
platform = injector.getInstance(FloodgatePlatform.class);
long endCtm = System.currentTimeMillis();
injector.getInstance(FloodgateLogger.class)
.translatedInfo("floodgate.core.finish", endCtm - ctm);
public VelocityPlugin(Injector guice) {
platform = guice.getInstance(VelocityPlatform.class);
platform.load();
}
@Subscribe
public void onProxyInitialization(ProxyInitializeEvent event) {
platform.enable(
new CommandModule(),
new VelocityListenerModule(),
new VelocityAddonModule(),
new PluginMessageModule()
);
platform.enable();
}
@Subscribe