From f639be6362d68409b0b249810abefae2895f7ce7 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Fri, 25 Mar 2022 20:22:39 -0400 Subject: [PATCH] Better handling of fake cooldown Because of Bedrock limitations, if a player has text background opacity enabled, they'll see an empty section where the title is usually displayed as the fake cooldown is shown. This commit minimizes the time that is shown by clearing the text as soon as possible. Reference issue: https://github.com/GeyserMC/Geyser/issues/1710 This commit also removes starting the fake cooldown process if the client switches to an inventory slot with the same Java ID. --- .../geyser/session/cache/WorldCache.java | 67 ++++++++++++++++++- .../BedrockMobEquipmentTranslator.java | 21 ++++-- .../java/title/JavaClearTitlesTranslator.java | 5 +- .../title/JavaSetTitleTextTranslator.java | 2 + .../JavaSetTitlesAnimationTranslator.java | 11 ++- .../geysermc/geyser/util/CooldownUtils.java | 22 +++--- 6 files changed, 105 insertions(+), 23 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/session/cache/WorldCache.java b/core/src/main/java/org/geysermc/geyser/session/cache/WorldCache.java index aa4d10d04..0ef5427ea 100644 --- a/core/src/main/java/org/geysermc/geyser/session/cache/WorldCache.java +++ b/core/src/main/java/org/geysermc/geyser/session/cache/WorldCache.java @@ -26,24 +26,36 @@ package org.geysermc.geyser.session.cache; import com.github.steveice10.mc.protocol.data.game.setting.Difficulty; +import com.nukkitx.protocol.bedrock.packet.SetTitlePacket; import lombok.Getter; import lombok.Setter; -import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.scoreboard.Scoreboard; import org.geysermc.geyser.scoreboard.ScoreboardUpdater.ScoreboardSession; +import org.geysermc.geyser.session.GeyserSession; -@Getter -public class WorldCache { +public final class WorldCache { private final GeyserSession session; + @Getter private final ScoreboardSession scoreboardSession; + @Getter private Scoreboard scoreboard; + @Getter @Setter private Difficulty difficulty = Difficulty.EASY; + /** + * Whether our cooldown changed the title time, and the true title times need to be re-sent. + */ + private boolean titleTimesNeedReset = false; + private int trueTitleFadeInTime; + private int trueTitleStayTime; + private int trueTitleFadeOutTime; + public WorldCache(GeyserSession session) { this.session = session; this.scoreboard = new Scoreboard(session); scoreboardSession = new ScoreboardSession(session); + resetTitleTimes(false); } public void removeScoreboard() { @@ -58,4 +70,53 @@ public class WorldCache { int pps = scoreboardSession.getPacketsPerSecond(); return Math.max(pps, pendingPps); } + + public void markTitleTimesAsIncorrect() { + titleTimesNeedReset = true; + } + + /** + * Store the true active title times. + */ + public void setTitleTimes(int fadeInTime, int stayTime, int fadeOutTime) { + trueTitleFadeInTime = fadeInTime; + trueTitleStayTime = stayTime; + trueTitleFadeOutTime = fadeOutTime; + } + + /** + * If needed, ensure that the Bedrock client will use the correct timings for titles. + */ + public void synchronizeCorrectTitleTimes() { + if (titleTimesNeedReset) { + forceSyncCorrectTitleTimes(); + titleTimesNeedReset = false; + } + } + + private void forceSyncCorrectTitleTimes() { + SetTitlePacket titlePacket = new SetTitlePacket(); + titlePacket.setType(SetTitlePacket.Type.TIMES); + titlePacket.setText(""); + titlePacket.setFadeInTime(trueTitleFadeInTime); + titlePacket.setStayTime(trueTitleStayTime); + titlePacket.setFadeOutTime(trueTitleFadeOutTime); + titlePacket.setPlatformOnlineId(""); + titlePacket.setXuid(""); + + session.sendUpstreamPacket(titlePacket); + } + + /** + * Reset the true active title times to the (Java Edition 1.18.2) defaults. + */ + public void resetTitleTimes(boolean clientSync) { + trueTitleFadeInTime = 10; + trueTitleStayTime = 70; + trueTitleFadeOutTime = 20; + + if (clientSync) { + forceSyncCorrectTitleTimes(); + } + } } \ No newline at end of file diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockMobEquipmentTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockMobEquipmentTranslator.java index 5c551dce4..2bbae4a49 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockMobEquipmentTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockMobEquipmentTranslator.java @@ -30,6 +30,7 @@ import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.Server import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.ServerboundUseItemPacket; import com.nukkitx.protocol.bedrock.data.inventory.ContainerId; import com.nukkitx.protocol.bedrock.packet.MobEquipmentPacket; +import org.geysermc.geyser.inventory.GeyserItemStack; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; @@ -42,8 +43,9 @@ public class BedrockMobEquipmentTranslator extends PacketTranslator 8 || - packet.getContainerId() != ContainerId.INVENTORY || session.getPlayerInventory().getHeldItemSlot() == packet.getHotbarSlot()) { + int newSlot = packet.getHotbarSlot(); + if (!session.isSpawned() || newSlot > 8 || packet.getContainerId() != ContainerId.INVENTORY + || session.getPlayerInventory().getHeldItemSlot() == newSlot) { // For the last condition - Don't update the slot if the slot is the same - not Java Edition behavior and messes with plugins such as Grief Prevention return; } @@ -51,12 +53,15 @@ public class BedrockMobEquipmentTranslator extends PacketTranslator 20) return; // 0.0 usually happens on login and causes issues with visuals; anything above 20 means a plugin like OldCombatMechanics is being used - // Needs to be sent or no subtitle packet is recognized by the client + // Set the times to stay a bit with no fade in nor out SetTitlePacket titlePacket = new SetTitlePacket(); + titlePacket.setType(SetTitlePacket.Type.TIMES); + titlePacket.setStayTime(1000); + titlePacket.setText(""); + titlePacket.setXuid(""); + titlePacket.setPlatformOnlineId(""); + session.sendUpstreamPacket(titlePacket); + + session.getWorldCache().markTitleTimesAsIncorrect(); + + // Needs to be sent or no subtitle packet is recognized by the client + titlePacket = new SetTitlePacket(); titlePacket.setType(SetTitlePacket.Type.TITLE); titlePacket.setText(" "); titlePacket.setXuid(""); @@ -85,9 +96,6 @@ public class CooldownUtils { titlePacket.setType(SetTitlePacket.Type.SUBTITLE); } titlePacket.setText(getTitle(session)); - titlePacket.setFadeInTime(0); - titlePacket.setFadeOutTime(5); - titlePacket.setStayTime(2); titlePacket.setXuid(""); titlePacket.setPlatformOnlineId(""); session.sendUpstreamPacket(titlePacket); @@ -96,11 +104,7 @@ public class CooldownUtils { computeCooldown(session, sessionPreference, lastHitTime), 50, TimeUnit.MILLISECONDS); // Updated per tick. 1000 divided by 20 ticks equals 50 } else { SetTitlePacket removeTitlePacket = new SetTitlePacket(); - if (sessionPreference == CooldownType.ACTIONBAR) { - removeTitlePacket.setType(SetTitlePacket.Type.ACTIONBAR); - } else { - removeTitlePacket.setType(SetTitlePacket.Type.SUBTITLE); - } + removeTitlePacket.setType(SetTitlePacket.Type.CLEAR); removeTitlePacket.setText(" "); removeTitlePacket.setXuid(""); removeTitlePacket.setPlatformOnlineId("");