diff --git a/bootstrap/standalone/src/main/java/org/geysermc/geyser/platform/standalone/GeyserStandaloneBootstrap.java b/bootstrap/standalone/src/main/java/org/geysermc/geyser/platform/standalone/GeyserStandaloneBootstrap.java index 1efbbac805d..3c4349ec353 100644 --- a/bootstrap/standalone/src/main/java/org/geysermc/geyser/platform/standalone/GeyserStandaloneBootstrap.java +++ b/bootstrap/standalone/src/main/java/org/geysermc/geyser/platform/standalone/GeyserStandaloneBootstrap.java @@ -180,9 +180,6 @@ public void onGeyserEnable() { // Event must be fired after CommandRegistry has subscribed its listener. // Also, the subscription for the Permissions class is created when Geyser is initialized. cloud.fireRegisterPermissionsEvent(); - } else { - // This isn't ideal - but geyserLogger#start won't ever finish, leading to a reloading deadlock - geyser.setReloading(false); } if (gui != null) { @@ -191,7 +188,10 @@ public void onGeyserEnable() { geyserPingPassthrough = GeyserLegacyPingPassthrough.init(geyser); - geyserLogger.start(); + if (!reloading) { + // Only start logger once; no need to re-start it on reload + geyserLogger.start(); + } } @Override diff --git a/core/src/main/java/org/geysermc/geyser/GeyserImpl.java b/core/src/main/java/org/geysermc/geyser/GeyserImpl.java index 536a54f3e65..9461141ccee 100644 --- a/core/src/main/java/org/geysermc/geyser/GeyserImpl.java +++ b/core/src/main/java/org/geysermc/geyser/GeyserImpl.java @@ -312,7 +312,7 @@ private void startInstance() { GeyserLogger logger = bootstrap.getGeyserLogger(); GeyserConfig config = bootstrap.config(); - ScoreboardUpdater.init(); + ScoreboardUpdater.init(this); SkinProvider.registerCacheImageTask(this); @@ -668,6 +668,7 @@ private void startInstance() { newsHandler.handleNews(null, NewsItemAction.ON_SERVER_STARTED); if (isReloading) { + isReloading = false; this.eventBus.fire(new GeyserPostReloadEvent(this.extensionManager, this.eventBus)); } else { this.eventBus.fire(new GeyserPostInitializeEvent(this.extensionManager, this.eventBus)); @@ -743,6 +744,7 @@ public void disable() { bootstrap.getGeyserLogger().info(GeyserLocale.getLocaleStringLog("geyser.core.shutdown.kick.done")); } + runIfNonNull(metrics, MetricsBase::shutdown); runIfNonNull(scheduledThread, ScheduledExecutorService::shutdown); runIfNonNull(geyserServer, GeyserServer::shutdown); runIfNonNull(skinUploader, FloodgateSkinUploader::close); @@ -778,8 +780,6 @@ public void reloadGeyser() { bootstrap.onGeyserDisable(); bootstrap.onGeyserEnable(); - - isReloading = false; } /** diff --git a/core/src/main/java/org/geysermc/geyser/ping/GeyserLegacyPingPassthrough.java b/core/src/main/java/org/geysermc/geyser/ping/GeyserLegacyPingPassthrough.java index aeae1d90142..08b6cf6c02b 100644 --- a/core/src/main/java/org/geysermc/geyser/ping/GeyserLegacyPingPassthrough.java +++ b/core/src/main/java/org/geysermc/geyser/ping/GeyserLegacyPingPassthrough.java @@ -32,6 +32,9 @@ import org.checkerframework.checker.nullness.qual.Nullable; import org.cloudburstmc.nbt.util.VarInts; import org.geysermc.geyser.GeyserImpl; +import org.geysermc.geyser.api.event.EventRegistrar; +import org.geysermc.geyser.api.event.lifecycle.GeyserPostInitializeEvent; +import org.geysermc.geyser.api.event.lifecycle.GeyserPostReloadEvent; import org.geysermc.geyser.network.GameProtocol; import org.geysermc.geyser.util.JsonUtils; @@ -47,7 +50,7 @@ import java.net.SocketTimeoutException; import java.net.UnknownHostException; -public class GeyserLegacyPingPassthrough extends Thread implements IGeyserPingPassthrough, Runnable { +public class GeyserLegacyPingPassthrough extends Thread implements IGeyserPingPassthrough, Runnable, EventRegistrar { private static final byte[] HAPROXY_BINARY_PREFIX = new byte[]{13, 10, 13, 10, 0, 13, 10, 81, 85, 73, 84, 10}; private final GeyserImpl geyser; @@ -73,12 +76,23 @@ public GeyserLegacyPingPassthrough(GeyserImpl geyser, int interval) { GeyserLegacyPingPassthrough pingPassthrough = new GeyserLegacyPingPassthrough(geyser, interval); pingPassthrough.setName("Geyser LegacyPingPassthrough Thread"); pingPassthrough.setDaemon(true); - pingPassthrough.start(); + if (geyser.isReloading()) { + geyser.eventBus().subscribe(pingPassthrough, GeyserPostReloadEvent.class, (ignored) -> pingPassthrough.start()); + } else { + geyser.eventBus().subscribe(pingPassthrough, GeyserPostInitializeEvent.class, (ignored) -> pingPassthrough.start()); + } return pingPassthrough; } return null; } + @Override + public void start() { + // Already started, no need to keep the subscription + geyser.eventBus().unregisterAll(this); + super.start(); + } + @Override public GeyserPingInfo getPingInformation(InetSocketAddress inetSocketAddress) { return pingInfo; diff --git a/core/src/main/java/org/geysermc/geyser/scoreboard/ScoreboardUpdater.java b/core/src/main/java/org/geysermc/geyser/scoreboard/ScoreboardUpdater.java index 19c5e64f0b8..e0ab4d38a4a 100644 --- a/core/src/main/java/org/geysermc/geyser/scoreboard/ScoreboardUpdater.java +++ b/core/src/main/java/org/geysermc/geyser/scoreboard/ScoreboardUpdater.java @@ -28,7 +28,9 @@ import lombok.Getter; import lombok.RequiredArgsConstructor; import org.geysermc.geyser.GeyserImpl; -import org.geysermc.geyser.configuration.GeyserConfig; +import org.geysermc.geyser.api.event.EventRegistrar; +import org.geysermc.geyser.api.event.lifecycle.GeyserPostInitializeEvent; +import org.geysermc.geyser.api.event.lifecycle.GeyserPostReloadEvent; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.cache.WorldCache; import org.geysermc.geyser.text.GeyserLocale; @@ -36,28 +38,39 @@ import java.util.Collection; import java.util.concurrent.atomic.AtomicInteger; -public final class ScoreboardUpdater extends Thread { - public static final int FIRST_SCORE_PACKETS_PER_SECOND_THRESHOLD; - public static final int SECOND_SCORE_PACKETS_PER_SECOND_THRESHOLD = 250; +public final class ScoreboardUpdater extends Thread implements EventRegistrar { private static final int FIRST_MILLIS_BETWEEN_UPDATES = 250; // 4 updates per second private static final int SECOND_MILLIS_BETWEEN_UPDATES = 1000; // 1 update per second + public static final int SECOND_SCORE_PACKETS_PER_SECOND_THRESHOLD = 250; + public static int firstScorePacketsPerSecondThreshold; + private final boolean debugEnabled; - private static final boolean DEBUG_ENABLED; + private final GeyserImpl geyser; + private long lastUpdate = System.currentTimeMillis(); + private long lastPacketsPerSecondUpdate = System.currentTimeMillis(); - static { - GeyserConfig config = GeyserImpl.getInstance().config(); - FIRST_SCORE_PACKETS_PER_SECOND_THRESHOLD = Math.min(config.advanced().scoreboardPacketThreshold(), SECOND_SCORE_PACKETS_PER_SECOND_THRESHOLD); - DEBUG_ENABLED = config.debugMode(); + public ScoreboardUpdater(GeyserImpl geyser) { + this.geyser = geyser; + firstScorePacketsPerSecondThreshold = Math.min(geyser.config().advanced().scoreboardPacketThreshold(), SECOND_SCORE_PACKETS_PER_SECOND_THRESHOLD); + this.debugEnabled = geyser.config().debugMode(); } - private final GeyserImpl geyser = GeyserImpl.getInstance(); - - private long lastUpdate = System.currentTimeMillis(); - private long lastPacketsPerSecondUpdate = System.currentTimeMillis(); + public static void init(GeyserImpl geyser) { + ScoreboardUpdater updater = new ScoreboardUpdater(geyser); + updater.setName("Geyser Scoreboard Updater Thread"); + updater.setDaemon(true); + if (geyser.isReloading()) { + geyser.eventBus().subscribe(updater, GeyserPostReloadEvent.class, (ignored) -> updater.start()); + } else { + geyser.eventBus().subscribe(updater, GeyserPostInitializeEvent.class, (ignored) -> updater.start()); + } + } - public static void init() { - new ScoreboardUpdater().start(); + @Override + public void start() { + geyser.eventBus().unregisterAll(this); + super.start(); } @Override @@ -86,8 +99,8 @@ public void run() { scoreboardSession.pendingPacketsPerSecond.set(0); // just making sure that all updates are pushed before giving up control - if (oldPps >= FIRST_SCORE_PACKETS_PER_SECOND_THRESHOLD && - newPps < FIRST_SCORE_PACKETS_PER_SECOND_THRESHOLD) { + if (oldPps >= firstScorePacketsPerSecondThreshold && + newPps < firstScorePacketsPerSecondThreshold) { session.getWorldCache().getScoreboard().onUpdate(); } } @@ -101,7 +114,7 @@ public void run() { ScoreboardSession scoreboardSession = worldCache.getScoreboardSession(); int pps = scoreboardSession.getPacketsPerSecond(); - if (pps >= FIRST_SCORE_PACKETS_PER_SECOND_THRESHOLD) { + if (pps >= firstScorePacketsPerSecondThreshold) { boolean reachedSecondThreshold = pps >= SECOND_SCORE_PACKETS_PER_SECOND_THRESHOLD; int millisBetweenUpdates = reachedSecondThreshold ? @@ -112,10 +125,10 @@ public void run() { worldCache.getScoreboard().onUpdate(); scoreboardSession.lastUpdate = currentTime; - if (DEBUG_ENABLED && (currentTime - scoreboardSession.lastLog >= 60000)) { // one minute + if (debugEnabled && (currentTime - scoreboardSession.lastLog >= 60000)) { // one minute int threshold = reachedSecondThreshold ? SECOND_SCORE_PACKETS_PER_SECOND_THRESHOLD : - FIRST_SCORE_PACKETS_PER_SECOND_THRESHOLD; + firstScorePacketsPerSecondThreshold; geyser.getLogger().info( GeyserLocale.getLocaleStringLog("geyser.scoreboard.updater.threshold_reached.log", session.bedrockUsername(), threshold, pps) + @@ -129,7 +142,7 @@ public void run() { } } - if (DEBUG_ENABLED) { + if (debugEnabled) { long timeSpent = System.currentTimeMillis() - currentTime; if (timeSpent > 0) { geyser.getLogger().info(String.format( diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/scoreboard/JavaResetScorePacket.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/scoreboard/JavaResetScorePacket.java index 72dcd40621e..e984b3be040 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/scoreboard/JavaResetScorePacket.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/scoreboard/JavaResetScorePacket.java @@ -66,7 +66,7 @@ public void translate(GeyserSession session, ClientboundResetScorePacket packet) // ScoreboardUpdater will handle it for us if the packets per second // (for score and team packets) is higher than the first threshold - if (pps < ScoreboardUpdater.FIRST_SCORE_PACKETS_PER_SECOND_THRESHOLD) { + if (pps < ScoreboardUpdater.firstScorePacketsPerSecondThreshold) { scoreboard.onUpdate(); } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/scoreboard/JavaSetDisplayObjectiveTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/scoreboard/JavaSetDisplayObjectiveTranslator.java index 241c54cba7a..4bd7a1d9a23 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/scoreboard/JavaSetDisplayObjectiveTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/scoreboard/JavaSetDisplayObjectiveTranslator.java @@ -46,7 +46,7 @@ public void translate(GeyserSession session, ClientboundSetDisplayObjectivePacke // ScoreboardUpdater will handle it for us if the packets per second // (for score and team packets) is higher than the first threshold - if (pps < ScoreboardUpdater.FIRST_SCORE_PACKETS_PER_SECOND_THRESHOLD) { + if (pps < ScoreboardUpdater.firstScorePacketsPerSecondThreshold) { scoreboard.onUpdate(); } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/scoreboard/JavaSetObjectiveTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/scoreboard/JavaSetObjectiveTranslator.java index 0a7c6131f76..499d217b64f 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/scoreboard/JavaSetObjectiveTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/scoreboard/JavaSetObjectiveTranslator.java @@ -69,7 +69,7 @@ public void translate(GeyserSession session, ClientboundSetObjectivePacket packe // ScoreboardUpdater will handle it for us if the packets per second // (for score and team packets) is higher than the first threshold - if (pps < ScoreboardUpdater.FIRST_SCORE_PACKETS_PER_SECOND_THRESHOLD) { + if (pps < ScoreboardUpdater.firstScorePacketsPerSecondThreshold) { scoreboard.onUpdate(); } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/scoreboard/JavaSetPlayerTeamTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/scoreboard/JavaSetPlayerTeamTranslator.java index 3a1ee63739d..62eab43b144 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/scoreboard/JavaSetPlayerTeamTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/scoreboard/JavaSetPlayerTeamTranslator.java @@ -95,7 +95,7 @@ public void translate(GeyserSession session, ClientboundSetPlayerTeamPacket pack // ScoreboardUpdater will handle it for us if the packets per second // (for score and team packets) is higher than the first threshold - if (pps < ScoreboardUpdater.FIRST_SCORE_PACKETS_PER_SECOND_THRESHOLD) { + if (pps < ScoreboardUpdater.firstScorePacketsPerSecondThreshold) { scoreboard.onUpdate(); } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/scoreboard/JavaSetScoreTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/scoreboard/JavaSetScoreTranslator.java index c7159041bea..88cd878e1e7 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/scoreboard/JavaSetScoreTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/scoreboard/JavaSetScoreTranslator.java @@ -61,7 +61,7 @@ public void translate(GeyserSession session, ClientboundSetScorePacket packet) { // ScoreboardUpdater will handle it for us if the packets per second // (for score and team packets) is higher than the first threshold - if (pps < ScoreboardUpdater.FIRST_SCORE_PACKETS_PER_SECOND_THRESHOLD) { + if (pps < ScoreboardUpdater.firstScorePacketsPerSecondThreshold) { scoreboard.onUpdate(); } }