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 05e14c41b..7019838c1 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 @@ -47,21 +47,23 @@ import org.geysermc.geyser.translator.protocol.Translator; @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(); switch (packet.getNotification()) { + // Yes, START_RAIN and STOP_RAIN are swapped in terms of what they cause the client to do. + // This is how the Mojang mappings name them, so we go with it + // It seems Mojang's intent was that START_RAIN would set the rain strength to 0 so that it can then be incremeneted on a gradient by the server + // The inverse is true for STOP_RAIN + // This is indeed the behavior of the vanilla server + // However, it seems most server software (at least Spigot and Paper) did not go along with this + // 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 startRainPacket = new LevelEventPacket(); - startRainPacket.setType(LevelEventType.START_RAINING); - startRainPacket.setData(Integer.MAX_VALUE); - startRainPacket.setPosition(Vector3f.ZERO); - session.sendUpstreamPacket(startRainPacket); - session.setRaining(true); - break; - case STOP_RAIN: LevelEventPacket stopRainPacket = new LevelEventPacket(); stopRainPacket.setType(LevelEventType.STOP_RAINING); stopRainPacket.setData(0); @@ -69,34 +71,35 @@ public class JavaGameEventTranslator extends PacketTranslator 0f; - // Java sends the rain level. Bedrock doesn't care, so we don't care if it's already raining. - if (isCurrentlyRaining != session.isRaining()) { - LevelEventPacket changeRainPacket = new LevelEventPacket(); - changeRainPacket.setType(isCurrentlyRaining ? LevelEventType.START_RAINING : LevelEventType.STOP_RAINING); - changeRainPacket.setData(Integer.MAX_VALUE); // Dunno what this does; used to be implemented with ThreadLocalRandom - changeRainPacket.setPosition(Vector3f.ZERO); - session.sendUpstreamPacket(changeRainPacket); - session.setRaining(isCurrentlyRaining); - } + float rainStrength = ((RainStrengthValue) packet.getValue()).getStrength(); + boolean isCurrentlyRaining = rainStrength > 0f; + LevelEventPacket changeRainPacket = new LevelEventPacket(); + changeRainPacket.setType(isCurrentlyRaining ? LevelEventType.START_RAINING : LevelEventType.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); break; case THUNDER_STRENGTH: // See above, same process - ThunderStrengthValue thunderValue = (ThunderStrengthValue) packet.getValue(); - boolean isCurrentlyThundering = thunderValue.getStrength() > 0f; - if (isCurrentlyThundering != session.isThunder()) { - LevelEventPacket changeThunderPacket = new LevelEventPacket(); - changeThunderPacket.setType(isCurrentlyThundering ? LevelEventType.START_THUNDERSTORM : LevelEventType.STOP_THUNDERSTORM); - changeThunderPacket.setData(Integer.MAX_VALUE); - changeThunderPacket.setPosition(Vector3f.ZERO); - session.sendUpstreamPacket(changeThunderPacket); - session.setThunder(isCurrentlyThundering); - } + float thunderStrength = ((ThunderStrengthValue) packet.getValue()).getStrength(); + boolean isCurrentlyThundering = thunderStrength > 0f; + LevelEventPacket changeThunderPacket = new LevelEventPacket(); + changeThunderPacket.setType(isCurrentlyThundering ? LevelEventType.START_THUNDERSTORM : LevelEventType.STOP_THUNDERSTORM); + changeThunderPacket.setData((int) (thunderStrength * MAX_STORM_STRENGTH)); + changeThunderPacket.setPosition(Vector3f.ZERO); + session.sendUpstreamPacket(changeThunderPacket); + session.setThunder(isCurrentlyThundering); break; case CHANGE_GAMEMODE: GameMode gameMode = (GameMode) packet.getValue();