From 72a9df58e0b14c0d1a4ee594a86c6166dfc53fca Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Wed, 8 Jun 2022 22:30:34 -0400 Subject: [PATCH 1/4] Properly support differently setup chat registries ViaVersion has two entries in its fake chat registry that are not in the same order as Java. This commit supports that properly and renders subtitled text correctly. Resolves #3023 --- core/pom.xml | 2 +- .../geyser/session/GeyserSession.java | 3 +- .../geysermc/geyser/text/ChatTypeEntry.java | 34 +++++++++++++++++++ .../protocol/java/JavaLoginTranslator.java | 30 +++++++++++----- .../java/JavaPlayerChatTranslator.java | 13 +++---- .../java/JavaSystemChatTranslator.java | 8 +---- 6 files changed, 64 insertions(+), 26 deletions(-) create mode 100644 core/src/main/java/org/geysermc/geyser/text/ChatTypeEntry.java diff --git a/core/pom.xml b/core/pom.xml index 66a3d21c0..e0db25db0 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -155,7 +155,7 @@ com.github.GeyserMC MCProtocolLib - bf3919a + 3023c4d compile 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 c18562c88..e8490c240 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java @@ -121,6 +121,7 @@ import org.geysermc.geyser.session.auth.AuthType; import org.geysermc.geyser.session.auth.BedrockClientData; import org.geysermc.geyser.session.cache.*; import org.geysermc.geyser.skin.FloodgateSkinUploader; +import org.geysermc.geyser.text.ChatTypeEntry; import org.geysermc.geyser.text.GeyserLocale; import org.geysermc.geyser.text.MinecraftLocale; import org.geysermc.geyser.text.TextDecoration; @@ -336,7 +337,7 @@ public class GeyserSession implements GeyserConnection, CommandSender { */ private final Map dimensions = new Object2ObjectOpenHashMap<>(3); - private final Map chatTypes = new EnumMap<>(MessageType.class); + private final Int2ObjectMap chatTypes = new Int2ObjectOpenHashMap<>(7); @Setter private int breakingBlock; diff --git a/core/src/main/java/org/geysermc/geyser/text/ChatTypeEntry.java b/core/src/main/java/org/geysermc/geyser/text/ChatTypeEntry.java new file mode 100644 index 000000000..32be209ca --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/text/ChatTypeEntry.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2019-2022 GeyserMC. http://geysermc.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + */ + +package org.geysermc.geyser.text; + +import com.nukkitx.protocol.bedrock.packet.TextPacket; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +public record ChatTypeEntry(@Nonnull TextPacket.Type bedrockChatType, @Nullable TextDecoration textDecoration) { +} diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaLoginTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaLoginTranslator.java index a5c949c10..74d12bd19 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaLoginTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaLoginTranslator.java @@ -30,16 +30,20 @@ import com.github.steveice10.mc.protocol.packet.ingame.clientbound.ClientboundLo import com.github.steveice10.mc.protocol.packet.ingame.serverbound.ServerboundCustomPayloadPacket; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import com.github.steveice10.opennbt.tag.builtin.IntTag; +import com.github.steveice10.opennbt.tag.builtin.StringTag; import com.nukkitx.protocol.bedrock.data.GameRuleData; import com.nukkitx.protocol.bedrock.data.PlayerPermission; import com.nukkitx.protocol.bedrock.packet.AdventureSettingsPacket; import com.nukkitx.protocol.bedrock.packet.GameRulesChangedPacket; import com.nukkitx.protocol.bedrock.packet.SetPlayerGameTypePacket; +import com.nukkitx.protocol.bedrock.packet.TextPacket; +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import org.geysermc.floodgate.pluginmessage.PluginMessageChannels; import org.geysermc.geyser.entity.type.player.SessionPlayerEntity; import org.geysermc.geyser.level.JavaDimension; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.auth.AuthType; +import org.geysermc.geyser.text.ChatTypeEntry; import org.geysermc.geyser.text.TextDecoration; import org.geysermc.geyser.translator.level.BiomeTranslator; import org.geysermc.geyser.translator.protocol.PacketTranslator; @@ -64,21 +68,29 @@ public class JavaLoginTranslator extends PacketTranslator chatTypes = session.getChatTypes(); + Int2ObjectMap chatTypes = session.getChatTypes(); chatTypes.clear(); for (CompoundTag tag : JavaCodecEntry.iterateAsTag(packet.getRegistry().get("minecraft:chat_type"))) { + // The ID is NOT ALWAYS THE SAME! ViaVersion as of 1.19 adds two registry entries that do NOT match vanilla. int id = ((IntTag) tag.get("id")).getValue(); CompoundTag element = tag.get("element"); CompoundTag chat = element.get("chat"); - if (chat == null) { - continue; + TextDecoration textDecoration = null; + if (chat != null) { + CompoundTag decorationTag = chat.get("decoration"); + if (decorationTag != null) { + textDecoration = new TextDecoration(decorationTag); + } } - CompoundTag decoration = chat.get("decoration"); - if (decoration == null) { - continue; - } - MessageType type = MessageType.from(id); - chatTypes.put(type, new TextDecoration(decoration)); + MessageType type = MessageType.from(((StringTag) tag.get("name")).getValue()); + // TODO new types? + TextPacket.Type bedrockType = switch (type) { + case CHAT -> TextPacket.Type.CHAT; + case SYSTEM -> TextPacket.Type.SYSTEM; + case GAME_INFO -> TextPacket.Type.TIP; + default -> TextPacket.Type.RAW; + }; + chatTypes.put(id, new ChatTypeEntry(bedrockType, textDecoration)); } // If the player is already initialized and a join game packet is sent, they diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaPlayerChatTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaPlayerChatTranslator.java index be1635fdd..f9f4407d9 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaPlayerChatTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaPlayerChatTranslator.java @@ -30,6 +30,7 @@ import com.nukkitx.protocol.bedrock.packet.TextPacket; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.TranslatableComponent; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.text.ChatTypeEntry; import org.geysermc.geyser.text.TextDecoration; import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; @@ -44,22 +45,18 @@ public class JavaPlayerChatTranslator extends PacketTranslator TextPacket.Type.CHAT; - case SYSTEM -> TextPacket.Type.SYSTEM; - case GAME_INFO -> TextPacket.Type.TIP; - default -> TextPacket.Type.RAW; - }); + textPacket.setType(entry.bedrockChatType()); textPacket.setNeedsTranslation(false); Component message = packet.getUnsignedContent() == null ? packet.getSignedContent() : packet.getUnsignedContent(); - TextDecoration decoration = session.getChatTypes().get(packet.getType()); + TextDecoration decoration = entry.textDecoration(); if (decoration != null) { // As of 1.19 - do this to apply all the styling for signed messages // Though, Bedrock cannot care about the signed stuff. diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaSystemChatTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaSystemChatTranslator.java index b82f2e194..fc4a32bac 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaSystemChatTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaSystemChatTranslator.java @@ -41,13 +41,7 @@ public class JavaSystemChatTranslator extends PacketTranslator TextPacket.Type.CHAT; - case SYSTEM -> TextPacket.Type.SYSTEM; - case GAME_INFO -> TextPacket.Type.TIP; - default -> TextPacket.Type.RAW; - }); + textPacket.setType(session.getChatTypes().get(packet.getTypeId()).bedrockChatType()); textPacket.setNeedsTranslation(false); textPacket.setMessage(MessageTranslator.convertMessage(packet.getContent(), session.getLocale())); From f1a12d1feb91014b7cda068072be15cf15833556 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Thu, 9 Jun 2022 18:34:25 -0400 Subject: [PATCH 2/4] Bump mappings and MCProtocolLib --- core/pom.xml | 2 +- core/src/main/resources/mappings | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core/pom.xml b/core/pom.xml index e0db25db0..df507e892 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -155,7 +155,7 @@ com.github.GeyserMC MCProtocolLib - 3023c4d + bb2b414 compile diff --git a/core/src/main/resources/mappings b/core/src/main/resources/mappings index e13611fd9..99a1f8070 160000 --- a/core/src/main/resources/mappings +++ b/core/src/main/resources/mappings @@ -1 +1 @@ -Subproject commit e13611fd97b1801d4c4b914cd409351a49d19537 +Subproject commit 99a1f8070e844d059454dacbb6e8b203521eed23 From 691d674f018ff25231a6bd018401e6bfc04e4e23 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Thu, 9 Jun 2022 21:40:54 -0400 Subject: [PATCH 3/4] Use PaperServerListPingEvent when available We need to support this or else events that exclusively use PaperServerListPingEvent will not see our call. Fixes https://github.com/GeyserMC/Geyser/issues/3003 --- .../spigot/GeyserPaperPingPassthrough.java | 105 ++++++++++++++++++ .../spigot/GeyserSpigotPingPassthrough.java | 2 +- .../platform/spigot/GeyserSpigotPlugin.java | 8 +- 3 files changed, 113 insertions(+), 2 deletions(-) create mode 100644 bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserPaperPingPassthrough.java diff --git a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserPaperPingPassthrough.java b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserPaperPingPassthrough.java new file mode 100644 index 000000000..cbe063931 --- /dev/null +++ b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserPaperPingPassthrough.java @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2019-2022 GeyserMC. http://geysermc.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + */ + +package org.geysermc.geyser.platform.spigot; + +import com.destroystokyo.paper.event.server.PaperServerListPingEvent; +import com.destroystokyo.paper.network.StatusClient; +import com.destroystokyo.paper.profile.PlayerProfile; +import org.bukkit.Bukkit; +import org.geysermc.geyser.network.MinecraftProtocol; +import org.geysermc.geyser.ping.GeyserPingInfo; +import org.geysermc.geyser.ping.IGeyserPingPassthrough; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.net.InetSocketAddress; + +/** + * This class is used if possible, so listeners listening for PaperServerListPingEvent exclusively have their changes + * applied. + */ +public final class GeyserPaperPingPassthrough implements IGeyserPingPassthrough { + private final GeyserSpigotLogger logger; + + public GeyserPaperPingPassthrough(GeyserSpigotLogger logger) { + this.logger = logger; + } + + @Nullable + @Override + public GeyserPingInfo getPingInformation(InetSocketAddress inetSocketAddress) { + try { + // We'd rather *not* use deprecations here, but unfortunately any Adventure class would be relocated at + // runtime because we still have to shade in our own Adventure class. For now. + PaperServerListPingEvent event = new PaperServerListPingEvent(new GeyserStatusClient(inetSocketAddress), + Bukkit.getMotd(), Bukkit.getOnlinePlayers().size(), Bukkit.getMaxPlayers(), Bukkit.getVersion(), + MinecraftProtocol.getJavaProtocolVersion(), null); + Bukkit.getPluginManager().callEvent(event); + if (event.isCancelled()) { + // We have to send a ping, so not really sure what else to do here. + return null; + } + + GeyserPingInfo.Players players; + if (event.shouldHidePlayers()) { + players = new GeyserPingInfo.Players(1, 0); + } else { + players = new GeyserPingInfo.Players(event.getMaxPlayers(), event.getNumPlayers()); + } + + GeyserPingInfo geyserPingInfo = new GeyserPingInfo(event.getMotd(), players, + new GeyserPingInfo.Version(Bukkit.getVersion(), MinecraftProtocol.getJavaProtocolVersion())); + + if (!event.shouldHidePlayers()) { + for (PlayerProfile profile : event.getPlayerSample()) { + geyserPingInfo.getPlayerList().add(profile.getName()); + } + } + + return geyserPingInfo; + } catch (Exception e) { + logger.debug("Error while getting Paper ping passthrough: " + e); + return null; + } + } + + private record GeyserStatusClient(InetSocketAddress address) implements StatusClient { + @Override + public @NotNull InetSocketAddress getAddress() { + return address; + } + + @Override + public int getProtocolVersion() { + return MinecraftProtocol.getJavaProtocolVersion(); + } + + @Override + public @Nullable InetSocketAddress getVirtualHost() { + return null; + } + } +} diff --git a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotPingPassthrough.java b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotPingPassthrough.java index 19153b750..ae01190c0 100644 --- a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotPingPassthrough.java +++ b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotPingPassthrough.java @@ -30,8 +30,8 @@ import org.bukkit.Bukkit; import org.bukkit.entity.Player; import org.bukkit.event.server.ServerListPingEvent; import org.bukkit.util.CachedServerIcon; -import org.geysermc.geyser.ping.GeyserPingInfo; import org.geysermc.geyser.network.MinecraftProtocol; +import org.geysermc.geyser.ping.GeyserPingInfo; import org.geysermc.geyser.ping.IGeyserPingPassthrough; import javax.annotation.Nonnull; diff --git a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotPlugin.java b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotPlugin.java index 4b41ad569..cee38228c 100644 --- a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotPlugin.java +++ b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotPlugin.java @@ -167,8 +167,14 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap { if (geyserConfig.isLegacyPingPassthrough()) { this.geyserSpigotPingPassthrough = GeyserLegacyPingPassthrough.init(geyser); } else { - this.geyserSpigotPingPassthrough = new GeyserSpigotPingPassthrough(geyserLogger); + try { + Class.forName("com.destroystokyo.paper.event.server.PaperServerListPingEvent"); + this.geyserSpigotPingPassthrough = new GeyserPaperPingPassthrough(geyserLogger); + } catch (ClassNotFoundException e) { + this.geyserSpigotPingPassthrough = new GeyserSpigotPingPassthrough(geyserLogger); + } } + geyserLogger.debug("Spigot ping passthrough type: " + (this.geyserSpigotPingPassthrough == null ? null : this.geyserSpigotPingPassthrough.getClass())); this.geyserCommandManager = new GeyserSpigotCommandManager(geyser); From 162aff49787286463189d304a45b683225119259 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Fri, 10 Jun 2022 10:27:07 -0400 Subject: [PATCH 4/4] Better handle chat packets sent before login --- .../geyser/session/GeyserSession.java | 11 +++++---- .../geyser/session/UpstreamSession.java | 22 ++++++++++++++++++ .../geysermc/geyser/text/ChatTypeEntry.java | 23 +++++++++++++++++++ .../protocol/java/JavaLoginTranslator.java | 3 +++ .../java/JavaSystemChatTranslator.java | 6 ++++- 5 files changed, 60 insertions(+), 5 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 e8490c240..c5fe7f2bf 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java @@ -37,7 +37,6 @@ import com.github.steveice10.mc.protocol.MinecraftProtocol; import com.github.steveice10.mc.protocol.codec.MinecraftCodecHelper; import com.github.steveice10.mc.protocol.data.ProtocolState; import com.github.steveice10.mc.protocol.data.UnexpectedEncryptionException; -import com.github.steveice10.mc.protocol.data.game.MessageType; import com.github.steveice10.mc.protocol.data.game.entity.metadata.Pose; import com.github.steveice10.mc.protocol.data.game.entity.object.Direction; import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode; @@ -124,10 +123,12 @@ import org.geysermc.geyser.skin.FloodgateSkinUploader; import org.geysermc.geyser.text.ChatTypeEntry; import org.geysermc.geyser.text.GeyserLocale; import org.geysermc.geyser.text.MinecraftLocale; -import org.geysermc.geyser.text.TextDecoration; import org.geysermc.geyser.translator.inventory.InventoryTranslator; import org.geysermc.geyser.translator.text.MessageTranslator; -import org.geysermc.geyser.util.*; +import org.geysermc.geyser.util.ChunkUtils; +import org.geysermc.geyser.util.DimensionUtils; +import org.geysermc.geyser.util.LoginEncryptionUtils; +import org.geysermc.geyser.util.MathUtils; import javax.annotation.Nonnull; import java.net.ConnectException; @@ -337,7 +338,7 @@ public class GeyserSession implements GeyserConnection, CommandSender { */ private final Map dimensions = new Object2ObjectOpenHashMap<>(3); - private final Int2ObjectMap chatTypes = new Int2ObjectOpenHashMap<>(7); + private final Int2ObjectMap chatTypes = new Int2ObjectOpenHashMap<>(8); @Setter private int breakingBlock; @@ -548,6 +549,8 @@ public class GeyserSession implements GeyserConnection, CommandSender { this.playerEntity = new SessionPlayerEntity(this); collisionManager.updatePlayerBoundingBox(this.playerEntity.getPosition()); + ChatTypeEntry.applyDefaults(chatTypes); + this.playerInventory = new PlayerInventory(); this.openInventory = null; this.craftingRecipes = new Int2ObjectOpenHashMap<>(); diff --git a/core/src/main/java/org/geysermc/geyser/session/UpstreamSession.java b/core/src/main/java/org/geysermc/geyser/session/UpstreamSession.java index 060dcc7fb..3250faf64 100644 --- a/core/src/main/java/org/geysermc/geyser/session/UpstreamSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/UpstreamSession.java @@ -33,12 +33,15 @@ import lombok.RequiredArgsConstructor; import lombok.Setter; import java.net.InetSocketAddress; +import java.util.ArrayDeque; +import java.util.Queue; @RequiredArgsConstructor public class UpstreamSession { @Getter private final BedrockServerSession session; @Getter @Setter private boolean initialized = false; + private Queue postStartGamePackets = new ArrayDeque<>(); public void sendPacket(@NonNull BedrockPacket packet) { if (!isClosed()) { @@ -56,6 +59,25 @@ public class UpstreamSession { session.disconnect(reason); } + /** + * Queue a packet that must be delayed until after login. + */ + public void queuePostStartGamePacket(BedrockPacket packet) { + postStartGamePackets.add(packet); + } + + public void sendPostStartGamePackets() { + if (isClosed()) { + return; + } + + BedrockPacket packet; + while ((packet = postStartGamePackets.poll()) != null) { + session.sendPacket(packet); + } + postStartGamePackets = null; + } + public boolean isClosed() { return session.isClosed(); } diff --git a/core/src/main/java/org/geysermc/geyser/text/ChatTypeEntry.java b/core/src/main/java/org/geysermc/geyser/text/ChatTypeEntry.java index 32be209ca..800eb6c0f 100644 --- a/core/src/main/java/org/geysermc/geyser/text/ChatTypeEntry.java +++ b/core/src/main/java/org/geysermc/geyser/text/ChatTypeEntry.java @@ -25,10 +25,33 @@ package org.geysermc.geyser.text; +import com.github.steveice10.mc.protocol.data.game.MessageType; import com.nukkitx.protocol.bedrock.packet.TextPacket; +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import javax.annotation.Nonnull; import javax.annotation.Nullable; public record ChatTypeEntry(@Nonnull TextPacket.Type bedrockChatType, @Nullable TextDecoration textDecoration) { + private static final ChatTypeEntry CHAT = new ChatTypeEntry(TextPacket.Type.CHAT, null); + private static final ChatTypeEntry SYSTEM = new ChatTypeEntry(TextPacket.Type.CHAT, null); + private static final ChatTypeEntry TIP = new ChatTypeEntry(TextPacket.Type.CHAT, null); + private static final ChatTypeEntry RAW = new ChatTypeEntry(TextPacket.Type.CHAT, null); + + /** + * Apply defaults to a map so it isn't empty in the event a chat message is sent before the login packet. + */ + public static void applyDefaults(Int2ObjectMap chatTypes) { + // So the proper way to do this, probably, would be to dump the NBT data from vanilla and load it. + // But, the only way this happens is if a chat message is sent to us before the login packet, which is rare. + // So we'll just make sure chat ends up in the right place. + chatTypes.put(MessageType.CHAT.ordinal(), CHAT); + chatTypes.put(MessageType.SYSTEM.ordinal(), SYSTEM); + chatTypes.put(MessageType.GAME_INFO.ordinal(), TIP); + chatTypes.put(MessageType.SAY_COMMAND.ordinal(), RAW); + chatTypes.put(MessageType.MSG_COMMAND.ordinal(), RAW); + chatTypes.put(MessageType.TEAM_MSG_COMMAND.ordinal(), RAW); + chatTypes.put(MessageType.EMOTE_COMMAND.ordinal(), RAW); + chatTypes.put(MessageType.TELLRAW_COMMAND.ordinal(), RAW); + } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaLoginTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaLoginTranslator.java index 74d12bd19..cd26e53e5 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaLoginTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaLoginTranslator.java @@ -115,6 +115,9 @@ public class JavaLoginTranslator extends PacketTranslator