From 64bff1878da93c3809fe643924d0f749c05f4ca5 Mon Sep 17 00:00:00 2001 From: AJ Ferguson Date: Sun, 8 Sep 2024 16:28:13 -0400 Subject: [PATCH] Delay clear weather packets --- .../geyser/session/GeyserSession.java | 58 ++++++++++++++++++- .../protocol/java/JavaRespawnTranslator.java | 17 +----- .../java/level/JavaGameEventTranslator.java | 37 ++---------- .../geysermc/geyser/util/DimensionUtils.java | 16 +---- 4 files changed, 65 insertions(+), 63 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java index a8b8480fb3a..f7ffcdd0e4d 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java @@ -66,6 +66,7 @@ import org.cloudburstmc.protocol.bedrock.data.GamePublishSetting; import org.cloudburstmc.protocol.bedrock.data.GameRuleData; import org.cloudburstmc.protocol.bedrock.data.GameType; +import org.cloudburstmc.protocol.bedrock.data.LevelEvent; import org.cloudburstmc.protocol.bedrock.data.PlayerPermission; import org.cloudburstmc.protocol.bedrock.data.SoundEvent; import org.cloudburstmc.protocol.bedrock.data.SpawnBiomeType; @@ -85,6 +86,7 @@ import org.cloudburstmc.protocol.bedrock.packet.EmoteListPacket; import org.cloudburstmc.protocol.bedrock.packet.GameRulesChangedPacket; import org.cloudburstmc.protocol.bedrock.packet.ItemComponentPacket; +import org.cloudburstmc.protocol.bedrock.packet.LevelEventPacket; import org.cloudburstmc.protocol.bedrock.packet.LevelSoundEvent2Packet; import org.cloudburstmc.protocol.bedrock.packet.PlayStatusPacket; import org.cloudburstmc.protocol.bedrock.packet.SetTimePacket; @@ -570,13 +572,11 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { /** * Caches current rain status. */ - @Setter private boolean raining = false; /** * Caches current thunder status. */ - @Setter private boolean thunder = false; /** @@ -2007,6 +2007,60 @@ public float getEyeHeight() { }; } + /** + * Sends a packet to update rain strength. + * Stops rain if strength is 0. + * + * @param strength value between 0 and 1 + */ + public void updateRain(float strength) { + this.raining = strength > 0; + + LevelEventPacket rainPacket = new LevelEventPacket(); + rainPacket.setType(this.raining ? LevelEvent.START_RAINING : LevelEvent.STOP_RAINING); + rainPacket.setData((int) (strength * 65535)); + rainPacket.setPosition(Vector3f.ZERO); + + if (this.raining) { + sendUpstreamPacket(rainPacket); + } else { + // The bedrock client might ignore this packet if it is sent in the same tick as another rain packet + // https://github.com/GeyserMC/Geyser/issues/3679 + scheduleInEventLoop(() -> { + if (!this.raining) { + sendUpstreamPacket(rainPacket); + } + }, 100, TimeUnit.MILLISECONDS); + } + } + + /** + * Sends a packet to update thunderstorm strength. + * Stops thunderstorm if strength is 0. + * + * @param strength value between 0 and 1 + */ + public void updateThunder(float strength) { + this.thunder = strength > 0; + + LevelEventPacket thunderPacket = new LevelEventPacket(); + thunderPacket.setType(this.thunder ? LevelEvent.START_THUNDERSTORM : LevelEvent.STOP_THUNDERSTORM); + thunderPacket.setData((int) (strength * 65535)); + thunderPacket.setPosition(Vector3f.ZERO); + + if (this.thunder) { + sendUpstreamPacket(thunderPacket); + } else { + // The bedrock client might ignore this packet if it is sent in the same tick as another thunderstorm packet + // https://github.com/GeyserMC/Geyser/issues/3679 + scheduleInEventLoop(() -> { + if (!this.thunder) { + sendUpstreamPacket(thunderPacket); + } + }, 100, TimeUnit.MILLISECONDS); + } + } + @Override public @NonNull String bedrockUsername() { return authData.name(); diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaRespawnTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaRespawnTranslator.java index ccd93ac97e6..5c477f23e2e 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaRespawnTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaRespawnTranslator.java @@ -25,9 +25,6 @@ package org.geysermc.geyser.translator.protocol.java; -import org.cloudburstmc.math.vector.Vector3f; -import org.cloudburstmc.protocol.bedrock.data.LevelEvent; -import org.cloudburstmc.protocol.bedrock.packet.LevelEventPacket; import org.cloudburstmc.protocol.bedrock.packet.SetPlayerGameTypePacket; import org.geysermc.geyser.entity.attribute.GeyserAttributeType; import org.geysermc.geyser.entity.type.player.SessionPlayerEntity; @@ -76,21 +73,11 @@ public void translate(GeyserSession session, ClientboundRespawnPacket packet) { session.setGameMode(spawnInfo.getGameMode()); if (session.isRaining()) { - LevelEventPacket stopRainPacket = new LevelEventPacket(); - stopRainPacket.setType(LevelEvent.STOP_RAINING); - stopRainPacket.setData(0); - stopRainPacket.setPosition(Vector3f.ZERO); - session.sendUpstreamPacket(stopRainPacket); - session.setRaining(false); + session.updateRain(0); } if (session.isThunder()) { - LevelEventPacket stopThunderPacket = new LevelEventPacket(); - stopThunderPacket.setType(LevelEvent.STOP_THUNDERSTORM); - stopThunderPacket.setData(0); - stopThunderPacket.setPosition(Vector3f.ZERO); - session.sendUpstreamPacket(stopThunderPacket); - session.setThunder(false); + session.updateThunder(0); } JavaDimension newDimension = session.getRegistryCache().dimensions().byId(spawnInfo.getDimension()); diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaGameEventTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaGameEventTranslator.java index 3aa343cf58f..6a58c1a1e63 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaGameEventTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaGameEventTranslator.java @@ -33,9 +33,7 @@ import org.geysermc.mcprotocollib.protocol.data.game.level.notify.ThunderStrengthValue; import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.level.ClientboundGameEventPacket; import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.ServerboundClientCommandPacket; -import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.GameRuleData; -import org.cloudburstmc.protocol.bedrock.data.LevelEvent; import org.cloudburstmc.protocol.bedrock.data.entity.EntityEventType; import org.cloudburstmc.protocol.bedrock.packet.*; import org.geysermc.geyser.entity.type.player.PlayerEntity; @@ -48,9 +46,6 @@ @Translator(packet = ClientboundGameEventPacket.class) public class JavaGameEventTranslator extends PacketTranslator { - // Strength of rainstorms and thunderstorms is a 0-1 float on Java, while on Bedrock it is a 0-65535 int - private static final int MAX_STORM_STRENGTH = 65535; - @Override public void translate(GeyserSession session, ClientboundGameEventPacket packet) { PlayerEntity entity = session.getPlayerEntity(); @@ -65,42 +60,20 @@ public void translate(GeyserSession session, ClientboundGameEventPacket packet) // As a result many developers use these packets for the opposite of what their names implies // Behavior last verified with Java 1.19.4 and Bedrock 1.19.71 case START_RAIN: - LevelEventPacket stopRainPacket = new LevelEventPacket(); - stopRainPacket.setType(LevelEvent.STOP_RAINING); - stopRainPacket.setData(0); - stopRainPacket.setPosition(Vector3f.ZERO); - session.sendUpstreamPacket(stopRainPacket); - session.setRaining(false); + session.updateRain(0); break; case STOP_RAIN: - LevelEventPacket startRainPacket = new LevelEventPacket(); - startRainPacket.setType(LevelEvent.START_RAINING); - startRainPacket.setData(MAX_STORM_STRENGTH); - startRainPacket.setPosition(Vector3f.ZERO); - session.sendUpstreamPacket(startRainPacket); - session.setRaining(true); + session.updateRain(1); break; case RAIN_STRENGTH: - float rainStrength = ((RainStrengthValue) packet.getValue()).getStrength(); - boolean isCurrentlyRaining = rainStrength > 0f; - LevelEventPacket changeRainPacket = new LevelEventPacket(); - changeRainPacket.setType(isCurrentlyRaining ? LevelEvent.START_RAINING : LevelEvent.STOP_RAINING); // This is the rain strength on LevelEventType.START_RAINING, but can be any value on LevelEventType.STOP_RAINING - changeRainPacket.setData((int) (rainStrength * MAX_STORM_STRENGTH)); - changeRainPacket.setPosition(Vector3f.ZERO); - session.sendUpstreamPacket(changeRainPacket); - session.setRaining(isCurrentlyRaining); + float rainStrength = ((RainStrengthValue) packet.getValue()).getStrength(); + session.updateRain(rainStrength); break; case THUNDER_STRENGTH: // See above, same process float thunderStrength = ((ThunderStrengthValue) packet.getValue()).getStrength(); - boolean isCurrentlyThundering = thunderStrength > 0f; - LevelEventPacket changeThunderPacket = new LevelEventPacket(); - changeThunderPacket.setType(isCurrentlyThundering ? LevelEvent.START_THUNDERSTORM : LevelEvent.STOP_THUNDERSTORM); - changeThunderPacket.setData((int) (thunderStrength * MAX_STORM_STRENGTH)); - changeThunderPacket.setPosition(Vector3f.ZERO); - session.sendUpstreamPacket(changeThunderPacket); - session.setThunder(isCurrentlyThundering); + session.updateThunder(thunderStrength); break; case CHANGE_GAMEMODE: GameMode gameMode = (GameMode) packet.getValue(); diff --git a/core/src/main/java/org/geysermc/geyser/util/DimensionUtils.java b/core/src/main/java/org/geysermc/geyser/util/DimensionUtils.java index f043631b67d..8dc94a165ae 100644 --- a/core/src/main/java/org/geysermc/geyser/util/DimensionUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/DimensionUtils.java @@ -28,11 +28,9 @@ import org.checkerframework.checker.nullness.qual.Nullable; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.math.vector.Vector3i; -import org.cloudburstmc.protocol.bedrock.data.LevelEvent; import org.cloudburstmc.protocol.bedrock.data.PlayerActionType; import org.cloudburstmc.protocol.bedrock.packet.ChangeDimensionPacket; import org.cloudburstmc.protocol.bedrock.packet.ChunkRadiusUpdatedPacket; -import org.cloudburstmc.protocol.bedrock.packet.LevelEventPacket; import org.cloudburstmc.protocol.bedrock.packet.MobEffectPacket; import org.cloudburstmc.protocol.bedrock.packet.PlayerActionPacket; import org.cloudburstmc.protocol.bedrock.packet.StopSoundPacket; @@ -89,18 +87,8 @@ public static void switchDimension(GeyserSession session, JavaDimension javaDime entityEffects.clear(); // Always reset weather, as it sometimes suddenly starts raining. See https://github.com/GeyserMC/Geyser/issues/3679 - LevelEventPacket stopRainPacket = new LevelEventPacket(); - stopRainPacket.setType(LevelEvent.STOP_RAINING); - stopRainPacket.setData(0); - stopRainPacket.setPosition(Vector3f.ZERO); - session.sendUpstreamPacket(stopRainPacket); - session.setRaining(false); - LevelEventPacket stopThunderPacket = new LevelEventPacket(); - stopThunderPacket.setType(LevelEvent.STOP_THUNDERSTORM); - stopThunderPacket.setData(0); - stopThunderPacket.setPosition(Vector3f.ZERO); - session.sendUpstreamPacket(stopThunderPacket); - session.setThunder(false); + session.updateRain(0); + session.updateThunder(0); finalizeDimensionSwitch(session, player);