Improve doDaylightCycle translation (#1711)

Previously, we wouldn't send the time if the server was sending the same time with doDaylightCycle on. However, this isn't vanilla behavior (for Bedrock nor Java) and can occasionally cause irregularities. The time is now always sent to Bedrock clients, and a daylightCycle field is added to GeyserSession to keep track of the doDaylightCycle gamerule we need to send to Bedrock. Removing the map we used to store the time may also improve memory usage since this was never cleaned up.
This commit is contained in:
Camotoy 2020-12-20 20:41:07 -05:00 committed by GitHub
parent d69896b381
commit b490dcfcbb
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 18 additions and 23 deletions

View file

@ -250,6 +250,12 @@ public class GeyserSession implements CommandSender {
@Setter @Setter
private ScheduledFuture<?> movementSendIfIdle; private ScheduledFuture<?> movementSendIfIdle;
/**
* Controls whether the daylight cycle gamerule has been sent to the client, so the sun/moon remain motionless.
*/
@Setter
private boolean daylightCycle = true;
private boolean reducedDebugInfo = false; private boolean reducedDebugInfo = false;
@Setter @Setter

View file

@ -25,49 +25,38 @@
package org.geysermc.connector.network.translators.java.world; package org.geysermc.connector.network.translators.java.world;
import com.nukkitx.protocol.bedrock.data.GameRuleData; import com.github.steveice10.mc.protocol.packet.ingame.server.world.ServerUpdateTimePacket;
import com.nukkitx.protocol.bedrock.packet.GameRulesChangedPacket; import com.nukkitx.protocol.bedrock.packet.SetTimePacket;
import it.unimi.dsi.fastutil.longs.Long2LongMap;
import it.unimi.dsi.fastutil.longs.Long2LongOpenHashMap;
import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.session.GeyserSession;
import org.geysermc.connector.network.translators.PacketTranslator; import org.geysermc.connector.network.translators.PacketTranslator;
import org.geysermc.connector.network.translators.Translator; import org.geysermc.connector.network.translators.Translator;
import com.github.steveice10.mc.protocol.packet.ingame.server.world.ServerUpdateTimePacket;
import com.nukkitx.protocol.bedrock.packet.SetTimePacket;
@Translator(packet = ServerUpdateTimePacket.class) @Translator(packet = ServerUpdateTimePacket.class)
public class JavaUpdateTimeTranslator extends PacketTranslator<ServerUpdateTimePacket> { public class JavaUpdateTimeTranslator extends PacketTranslator<ServerUpdateTimePacket> {
// If negative, the last time is stored so we know it's not some plugin behavior doing weird things.
// Per-player for multi-world support
private static final Long2LongMap LAST_RECORDED_TIMES = new Long2LongOpenHashMap();
@Override @Override
public void translate(ServerUpdateTimePacket packet, GeyserSession session) { public void translate(ServerUpdateTimePacket packet, GeyserSession session) {
// Bedrock sends a GameRulesChangedPacket if there is no daylight cycle // Bedrock sends a GameRulesChangedPacket if there is no daylight cycle
// Java just sends a negative long if there is no daylight cycle // Java just sends a negative long if there is no daylight cycle
long lastTime = LAST_RECORDED_TIMES.getOrDefault(session.getPlayerEntity().getEntityId(), 0);
long time = packet.getTime(); long time = packet.getTime();
if (lastTime != time) {
// https://minecraft.gamepedia.com/Day-night_cycle#24-hour_Minecraft_day // https://minecraft.gamepedia.com/Day-night_cycle#24-hour_Minecraft_day
SetTimePacket setTimePacket = new SetTimePacket(); SetTimePacket setTimePacket = new SetTimePacket();
setTimePacket.setTime((int) Math.abs(time) % 24000); setTimePacket.setTime((int) Math.abs(time) % 24000);
session.sendUpstreamPacket(setTimePacket); session.sendUpstreamPacket(setTimePacket);
// TODO: Performance efficient to always do this? if (!session.isDaylightCycle() && time >= 0) {
LAST_RECORDED_TIMES.put(session.getPlayerEntity().getEntityId(), time); // Client thinks there is no daylight cycle but there is
}
if (lastTime < 0 && time >= 0) {
setDoDaylightCycleGamerule(session, true); setDoDaylightCycleGamerule(session, true);
} else if (lastTime != time && time < 0) { } else if (session.isDaylightCycle() && time < 0) {
// Client thinks there is daylight cycle but there isn't
setDoDaylightCycleGamerule(session, false); setDoDaylightCycleGamerule(session, false);
} }
} }
private void setDoDaylightCycleGamerule(GeyserSession session, boolean doCycle) { private void setDoDaylightCycleGamerule(GeyserSession session, boolean doCycle) {
session.sendGameRule("dodaylightcycle", doCycle); session.sendGameRule("dodaylightcycle", doCycle);
// Save the value so we don't have to constantly send a daylight cycle gamerule update
session.setDaylightCycle(doCycle);
} }
} }