Better handle chat packets sent before login

This commit is contained in:
Camotoy 2022-06-10 10:27:07 -04:00
parent 691d674f01
commit 162aff4978
No known key found for this signature in database
GPG key ID: 7EEFB66FE798081F
5 changed files with 60 additions and 5 deletions

View file

@ -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<String, JavaDimension> dimensions = new Object2ObjectOpenHashMap<>(3);
private final Int2ObjectMap<ChatTypeEntry> chatTypes = new Int2ObjectOpenHashMap<>(7);
private final Int2ObjectMap<ChatTypeEntry> 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<>();

View file

@ -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<BedrockPacket> 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();
}

View file

@ -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<ChatTypeEntry> 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);
}
}

View file

@ -115,6 +115,9 @@ public class JavaLoginTranslator extends PacketTranslator<ClientboundLoginPacket
// The player has yet to spawn so let's do that using some of the information in this Java packet
session.setDimension(newDimension);
session.connect();
// It is now safe to send these packets
session.getUpstream().sendPostStartGamePackets();
}
AdventureSettingsPacket bedrockPacket = new AdventureSettingsPacket();

View file

@ -46,6 +46,10 @@ public class JavaSystemChatTranslator extends PacketTranslator<ClientboundSystem
textPacket.setNeedsTranslation(false);
textPacket.setMessage(MessageTranslator.convertMessage(packet.getContent(), session.getLocale()));
session.sendUpstreamPacket(textPacket);
if (session.isSentSpawnPacket()) {
session.sendUpstreamPacket(textPacket);
} else {
session.getUpstream().queuePostStartGamePacket(textPacket);
}
}
}