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

Merge remote-tracking branch 'origin/master' into feature/micronaut-inject

# Conflicts:
#	build-logic/src/main/kotlin/Versions.kt
#	bungee/build.gradle.kts
#	core/build.gradle.kts
#	core/src/main/java/org/geysermc/floodgate/core/util/Metrics.java
#	database/mysql/build.gradle.kts
#	spigot/src/main/java/org/geysermc/floodgate/spigot/pluginmessage/SpigotSkinApplier.java
#	spigot/src/main/resources/plugin.yml
This commit is contained in:
Tim203
2023-05-03 11:26:05 +02:00
17 changed files with 138 additions and 57 deletions

View File

@@ -13,47 +13,58 @@ jobs:
- uses: actions/setup-java@v3
with:
java-version: 8
java-version: 17
distribution: temurin
cache: gradle
- name: Build
uses: gradle/gradle-build-action@v2
with:
arguments: build
cache-read-only: ${{ github.ref_name != 'master' && github.ref_name != 'development' }}
- name: Publish to Maven Repository
if: ${{ job.status == 'success' && github.repository == 'GeyserMC/Floodgate' }}
if: ${{ github.repository == 'GeyserMC/Floodgate' }}
uses: gradle/gradle-build-action@v2
env:
ORG_GRADLE_PROJECT_geysermcUsername: ${{ vars.DEPLOY_USER }}
ORG_GRADLE_PROJECT_geysermcPassword: ${{ secrets.DEPLOY_PASS }}
with:
arguments: publish
cache-read-only: ${{ github.ref_name != 'master' && github.ref_name != 'development' }}
- name: Publish to Downloads API
if: ${{ github.ref_name == 'master' && job.status == 'success' && github.repository == 'GeyserMC/Floodgate' }}
if: ${{ github.ref_name == 'master' && github.repository == 'GeyserMC/Floodgate' }}
shell: bash
env:
DOWNLOADS_USERNAME: ${{ vars.DOWNLOADS_USERNAME }}
DOWNLOADS_PRIVATE_KEY: ${{ secrets.DOWNLOADS_PRIVATE_KEY }}
DOWNLOADS_SERVER_IP: ${{ secrets.DOWNLOADS_SERVER_IP }}
run: |
# Save the private key to a file
echo "$DOWNLOADS_PRIVATE_KEY" > id_ecdsa
chmod 600 id_ecdsa
# Set the project
project=floodgate
# Get the version from gradle.properties
version=$(cat gradle.properties | grep -o "version=[0-9\\.]*" | cut -d"=" -f2)
# Create the build folder
ssh -o StrictHostKeyChecking=no -i id_ecdsa $DOWNLOADS_USERNAME@$DOWNLOADS_SERVER_IP mkdir -p "~/uploads/$project/$GITHUB_RUN_NUMBER/"
# Copy over artifacts
scp -B -o StrictHostKeyChecking=no -i id_ecdsa **/build/libs/floodgate-*.jar $DOWNLOADS_USERNAME@$DOWNLOADS_SERVER_IP:~/files/
rsync -P -e "ssh -o StrictHostKeyChecking=no -i id_ecdsa" **/build/libs/floodgate-*.jar $DOWNLOADS_USERNAME@$DOWNLOADS_SERVER_IP:~/uploads/$project/$GITHUB_RUN_NUMBER/
# Remove un-needed artifacts
ssh -o StrictHostKeyChecking=no -i id_ecdsa $DOWNLOADS_USERNAME@$DOWNLOADS_SERVER_IP rm ~/files/floodgate-parent-*.jar ~/files/floodgate-api.jar ~/files/floodgate-core.jar
ssh -o StrictHostKeyChecking=no -i id_ecdsa $DOWNLOADS_USERNAME@$DOWNLOADS_SERVER_IP rm ./uploads/$project/$GITHUB_RUN_NUMBER/floodgate-api.jar ./uploads/$project/$GITHUB_RUN_NUMBER/floodgate-core.jar
# Run the build script
ssh -o StrictHostKeyChecking=no -i id_ecdsa $DOWNLOADS_USERNAME@$DOWNLOADS_SERVER_IP ./handleBuild.sh floodgate $version $GITHUB_RUN_ID $GITHUB_SHA
# Push the metadata
echo "{\"project\": \"$project\", \"version\": \"$version\", \"id\": $GITHUB_RUN_NUMBER, \"commit\": \"$GITHUB_SHA\"}" > metadata.json
rsync -P -e "ssh -o StrictHostKeyChecking=no -i id_ecdsa" metadata.json $DOWNLOADS_USERNAME@$DOWNLOADS_SERVER_IP:~/uploads/$project/$GITHUB_RUN_NUMBER/
- name: Notify Discord
if: ${{ github.repository == 'GeyserMC/Floodgate' }}
if: ${{ (success() || failure()) && github.repository == 'GeyserMC/Floodgate' }}
uses: Tim203/actions-git-discord-webhook@main
with:
webhook_url: ${{ secrets.DISCORD_WEBHOOK }}
status: ${{ job.status }}

