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