View File

@@ -10,11 +10,11 @@ jobs:
steps:
- uses: actions/checkout@v2
- name: Set up JDK 1.8
- name: Set up JDK 17
uses: actions/setup-java@v2
with:
distribution: 'temurin'
java-version: '8'
java-version: '17'
cache: 'gradle'
- name: Build with Maven

2
Jenkinsfile vendored
View File

@@ -2,7 +2,7 @@ pipeline {
agent any
tools {
gradle 'Gradle 7'
jdk 'Java 8'
jdk 'Java 17'
}
options {
buildDiscarder(logRotator(artifactNumToKeepStr: '5'))

View File

@@ -33,7 +33,7 @@ object Versions {
const val nettyVersion = "4.1.49.Final"
const val snakeyamlVersion = "2.0"
const val cloudVersion = "1.5.0"
const val bstatsVersion = "3.0.1"
const val bstatsVersion = "3.0.2"
const val javaWebsocketVersion = "1.5.2"
@@ -41,6 +41,5 @@ object Versions {
// Platform versions
const val velocityVersion = "3.1.1"
const val bungeeCommit = "ff5727c"
const val spigotVersion = "1.13-R0.1-SNAPSHOT"
const val spigotVersion = "1.19.4-R0.1-SNAPSHOT"
}

View File

@@ -10,6 +10,6 @@ indra {
}
}
publishSnapshotsTo("geysermc", "https://repo.opencollab.dev/artifactory/maven-snapshots")
publishReleasesTo("geysermc", "https://repo.opencollab.dev/artifactory/maven-releases")
publishSnapshotsTo("geysermc", "https://repo.opencollab.dev/maven-snapshots")
publishReleasesTo("geysermc", "https://repo.opencollab.dev/maven-releases")
}

View File

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

View File

@@ -36,6 +36,7 @@ import lombok.Getter;
import lombok.RequiredArgsConstructor;
import net.md_5.bungee.netty.PipelineUtils;
import net.md_5.bungee.protocol.MinecraftEncoder;
import net.md_5.bungee.protocol.Varint21LengthFieldExtraBufPrepender;
import net.md_5.bungee.protocol.Varint21LengthFieldPrepender;
import org.geysermc.floodgate.api.logger.FloodgateLogger;
import org.geysermc.floodgate.bungee.util.BungeeReflectionUtils;
@@ -54,6 +55,16 @@ public final class BungeeInjector extends CommonPlatformInjector {
public void inject() {
// Can everyone just switch to Velocity please :)
// Newer Bungee versions have a separate prepender for backend and client connections
Field serverFramePrepender =
ReflectionUtils.getField(PipelineUtils.class, "serverFramePrepender");
if (serverFramePrepender != null) {
BungeeCustomServerPrepender customServerPrepender = new BungeeCustomServerPrepender(
this, ReflectionUtils.castedStaticValue(serverFramePrepender)
);
BungeeReflectionUtils.setFieldValue(null, serverFramePrepender, customServerPrepender);
}
Field framePrepender = ReflectionUtils.getField(PipelineUtils.class, "framePrepender");
// Required in order to inject into both Geyser <-> proxy AND proxy <-> server
@@ -121,6 +132,22 @@ public final class BungeeInjector extends CommonPlatformInjector {
}
}
@RequiredArgsConstructor
private static final class BungeeCustomServerPrepender
extends Varint21LengthFieldExtraBufPrepender {
private final BungeeInjector injector;
private final Varint21LengthFieldExtraBufPrepender original;
@Override
public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
original.handlerAdded(ctx);
// The Minecraft encoder being in the pipeline isn't present until later
// Proxy <-> Server
ctx.pipeline().addLast(BUNGEE_INIT, new BungeeProxyToServerInjectInitializer(injector));
}
}
@RequiredArgsConstructor
private static final class BungeeClientToProxyInjectInitializer
extends ChannelInboundHandlerAdapter {

View File

@@ -27,6 +27,7 @@ package org.geysermc.floodgate.core.pluginmessage.channel;
import com.google.common.base.Charsets;
import it.unimi.dsi.fastutil.shorts.Short2ObjectMap;
import it.unimi.dsi.fastutil.shorts.Short2ObjectMaps;
import it.unimi.dsi.fastutil.shorts.Short2ObjectOpenHashMap;
import jakarta.inject.Inject;
import java.util.UUID;
@@ -41,7 +42,8 @@ import org.geysermc.floodgate.core.pluginmessage.PluginMessageChannel;
public class FormChannel implements PluginMessageChannel {
private final FormDefinitions formDefinitions = FormDefinitions.instance();
private final Short2ObjectMap<Form> storedForms = new Short2ObjectOpenHashMap<>();
private final Short2ObjectMap<Form> storedForms =
Short2ObjectMaps.synchronize(new Short2ObjectOpenHashMap<>());
private final AtomicInteger nextFormId = new AtomicInteger(0);
@Inject PluginMessageUtils pluginMessageUtils;

View File

@@ -25,6 +25,7 @@
package org.geysermc.floodgate.core.util;
import io.micronaut.runtime.event.annotation.EventListener;
import jakarta.inject.Inject;
import jakarta.inject.Named;
import jakarta.inject.Singleton;
@@ -43,6 +44,7 @@ import org.geysermc.floodgate.api.FloodgateApi;
import org.geysermc.floodgate.api.logger.FloodgateLogger;
import org.geysermc.floodgate.core.config.FloodgateConfig;
import org.geysermc.floodgate.core.config.FloodgateConfig.MetricsConfig;
import org.geysermc.floodgate.core.event.lifecycle.ShutdownEvent;
import org.geysermc.floodgate.core.platform.util.PlatformUtils;
@Singleton
@@ -150,4 +152,9 @@ public final class Metrics {
builder.appendField("osVersion", System.getProperty("os.version"));
builder.appendField("coreCount", Runtime.getRuntime().availableProcessors());
}
@EventListener
public void onShutdown(ShutdownEvent ignored) {
metricsBase.shutdown();
}
}

View File

@@ -21,13 +21,7 @@ dependencyResolutionManagement {
// maven("https://repo.papermc.io/repository/maven-snapshots") {
// mavenContent { snapshotsOnly() }
// }
maven("https://repo.papermc.io/repository/maven-public") {
content {
includeGroupByRegex(
"(io\\.papermc\\..*|com\\.destroystokyo\\..*|com\\.velocitypowered)"
)
}
}
maven("https://repo.papermc.io/repository/maven-public")
// Spigot
maven("https://hub.spigotmc.org/nexus/content/repositories/snapshots") {
mavenContent { snapshotsOnly() }

View File

@@ -2,12 +2,26 @@ var authlibVersion = "1.5.21"
var guavaVersion = "21.0"
var gsonVersion = "2.8.5"
indra {
javaVersions {
// For Folia
target(8)
minimumToolchain(17)
}
}
dependencies {
api(projects.core)
implementation("cloud.commandframework", "cloud-bukkit", Versions.cloudVersion)
// hack to make pre 1.12 work
implementation("com.google.guava", "guava", guavaVersion)
compileOnlyApi("dev.folia", "folia-api", Versions.spigotVersion) {
attributes {
attribute(TargetJvmVersion.TARGET_JVM_VERSION_ATTRIBUTE, 17)
}
}
}
relocate("com.google.inject")
@@ -21,7 +35,6 @@ relocate("com.google.guava")
relocate("it.unimi")
// these dependencies are already present on the platform
provided("com.destroystokyo.paper", "paper-api", Versions.spigotVersion)
provided("com.mojang", "authlib", authlibVersion)
provided("io.netty", "netty-transport", Versions.nettyVersion)
provided("io.netty", "netty-codec", Versions.nettyVersion)

View File

@@ -85,7 +85,7 @@ public final class SpigotPlatformModule extends AbstractModule {
SpigotVersionSpecificMethods versionSpecificMethods,
LanguageManager languageManager) {
return new SpigotCommandUtil(
languageManager, plugin.getServer(), api, versionSpecificMethods, plugin);
languageManager, plugin.getServer(), api, versionSpecificMethods);
}
@Provides

View File

@@ -32,7 +32,6 @@ import jakarta.inject.Inject;
import jakarta.inject.Singleton;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.plugin.java.JavaPlugin;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.geysermc.floodgate.api.event.skin.SkinApplyEvent;
import org.geysermc.floodgate.api.event.skin.SkinApplyEvent.SkinData;
@@ -48,7 +47,6 @@ import org.geysermc.floodgate.spigot.util.SpigotVersionSpecificMethods;
@Singleton
public final class SpigotSkinApplier implements SkinApplier {
@Inject SpigotVersionSpecificMethods versionSpecificMethods;
@Inject JavaPlugin plugin;
@Inject EventBus eventBus;
@Override
@@ -62,8 +60,7 @@ public final class SpigotSkinApplier implements SkinApplier {
// player is probably not logged in yet
if (player == null) {
if (firstTry) {
Bukkit.getScheduler().runTaskLater(
plugin,
versionSpecificMethods.schedule(
() -> applySkin0(floodgatePlayer, skinData, false),
10 * 20
);
@@ -94,12 +91,10 @@ public final class SpigotSkinApplier implements SkinApplier {
replaceSkin(properties, event.newSkin());
// By running as a task, we don't run into async issues
plugin.getServer().getScheduler().runTask(plugin, () -> {
versionSpecificMethods.maybeSchedule(() -> {
for (Player p : Bukkit.getOnlinePlayers()) {
if (!p.equals(player) && p.canSee(player)) {
versionSpecificMethods.hidePlayer(p, player);
versionSpecificMethods.showPlayer(p, player);
versionSpecificMethods.hideAndShowPlayer(p, player);
}
}
});

View File

@@ -79,6 +79,8 @@ public class ClassNames {
public static final Field BUNGEE;
public static final boolean IS_FOLIA;
static {
String version = Bukkit.getServer().getClass().getPackage().getName().split("\\.")[3];
SPIGOT_MAPPING_PREFIX = "net.minecraft.server." + version;
@@ -224,6 +226,10 @@ public class ClassNames {
PAPER_VELOCITY_SUPPORT = null;
}
}
IS_FOLIA = ReflectionUtils.getClassSilently(
"io.papermc.paper.threadedregions.scheduler.EntityScheduler"
) != null;
}
private static <T> T checkNotNull(@CheckForNull T toCheck, @CheckForNull String objectName) {

View File

@@ -27,11 +27,9 @@ package org.geysermc.floodgate.spigot.util;
import java.util.Collection;
import java.util.UUID;
import org.bukkit.Bukkit;
import org.bukkit.Server;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.plugin.java.JavaPlugin;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.geysermc.floodgate.api.FloodgateApi;
import org.geysermc.floodgate.core.platform.command.CommandUtil;
@@ -43,19 +41,17 @@ import org.geysermc.floodgate.core.util.LanguageManager;
public final class SpigotCommandUtil extends CommandUtil {
private final Server server;
private final SpigotVersionSpecificMethods versionSpecificMethods;
private final JavaPlugin plugin;
private UserAudience console;
public SpigotCommandUtil(
LanguageManager manager,
Server server,
FloodgateApi api,
SpigotVersionSpecificMethods versionSpecificMethods,
JavaPlugin plugin) {
SpigotVersionSpecificMethods versionSpecificMethods
) {
super(manager, api);
this.server = server;
this.versionSpecificMethods = versionSpecificMethods;
this.plugin = plugin;
}
@Override
@@ -121,7 +117,7 @@ public final class SpigotCommandUtil extends CommandUtil {
public void kickPlayer(Object player, String message) {
// can also be console
if (player instanceof Player) {
Bukkit.getScheduler().runTask(plugin, () -> ((Player) player).kickPlayer(message));
versionSpecificMethods.schedule(() -> ((Player) player).kickPlayer(message), 0);
}
}

View File

@@ -25,17 +25,22 @@
package org.geysermc.floodgate.spigot.util;
import java.lang.reflect.Method;
import java.util.concurrent.TimeUnit;
import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.java.JavaPlugin;
import org.geysermc.floodgate.core.util.ReflectionUtils;
public final class SpigotVersionSpecificMethods {
private static final boolean NEW_GET_LOCALE;
private static final Method GET_SPIGOT;
private static final Method OLD_GET_LOCALE;
private static final boolean NEW_VISIBILITY;
static {
NEW_GET_LOCALE = ReflectionUtils.getMethod(Player.class, "getLocale") != null;
GET_SPIGOT = ReflectionUtils.getMethod(Player.class, "spigot");
OLD_GET_LOCALE = ReflectionUtils.getMethod(Player.Spigot.class, "getLocale");
NEW_VISIBILITY = null != ReflectionUtils.getMethod(
Player.class, "hidePlayer",
Plugin.class, Player.class
@@ -49,27 +54,51 @@ public final class SpigotVersionSpecificMethods {
}
public String getLocale(Player player) {
if (NEW_GET_LOCALE) {
if (OLD_GET_LOCALE == null) {
return player.getLocale();
}
return player.spigot().getLocale();
Object spigot = ReflectionUtils.invoke(player, GET_SPIGOT);
return ReflectionUtils.castedInvoke(spigot, OLD_GET_LOCALE);
}
public void hideAndShowPlayer(Player on, Player target) {
// In Folia we don't have to schedule this as there is no concept of a single main thread.
// Instead, we have to schedule the task per player.
if (ClassNames.IS_FOLIA) {
on.getScheduler().execute(plugin, () -> hideAndShowPlayer0(on, target), null, 0);
return;
}
hideAndShowPlayer0(on, target);
}
public void schedule(Runnable runnable, long delay) {
if (ClassNames.IS_FOLIA) {
plugin.getServer().getAsyncScheduler().runDelayed(
plugin, $ -> runnable.run(), delay * 50, TimeUnit.MILLISECONDS
);
return;
}
plugin.getServer().getScheduler().runTaskLater(plugin, runnable, delay);
}
@SuppressWarnings("deprecation")
public void hidePlayer(Player hideFor, Player playerToHide) {
private void hideAndShowPlayer0(Player source, Player target) {
if (NEW_VISIBILITY) {
hideFor.hidePlayer(plugin, playerToHide);
source.hidePlayer(plugin, target);
source.showPlayer(plugin, target);
return;
}
hideFor.hidePlayer(playerToHide);
source.hidePlayer(target);
source.showPlayer(target);
}
@SuppressWarnings("deprecation")
public void showPlayer(Player showFor, Player playerToShow) {
if (NEW_VISIBILITY) {
showFor.showPlayer(plugin, playerToShow);
public void maybeSchedule(Runnable runnable) {
// In Folia we don't have to schedule this as there is no concept of a single main thread.
// Instead, we have to schedule the task per player.
if (ClassNames.IS_FOLIA) {
runnable.run();
return;
}
showFor.showPlayer(playerToShow);
plugin.getServer().getScheduler().runTask(plugin, runnable);
}
}

View File

@@ -4,4 +4,5 @@ version: ${version}
author: ${author}
website: ${url}
main: org.geysermc.floodgate.spigot.SpigotPlugin
api-version: 1.13
api-version: 1.13
folia-supported: true