From e0294f1bebcc018431a0b663618d74360414b420 Mon Sep 17 00:00:00 2001 From: BruceChen Date: Sat, 14 Jan 2023 15:55:40 +0800 Subject: [PATCH] 1.19.3 PlayerRemove & Explosion packet --- .../Protocol/Handlers/Protocol18.cs | 3160 +++++++++-------- .../Protocol/Handlers/Protocol18Terrain.cs | 2 - 2 files changed, 1587 insertions(+), 1575 deletions(-) diff --git a/MinecraftClient/Protocol/Handlers/Protocol18.cs b/MinecraftClient/Protocol/Handlers/Protocol18.cs index 9ad6a9e2..c71936b3 100644 --- a/MinecraftClient/Protocol/Handlers/Protocol18.cs +++ b/MinecraftClient/Protocol/Handlers/Protocol18.cs @@ -329,1649 +329,1662 @@ namespace MinecraftClient.Protocol.Handlers /// TRUE if the packet was processed, FALSE if ignored or unknown internal bool HandlePacket(int packetID, Queue packetData) { +#if Release try { - if (login_phase) +#endif + if (login_phase) + { + switch (packetID) //Packet IDs are different while logging in { - switch (packetID) //Packet IDs are different while logging in - { - case 0x03: - if (protocolVersion >= MC_1_8_Version) - compression_treshold = dataTypes.ReadNextVarInt(packetData); - break; - case 0x04: - int messageId = dataTypes.ReadNextVarInt(packetData); - string channel = dataTypes.ReadNextString(packetData); - List responseData = new(); - bool understood = pForge.HandleLoginPluginRequest(channel, packetData, ref responseData); - SendLoginPluginResponse(messageId, understood, responseData.ToArray()); - return understood; - default: - return false; //Ignored packet - } + case 0x03: + if (protocolVersion >= MC_1_8_Version) + compression_treshold = dataTypes.ReadNextVarInt(packetData); + break; + case 0x04: + int messageId = dataTypes.ReadNextVarInt(packetData); + string channel = dataTypes.ReadNextString(packetData); + List responseData = new(); + bool understood = pForge.HandleLoginPluginRequest(channel, packetData, ref responseData); + SendLoginPluginResponse(messageId, understood, responseData.ToArray()); + return understood; + default: + return false; //Ignored packet } - // Regular in-game packets - else switch (packetPalette.GetIncommingTypeById(packetID)) - { - case PacketTypesIn.KeepAlive: - SendPacket(PacketTypesOut.KeepAlive, packetData); - handler.OnServerKeepAlive(); - break; - case PacketTypesIn.Ping: - SendPacket(PacketTypesOut.Pong, packetData); - break; - case PacketTypesIn.JoinGame: - handler.OnGameJoined(); - int playerEntityID = dataTypes.ReadNextInt(packetData); - handler.OnReceivePlayerEntityID(playerEntityID); + } + // Regular in-game packets + else switch (packetPalette.GetIncommingTypeById(packetID)) + { + case PacketTypesIn.KeepAlive: + SendPacket(PacketTypesOut.KeepAlive, packetData); + handler.OnServerKeepAlive(); + break; + case PacketTypesIn.Ping: + SendPacket(PacketTypesOut.Pong, packetData); + break; + case PacketTypesIn.JoinGame: + handler.OnGameJoined(); + int playerEntityID = dataTypes.ReadNextInt(packetData); + handler.OnReceivePlayerEntityID(playerEntityID); - if (protocolVersion >= MC_1_16_2_Version) - dataTypes.ReadNextBool(packetData); // Is hardcore - 1.16.2 and above + if (protocolVersion >= MC_1_16_2_Version) + dataTypes.ReadNextBool(packetData); // Is hardcore - 1.16.2 and above - handler.OnGamemodeUpdate(Guid.Empty, dataTypes.ReadNextByte(packetData)); + handler.OnGamemodeUpdate(Guid.Empty, dataTypes.ReadNextByte(packetData)); - if (protocolVersion >= MC_1_16_Version) - { - dataTypes.ReadNextByte(packetData); // Previous Gamemode - 1.16 and above - int worldCount = dataTypes.ReadNextVarInt(packetData); // Dimension Count (World Count) - 1.16 and above - for (int i = 0; i < worldCount; i++) - dataTypes.ReadNextString(packetData); // Dimension Names (World Names) - 1.16 and above - var registryCodec = dataTypes.ReadNextNbt(packetData); // Registry Codec (Dimension Codec) - 1.16 and above - if (protocolVersion >= MC_1_19_Version) - ChatParser.ReadChatType(registryCodec); - if (handler.GetTerrainEnabled()) - World.StoreDimensionList(registryCodec); - } - - // Current dimension - // String: 1.19 and above - // NBT Tag Compound: [1.16.2 to 1.18.2] - // String identifier: 1.16 and 1.16.1 - // varInt: [1.9.1 to 1.15.2] - // byte: below 1.9.1 - string? dimensionTypeName = null; - Dictionary? dimensionType = null; - if (protocolVersion >= MC_1_16_Version) - { - if (protocolVersion >= MC_1_19_Version) - dimensionTypeName = dataTypes.ReadNextString(packetData); // Dimension Type: Identifier - else if (protocolVersion >= MC_1_16_2_Version) - dimensionType = dataTypes.ReadNextNbt(packetData); // Dimension Type: NBT Tag Compound - else - dataTypes.ReadNextString(packetData); - currentDimension = 0; - } - else if (protocolVersion >= MC_1_9_1_Version) - currentDimension = dataTypes.ReadNextInt(packetData); - else - currentDimension = (sbyte)dataTypes.ReadNextByte(packetData); - - if (protocolVersion < MC_1_14_Version) - dataTypes.ReadNextByte(packetData); // Difficulty - 1.13 and below - - if (protocolVersion >= MC_1_16_Version) - { - string dimensionName = dataTypes.ReadNextString(packetData); // Dimension Name (World Name) - 1.16 and above - if (handler.GetTerrainEnabled()) - { - if (protocolVersion >= MC_1_16_2_Version && protocolVersion <= MC_1_18_2_Version) - { - World.StoreOneDimension(dimensionName, dimensionType!); - World.SetDimension(dimensionName); - } - else if (protocolVersion >= MC_1_19_Version) - { - World.SetDimension(dimensionTypeName!); - } - } - } - - if (protocolVersion >= MC_1_15_Version) - dataTypes.ReadNextLong(packetData); // Hashed world seed - 1.15 and above - if (protocolVersion >= MC_1_16_2_Version) - dataTypes.ReadNextVarInt(packetData); // Max Players - 1.16.2 and above - else - dataTypes.ReadNextByte(packetData); // Max Players - 1.16.1 and below - if (protocolVersion < MC_1_16_Version) - dataTypes.SkipNextString(packetData); // Level Type - 1.15 and below - if (protocolVersion >= MC_1_14_Version) - dataTypes.ReadNextVarInt(packetData); // View distance - 1.14 and above - if (protocolVersion >= MC_1_18_1_Version) - dataTypes.ReadNextVarInt(packetData); // Simulation Distance - 1.18 and above - if (protocolVersion >= MC_1_8_Version) - dataTypes.ReadNextBool(packetData); // Reduced debug info - 1.8 and above - if (protocolVersion >= MC_1_15_Version) - dataTypes.ReadNextBool(packetData); // Enable respawn screen - 1.15 and above - if (protocolVersion >= MC_1_16_Version) - { - dataTypes.ReadNextBool(packetData); // Is Debug - 1.16 and above - dataTypes.ReadNextBool(packetData); // Is Flat - 1.16 and above - } + if (protocolVersion >= MC_1_16_Version) + { + dataTypes.ReadNextByte(packetData); // Previous Gamemode - 1.16 and above + int worldCount = dataTypes.ReadNextVarInt(packetData); // Dimension Count (World Count) - 1.16 and above + for (int i = 0; i < worldCount; i++) + dataTypes.ReadNextString(packetData); // Dimension Names (World Names) - 1.16 and above + var registryCodec = dataTypes.ReadNextNbt(packetData); // Registry Codec (Dimension Codec) - 1.16 and above if (protocolVersion >= MC_1_19_Version) - { - bool hasDeathLocation = dataTypes.ReadNextBool(packetData); // Has death location - if (hasDeathLocation) - { - dataTypes.SkipNextString(packetData); // Death dimension name: Identifier - dataTypes.ReadNextLocation(packetData); // Death location - } - } + ChatParser.ReadChatType(registryCodec); + if (handler.GetTerrainEnabled()) + World.StoreDimensionList(registryCodec); + } - break; - case PacketTypesIn.DeclareCommands: + // Current dimension + // String: 1.19 and above + // NBT Tag Compound: [1.16.2 to 1.18.2] + // String identifier: 1.16 and 1.16.1 + // varInt: [1.9.1 to 1.15.2] + // byte: below 1.9.1 + string? dimensionTypeName = null; + Dictionary? dimensionType = null; + if (protocolVersion >= MC_1_16_Version) + { if (protocolVersion >= MC_1_19_Version) - DeclareCommands.Read(dataTypes, packetData); - break; - case PacketTypesIn.ChatMessage: - int messageType = 0; - - if (protocolVersion <= MC_1_18_2_Version) // 1.18 and bellow - { - string message = dataTypes.ReadNextString(packetData); - - Guid senderUUID; - if (protocolVersion >= MC_1_8_Version) - { - //Hide system messages or xp bar messages? - messageType = dataTypes.ReadNextByte(packetData); - if ((messageType == 1 && !Config.Main.Advanced.ShowSystemMessages) - || (messageType == 2 && !Config.Main.Advanced.ShowSystemMessages)) - break; - - if (protocolVersion >= MC_1_16_5_Version) - senderUUID = dataTypes.ReadNextUUID(packetData); - else senderUUID = Guid.Empty; - } - else - senderUUID = Guid.Empty; - - handler.OnTextReceived(new(message, null, true, messageType, senderUUID)); - } - else if (protocolVersion == MC_1_19_Version) // 1.19 - { - string signedChat = dataTypes.ReadNextString(packetData); - - bool hasUnsignedChatContent = dataTypes.ReadNextBool(packetData); - string? unsignedChatContent = hasUnsignedChatContent ? dataTypes.ReadNextString(packetData) : null; - - messageType = dataTypes.ReadNextVarInt(packetData); - if ((messageType == 1 && !Config.Main.Advanced.ShowSystemMessages) - || (messageType == 2 && !Config.Main.Advanced.ShowXPBarMessages)) - break; - - Guid senderUUID = dataTypes.ReadNextUUID(packetData); - string senderDisplayName = ChatParser.ParseText(dataTypes.ReadNextString(packetData)); - - bool hasSenderTeamName = dataTypes.ReadNextBool(packetData); - string? senderTeamName = hasSenderTeamName ? ChatParser.ParseText(dataTypes.ReadNextString(packetData)) : null; - - long timestamp = dataTypes.ReadNextLong(packetData); - - long salt = dataTypes.ReadNextLong(packetData); - - byte[] messageSignature = dataTypes.ReadNextByteArray(packetData); - - bool verifyResult; - if (!isOnlineMode) - verifyResult = false; - else if (senderUUID == handler.GetUserUuid()) - verifyResult = true; - else - { - PlayerInfo? player = handler.GetPlayerInfo(senderUUID); - verifyResult = player != null && player.VerifyMessage(signedChat, timestamp, salt, ref messageSignature); - } - - ChatMessage chat = new(signedChat, true, messageType, senderUUID, unsignedChatContent, senderDisplayName, senderTeamName, timestamp, messageSignature, verifyResult); - handler.OnTextReceived(chat); - } - else if (protocolVersion == MC_1_19_2_Version) - { - // 1.19.1 - 1.19.2 - byte[]? precedingSignature = dataTypes.ReadNextBool(packetData) ? dataTypes.ReadNextByteArray(packetData) : null; - Guid senderUUID = dataTypes.ReadNextUUID(packetData); - byte[] headerSignature = dataTypes.ReadNextByteArray(packetData); - - string signedChat = dataTypes.ReadNextString(packetData); - string? decorated = dataTypes.ReadNextBool(packetData) ? dataTypes.ReadNextString(packetData) : null; - - long timestamp = dataTypes.ReadNextLong(packetData); - long salt = dataTypes.ReadNextLong(packetData); - - int lastSeenMessageListLen = dataTypes.ReadNextVarInt(packetData); - LastSeenMessageList.AcknowledgedMessage[] lastSeenMessageList = new LastSeenMessageList.AcknowledgedMessage[lastSeenMessageListLen]; - for (int i = 0; i < lastSeenMessageListLen; ++i) - { - Guid user = dataTypes.ReadNextUUID(packetData); - byte[] lastSignature = dataTypes.ReadNextByteArray(packetData); - lastSeenMessageList[i] = new(user, lastSignature, true); - } - LastSeenMessageList lastSeenMessages = new(lastSeenMessageList); - - string? unsignedChatContent = dataTypes.ReadNextBool(packetData) ? dataTypes.ReadNextString(packetData) : null; - - MessageFilterType filterEnum = (MessageFilterType)dataTypes.ReadNextVarInt(packetData); - if (filterEnum == MessageFilterType.PartiallyFiltered) - dataTypes.ReadNextULongArray(packetData); - - int chatTypeId = dataTypes.ReadNextVarInt(packetData); - string chatName = dataTypes.ReadNextString(packetData); - string? targetName = dataTypes.ReadNextBool(packetData) ? dataTypes.ReadNextString(packetData) : null; - - Dictionary chatInfo = Json.ParseJson(chatName).Properties; - string senderDisplayName = (chatInfo.ContainsKey("insertion") ? chatInfo["insertion"] : chatInfo["text"]).StringValue; - string? senderTeamName = null; - ChatParser.MessageType messageTypeEnum = ChatParser.ChatId2Type!.GetValueOrDefault(chatTypeId, ChatParser.MessageType.CHAT); - if (targetName != null && - (messageTypeEnum == ChatParser.MessageType.TEAM_MSG_COMMAND_INCOMING || messageTypeEnum == ChatParser.MessageType.TEAM_MSG_COMMAND_OUTGOING)) - senderTeamName = Json.ParseJson(targetName).Properties["with"].DataArray[0].Properties["text"].StringValue; - - if (string.IsNullOrWhiteSpace(senderDisplayName)) - { - PlayerInfo? player = handler.GetPlayerInfo(senderUUID); - if (player != null && (player.DisplayName != null || player.Name != null) && string.IsNullOrWhiteSpace(senderDisplayName)) - { - senderDisplayName = ChatParser.ParseText(player.DisplayName ?? player.Name); - if (string.IsNullOrWhiteSpace(senderDisplayName)) - senderDisplayName = player.DisplayName ?? player.Name; - else - senderDisplayName += "§r"; - } - } - - bool verifyResult; - if (!isOnlineMode) - verifyResult = false; - else if (senderUUID == handler.GetUserUuid()) - verifyResult = true; - else - { - PlayerInfo? player = handler.GetPlayerInfo(senderUUID); - if (player == null || !player.IsMessageChainLegal()) - verifyResult = false; - else - { - bool lastVerifyResult = player.IsMessageChainLegal(); - verifyResult = player.VerifyMessage(signedChat, timestamp, salt, ref headerSignature, ref precedingSignature, lastSeenMessages); - if (lastVerifyResult && !verifyResult) - log.Warn(string.Format(Translations.chat_message_chain_broken, senderDisplayName)); - } - } - - ChatMessage chat = new(signedChat, false, chatTypeId, senderUUID, unsignedChatContent, senderDisplayName, senderTeamName, timestamp, headerSignature, verifyResult); - if (isOnlineMode && !chat.LacksSender()) - Acknowledge(chat); - handler.OnTextReceived(chat); - } - else if (protocolVersion >= MC_1_19_3_Version) - { - // 1.19.3+ - // Header section - // net.minecraft.network.packet.s2c.play.ChatMessageS2CPacket#write - Guid senderUUID = dataTypes.ReadNextUUID(packetData); - int index = dataTypes.ReadNextVarInt(packetData); - // Signature is fixed size of 256 bytes - byte[]? messageSignature = dataTypes.ReadNextBool(packetData) ? dataTypes.ReadNextByteArray(packetData, 256) : null; - - // Body - // net.minecraft.network.message.MessageBody.Serialized#write - string message = dataTypes.ReadNextString(packetData); - long timestamp = dataTypes.ReadNextLong(packetData); - long salt = dataTypes.ReadNextLong(packetData); - - // Previous Messages - // net.minecraft.network.message.LastSeenMessageList.Indexed#write - // net.minecraft.network.message.MessageSignatureData.Indexed#write - int totalPreviousMessages = dataTypes.ReadNextVarInt(packetData); - Tuple[] previousMessageSignatures = new Tuple[totalPreviousMessages]; - for (int i = 0; i < totalPreviousMessages; i++) - { - // net.minecraft.network.message.MessageSignatureData.Indexed#fromBuf - int messageId = dataTypes.ReadNextVarInt(packetData) - 1; - if (messageId == -1) - previousMessageSignatures[i] = new Tuple(messageId, dataTypes.ReadNextByteArray(packetData, 256)); - else - previousMessageSignatures[i] = new Tuple(messageId, null); - } - - // Other - string? unsignedChatContent = dataTypes.ReadNextBool(packetData) ? dataTypes.ReadNextString(packetData) : null; - - MessageFilterType filterType = (MessageFilterType)dataTypes.ReadNextVarInt(packetData); - - if (filterType == MessageFilterType.PartiallyFiltered) - dataTypes.ReadNextULongArray(packetData); - - // Network Target - // net.minecraft.network.message.MessageType.Serialized#write - int chatTypeId = dataTypes.ReadNextVarInt(packetData); - string chatName = dataTypes.ReadNextString(packetData); - string? targetName = dataTypes.ReadNextBool(packetData) ? dataTypes.ReadNextString(packetData) : null; - - ChatParser.MessageType messageTypeEnum = ChatParser.ChatId2Type!.GetValueOrDefault(chatTypeId, ChatParser.MessageType.CHAT); - - Dictionary chatInfo = Json.ParseJson(targetName ?? chatName).Properties; - string senderDisplayName = (chatInfo.ContainsKey("insertion") ? chatInfo["insertion"] : chatInfo["text"]).StringValue; - string? senderTeamName = null; - if (targetName != null && - (messageTypeEnum == ChatParser.MessageType.TEAM_MSG_COMMAND_INCOMING || messageTypeEnum == ChatParser.MessageType.TEAM_MSG_COMMAND_OUTGOING)) - senderTeamName = Json.ParseJson(targetName).Properties["with"].DataArray[0].Properties["text"].StringValue; - - if (string.IsNullOrWhiteSpace(senderDisplayName)) - { - PlayerInfo? player = handler.GetPlayerInfo(senderUUID); - if (player != null && (player.DisplayName != null || player.Name != null) && string.IsNullOrWhiteSpace(senderDisplayName)) - { - senderDisplayName = ChatParser.ParseText(player.DisplayName ?? player.Name); - if (string.IsNullOrWhiteSpace(senderDisplayName)) - senderDisplayName = player.DisplayName ?? player.Name; - else - senderDisplayName += "§r"; - } - } - - bool verifyResult; - if (!isOnlineMode || messageSignature == null) - verifyResult = false; - else - { - if (senderUUID == handler.GetUserUuid()) - verifyResult = true; - else - { - PlayerInfo? player = handler.GetPlayerInfo(senderUUID); - if (player == null || !player.IsMessageChainLegal()) - verifyResult = false; - else - { - verifyResult = false; - verifyResult = player.VerifyMessage(message, senderUUID, player.ChatUuid, index, timestamp, salt, ref messageSignature, previousMessageSignatures); - } - } - } - - ChatMessage chat = new(message, false, chatTypeId, senderUUID, unsignedChatContent, senderDisplayName, senderTeamName, timestamp, messageSignature, verifyResult); - if (isOnlineMode && !chat.LacksSender() && verifyResult) - Acknowledge(chat); - handler.OnTextReceived(chat); - } - break; - case PacketTypesIn.SystemChat: - string systemMessage = dataTypes.ReadNextString(packetData); - if (protocolVersion >= MC_1_19_3_Version) - { - bool isOverlay = dataTypes.ReadNextBool(packetData); - if (isOverlay) - { - if (!Config.Main.Advanced.ShowXPBarMessages) - break; - } - else - { - if (!Config.Main.Advanced.ShowSystemMessages) - break; - } - handler.OnTextReceived(new(systemMessage, null, true, -1, Guid.Empty, true)); - } + dimensionTypeName = dataTypes.ReadNextString(packetData); // Dimension Type: Identifier + else if (protocolVersion >= MC_1_16_2_Version) + dimensionType = dataTypes.ReadNextNbt(packetData); // Dimension Type: NBT Tag Compound else - { - int msgType = dataTypes.ReadNextVarInt(packetData); - if ((msgType == 1 && !Config.Main.Advanced.ShowSystemMessages)) - break; - handler.OnTextReceived(new(systemMessage, null, true, msgType, Guid.Empty, true)); - } - break; - case PacketTypesIn.ProfilelessChatMessage: - string message_ = dataTypes.ReadNextString(packetData); - int messageType_ = dataTypes.ReadNextVarInt(packetData); - string messageName = dataTypes.ReadNextString(packetData); - string? targetName_ = dataTypes.ReadNextBool(packetData) ? dataTypes.ReadNextString(packetData) : null; - ChatMessage profilelessChat = new(message_, targetName_ ?? messageName, true, messageType_, Guid.Empty, true); - profilelessChat.isSenderJson = true; - handler.OnTextReceived(profilelessChat); - break; - case PacketTypesIn.CombatEvent: - // 1.8 - 1.16.5 - if (protocolVersion >= MC_1_8_Version && protocolVersion <= MC_1_16_5_Version) - { - CombatEventType eventType = (CombatEventType)dataTypes.ReadNextVarInt(packetData); + dataTypes.ReadNextString(packetData); + currentDimension = 0; + } + else if (protocolVersion >= MC_1_9_1_Version) + currentDimension = dataTypes.ReadNextInt(packetData); + else + currentDimension = (sbyte)dataTypes.ReadNextByte(packetData); - if (eventType == CombatEventType.EntityDead) - { - dataTypes.SkipNextVarInt(packetData); + if (protocolVersion < MC_1_14_Version) + dataTypes.ReadNextByte(packetData); // Difficulty - 1.13 and below - handler.OnPlayerKilled( - dataTypes.ReadNextInt(packetData), - ChatParser.ParseText(dataTypes.ReadNextString(packetData)) - ); - } - } - - break; - case PacketTypesIn.DeathCombatEvent: - dataTypes.SkipNextVarInt(packetData); - - handler.OnPlayerKilled( - dataTypes.ReadNextInt(packetData), - ChatParser.ParseText(dataTypes.ReadNextString(packetData)) - ); - - break; - case PacketTypesIn.MessageHeader: // 1.19.2 only - if (protocolVersion == MC_1_19_2_Version) - { - byte[]? precedingSignature = dataTypes.ReadNextBool(packetData) ? dataTypes.ReadNextByteArray(packetData) : null; - Guid senderUUID = dataTypes.ReadNextUUID(packetData); - byte[] headerSignature = dataTypes.ReadNextByteArray(packetData); - byte[] bodyDigest = dataTypes.ReadNextByteArray(packetData); - - bool verifyResult; - - if (!isOnlineMode) - verifyResult = false; - else if (senderUUID == handler.GetUserUuid()) - verifyResult = true; - else - { - PlayerInfo? player = handler.GetPlayerInfo(senderUUID); - - if (player == null || !player.IsMessageChainLegal()) - verifyResult = false; - else - { - bool lastVerifyResult = player.IsMessageChainLegal(); - verifyResult = player.VerifyMessageHead(ref precedingSignature, ref headerSignature, ref bodyDigest); - if (lastVerifyResult && !verifyResult) - log.Warn(string.Format(Translations.chat_message_chain_broken, player.Name)); - } - } - } - - break; - case PacketTypesIn.Respawn: - string? dimensionTypeNameRespawn = null; - Dictionary? dimensionTypeRespawn = null; - if (protocolVersion >= MC_1_16_Version) - { - if (protocolVersion >= MC_1_19_Version) - dimensionTypeNameRespawn = dataTypes.ReadNextString(packetData); // Dimension Type: Identifier - else if (protocolVersion >= MC_1_16_2_Version) - dimensionTypeRespawn = dataTypes.ReadNextNbt(packetData); // Dimension Type: NBT Tag Compound - else - dataTypes.ReadNextString(packetData); - currentDimension = 0; - } - else - { // 1.15 and below - currentDimension = dataTypes.ReadNextInt(packetData); - } - - if (protocolVersion >= MC_1_16_Version) - { - string dimensionName = dataTypes.ReadNextString(packetData); // Dimension Name (World Name) - 1.16 and above - if (handler.GetTerrainEnabled()) - { - if (protocolVersion >= MC_1_16_2_Version && protocolVersion <= MC_1_18_2_Version) - { - World.StoreOneDimension(dimensionName, dimensionTypeRespawn!); - World.SetDimension(dimensionName); - } - else if (protocolVersion >= MC_1_19_Version) - { - World.SetDimension(dimensionTypeNameRespawn!); - } - } - } - - if (protocolVersion < MC_1_14_Version) - dataTypes.ReadNextByte(packetData); // Difficulty - 1.13 and below - if (protocolVersion >= MC_1_15_Version) - dataTypes.ReadNextLong(packetData); // Hashed world seed - 1.15 and above - dataTypes.ReadNextByte(packetData); // Gamemode - if (protocolVersion >= MC_1_16_Version) - dataTypes.ReadNextByte(packetData); // Previous Game mode - 1.16 and above - if (protocolVersion < MC_1_16_Version) - dataTypes.SkipNextString(packetData); // Level Type - 1.15 and below - if (protocolVersion >= MC_1_16_Version) - { - dataTypes.ReadNextBool(packetData); // Is Debug - 1.16 and above - dataTypes.ReadNextBool(packetData); // Is Flat - 1.16 and above - dataTypes.ReadNextBool(packetData); // Copy metadata - 1.16 and above - } - if (protocolVersion >= MC_1_19_Version) - { - bool hasDeathLocation = dataTypes.ReadNextBool(packetData); // Has death location - if (hasDeathLocation) - { - dataTypes.ReadNextString(packetData); // Death dimension name: Identifier - dataTypes.ReadNextLocation(packetData); // Death location - } - } - handler.OnRespawn(); - break; - case PacketTypesIn.PlayerPositionAndLook: - { - // These always need to be read, since we need the field after them for teleport confirm - double x = dataTypes.ReadNextDouble(packetData); - double y = dataTypes.ReadNextDouble(packetData); - double z = dataTypes.ReadNextDouble(packetData); - Location location = new(x, y, z); - float yaw = dataTypes.ReadNextFloat(packetData); - float pitch = dataTypes.ReadNextFloat(packetData); - byte locMask = dataTypes.ReadNextByte(packetData); - - // entity handling require player pos for distance calculating - if (handler.GetTerrainEnabled() || handler.GetEntityHandlingEnabled()) - { - if (protocolVersion >= MC_1_8_Version) - { - Location current = handler.GetCurrentLocation(); - location.X = (locMask & 1 << 0) != 0 ? current.X + x : x; - location.Y = (locMask & 1 << 1) != 0 ? current.Y + y : y; - location.Z = (locMask & 1 << 2) != 0 ? current.Z + z : z; - } - } - - if (protocolVersion >= MC_1_9_Version) - { - int teleportID = dataTypes.ReadNextVarInt(packetData); - - if (teleportID < 0) { yaw = LastYaw; pitch = LastPitch; } - else { LastYaw = yaw; LastPitch = pitch; } - - handler.UpdateLocation(location, yaw, pitch); - - // Teleport confirm packet - SendPacket(PacketTypesOut.TeleportConfirm, DataTypes.GetVarInt(teleportID)); - if (Config.Main.Advanced.TemporaryFixBadpacket) - { - SendLocationUpdate(location, true, yaw, pitch, true); - if (teleportID == 1) - SendLocationUpdate(location, true, yaw, pitch, true); - } - } - else - { - handler.UpdateLocation(location, yaw, pitch); - LastYaw = yaw; LastPitch = pitch; - } - - if (protocolVersion >= MC_1_17_Version) - dataTypes.ReadNextBool(packetData); // Dismount Vehicle - 1.17 and above - } - break; - case PacketTypesIn.ChunkData: + if (protocolVersion >= MC_1_16_Version) + { + string dimensionName = dataTypes.ReadNextString(packetData); // Dimension Name (World Name) - 1.16 and above if (handler.GetTerrainEnabled()) { - Interlocked.Increment(ref handler.GetWorld().chunkCnt); - Interlocked.Increment(ref handler.GetWorld().chunkLoadNotCompleted); - - int chunkX = dataTypes.ReadNextInt(packetData); - int chunkZ = dataTypes.ReadNextInt(packetData); - if (protocolVersion >= MC_1_17_Version) + if (protocolVersion >= MC_1_16_2_Version && protocolVersion <= MC_1_18_2_Version) { - ulong[]? verticalStripBitmask = null; - - if (protocolVersion == MC_1_17_Version || protocolVersion == MC_1_17_1_Version) - verticalStripBitmask = dataTypes.ReadNextULongArray(packetData); // Bit Mask Length and Primary Bit Mask - - dataTypes.ReadNextNbt(packetData); // Heightmaps - - if (protocolVersion == MC_1_17_Version || protocolVersion == MC_1_17_1_Version) - { - int biomesLength = dataTypes.ReadNextVarInt(packetData); // Biomes length - for (int i = 0; i < biomesLength; i++) - dataTypes.SkipNextVarInt(packetData); // Biomes - } - - int dataSize = dataTypes.ReadNextVarInt(packetData); // Size - - pTerrain.ProcessChunkColumnData(chunkX, chunkZ, verticalStripBitmask, packetData); - Interlocked.Decrement(ref handler.GetWorld().chunkLoadNotCompleted); - - // Block Entity data: ignored - // Light data: ignored + World.StoreOneDimension(dimensionName, dimensionType!); + World.SetDimension(dimensionName); } + else if (protocolVersion >= MC_1_19_Version) + { + World.SetDimension(dimensionTypeName!); + } + } + } + + if (protocolVersion >= MC_1_15_Version) + dataTypes.ReadNextLong(packetData); // Hashed world seed - 1.15 and above + if (protocolVersion >= MC_1_16_2_Version) + dataTypes.ReadNextVarInt(packetData); // Max Players - 1.16.2 and above + else + dataTypes.ReadNextByte(packetData); // Max Players - 1.16.1 and below + if (protocolVersion < MC_1_16_Version) + dataTypes.SkipNextString(packetData); // Level Type - 1.15 and below + if (protocolVersion >= MC_1_14_Version) + dataTypes.ReadNextVarInt(packetData); // View distance - 1.14 and above + if (protocolVersion >= MC_1_18_1_Version) + dataTypes.ReadNextVarInt(packetData); // Simulation Distance - 1.18 and above + if (protocolVersion >= MC_1_8_Version) + dataTypes.ReadNextBool(packetData); // Reduced debug info - 1.8 and above + if (protocolVersion >= MC_1_15_Version) + dataTypes.ReadNextBool(packetData); // Enable respawn screen - 1.15 and above + if (protocolVersion >= MC_1_16_Version) + { + dataTypes.ReadNextBool(packetData); // Is Debug - 1.16 and above + dataTypes.ReadNextBool(packetData); // Is Flat - 1.16 and above + } + if (protocolVersion >= MC_1_19_Version) + { + bool hasDeathLocation = dataTypes.ReadNextBool(packetData); // Has death location + if (hasDeathLocation) + { + dataTypes.SkipNextString(packetData); // Death dimension name: Identifier + dataTypes.ReadNextLocation(packetData); // Death location + } + } + + break; + case PacketTypesIn.DeclareCommands: + if (protocolVersion >= MC_1_19_Version) + DeclareCommands.Read(dataTypes, packetData); + break; + case PacketTypesIn.ChatMessage: + int messageType = 0; + + if (protocolVersion <= MC_1_18_2_Version) // 1.18 and bellow + { + string message = dataTypes.ReadNextString(packetData); + + Guid senderUUID; + if (protocolVersion >= MC_1_8_Version) + { + //Hide system messages or xp bar messages? + messageType = dataTypes.ReadNextByte(packetData); + if ((messageType == 1 && !Config.Main.Advanced.ShowSystemMessages) + || (messageType == 2 && !Config.Main.Advanced.ShowSystemMessages)) + break; + + if (protocolVersion >= MC_1_16_5_Version) + senderUUID = dataTypes.ReadNextUUID(packetData); + else senderUUID = Guid.Empty; + } + else + senderUUID = Guid.Empty; + + handler.OnTextReceived(new(message, null, true, messageType, senderUUID)); + } + else if (protocolVersion == MC_1_19_Version) // 1.19 + { + string signedChat = dataTypes.ReadNextString(packetData); + + bool hasUnsignedChatContent = dataTypes.ReadNextBool(packetData); + string? unsignedChatContent = hasUnsignedChatContent ? dataTypes.ReadNextString(packetData) : null; + + messageType = dataTypes.ReadNextVarInt(packetData); + if ((messageType == 1 && !Config.Main.Advanced.ShowSystemMessages) + || (messageType == 2 && !Config.Main.Advanced.ShowXPBarMessages)) + break; + + Guid senderUUID = dataTypes.ReadNextUUID(packetData); + string senderDisplayName = ChatParser.ParseText(dataTypes.ReadNextString(packetData)); + + bool hasSenderTeamName = dataTypes.ReadNextBool(packetData); + string? senderTeamName = hasSenderTeamName ? ChatParser.ParseText(dataTypes.ReadNextString(packetData)) : null; + + long timestamp = dataTypes.ReadNextLong(packetData); + + long salt = dataTypes.ReadNextLong(packetData); + + byte[] messageSignature = dataTypes.ReadNextByteArray(packetData); + + bool verifyResult; + if (!isOnlineMode) + verifyResult = false; + else if (senderUUID == handler.GetUserUuid()) + verifyResult = true; + else + { + PlayerInfo? player = handler.GetPlayerInfo(senderUUID); + verifyResult = player != null && player.VerifyMessage(signedChat, timestamp, salt, ref messageSignature); + } + + ChatMessage chat = new(signedChat, true, messageType, senderUUID, unsignedChatContent, senderDisplayName, senderTeamName, timestamp, messageSignature, verifyResult); + handler.OnTextReceived(chat); + } + else if (protocolVersion == MC_1_19_2_Version) + { + // 1.19.1 - 1.19.2 + byte[]? precedingSignature = dataTypes.ReadNextBool(packetData) ? dataTypes.ReadNextByteArray(packetData) : null; + Guid senderUUID = dataTypes.ReadNextUUID(packetData); + byte[] headerSignature = dataTypes.ReadNextByteArray(packetData); + + string signedChat = dataTypes.ReadNextString(packetData); + string? decorated = dataTypes.ReadNextBool(packetData) ? dataTypes.ReadNextString(packetData) : null; + + long timestamp = dataTypes.ReadNextLong(packetData); + long salt = dataTypes.ReadNextLong(packetData); + + int lastSeenMessageListLen = dataTypes.ReadNextVarInt(packetData); + LastSeenMessageList.AcknowledgedMessage[] lastSeenMessageList = new LastSeenMessageList.AcknowledgedMessage[lastSeenMessageListLen]; + for (int i = 0; i < lastSeenMessageListLen; ++i) + { + Guid user = dataTypes.ReadNextUUID(packetData); + byte[] lastSignature = dataTypes.ReadNextByteArray(packetData); + lastSeenMessageList[i] = new(user, lastSignature, true); + } + LastSeenMessageList lastSeenMessages = new(lastSeenMessageList); + + string? unsignedChatContent = dataTypes.ReadNextBool(packetData) ? dataTypes.ReadNextString(packetData) : null; + + MessageFilterType filterEnum = (MessageFilterType)dataTypes.ReadNextVarInt(packetData); + if (filterEnum == MessageFilterType.PartiallyFiltered) + dataTypes.ReadNextULongArray(packetData); + + int chatTypeId = dataTypes.ReadNextVarInt(packetData); + string chatName = dataTypes.ReadNextString(packetData); + string? targetName = dataTypes.ReadNextBool(packetData) ? dataTypes.ReadNextString(packetData) : null; + + Dictionary chatInfo = Json.ParseJson(chatName).Properties; + string senderDisplayName = (chatInfo.ContainsKey("insertion") ? chatInfo["insertion"] : chatInfo["text"]).StringValue; + string? senderTeamName = null; + ChatParser.MessageType messageTypeEnum = ChatParser.ChatId2Type!.GetValueOrDefault(chatTypeId, ChatParser.MessageType.CHAT); + if (targetName != null && + (messageTypeEnum == ChatParser.MessageType.TEAM_MSG_COMMAND_INCOMING || messageTypeEnum == ChatParser.MessageType.TEAM_MSG_COMMAND_OUTGOING)) + senderTeamName = Json.ParseJson(targetName).Properties["with"].DataArray[0].Properties["text"].StringValue; + + if (string.IsNullOrWhiteSpace(senderDisplayName)) + { + PlayerInfo? player = handler.GetPlayerInfo(senderUUID); + if (player != null && (player.DisplayName != null || player.Name != null) && string.IsNullOrWhiteSpace(senderDisplayName)) + { + senderDisplayName = ChatParser.ParseText(player.DisplayName ?? player.Name); + if (string.IsNullOrWhiteSpace(senderDisplayName)) + senderDisplayName = player.DisplayName ?? player.Name; + else + senderDisplayName += "§r"; + } + } + + bool verifyResult; + if (!isOnlineMode) + verifyResult = false; + else if (senderUUID == handler.GetUserUuid()) + verifyResult = true; + else + { + PlayerInfo? player = handler.GetPlayerInfo(senderUUID); + if (player == null || !player.IsMessageChainLegal()) + verifyResult = false; else { - bool chunksContinuous = dataTypes.ReadNextBool(packetData); - if (protocolVersion >= MC_1_16_Version && protocolVersion <= MC_1_16_1_Version) - dataTypes.ReadNextBool(packetData); // Ignore old data - 1.16 to 1.16.1 only - ushort chunkMask = protocolVersion >= MC_1_9_Version - ? (ushort)dataTypes.ReadNextVarInt(packetData) - : dataTypes.ReadNextUShort(packetData); - if (protocolVersion < MC_1_8_Version) - { - ushort addBitmap = dataTypes.ReadNextUShort(packetData); - int compressedDataSize = dataTypes.ReadNextInt(packetData); - byte[] compressed = dataTypes.ReadData(compressedDataSize, packetData); - byte[] decompressed = ZlibUtils.Decompress(compressed); + bool lastVerifyResult = player.IsMessageChainLegal(); + verifyResult = player.VerifyMessage(signedChat, timestamp, salt, ref headerSignature, ref precedingSignature, lastSeenMessages); + if (lastVerifyResult && !verifyResult) + log.Warn(string.Format(Translations.chat_message_chain_broken, senderDisplayName)); + } + } - pTerrain.ProcessChunkColumnData(chunkX, chunkZ, chunkMask, addBitmap, currentDimension == 0, chunksContinuous, currentDimension, new Queue(decompressed)); - Interlocked.Decrement(ref handler.GetWorld().chunkLoadNotCompleted); - } + ChatMessage chat = new(signedChat, false, chatTypeId, senderUUID, unsignedChatContent, senderDisplayName, senderTeamName, timestamp, headerSignature, verifyResult); + if (isOnlineMode && !chat.LacksSender()) + Acknowledge(chat); + handler.OnTextReceived(chat); + } + else if (protocolVersion >= MC_1_19_3_Version) + { + // 1.19.3+ + // Header section + // net.minecraft.network.packet.s2c.play.ChatMessageS2CPacket#write + Guid senderUUID = dataTypes.ReadNextUUID(packetData); + int index = dataTypes.ReadNextVarInt(packetData); + // Signature is fixed size of 256 bytes + byte[]? messageSignature = dataTypes.ReadNextBool(packetData) ? dataTypes.ReadNextByteArray(packetData, 256) : null; + + // Body + // net.minecraft.network.message.MessageBody.Serialized#write + string message = dataTypes.ReadNextString(packetData); + long timestamp = dataTypes.ReadNextLong(packetData); + long salt = dataTypes.ReadNextLong(packetData); + + // Previous Messages + // net.minecraft.network.message.LastSeenMessageList.Indexed#write + // net.minecraft.network.message.MessageSignatureData.Indexed#write + int totalPreviousMessages = dataTypes.ReadNextVarInt(packetData); + Tuple[] previousMessageSignatures = new Tuple[totalPreviousMessages]; + for (int i = 0; i < totalPreviousMessages; i++) + { + // net.minecraft.network.message.MessageSignatureData.Indexed#fromBuf + int messageId = dataTypes.ReadNextVarInt(packetData) - 1; + if (messageId == -1) + previousMessageSignatures[i] = new Tuple(messageId, dataTypes.ReadNextByteArray(packetData, 256)); + else + previousMessageSignatures[i] = new Tuple(messageId, null); + } + + // Other + string? unsignedChatContent = dataTypes.ReadNextBool(packetData) ? dataTypes.ReadNextString(packetData) : null; + + MessageFilterType filterType = (MessageFilterType)dataTypes.ReadNextVarInt(packetData); + + if (filterType == MessageFilterType.PartiallyFiltered) + dataTypes.ReadNextULongArray(packetData); + + // Network Target + // net.minecraft.network.message.MessageType.Serialized#write + int chatTypeId = dataTypes.ReadNextVarInt(packetData); + string chatName = dataTypes.ReadNextString(packetData); + string? targetName = dataTypes.ReadNextBool(packetData) ? dataTypes.ReadNextString(packetData) : null; + + ChatParser.MessageType messageTypeEnum = ChatParser.ChatId2Type!.GetValueOrDefault(chatTypeId, ChatParser.MessageType.CHAT); + + Dictionary chatInfo = Json.ParseJson(targetName ?? chatName).Properties; + string senderDisplayName = (chatInfo.ContainsKey("insertion") ? chatInfo["insertion"] : chatInfo["text"]).StringValue; + string? senderTeamName = null; + if (targetName != null && + (messageTypeEnum == ChatParser.MessageType.TEAM_MSG_COMMAND_INCOMING || messageTypeEnum == ChatParser.MessageType.TEAM_MSG_COMMAND_OUTGOING)) + senderTeamName = Json.ParseJson(targetName).Properties["with"].DataArray[0].Properties["text"].StringValue; + + if (string.IsNullOrWhiteSpace(senderDisplayName)) + { + PlayerInfo? player = handler.GetPlayerInfo(senderUUID); + if (player != null && (player.DisplayName != null || player.Name != null) && string.IsNullOrWhiteSpace(senderDisplayName)) + { + senderDisplayName = ChatParser.ParseText(player.DisplayName ?? player.Name); + if (string.IsNullOrWhiteSpace(senderDisplayName)) + senderDisplayName = player.DisplayName ?? player.Name; + else + senderDisplayName += "§r"; + } + } + + bool verifyResult; + if (!isOnlineMode || messageSignature == null) + verifyResult = false; + else + { + if (senderUUID == handler.GetUserUuid()) + verifyResult = true; + else + { + PlayerInfo? player = handler.GetPlayerInfo(senderUUID); + if (player == null || !player.IsMessageChainLegal()) + verifyResult = false; else { - if (protocolVersion >= MC_1_14_Version) - dataTypes.ReadNextNbt(packetData); // Heightmaps - 1.14 and above - int biomesLength = 0; - if (protocolVersion >= MC_1_16_2_Version) - if (chunksContinuous) - biomesLength = dataTypes.ReadNextVarInt(packetData); // Biomes length - 1.16.2 and above - if (protocolVersion >= MC_1_15_Version && chunksContinuous) - { - if (protocolVersion >= MC_1_16_2_Version) - { - for (int i = 0; i < biomesLength; i++) - { - // Biomes - 1.16.2 and above - // Don't use ReadNextVarInt because it cost too much time - dataTypes.SkipNextVarInt(packetData); - } - } - else dataTypes.DropData(1024 * 4, packetData); // Biomes - 1.15 and above - } - int dataSize = dataTypes.ReadNextVarInt(packetData); - - pTerrain.ProcessChunkColumnData(chunkX, chunkZ, chunkMask, 0, false, chunksContinuous, currentDimension, packetData); - Interlocked.Decrement(ref handler.GetWorld().chunkLoadNotCompleted); + verifyResult = false; + verifyResult = player.VerifyMessage(message, senderUUID, player.ChatUuid, index, timestamp, salt, ref messageSignature, previousMessageSignatures); } } } - break; - case PacketTypesIn.MapData: - if (protocolVersion < MC_1_8_Version) - break; - int mapid = dataTypes.ReadNextVarInt(packetData); - byte scale = dataTypes.ReadNextByte(packetData); - - - // 1.9 + - bool trackingPosition = true; - - // 1.14+ - bool locked = false; - - // 1.17+ (locked and trackingPosition switched places) - if (protocolVersion >= MC_1_17_Version) + ChatMessage chat = new(message, false, chatTypeId, senderUUID, unsignedChatContent, senderDisplayName, senderTeamName, timestamp, messageSignature, verifyResult); + if (isOnlineMode && !chat.LacksSender() && verifyResult) + Acknowledge(chat); + handler.OnTextReceived(chat); + } + break; + case PacketTypesIn.SystemChat: + string systemMessage = dataTypes.ReadNextString(packetData); + if (protocolVersion >= MC_1_19_3_Version) + { + bool isOverlay = dataTypes.ReadNextBool(packetData); + if (isOverlay) { - if (protocolVersion >= MC_1_14_Version) - locked = dataTypes.ReadNextBool(packetData); - - if (protocolVersion >= MC_1_9_Version) - trackingPosition = dataTypes.ReadNextBool(packetData); + if (!Config.Main.Advanced.ShowXPBarMessages) + break; } else { - if (protocolVersion >= MC_1_9_Version) - trackingPosition = dataTypes.ReadNextBool(packetData); - - if (protocolVersion >= MC_1_14_Version) - locked = dataTypes.ReadNextBool(packetData); + if (!Config.Main.Advanced.ShowSystemMessages) + break; } + handler.OnTextReceived(new(systemMessage, null, true, -1, Guid.Empty, true)); + } + else + { + int msgType = dataTypes.ReadNextVarInt(packetData); + if ((msgType == 1 && !Config.Main.Advanced.ShowSystemMessages)) + break; + handler.OnTextReceived(new(systemMessage, null, true, msgType, Guid.Empty, true)); + } + break; + case PacketTypesIn.ProfilelessChatMessage: + string message_ = dataTypes.ReadNextString(packetData); + int messageType_ = dataTypes.ReadNextVarInt(packetData); + string messageName = dataTypes.ReadNextString(packetData); + string? targetName_ = dataTypes.ReadNextBool(packetData) ? dataTypes.ReadNextString(packetData) : null; + ChatMessage profilelessChat = new(message_, targetName_ ?? messageName, true, messageType_, Guid.Empty, true); + profilelessChat.isSenderJson = true; + handler.OnTextReceived(profilelessChat); + break; + case PacketTypesIn.CombatEvent: + // 1.8 - 1.16.5 + if (protocolVersion >= MC_1_8_Version && protocolVersion <= MC_1_16_5_Version) + { + CombatEventType eventType = (CombatEventType)dataTypes.ReadNextVarInt(packetData); - int iconcount = 0; - List icons = new(); - - // 1,9 + = needs tracking position to be true to get the icons - if (protocolVersion <= MC_1_16_5_Version || trackingPosition) + if (eventType == CombatEventType.EntityDead) { - iconcount = dataTypes.ReadNextVarInt(packetData); + dataTypes.SkipNextVarInt(packetData); - for (int i = 0; i < iconcount; i++) + handler.OnPlayerKilled( + dataTypes.ReadNextInt(packetData), + ChatParser.ParseText(dataTypes.ReadNextString(packetData)) + ); + } + } + + break; + case PacketTypesIn.DeathCombatEvent: + dataTypes.SkipNextVarInt(packetData); + + handler.OnPlayerKilled( + dataTypes.ReadNextInt(packetData), + ChatParser.ParseText(dataTypes.ReadNextString(packetData)) + ); + + break; + case PacketTypesIn.MessageHeader: // 1.19.2 only + if (protocolVersion == MC_1_19_2_Version) + { + byte[]? precedingSignature = dataTypes.ReadNextBool(packetData) ? dataTypes.ReadNextByteArray(packetData) : null; + Guid senderUUID = dataTypes.ReadNextUUID(packetData); + byte[] headerSignature = dataTypes.ReadNextByteArray(packetData); + byte[] bodyDigest = dataTypes.ReadNextByteArray(packetData); + + bool verifyResult; + + if (!isOnlineMode) + verifyResult = false; + else if (senderUUID == handler.GetUserUuid()) + verifyResult = true; + else + { + PlayerInfo? player = handler.GetPlayerInfo(senderUUID); + + if (player == null || !player.IsMessageChainLegal()) + verifyResult = false; + else { - MapIcon mapIcon = new(); + bool lastVerifyResult = player.IsMessageChainLegal(); + verifyResult = player.VerifyMessageHead(ref precedingSignature, ref headerSignature, ref bodyDigest); + if (lastVerifyResult && !verifyResult) + log.Warn(string.Format(Translations.chat_message_chain_broken, player.Name)); + } + } + } - // 1.8 - 1.13 - if (protocolVersion < MC_1_13_2_Version) - { - byte directionAndtype = dataTypes.ReadNextByte(packetData); - byte direction, type; + break; + case PacketTypesIn.Respawn: + string? dimensionTypeNameRespawn = null; + Dictionary? dimensionTypeRespawn = null; + if (protocolVersion >= MC_1_16_Version) + { + if (protocolVersion >= MC_1_19_Version) + dimensionTypeNameRespawn = dataTypes.ReadNextString(packetData); // Dimension Type: Identifier + else if (protocolVersion >= MC_1_16_2_Version) + dimensionTypeRespawn = dataTypes.ReadNextNbt(packetData); // Dimension Type: NBT Tag Compound + else + dataTypes.ReadNextString(packetData); + currentDimension = 0; + } + else + { // 1.15 and below + currentDimension = dataTypes.ReadNextInt(packetData); + } - // 1.12.2+ - if (protocolVersion >= MC_1_12_2_Version) - { - direction = (byte)(directionAndtype & 0xF); - type = (byte)((directionAndtype >> 4) & 0xF); - } - else // 1.8 - 1.12 - { - direction = (byte)((directionAndtype >> 4) & 0xF); - type = (byte)(directionAndtype & 0xF); - } + if (protocolVersion >= MC_1_16_Version) + { + string dimensionName = dataTypes.ReadNextString(packetData); // Dimension Name (World Name) - 1.16 and above + if (handler.GetTerrainEnabled()) + { + if (protocolVersion >= MC_1_16_2_Version && protocolVersion <= MC_1_18_2_Version) + { + World.StoreOneDimension(dimensionName, dimensionTypeRespawn!); + World.SetDimension(dimensionName); + } + else if (protocolVersion >= MC_1_19_Version) + { + World.SetDimension(dimensionTypeNameRespawn!); + } + } + } - mapIcon.Type = (MapIconType)type; - mapIcon.Direction = direction; - } + if (protocolVersion < MC_1_14_Version) + dataTypes.ReadNextByte(packetData); // Difficulty - 1.13 and below + if (protocolVersion >= MC_1_15_Version) + dataTypes.ReadNextLong(packetData); // Hashed world seed - 1.15 and above + dataTypes.ReadNextByte(packetData); // Gamemode + if (protocolVersion >= MC_1_16_Version) + dataTypes.ReadNextByte(packetData); // Previous Game mode - 1.16 and above + if (protocolVersion < MC_1_16_Version) + dataTypes.SkipNextString(packetData); // Level Type - 1.15 and below + if (protocolVersion >= MC_1_16_Version) + { + dataTypes.ReadNextBool(packetData); // Is Debug - 1.16 and above + dataTypes.ReadNextBool(packetData); // Is Flat - 1.16 and above + dataTypes.ReadNextBool(packetData); // Copy metadata - 1.16 and above + } + if (protocolVersion >= MC_1_19_Version) + { + bool hasDeathLocation = dataTypes.ReadNextBool(packetData); // Has death location + if (hasDeathLocation) + { + dataTypes.ReadNextString(packetData); // Death dimension name: Identifier + dataTypes.ReadNextLocation(packetData); // Death location + } + } + handler.OnRespawn(); + break; + case PacketTypesIn.PlayerPositionAndLook: + { + // These always need to be read, since we need the field after them for teleport confirm + double x = dataTypes.ReadNextDouble(packetData); + double y = dataTypes.ReadNextDouble(packetData); + double z = dataTypes.ReadNextDouble(packetData); + Location location = new(x, y, z); + float yaw = dataTypes.ReadNextFloat(packetData); + float pitch = dataTypes.ReadNextFloat(packetData); + byte locMask = dataTypes.ReadNextByte(packetData); - // 1.13.2+ - if (protocolVersion >= MC_1_13_2_Version) - mapIcon.Type = (MapIconType)dataTypes.ReadNextVarInt(packetData); - - mapIcon.X = dataTypes.ReadNextByte(packetData); - mapIcon.Z = dataTypes.ReadNextByte(packetData); - - // 1.13.2+ - if (protocolVersion >= MC_1_13_2_Version) - { - mapIcon.Direction = dataTypes.ReadNextByte(packetData); - - if (dataTypes.ReadNextBool(packetData)) // Has Display Name? - mapIcon.DisplayName = ChatParser.ParseText(dataTypes.ReadNextString(packetData)); - } - - icons.Add(mapIcon); + // entity handling require player pos for distance calculating + if (handler.GetTerrainEnabled() || handler.GetEntityHandlingEnabled()) + { + if (protocolVersion >= MC_1_8_Version) + { + Location current = handler.GetCurrentLocation(); + location.X = (locMask & 1 << 0) != 0 ? current.X + x : x; + location.Y = (locMask & 1 << 1) != 0 ? current.Y + y : y; + location.Z = (locMask & 1 << 2) != 0 ? current.Z + z : z; } } - byte columnsUpdated = dataTypes.ReadNextByte(packetData); // width - byte rowsUpdated = 0; // height - byte mapCoulmnX = 0; - byte mapRowZ = 0; - byte[]? colors = null; - - if (columnsUpdated > 0) + if (protocolVersion >= MC_1_9_Version) { - rowsUpdated = dataTypes.ReadNextByte(packetData); // height - mapCoulmnX = dataTypes.ReadNextByte(packetData); - mapRowZ = dataTypes.ReadNextByte(packetData); - colors = dataTypes.ReadNextByteArray(packetData); + int teleportID = dataTypes.ReadNextVarInt(packetData); + + if (teleportID < 0) { yaw = LastYaw; pitch = LastPitch; } + else { LastYaw = yaw; LastPitch = pitch; } + + handler.UpdateLocation(location, yaw, pitch); + + // Teleport confirm packet + SendPacket(PacketTypesOut.TeleportConfirm, DataTypes.GetVarInt(teleportID)); + if (Config.Main.Advanced.TemporaryFixBadpacket) + { + SendLocationUpdate(location, true, yaw, pitch, true); + if (teleportID == 1) + SendLocationUpdate(location, true, yaw, pitch, true); + } + } + else + { + handler.UpdateLocation(location, yaw, pitch); + LastYaw = yaw; LastPitch = pitch; } - handler.OnMapData(mapid, scale, trackingPosition, locked, icons, columnsUpdated, rowsUpdated, mapCoulmnX, mapRowZ, colors); + if (protocolVersion >= MC_1_17_Version) + dataTypes.ReadNextBool(packetData); // Dismount Vehicle - 1.17 and above + } + break; + case PacketTypesIn.ChunkData: + if (handler.GetTerrainEnabled()) + { + Interlocked.Increment(ref handler.GetWorld().chunkCnt); + Interlocked.Increment(ref handler.GetWorld().chunkLoadNotCompleted); + + int chunkX = dataTypes.ReadNextInt(packetData); + int chunkZ = dataTypes.ReadNextInt(packetData); + if (protocolVersion >= MC_1_17_Version) + { + ulong[]? verticalStripBitmask = null; + + if (protocolVersion == MC_1_17_Version || protocolVersion == MC_1_17_1_Version) + verticalStripBitmask = dataTypes.ReadNextULongArray(packetData); // Bit Mask Length and Primary Bit Mask + + dataTypes.ReadNextNbt(packetData); // Heightmaps + + if (protocolVersion == MC_1_17_Version || protocolVersion == MC_1_17_1_Version) + { + int biomesLength = dataTypes.ReadNextVarInt(packetData); // Biomes length + for (int i = 0; i < biomesLength; i++) + dataTypes.SkipNextVarInt(packetData); // Biomes + } + + int dataSize = dataTypes.ReadNextVarInt(packetData); // Size + + pTerrain.ProcessChunkColumnData(chunkX, chunkZ, verticalStripBitmask, packetData); + Interlocked.Decrement(ref handler.GetWorld().chunkLoadNotCompleted); + + // Block Entity data: ignored + // Light data: ignored + } + else + { + bool chunksContinuous = dataTypes.ReadNextBool(packetData); + if (protocolVersion >= MC_1_16_Version && protocolVersion <= MC_1_16_1_Version) + dataTypes.ReadNextBool(packetData); // Ignore old data - 1.16 to 1.16.1 only + ushort chunkMask = protocolVersion >= MC_1_9_Version + ? (ushort)dataTypes.ReadNextVarInt(packetData) + : dataTypes.ReadNextUShort(packetData); + if (protocolVersion < MC_1_8_Version) + { + ushort addBitmap = dataTypes.ReadNextUShort(packetData); + int compressedDataSize = dataTypes.ReadNextInt(packetData); + byte[] compressed = dataTypes.ReadData(compressedDataSize, packetData); + byte[] decompressed = ZlibUtils.Decompress(compressed); + + pTerrain.ProcessChunkColumnData(chunkX, chunkZ, chunkMask, addBitmap, currentDimension == 0, chunksContinuous, currentDimension, new Queue(decompressed)); + Interlocked.Decrement(ref handler.GetWorld().chunkLoadNotCompleted); + } + else + { + if (protocolVersion >= MC_1_14_Version) + dataTypes.ReadNextNbt(packetData); // Heightmaps - 1.14 and above + int biomesLength = 0; + if (protocolVersion >= MC_1_16_2_Version) + if (chunksContinuous) + biomesLength = dataTypes.ReadNextVarInt(packetData); // Biomes length - 1.16.2 and above + if (protocolVersion >= MC_1_15_Version && chunksContinuous) + { + if (protocolVersion >= MC_1_16_2_Version) + { + for (int i = 0; i < biomesLength; i++) + { + // Biomes - 1.16.2 and above + // Don't use ReadNextVarInt because it cost too much time + dataTypes.SkipNextVarInt(packetData); + } + } + else dataTypes.DropData(1024 * 4, packetData); // Biomes - 1.15 and above + } + int dataSize = dataTypes.ReadNextVarInt(packetData); + + pTerrain.ProcessChunkColumnData(chunkX, chunkZ, chunkMask, 0, false, chunksContinuous, currentDimension, packetData); + Interlocked.Decrement(ref handler.GetWorld().chunkLoadNotCompleted); + } + } + } + break; + case PacketTypesIn.MapData: + if (protocolVersion < MC_1_8_Version) break; - case PacketTypesIn.TradeList: - if ((protocolVersion >= MC_1_14_Version) && (handler.GetInventoryEnabled())) + + int mapid = dataTypes.ReadNextVarInt(packetData); + byte scale = dataTypes.ReadNextByte(packetData); + + + // 1.9 + + bool trackingPosition = true; + + // 1.14+ + bool locked = false; + + // 1.17+ (locked and trackingPosition switched places) + if (protocolVersion >= MC_1_17_Version) + { + if (protocolVersion >= MC_1_14_Version) + locked = dataTypes.ReadNextBool(packetData); + + if (protocolVersion >= MC_1_9_Version) + trackingPosition = dataTypes.ReadNextBool(packetData); + } + else + { + if (protocolVersion >= MC_1_9_Version) + trackingPosition = dataTypes.ReadNextBool(packetData); + + if (protocolVersion >= MC_1_14_Version) + locked = dataTypes.ReadNextBool(packetData); + } + + int iconcount = 0; + List icons = new(); + + // 1,9 + = needs tracking position to be true to get the icons + if (protocolVersion <= MC_1_16_5_Version || trackingPosition) + { + iconcount = dataTypes.ReadNextVarInt(packetData); + + for (int i = 0; i < iconcount; i++) + { + MapIcon mapIcon = new(); + + // 1.8 - 1.13 + if (protocolVersion < MC_1_13_2_Version) + { + byte directionAndtype = dataTypes.ReadNextByte(packetData); + byte direction, type; + + // 1.12.2+ + if (protocolVersion >= MC_1_12_2_Version) + { + direction = (byte)(directionAndtype & 0xF); + type = (byte)((directionAndtype >> 4) & 0xF); + } + else // 1.8 - 1.12 + { + direction = (byte)((directionAndtype >> 4) & 0xF); + type = (byte)(directionAndtype & 0xF); + } + + mapIcon.Type = (MapIconType)type; + mapIcon.Direction = direction; + } + + // 1.13.2+ + if (protocolVersion >= MC_1_13_2_Version) + mapIcon.Type = (MapIconType)dataTypes.ReadNextVarInt(packetData); + + mapIcon.X = dataTypes.ReadNextByte(packetData); + mapIcon.Z = dataTypes.ReadNextByte(packetData); + + // 1.13.2+ + if (protocolVersion >= MC_1_13_2_Version) + { + mapIcon.Direction = dataTypes.ReadNextByte(packetData); + + if (dataTypes.ReadNextBool(packetData)) // Has Display Name? + mapIcon.DisplayName = ChatParser.ParseText(dataTypes.ReadNextString(packetData)); + } + + icons.Add(mapIcon); + } + } + + byte columnsUpdated = dataTypes.ReadNextByte(packetData); // width + byte rowsUpdated = 0; // height + byte mapCoulmnX = 0; + byte mapRowZ = 0; + byte[]? colors = null; + + if (columnsUpdated > 0) + { + rowsUpdated = dataTypes.ReadNextByte(packetData); // height + mapCoulmnX = dataTypes.ReadNextByte(packetData); + mapRowZ = dataTypes.ReadNextByte(packetData); + colors = dataTypes.ReadNextByteArray(packetData); + } + + handler.OnMapData(mapid, scale, trackingPosition, locked, icons, columnsUpdated, rowsUpdated, mapCoulmnX, mapRowZ, colors); + break; + case PacketTypesIn.TradeList: + if ((protocolVersion >= MC_1_14_Version) && (handler.GetInventoryEnabled())) + { + // MC 1.14 or greater + int windowID = dataTypes.ReadNextVarInt(packetData); + int size = dataTypes.ReadNextByte(packetData); + List trades = new(); + for (int tradeId = 0; tradeId < size; tradeId++) + { + VillagerTrade trade = dataTypes.ReadNextTrade(packetData, itemPalette); + trades.Add(trade); + } + VillagerInfo villagerInfo = new() + { + Level = dataTypes.ReadNextVarInt(packetData), + Experience = dataTypes.ReadNextVarInt(packetData), + IsRegularVillager = dataTypes.ReadNextBool(packetData), + CanRestock = dataTypes.ReadNextBool(packetData) + }; + handler.OnTradeList(windowID, trades, villagerInfo); + } + break; + case PacketTypesIn.Title: + if (protocolVersion >= MC_1_8_Version) + { + int action2 = dataTypes.ReadNextVarInt(packetData); + string titletext = String.Empty; + string subtitletext = String.Empty; + string actionbartext = String.Empty; + string json = String.Empty; + int fadein = -1; + int stay = -1; + int fadeout = -1; + if (protocolVersion >= MC_1_10_Version) + { + if (action2 == 0) + { + json = titletext; + titletext = ChatParser.ParseText(dataTypes.ReadNextString(packetData)); + } + else if (action2 == 1) + { + json = subtitletext; + subtitletext = ChatParser.ParseText(dataTypes.ReadNextString(packetData)); + } + else if (action2 == 2) + { + json = actionbartext; + actionbartext = ChatParser.ParseText(dataTypes.ReadNextString(packetData)); + } + else if (action2 == 3) + { + fadein = dataTypes.ReadNextInt(packetData); + stay = dataTypes.ReadNextInt(packetData); + fadeout = dataTypes.ReadNextInt(packetData); + } + } + else + { + if (action2 == 0) + { + json = titletext; + titletext = ChatParser.ParseText(dataTypes.ReadNextString(packetData)); + } + else if (action2 == 1) + { + json = subtitletext; + subtitletext = ChatParser.ParseText(dataTypes.ReadNextString(packetData)); + } + else if (action2 == 2) + { + fadein = dataTypes.ReadNextInt(packetData); + stay = dataTypes.ReadNextInt(packetData); + fadeout = dataTypes.ReadNextInt(packetData); + } + } + handler.OnTitle(action2, titletext, subtitletext, actionbartext, fadein, stay, fadeout, json); + } + break; + case PacketTypesIn.MultiBlockChange: + if (handler.GetTerrainEnabled()) + { + if (protocolVersion >= MC_1_16_2_Version) + { + long chunkSection = dataTypes.ReadNextLong(packetData); + int sectionX = (int)(chunkSection >> 42); + int sectionY = (int)((chunkSection << 44) >> 44); + int sectionZ = (int)((chunkSection << 22) >> 42); + dataTypes.ReadNextBool(packetData); // Useless boolean (Related to light update) + int blocksSize = dataTypes.ReadNextVarInt(packetData); + for (int i = 0; i < blocksSize; i++) + { + ulong chunkSectionPosition = (ulong)dataTypes.ReadNextVarLong(packetData); + int blockId = (int)(chunkSectionPosition >> 12); + int localX = (int)((chunkSectionPosition >> 8) & 0x0F); + int localZ = (int)((chunkSectionPosition >> 4) & 0x0F); + int localY = (int)(chunkSectionPosition & 0x0F); + + Block block = new((ushort)blockId); + int blockX = (sectionX * 16) + localX; + int blockY = (sectionY * 16) + localY; + int blockZ = (sectionZ * 16) + localZ; + + Location location = new(blockX, blockY, blockZ); + + handler.OnBlockChange(location, block); + } + } + else + { + int chunkX = dataTypes.ReadNextInt(packetData); + int chunkZ = dataTypes.ReadNextInt(packetData); + int recordCount = protocolVersion < MC_1_8_Version + ? (int)dataTypes.ReadNextShort(packetData) + : dataTypes.ReadNextVarInt(packetData); + + for (int i = 0; i < recordCount; i++) + { + byte locationXZ; + ushort blockIdMeta; + int blockY; + + if (protocolVersion < MC_1_8_Version) + { + blockIdMeta = dataTypes.ReadNextUShort(packetData); + blockY = (ushort)dataTypes.ReadNextByte(packetData); + locationXZ = dataTypes.ReadNextByte(packetData); + } + else + { + locationXZ = dataTypes.ReadNextByte(packetData); + blockY = (ushort)dataTypes.ReadNextByte(packetData); + blockIdMeta = (ushort)dataTypes.ReadNextVarInt(packetData); + } + + int blockX = locationXZ >> 4; + int blockZ = locationXZ & 0x0F; + + Location location = new(chunkX, chunkZ, blockX, blockY, blockZ); + Block block = new(blockIdMeta); + handler.OnBlockChange(location, block); + } + } + } + break; + case PacketTypesIn.ServerData: + string motd = "-"; + bool hasMotd = dataTypes.ReadNextBool(packetData); + if (hasMotd) + motd = ChatParser.ParseText(dataTypes.ReadNextString(packetData)); + + string iconBase64 = "-"; + bool hasIcon = dataTypes.ReadNextBool(packetData); + if (hasIcon) + iconBase64 = dataTypes.ReadNextString(packetData); + + bool previewsChat = false; + if (protocolVersion < MC_1_19_3_Version) + previewsChat = dataTypes.ReadNextBool(packetData); + + handler.OnServerDataRecived(hasMotd, motd, hasIcon, iconBase64, previewsChat); + break; + case PacketTypesIn.BlockChange: + if (handler.GetTerrainEnabled()) + { + if (protocolVersion < MC_1_8_Version) + { + int blockX = dataTypes.ReadNextInt(packetData); + int blockY = dataTypes.ReadNextByte(packetData); + int blockZ = dataTypes.ReadNextInt(packetData); + short blockId = (short)dataTypes.ReadNextVarInt(packetData); + byte blockMeta = dataTypes.ReadNextByte(packetData); + + Location location = new(blockX, blockY, blockZ); + Block block = new(blockId, blockMeta); + handler.OnBlockChange(location, block); + } + else + { + Location location = dataTypes.ReadNextLocation(packetData); + Block block = new((ushort)dataTypes.ReadNextVarInt(packetData)); + handler.OnBlockChange(location, block); + } + } + break; + case PacketTypesIn.SetDisplayChatPreview: + bool previewsChatSetting = dataTypes.ReadNextBool(packetData); + handler.OnChatPreviewSettingUpdate(previewsChatSetting); + break; + case PacketTypesIn.ChatSuggestions: + break; + case PacketTypesIn.MapChunkBulk: + if (protocolVersion < MC_1_9_Version && handler.GetTerrainEnabled()) + { + int chunkCount; + bool hasSkyLight; + Queue chunkData = packetData; + + //Read global fields + if (protocolVersion < MC_1_8_Version) + { + chunkCount = dataTypes.ReadNextShort(packetData); + int compressedDataSize = dataTypes.ReadNextInt(packetData); + hasSkyLight = dataTypes.ReadNextBool(packetData); + byte[] compressed = dataTypes.ReadData(compressedDataSize, packetData); + byte[] decompressed = ZlibUtils.Decompress(compressed); + chunkData = new Queue(decompressed); + } + else + { + hasSkyLight = dataTypes.ReadNextBool(packetData); + chunkCount = dataTypes.ReadNextVarInt(packetData); + } + + //Read chunk records + int[] chunkXs = new int[chunkCount]; + int[] chunkZs = new int[chunkCount]; + ushort[] chunkMasks = new ushort[chunkCount]; + ushort[] addBitmaps = new ushort[chunkCount]; + for (int chunkColumnNo = 0; chunkColumnNo < chunkCount; chunkColumnNo++) + { + chunkXs[chunkColumnNo] = dataTypes.ReadNextInt(packetData); + chunkZs[chunkColumnNo] = dataTypes.ReadNextInt(packetData); + chunkMasks[chunkColumnNo] = dataTypes.ReadNextUShort(packetData); + addBitmaps[chunkColumnNo] = protocolVersion < MC_1_8_Version + ? dataTypes.ReadNextUShort(packetData) + : (ushort)0; + } + + //Process chunk records + for (int chunkColumnNo = 0; chunkColumnNo < chunkCount; chunkColumnNo++) + { + pTerrain.ProcessChunkColumnData(chunkXs[chunkColumnNo], chunkZs[chunkColumnNo], chunkMasks[chunkColumnNo], addBitmaps[chunkColumnNo], hasSkyLight, true, currentDimension, chunkData); + Interlocked.Decrement(ref handler.GetWorld().chunkLoadNotCompleted); + } + + } + break; + case PacketTypesIn.UnloadChunk: + if (protocolVersion >= MC_1_9_Version && handler.GetTerrainEnabled()) + { + int chunkX = dataTypes.ReadNextInt(packetData); + int chunkZ = dataTypes.ReadNextInt(packetData); + + // Warning: It is legal to include unloaded chunks in the UnloadChunk packet. + // Since chunks that have not been loaded are not recorded, this may result + // in loading chunks that should be unloaded and inaccurate statistics. + if (handler.GetWorld()[chunkX, chunkZ] != null) + Interlocked.Decrement(ref handler.GetWorld().chunkCnt); + + handler.GetWorld()[chunkX, chunkZ] = null; + } + break; + case PacketTypesIn.ChangeGameState: + if (protocolVersion >= MC_1_15_2_Version) + { + byte reason = dataTypes.ReadNextByte(packetData); + float state = dataTypes.ReadNextFloat(packetData); + + handler.OnGameEvent(reason, state); + } + break; + case PacketTypesIn.PlayerInfo: + if (protocolVersion >= MC_1_19_3_Version) + { + byte actionBitset = dataTypes.ReadNextByte(packetData); + int numberOfActions = dataTypes.ReadNextVarInt(packetData); + for (int i = 0; i < numberOfActions; i++) + { + Guid playerUuid = dataTypes.ReadNextUUID(packetData); + + if ((actionBitset & (1 << 0)) > 0) // Actions bit 0: add player + { + string name = dataTypes.ReadNextString(packetData); + int numberOfProperties = dataTypes.ReadNextVarInt(packetData); + for (int j = 0; j < numberOfProperties; ++j) + { + dataTypes.SkipNextString(packetData); + dataTypes.SkipNextString(packetData); + if (dataTypes.ReadNextBool(packetData)) + dataTypes.SkipNextString(packetData); + } + handler.OnPlayerJoin(new(name, playerUuid)); + } + + PlayerInfo player = handler.GetPlayerInfo(playerUuid)!; + if ((actionBitset & (1 << 1)) > 0) // Actions bit 1: initialize chat + { + bool hasSignatureData = dataTypes.ReadNextBool(packetData); + if (hasSignatureData) + { + Guid chatUuid = dataTypes.ReadNextUUID(packetData); + long publicKeyExpiryTime = dataTypes.ReadNextLong(packetData); + byte[] encodedPublicKey = dataTypes.ReadNextByteArray(packetData); + byte[] publicKeySignature = dataTypes.ReadNextByteArray(packetData); + player.SetPublicKey(chatUuid, publicKeyExpiryTime, encodedPublicKey, publicKeySignature); + } + else + { + player.ClearPublicKey(); + } + } + if ((actionBitset & 1 << 2) > 0) // Actions bit 2: update gamemode + { + handler.OnGamemodeUpdate(playerUuid, dataTypes.ReadNextVarInt(packetData)); + } + if ((actionBitset & (1 << 3)) > 0) // Actions bit 3: update listed + { + player.Listed = dataTypes.ReadNextBool(packetData); + } + if ((actionBitset & (1 << 4)) > 0) // Actions bit 4: update latency + { + int latency = dataTypes.ReadNextVarInt(packetData); + handler.OnLatencyUpdate(playerUuid, latency); //Update latency; + } + if ((actionBitset & (1 << 5)) > 0) // Actions bit 5: update display name + { + if (dataTypes.ReadNextBool(packetData)) + player.DisplayName = dataTypes.ReadNextString(packetData); + else + player.DisplayName = null; + } + } + } + else if (protocolVersion >= MC_1_8_Version) + { + int action = dataTypes.ReadNextVarInt(packetData); // Action Name + int numberOfPlayers = dataTypes.ReadNextVarInt(packetData); // Number Of Players + + for (int i = 0; i < numberOfPlayers; i++) + { + Guid uuid = dataTypes.ReadNextUUID(packetData); // Player UUID + + switch (action) + { + case 0x00: //Player Join (Add player since 1.19) + string name = dataTypes.ReadNextString(packetData); // Player name + int propNum = dataTypes.ReadNextVarInt(packetData); // Number of properties in the following array + + // Property: Tuple[]? properties = useProperty ? + new Tuple[propNum] : null; + for (int p = 0; p < propNum; p++) + { + string propertyName = dataTypes.ReadNextString(packetData); // Name: String (32767) + string val = dataTypes.ReadNextString(packetData); // Value: String (32767) + string? propertySignature = null; + if (dataTypes.ReadNextBool(packetData)) // Is Signed + propertySignature = dataTypes.ReadNextString(packetData); // Signature: String (32767) + if (useProperty) + properties![p] = new(propertyName, val, propertySignature); + } +#pragma warning restore CS0162 // Unreachable code detected + + int gameMode = dataTypes.ReadNextVarInt(packetData); // Gamemode + handler.OnGamemodeUpdate(uuid, gameMode); + + int ping = dataTypes.ReadNextVarInt(packetData); // Ping + + string? displayName = null; + if (dataTypes.ReadNextBool(packetData)) // Has display name + displayName = dataTypes.ReadNextString(packetData); // Display name + + // 1.19 Additions + long? keyExpiration = null; + byte[]? publicKey = null, signature = null; + if (protocolVersion >= MC_1_19_Version) + { + if (dataTypes.ReadNextBool(packetData)) // Has Sig Data (if true, red the following fields) + { + keyExpiration = dataTypes.ReadNextLong(packetData); // Timestamp + + int publicKeyLength = dataTypes.ReadNextVarInt(packetData); // Public Key Length + if (publicKeyLength > 0) + publicKey = dataTypes.ReadData(publicKeyLength, packetData); // Public key + + int signatureLength = dataTypes.ReadNextVarInt(packetData); // Signature Length + if (signatureLength > 0) + signature = dataTypes.ReadData(signatureLength, packetData); // Public key + } + } + + handler.OnPlayerJoin(new PlayerInfo(uuid, name, properties, gameMode, ping, displayName, keyExpiration, publicKey, signature)); + break; + case 0x01: //Update gamemode + handler.OnGamemodeUpdate(uuid, dataTypes.ReadNextVarInt(packetData)); + break; + case 0x02: //Update latency + int latency = dataTypes.ReadNextVarInt(packetData); + handler.OnLatencyUpdate(uuid, latency); //Update latency; + break; + case 0x03: //Update display name + if (dataTypes.ReadNextBool(packetData)) + { + PlayerInfo? player = handler.GetPlayerInfo(uuid); + if (player != null) + player.DisplayName = dataTypes.ReadNextString(packetData); + else + dataTypes.SkipNextString(packetData); + } + break; + case 0x04: //Player Leave + handler.OnPlayerLeave(uuid); + break; + default: + //Unknown player list item type + break; + } + } + } + else //MC 1.7.X does not provide UUID in tab-list updates + { + string name = dataTypes.ReadNextString(packetData); + bool online = dataTypes.ReadNextBool(packetData); + short ping = dataTypes.ReadNextShort(packetData); + Guid FakeUUID = new(MD5.Create().ComputeHash(Encoding.UTF8.GetBytes(name)).Take(16).ToArray()); + if (online) + handler.OnPlayerJoin(new PlayerInfo(name, FakeUUID)); + else handler.OnPlayerLeave(FakeUUID); + } + break; + case PacketTypesIn.PlayerRemove: + int numberOfLeavePlayers = dataTypes.ReadNextVarInt(packetData); + for (int i = 0; i < numberOfLeavePlayers; ++i) + { + Guid playerUuid = dataTypes.ReadNextUUID(packetData); + handler.OnPlayerLeave(playerUuid); + } + break; + case PacketTypesIn.TabComplete: + if (protocolVersion >= MC_1_13_Version) + { + autocomplete_transaction_id = dataTypes.ReadNextVarInt(packetData); + dataTypes.ReadNextVarInt(packetData); // Start of text to replace + dataTypes.ReadNextVarInt(packetData); // Length of text to replace + } + + int autocomplete_count = dataTypes.ReadNextVarInt(packetData); + autocomplete_result.Clear(); + + for (int i = 0; i < autocomplete_count; i++) + { + autocomplete_result.Add(dataTypes.ReadNextString(packetData)); + if (protocolVersion >= MC_1_13_Version) + { + // Skip optional tooltip for each tab-complete result + if (dataTypes.ReadNextBool(packetData)) + dataTypes.SkipNextString(packetData); + } + } + + autocomplete_received = true; + break; + case PacketTypesIn.PluginMessage: + String channel = dataTypes.ReadNextString(packetData); + // Length is unneeded as the whole remaining packetData is the entire payload of the packet. + if (protocolVersion < MC_1_8_Version) + pForge.ReadNextVarShort(packetData); + handler.OnPluginChannelMessage(channel, packetData.ToArray()); + return pForge.HandlePluginMessage(channel, packetData, ref currentDimension); + case PacketTypesIn.Disconnect: + handler.OnConnectionLost(ChatBot.DisconnectReason.InGameKick, ChatParser.ParseText(dataTypes.ReadNextString(packetData))); + return false; + case PacketTypesIn.SetCompression: + if (protocolVersion >= MC_1_8_Version && protocolVersion < MC_1_9_Version) + compression_treshold = dataTypes.ReadNextVarInt(packetData); + break; + case PacketTypesIn.OpenWindow: + if (handler.GetInventoryEnabled()) + { + if (protocolVersion < MC_1_14_Version) + { + // MC 1.13 or lower + byte windowID = dataTypes.ReadNextByte(packetData); + string type = dataTypes.ReadNextString(packetData).Replace("minecraft:", "").ToUpper(); + ContainerTypeOld inventoryType = (ContainerTypeOld)Enum.Parse(typeof(ContainerTypeOld), type); + string title = dataTypes.ReadNextString(packetData); + byte slots = dataTypes.ReadNextByte(packetData); + Container inventory = new(windowID, inventoryType, ChatParser.ParseText(title)); + handler.OnInventoryOpen(windowID, inventory); + } + else { // MC 1.14 or greater int windowID = dataTypes.ReadNextVarInt(packetData); - int size = dataTypes.ReadNextByte(packetData); - List trades = new(); - for (int tradeId = 0; tradeId < size; tradeId++) - { - VillagerTrade trade = dataTypes.ReadNextTrade(packetData, itemPalette); - trades.Add(trade); - } - VillagerInfo villagerInfo = new() - { - Level = dataTypes.ReadNextVarInt(packetData), - Experience = dataTypes.ReadNextVarInt(packetData), - IsRegularVillager = dataTypes.ReadNextBool(packetData), - CanRestock = dataTypes.ReadNextBool(packetData) - }; - handler.OnTradeList(windowID, trades, villagerInfo); + int windowType = dataTypes.ReadNextVarInt(packetData); + string title = dataTypes.ReadNextString(packetData); + Container inventory = new(windowID, windowType, ChatParser.ParseText(title)); + handler.OnInventoryOpen(windowID, inventory); } - break; - case PacketTypesIn.Title: - if (protocolVersion >= MC_1_8_Version) + } + break; + case PacketTypesIn.CloseWindow: + if (handler.GetInventoryEnabled()) + { + byte windowID = dataTypes.ReadNextByte(packetData); + lock (window_actions) { window_actions[windowID] = 0; } + handler.OnInventoryClose(windowID); + } + break; + case PacketTypesIn.WindowItems: + if (handler.GetInventoryEnabled()) + { + byte windowId = dataTypes.ReadNextByte(packetData); + int stateId = -1; + int elements = 0; + + if (protocolVersion >= MC_1_17_1_Version) { - int action2 = dataTypes.ReadNextVarInt(packetData); - string titletext = String.Empty; - string subtitletext = String.Empty; - string actionbartext = String.Empty; - string json = String.Empty; - int fadein = -1; - int stay = -1; - int fadeout = -1; - if (protocolVersion >= MC_1_10_Version) - { - if (action2 == 0) - { - json = titletext; - titletext = ChatParser.ParseText(dataTypes.ReadNextString(packetData)); - } - else if (action2 == 1) - { - json = subtitletext; - subtitletext = ChatParser.ParseText(dataTypes.ReadNextString(packetData)); - } - else if (action2 == 2) - { - json = actionbartext; - actionbartext = ChatParser.ParseText(dataTypes.ReadNextString(packetData)); - } - else if (action2 == 3) - { - fadein = dataTypes.ReadNextInt(packetData); - stay = dataTypes.ReadNextInt(packetData); - fadeout = dataTypes.ReadNextInt(packetData); - } - } - else - { - if (action2 == 0) - { - json = titletext; - titletext = ChatParser.ParseText(dataTypes.ReadNextString(packetData)); - } - else if (action2 == 1) - { - json = subtitletext; - subtitletext = ChatParser.ParseText(dataTypes.ReadNextString(packetData)); - } - else if (action2 == 2) - { - fadein = dataTypes.ReadNextInt(packetData); - stay = dataTypes.ReadNextInt(packetData); - fadeout = dataTypes.ReadNextInt(packetData); - } - } - handler.OnTitle(action2, titletext, subtitletext, actionbartext, fadein, stay, fadeout, json); + // State ID and Elements as VarInt - 1.17.1 and above + stateId = dataTypes.ReadNextVarInt(packetData); + elements = dataTypes.ReadNextVarInt(packetData); } - break; - case PacketTypesIn.MultiBlockChange: - if (handler.GetTerrainEnabled()) + else { - if (protocolVersion >= MC_1_16_2_Version) - { - long chunkSection = dataTypes.ReadNextLong(packetData); - int sectionX = (int)(chunkSection >> 42); - int sectionY = (int)((chunkSection << 44) >> 44); - int sectionZ = (int)((chunkSection << 22) >> 42); - dataTypes.ReadNextBool(packetData); // Useless boolean (Related to light update) - int blocksSize = dataTypes.ReadNextVarInt(packetData); - for (int i = 0; i < blocksSize; i++) - { - ulong chunkSectionPosition = (ulong)dataTypes.ReadNextVarLong(packetData); - int blockId = (int)(chunkSectionPosition >> 12); - int localX = (int)((chunkSectionPosition >> 8) & 0x0F); - int localZ = (int)((chunkSectionPosition >> 4) & 0x0F); - int localY = (int)(chunkSectionPosition & 0x0F); - - Block block = new((ushort)blockId); - int blockX = (sectionX * 16) + localX; - int blockY = (sectionY * 16) + localY; - int blockZ = (sectionZ * 16) + localZ; - - Location location = new(blockX, blockY, blockZ); - - handler.OnBlockChange(location, block); - } - } - else - { - int chunkX = dataTypes.ReadNextInt(packetData); - int chunkZ = dataTypes.ReadNextInt(packetData); - int recordCount = protocolVersion < MC_1_8_Version - ? (int)dataTypes.ReadNextShort(packetData) - : dataTypes.ReadNextVarInt(packetData); - - for (int i = 0; i < recordCount; i++) - { - byte locationXZ; - ushort blockIdMeta; - int blockY; - - if (protocolVersion < MC_1_8_Version) - { - blockIdMeta = dataTypes.ReadNextUShort(packetData); - blockY = (ushort)dataTypes.ReadNextByte(packetData); - locationXZ = dataTypes.ReadNextByte(packetData); - } - else - { - locationXZ = dataTypes.ReadNextByte(packetData); - blockY = (ushort)dataTypes.ReadNextByte(packetData); - blockIdMeta = (ushort)dataTypes.ReadNextVarInt(packetData); - } - - int blockX = locationXZ >> 4; - int blockZ = locationXZ & 0x0F; - - Location location = new(chunkX, chunkZ, blockX, blockY, blockZ); - Block block = new(blockIdMeta); - handler.OnBlockChange(location, block); - } - } - } - break; - case PacketTypesIn.ServerData: - string motd = "-"; - bool hasMotd = dataTypes.ReadNextBool(packetData); - if (hasMotd) - motd = ChatParser.ParseText(dataTypes.ReadNextString(packetData)); - - string iconBase64 = "-"; - bool hasIcon = dataTypes.ReadNextBool(packetData); - if (hasIcon) - iconBase64 = dataTypes.ReadNextString(packetData); - - - bool previewsChat = false; - - if (protocolVersion < MC_1_19_3_Version) - dataTypes.ReadNextBool(packetData); - - handler.OnServerDataRecived(hasMotd, motd, hasIcon, iconBase64, previewsChat); - break; - case PacketTypesIn.BlockChange: - if (handler.GetTerrainEnabled()) - { - if (protocolVersion < MC_1_8_Version) - { - int blockX = dataTypes.ReadNextInt(packetData); - int blockY = dataTypes.ReadNextByte(packetData); - int blockZ = dataTypes.ReadNextInt(packetData); - short blockId = (short)dataTypes.ReadNextVarInt(packetData); - byte blockMeta = dataTypes.ReadNextByte(packetData); - - Location location = new(blockX, blockY, blockZ); - Block block = new(blockId, blockMeta); - handler.OnBlockChange(location, block); - } - else - { - Location location = dataTypes.ReadNextLocation(packetData); - Block block = new((ushort)dataTypes.ReadNextVarInt(packetData)); - handler.OnBlockChange(location, block); - } - } - break; - case PacketTypesIn.SetDisplayChatPreview: - bool previewsChatSetting = dataTypes.ReadNextBool(packetData); - handler.OnChatPreviewSettingUpdate(previewsChatSetting); - break; - case PacketTypesIn.ChatSuggestions: - break; - case PacketTypesIn.MapChunkBulk: - if (protocolVersion < MC_1_9_Version && handler.GetTerrainEnabled()) - { - int chunkCount; - bool hasSkyLight; - Queue chunkData = packetData; - - //Read global fields - if (protocolVersion < MC_1_8_Version) - { - chunkCount = dataTypes.ReadNextShort(packetData); - int compressedDataSize = dataTypes.ReadNextInt(packetData); - hasSkyLight = dataTypes.ReadNextBool(packetData); - byte[] compressed = dataTypes.ReadData(compressedDataSize, packetData); - byte[] decompressed = ZlibUtils.Decompress(compressed); - chunkData = new Queue(decompressed); - } - else - { - hasSkyLight = dataTypes.ReadNextBool(packetData); - chunkCount = dataTypes.ReadNextVarInt(packetData); - } - - //Read chunk records - int[] chunkXs = new int[chunkCount]; - int[] chunkZs = new int[chunkCount]; - ushort[] chunkMasks = new ushort[chunkCount]; - ushort[] addBitmaps = new ushort[chunkCount]; - for (int chunkColumnNo = 0; chunkColumnNo < chunkCount; chunkColumnNo++) - { - chunkXs[chunkColumnNo] = dataTypes.ReadNextInt(packetData); - chunkZs[chunkColumnNo] = dataTypes.ReadNextInt(packetData); - chunkMasks[chunkColumnNo] = dataTypes.ReadNextUShort(packetData); - addBitmaps[chunkColumnNo] = protocolVersion < MC_1_8_Version - ? dataTypes.ReadNextUShort(packetData) - : (ushort)0; - } - - //Process chunk records - for (int chunkColumnNo = 0; chunkColumnNo < chunkCount; chunkColumnNo++) - { - pTerrain.ProcessChunkColumnData(chunkXs[chunkColumnNo], chunkZs[chunkColumnNo], chunkMasks[chunkColumnNo], addBitmaps[chunkColumnNo], hasSkyLight, true, currentDimension, chunkData); - Interlocked.Decrement(ref handler.GetWorld().chunkLoadNotCompleted); - } - - } - break; - case PacketTypesIn.UnloadChunk: - if (protocolVersion >= MC_1_9_Version && handler.GetTerrainEnabled()) - { - int chunkX = dataTypes.ReadNextInt(packetData); - int chunkZ = dataTypes.ReadNextInt(packetData); - - // Warning: It is legal to include unloaded chunks in the UnloadChunk packet. - // Since chunks that have not been loaded are not recorded, this may result - // in loading chunks that should be unloaded and inaccurate statistics. - if (handler.GetWorld()[chunkX, chunkZ] != null) - Interlocked.Decrement(ref handler.GetWorld().chunkCnt); - - handler.GetWorld()[chunkX, chunkZ] = null; - } - break; - case PacketTypesIn.ChangeGameState: - if (protocolVersion >= MC_1_15_2_Version) - { - byte reason = dataTypes.ReadNextByte(packetData); - float state = dataTypes.ReadNextFloat(packetData); - - handler.OnGameEvent(reason, state); - } - break; - case PacketTypesIn.PlayerInfo: - if (protocolVersion >= MC_1_19_3_Version) - { - byte actionBitset = dataTypes.ReadNextByte(packetData); - int numberOfActions = dataTypes.ReadNextVarInt(packetData); - for (int i = 0; i < numberOfActions; i++) - { - Guid playerUuid = dataTypes.ReadNextUUID(packetData); - - if ((actionBitset & (1 << 0)) > 0) // Actions bit 0: add player - { - string name = dataTypes.ReadNextString(packetData); - int numberOfProperties = dataTypes.ReadNextVarInt(packetData); - for (int j = 0; j < numberOfProperties; ++j) - { - dataTypes.SkipNextString(packetData); - dataTypes.SkipNextString(packetData); - if (dataTypes.ReadNextBool(packetData)) - dataTypes.SkipNextString(packetData); - } - handler.OnPlayerJoin(new(name, playerUuid)); - } - - PlayerInfo player = handler.GetPlayerInfo(playerUuid)!; - if ((actionBitset & (1 << 1)) > 0) // Actions bit 1: initialize chat - { - bool hasSignatureData = dataTypes.ReadNextBool(packetData); - if (hasSignatureData) - { - Guid chatUuid = dataTypes.ReadNextUUID(packetData); - long publicKeyExpiryTime = dataTypes.ReadNextLong(packetData); - byte[] encodedPublicKey = dataTypes.ReadNextByteArray(packetData); - byte[] publicKeySignature = dataTypes.ReadNextByteArray(packetData); - player.SetPublicKey(chatUuid, publicKeyExpiryTime, encodedPublicKey, publicKeySignature); - } - else - { - player.ClearPublicKey(); - } - } - if ((actionBitset & 1 << 2) > 0) // Actions bit 2: update gamemode - { - handler.OnGamemodeUpdate(playerUuid, dataTypes.ReadNextVarInt(packetData)); - } - if ((actionBitset & (1 << 3)) > 0) // Actions bit 3: update listed - { - player.Listed = dataTypes.ReadNextBool(packetData); - } - if ((actionBitset & (1 << 4)) > 0) // Actions bit 4: update latency - { - int latency = dataTypes.ReadNextVarInt(packetData); - handler.OnLatencyUpdate(playerUuid, latency); //Update latency; - } - if ((actionBitset & (1 << 5)) > 0) // Actions bit 5: update display name - { - if (dataTypes.ReadNextBool(packetData)) - player.DisplayName = dataTypes.ReadNextString(packetData); - else - player.DisplayName = null; - } - } - } - else if (protocolVersion >= MC_1_8_Version) - { - int action = dataTypes.ReadNextVarInt(packetData); // Action Name - int numberOfPlayers = dataTypes.ReadNextVarInt(packetData); // Number Of Players - - for (int i = 0; i < numberOfPlayers; i++) - { - Guid uuid = dataTypes.ReadNextUUID(packetData); // Player UUID - - switch (action) - { - case 0x00: //Player Join (Add player since 1.19) - string name = dataTypes.ReadNextString(packetData); // Player name - int propNum = dataTypes.ReadNextVarInt(packetData); // Number of properties in the following array - - // Property: Tuple[]? properties = useProperty ? - new Tuple[propNum] : null; - for (int p = 0; p < propNum; p++) - { - string propertyName = dataTypes.ReadNextString(packetData); // Name: String (32767) - string val = dataTypes.ReadNextString(packetData); // Value: String (32767) - string? propertySignature = null; - if (dataTypes.ReadNextBool(packetData)) // Is Signed - propertySignature = dataTypes.ReadNextString(packetData); // Signature: String (32767) - if (useProperty) - properties![p] = new(propertyName, val, propertySignature); - } -#pragma warning restore CS0162 // Unreachable code detected - - int gameMode = dataTypes.ReadNextVarInt(packetData); // Gamemode - handler.OnGamemodeUpdate(uuid, gameMode); - - int ping = dataTypes.ReadNextVarInt(packetData); // Ping - - string? displayName = null; - if (dataTypes.ReadNextBool(packetData)) // Has display name - displayName = dataTypes.ReadNextString(packetData); // Display name - - // 1.19 Additions - long? keyExpiration = null; - byte[]? publicKey = null, signature = null; - if (protocolVersion >= MC_1_19_Version) - { - if (dataTypes.ReadNextBool(packetData)) // Has Sig Data (if true, red the following fields) - { - keyExpiration = dataTypes.ReadNextLong(packetData); // Timestamp - - int publicKeyLength = dataTypes.ReadNextVarInt(packetData); // Public Key Length - if (publicKeyLength > 0) - publicKey = dataTypes.ReadData(publicKeyLength, packetData); // Public key - - int signatureLength = dataTypes.ReadNextVarInt(packetData); // Signature Length - if (signatureLength > 0) - signature = dataTypes.ReadData(signatureLength, packetData); // Public key - } - } - - handler.OnPlayerJoin(new PlayerInfo(uuid, name, properties, gameMode, ping, displayName, keyExpiration, publicKey, signature)); - break; - case 0x01: //Update gamemode - handler.OnGamemodeUpdate(uuid, dataTypes.ReadNextVarInt(packetData)); - break; - case 0x02: //Update latency - int latency = dataTypes.ReadNextVarInt(packetData); - handler.OnLatencyUpdate(uuid, latency); //Update latency; - break; - case 0x03: //Update display name - if (dataTypes.ReadNextBool(packetData)) - { - PlayerInfo? player = handler.GetPlayerInfo(uuid); - if (player != null) - player.DisplayName = dataTypes.ReadNextString(packetData); - else - dataTypes.SkipNextString(packetData); - } - break; - case 0x04: //Player Leave - handler.OnPlayerLeave(uuid); - break; - default: - //Unknown player list item type - break; - } - } - } - else //MC 1.7.X does not provide UUID in tab-list updates - { - string name = dataTypes.ReadNextString(packetData); - bool online = dataTypes.ReadNextBool(packetData); - short ping = dataTypes.ReadNextShort(packetData); - Guid FakeUUID = new(MD5.Create().ComputeHash(Encoding.UTF8.GetBytes(name)).Take(16).ToArray()); - if (online) - handler.OnPlayerJoin(new PlayerInfo(name, FakeUUID)); - else handler.OnPlayerLeave(FakeUUID); - } - break; - case PacketTypesIn.TabComplete: - if (protocolVersion >= MC_1_13_Version) - { - autocomplete_transaction_id = dataTypes.ReadNextVarInt(packetData); - dataTypes.ReadNextVarInt(packetData); // Start of text to replace - dataTypes.ReadNextVarInt(packetData); // Length of text to replace + // Elements as Short - 1.17.0 and below + dataTypes.ReadNextShort(packetData); } - int autocomplete_count = dataTypes.ReadNextVarInt(packetData); - autocomplete_result.Clear(); - - for (int i = 0; i < autocomplete_count; i++) + Dictionary inventorySlots = new(); + for (int slotId = 0; slotId < elements; slotId++) { - autocomplete_result.Add(dataTypes.ReadNextString(packetData)); - if (protocolVersion >= MC_1_13_Version) - { - // Skip optional tooltip for each tab-complete result - if (dataTypes.ReadNextBool(packetData)) - dataTypes.SkipNextString(packetData); - } - } - - autocomplete_received = true; - break; - case PacketTypesIn.PluginMessage: - String channel = dataTypes.ReadNextString(packetData); - // Length is unneeded as the whole remaining packetData is the entire payload of the packet. - if (protocolVersion < MC_1_8_Version) - pForge.ReadNextVarShort(packetData); - handler.OnPluginChannelMessage(channel, packetData.ToArray()); - return pForge.HandlePluginMessage(channel, packetData, ref currentDimension); - case PacketTypesIn.Disconnect: - handler.OnConnectionLost(ChatBot.DisconnectReason.InGameKick, ChatParser.ParseText(dataTypes.ReadNextString(packetData))); - return false; - case PacketTypesIn.SetCompression: - if (protocolVersion >= MC_1_8_Version && protocolVersion < MC_1_9_Version) - compression_treshold = dataTypes.ReadNextVarInt(packetData); - break; - case PacketTypesIn.OpenWindow: - if (handler.GetInventoryEnabled()) - { - if (protocolVersion < MC_1_14_Version) - { - // MC 1.13 or lower - byte windowID = dataTypes.ReadNextByte(packetData); - string type = dataTypes.ReadNextString(packetData).Replace("minecraft:", "").ToUpper(); - ContainerTypeOld inventoryType = (ContainerTypeOld)Enum.Parse(typeof(ContainerTypeOld), type); - string title = dataTypes.ReadNextString(packetData); - byte slots = dataTypes.ReadNextByte(packetData); - Container inventory = new(windowID, inventoryType, ChatParser.ParseText(title)); - handler.OnInventoryOpen(windowID, inventory); - } - else - { - // MC 1.14 or greater - int windowID = dataTypes.ReadNextVarInt(packetData); - int windowType = dataTypes.ReadNextVarInt(packetData); - string title = dataTypes.ReadNextString(packetData); - Container inventory = new(windowID, windowType, ChatParser.ParseText(title)); - handler.OnInventoryOpen(windowID, inventory); - } - } - break; - case PacketTypesIn.CloseWindow: - if (handler.GetInventoryEnabled()) - { - byte windowID = dataTypes.ReadNextByte(packetData); - lock (window_actions) { window_actions[windowID] = 0; } - handler.OnInventoryClose(windowID); - } - break; - case PacketTypesIn.WindowItems: - if (handler.GetInventoryEnabled()) - { - byte windowId = dataTypes.ReadNextByte(packetData); - int stateId = -1; - int elements = 0; - - if (protocolVersion >= MC_1_17_1_Version) - { - // State ID and Elements as VarInt - 1.17.1 and above - stateId = dataTypes.ReadNextVarInt(packetData); - elements = dataTypes.ReadNextVarInt(packetData); - } - else - { - // Elements as Short - 1.17.0 and below - dataTypes.ReadNextShort(packetData); - } - - Dictionary inventorySlots = new(); - for (int slotId = 0; slotId < elements; slotId++) - { - Item? item = dataTypes.ReadNextItemSlot(packetData, itemPalette); - if (item != null) - inventorySlots[slotId] = item; - } - - if (protocolVersion >= MC_1_17_1_Version) // Carried Item - 1.17.1 and above - dataTypes.ReadNextItemSlot(packetData, itemPalette); - - handler.OnWindowItems(windowId, inventorySlots, stateId); - } - break; - case PacketTypesIn.WindowProperty: - byte containerId = dataTypes.ReadNextByte(packetData); - short propertyId = dataTypes.ReadNextShort(packetData); - short propertyValue = dataTypes.ReadNextShort(packetData); - - handler.OnWindowProperties(containerId, propertyId, propertyValue); - break; - case PacketTypesIn.SetSlot: - if (handler.GetInventoryEnabled()) - { - byte windowID = dataTypes.ReadNextByte(packetData); - int stateId = -1; - if (protocolVersion >= MC_1_17_1_Version) - stateId = dataTypes.ReadNextVarInt(packetData); // State ID - 1.17.1 and above - short slotID = dataTypes.ReadNextShort(packetData); Item? item = dataTypes.ReadNextItemSlot(packetData, itemPalette); - handler.OnSetSlot(windowID, slotID, item, stateId); + if (item != null) + inventorySlots[slotId] = item; } + + if (protocolVersion >= MC_1_17_1_Version) // Carried Item - 1.17.1 and above + dataTypes.ReadNextItemSlot(packetData, itemPalette); + + handler.OnWindowItems(windowId, inventorySlots, stateId); + } + break; + case PacketTypesIn.WindowProperty: + byte containerId = dataTypes.ReadNextByte(packetData); + short propertyId = dataTypes.ReadNextShort(packetData); + short propertyValue = dataTypes.ReadNextShort(packetData); + + handler.OnWindowProperties(containerId, propertyId, propertyValue); + break; + case PacketTypesIn.SetSlot: + if (handler.GetInventoryEnabled()) + { + byte windowID = dataTypes.ReadNextByte(packetData); + int stateId = -1; + if (protocolVersion >= MC_1_17_1_Version) + stateId = dataTypes.ReadNextVarInt(packetData); // State ID - 1.17.1 and above + short slotID = dataTypes.ReadNextShort(packetData); + Item? item = dataTypes.ReadNextItemSlot(packetData, itemPalette); + handler.OnSetSlot(windowID, slotID, item, stateId); + } + break; + case PacketTypesIn.WindowConfirmation: + if (handler.GetInventoryEnabled()) + { + byte windowID = dataTypes.ReadNextByte(packetData); + short actionID = dataTypes.ReadNextShort(packetData); + bool accepted = dataTypes.ReadNextBool(packetData); + if (!accepted) + SendWindowConfirmation(windowID, actionID, true); + } + break; + case PacketTypesIn.ResourcePackSend: + string url = dataTypes.ReadNextString(packetData); + string hash = dataTypes.ReadNextString(packetData); + bool forced = true; // Assume forced for MC 1.16 and below + if (protocolVersion >= MC_1_17_Version) + { + forced = dataTypes.ReadNextBool(packetData); + bool hasPromptMessage = dataTypes.ReadNextBool(packetData); // Has Prompt Message (Boolean) - 1.17 and above + if (hasPromptMessage) + dataTypes.SkipNextString(packetData); // Prompt Message (Optional Chat) - 1.17 and above + } + // Some server plugins may send invalid resource packs to probe the client and we need to ignore them (issue #1056) + if (!url.StartsWith("http") && hash.Length != 40) // Some server may have null hash value break; - case PacketTypesIn.WindowConfirmation: - if (handler.GetInventoryEnabled()) + //Send back "accepted" and "successfully loaded" responses for plugins or server config making use of resource pack mandatory + byte[] responseHeader = Array.Empty(); + if (protocolVersion < MC_1_10_Version) //MC 1.10 does not include resource pack hash in responses + responseHeader = dataTypes.ConcatBytes(DataTypes.GetVarInt(hash.Length), Encoding.UTF8.GetBytes(hash)); + SendPacket(PacketTypesOut.ResourcePackStatus, dataTypes.ConcatBytes(responseHeader, DataTypes.GetVarInt(3))); //Accepted pack + SendPacket(PacketTypesOut.ResourcePackStatus, dataTypes.ConcatBytes(responseHeader, DataTypes.GetVarInt(0))); //Successfully loaded + break; + case PacketTypesIn.SpawnEntity: + if (handler.GetEntityHandlingEnabled()) + { + Entity entity = dataTypes.ReadNextEntity(packetData, entityPalette, false); + handler.OnSpawnEntity(entity); + } + break; + case PacketTypesIn.EntityEquipment: + if (handler.GetEntityHandlingEnabled()) + { + int entityid = dataTypes.ReadNextVarInt(packetData); + if (protocolVersion >= MC_1_16_Version) { - byte windowID = dataTypes.ReadNextByte(packetData); - short actionID = dataTypes.ReadNextShort(packetData); - bool accepted = dataTypes.ReadNextBool(packetData); - if (!accepted) - SendWindowConfirmation(windowID, actionID, true); - } - break; - case PacketTypesIn.ResourcePackSend: - string url = dataTypes.ReadNextString(packetData); - string hash = dataTypes.ReadNextString(packetData); - bool forced = true; // Assume forced for MC 1.16 and below - if (protocolVersion >= MC_1_17_Version) - { - forced = dataTypes.ReadNextBool(packetData); - bool hasPromptMessage = dataTypes.ReadNextBool(packetData); // Has Prompt Message (Boolean) - 1.17 and above - if (hasPromptMessage) - dataTypes.SkipNextString(packetData); // Prompt Message (Optional Chat) - 1.17 and above - } - // Some server plugins may send invalid resource packs to probe the client and we need to ignore them (issue #1056) - if (!url.StartsWith("http") && hash.Length != 40) // Some server may have null hash value - break; - //Send back "accepted" and "successfully loaded" responses for plugins or server config making use of resource pack mandatory - byte[] responseHeader = Array.Empty(); - if (protocolVersion < MC_1_10_Version) //MC 1.10 does not include resource pack hash in responses - responseHeader = dataTypes.ConcatBytes(DataTypes.GetVarInt(hash.Length), Encoding.UTF8.GetBytes(hash)); - SendPacket(PacketTypesOut.ResourcePackStatus, dataTypes.ConcatBytes(responseHeader, DataTypes.GetVarInt(3))); //Accepted pack - SendPacket(PacketTypesOut.ResourcePackStatus, dataTypes.ConcatBytes(responseHeader, DataTypes.GetVarInt(0))); //Successfully loaded - break; - case PacketTypesIn.SpawnEntity: - if (handler.GetEntityHandlingEnabled()) - { - Entity entity = dataTypes.ReadNextEntity(packetData, entityPalette, false); - handler.OnSpawnEntity(entity); - } - break; - case PacketTypesIn.EntityEquipment: - if (handler.GetEntityHandlingEnabled()) - { - int entityid = dataTypes.ReadNextVarInt(packetData); - if (protocolVersion >= MC_1_16_Version) + bool hasNext; + do { - bool hasNext; - do - { - byte bitsData = dataTypes.ReadNextByte(packetData); - // Top bit set if another entry follows, and otherwise unset if this is the last item in the array - hasNext = (bitsData >> 7) == 1; - int slot2 = bitsData >> 1; - Item? item = dataTypes.ReadNextItemSlot(packetData, itemPalette); - handler.OnEntityEquipment(entityid, slot2, item); - } while (hasNext); - } - else - { - int slot2 = dataTypes.ReadNextVarInt(packetData); + byte bitsData = dataTypes.ReadNextByte(packetData); + // Top bit set if another entry follows, and otherwise unset if this is the last item in the array + hasNext = (bitsData >> 7) == 1; + int slot2 = bitsData >> 1; Item? item = dataTypes.ReadNextItemSlot(packetData, itemPalette); handler.OnEntityEquipment(entityid, slot2, item); - } - } - break; - case PacketTypesIn.SpawnLivingEntity: - if (handler.GetEntityHandlingEnabled()) - { - Entity entity = dataTypes.ReadNextEntity(packetData, entityPalette, true); - // packet before 1.15 has metadata at the end - // this is not handled in dataTypes.ReadNextEntity() - // we are simply ignoring leftover data in packet - handler.OnSpawnEntity(entity); - } - break; - case PacketTypesIn.SpawnPlayer: - if (handler.GetEntityHandlingEnabled()) - { - int EntityID = dataTypes.ReadNextVarInt(packetData); - Guid UUID = dataTypes.ReadNextUUID(packetData); - double X = dataTypes.ReadNextDouble(packetData); - double Y = dataTypes.ReadNextDouble(packetData); - double Z = dataTypes.ReadNextDouble(packetData); - byte Yaw = dataTypes.ReadNextByte(packetData); - byte Pitch = dataTypes.ReadNextByte(packetData); - - Location EntityLocation = new(X, Y, Z); - - handler.OnSpawnPlayer(EntityID, UUID, EntityLocation, Yaw, Pitch); - } - break; - case PacketTypesIn.EntityEffect: - if (handler.GetEntityHandlingEnabled()) - { - int entityid = dataTypes.ReadNextVarInt(packetData); - Inventory.Effects effect = Effects.Speed; - int effectId = protocolVersion >= MC_1_18_2_Version ? - dataTypes.ReadNextVarInt(packetData) : dataTypes.ReadNextByte(packetData); - if (Enum.TryParse(effectId.ToString(), out effect)) - { - int amplifier = dataTypes.ReadNextByte(packetData); - int duration = dataTypes.ReadNextVarInt(packetData); - byte flags = dataTypes.ReadNextByte(packetData); - - bool hasFactorData = false; - Dictionary? factorCodec = null; - - if (protocolVersion >= MC_1_19_Version) - { - hasFactorData = dataTypes.ReadNextBool(packetData); - if (hasFactorData) - factorCodec = dataTypes.ReadNextNbt(packetData); - } - - handler.OnEntityEffect(entityid, effect, amplifier, duration, flags, hasFactorData, factorCodec); - } - } - break; - case PacketTypesIn.DestroyEntities: - if (handler.GetEntityHandlingEnabled()) - { - int entityCount = 1; // 1.17.0 has only one entity per packet - if (protocolVersion != MC_1_17_Version) - entityCount = dataTypes.ReadNextVarInt(packetData); // All other versions have a "count" field - int[] entityList = new int[entityCount]; - for (int i = 0; i < entityCount; i++) - { - entityList[i] = dataTypes.ReadNextVarInt(packetData); - } - handler.OnDestroyEntities(entityList); - } - break; - case PacketTypesIn.EntityPosition: - if (handler.GetEntityHandlingEnabled()) - { - int EntityID = dataTypes.ReadNextVarInt(packetData); - Double DeltaX = Convert.ToDouble(dataTypes.ReadNextShort(packetData)); - Double DeltaY = Convert.ToDouble(dataTypes.ReadNextShort(packetData)); - Double DeltaZ = Convert.ToDouble(dataTypes.ReadNextShort(packetData)); - bool OnGround = dataTypes.ReadNextBool(packetData); - DeltaX /= (128 * 32); - DeltaY /= (128 * 32); - DeltaZ /= (128 * 32); - handler.OnEntityPosition(EntityID, DeltaX, DeltaY, DeltaZ, OnGround); - } - break; - case PacketTypesIn.EntityPositionAndRotation: - if (handler.GetEntityHandlingEnabled()) - { - int EntityID = dataTypes.ReadNextVarInt(packetData); - Double DeltaX = Convert.ToDouble(dataTypes.ReadNextShort(packetData)); - Double DeltaY = Convert.ToDouble(dataTypes.ReadNextShort(packetData)); - Double DeltaZ = Convert.ToDouble(dataTypes.ReadNextShort(packetData)); - byte _yaw = dataTypes.ReadNextByte(packetData); - byte _pitch = dataTypes.ReadNextByte(packetData); - bool OnGround = dataTypes.ReadNextBool(packetData); - DeltaX /= (128 * 32); - DeltaY /= (128 * 32); - DeltaZ /= (128 * 32); - handler.OnEntityPosition(EntityID, DeltaX, DeltaY, DeltaZ, OnGround); - } - break; - case PacketTypesIn.EntityProperties: - if (handler.GetEntityHandlingEnabled()) - { - int EntityID = dataTypes.ReadNextVarInt(packetData); - int NumberOfProperties = protocolVersion >= MC_1_17_Version ? dataTypes.ReadNextVarInt(packetData) : dataTypes.ReadNextInt(packetData); - Dictionary keys = new(); - for (int i = 0; i < NumberOfProperties; i++) - { - string _key = dataTypes.ReadNextString(packetData); - Double _value = dataTypes.ReadNextDouble(packetData); - - List op0 = new(); - List op1 = new(); - List op2 = new(); - int NumberOfModifiers = dataTypes.ReadNextVarInt(packetData); - for (int j = 0; j < NumberOfModifiers; j++) - { - dataTypes.ReadNextUUID(packetData); - Double amount = dataTypes.ReadNextDouble(packetData); - byte operation = dataTypes.ReadNextByte(packetData); - switch (operation) - { - case 0: op0.Add(amount); break; - case 1: op1.Add(amount); break; - case 2: op2.Add(amount + 1); break; - } - } - if (op0.Count > 0) _value += op0.Sum(); - if (op1.Count > 0) _value *= 1 + op1.Sum(); - if (op2.Count > 0) _value *= op2.Aggregate((a, _x) => a * _x); - keys.Add(_key, _value); - } - handler.OnEntityProperties(EntityID, keys); - } - break; - case PacketTypesIn.EntityMetadata: - if (handler.GetEntityHandlingEnabled()) - { - int EntityID = dataTypes.ReadNextVarInt(packetData); - Dictionary metadata = dataTypes.ReadNextMetadata(packetData, itemPalette); - - int healthField; // See https://wiki.vg/Entity_metadata#Living_Entity - if (protocolVersion > MC_1_19_2_Version) - throw new NotImplementedException(Translations.exception_palette_healthfield); - else if (protocolVersion >= MC_1_17_Version) // 1.17 and above - healthField = 9; - else if (protocolVersion >= MC_1_14_Version) // 1.14 and above - healthField = 8; - else if (protocolVersion >= MC_1_10_Version) // 1.10 and above - healthField = 7; - else - throw new NotImplementedException(Translations.exception_palette_healthfield); - - if (metadata.TryGetValue(healthField, out object? healthObj) && healthObj != null && healthObj.GetType() == typeof(float)) - handler.OnEntityHealth(EntityID, (float)healthObj); - - handler.OnEntityMetadata(EntityID, metadata); - } - break; - case PacketTypesIn.EntityStatus: - if (handler.GetEntityHandlingEnabled()) - { - int entityId = dataTypes.ReadNextInt(packetData); - byte status = dataTypes.ReadNextByte(packetData); - handler.OnEntityStatus(entityId, status); - } - break; - case PacketTypesIn.TimeUpdate: - long WorldAge = dataTypes.ReadNextLong(packetData); - long TimeOfday = dataTypes.ReadNextLong(packetData); - handler.OnTimeUpdate(WorldAge, TimeOfday); - break; - case PacketTypesIn.EntityTeleport: - if (handler.GetEntityHandlingEnabled()) - { - int EntityID = dataTypes.ReadNextVarInt(packetData); - Double X = dataTypes.ReadNextDouble(packetData); - Double Y = dataTypes.ReadNextDouble(packetData); - Double Z = dataTypes.ReadNextDouble(packetData); - byte EntityYaw = dataTypes.ReadNextByte(packetData); - byte EntityPitch = dataTypes.ReadNextByte(packetData); - bool OnGround = dataTypes.ReadNextBool(packetData); - handler.OnEntityTeleport(EntityID, X, Y, Z, OnGround); - } - break; - case PacketTypesIn.UpdateHealth: - float health = dataTypes.ReadNextFloat(packetData); - int food; - if (protocolVersion >= MC_1_8_Version) - food = dataTypes.ReadNextVarInt(packetData); - else - food = dataTypes.ReadNextShort(packetData); - dataTypes.ReadNextFloat(packetData); // Food Saturation - handler.OnUpdateHealth(health, food); - break; - case PacketTypesIn.SetExperience: - float experiencebar = dataTypes.ReadNextFloat(packetData); - int totalexperience, level; - - if (protocolVersion >= MC_1_19_3_Version) - { - totalexperience = dataTypes.ReadNextVarInt(packetData); - level = dataTypes.ReadNextVarInt(packetData); + } while (hasNext); } else { - level = dataTypes.ReadNextVarInt(packetData); - totalexperience = dataTypes.ReadNextVarInt(packetData); + int slot2 = dataTypes.ReadNextVarInt(packetData); + Item? item = dataTypes.ReadNextItemSlot(packetData, itemPalette); + handler.OnEntityEquipment(entityid, slot2, item); } + } + break; + case PacketTypesIn.SpawnLivingEntity: + if (handler.GetEntityHandlingEnabled()) + { + Entity entity = dataTypes.ReadNextEntity(packetData, entityPalette, true); + // packet before 1.15 has metadata at the end + // this is not handled in dataTypes.ReadNextEntity() + // we are simply ignoring leftover data in packet + handler.OnSpawnEntity(entity); + } + break; + case PacketTypesIn.SpawnPlayer: + if (handler.GetEntityHandlingEnabled()) + { + int EntityID = dataTypes.ReadNextVarInt(packetData); + Guid UUID = dataTypes.ReadNextUUID(packetData); + double X = dataTypes.ReadNextDouble(packetData); + double Y = dataTypes.ReadNextDouble(packetData); + double Z = dataTypes.ReadNextDouble(packetData); + byte Yaw = dataTypes.ReadNextByte(packetData); + byte Pitch = dataTypes.ReadNextByte(packetData); - handler.OnSetExperience(experiencebar, level, totalexperience); - break; - case PacketTypesIn.Explosion: - Location explosionLocation = new(dataTypes.ReadNextFloat(packetData), dataTypes.ReadNextFloat(packetData), dataTypes.ReadNextFloat(packetData)); + Location EntityLocation = new(X, Y, Z); - float explosionStrength = dataTypes.ReadNextFloat(packetData); - int explosionBlockCount = protocolVersion >= MC_1_17_Version + handler.OnSpawnPlayer(EntityID, UUID, EntityLocation, Yaw, Pitch); + } + break; + case PacketTypesIn.EntityEffect: + if (handler.GetEntityHandlingEnabled()) + { + int entityid = dataTypes.ReadNextVarInt(packetData); + Inventory.Effects effect = Effects.Speed; + int effectId = protocolVersion >= MC_1_18_2_Version ? + dataTypes.ReadNextVarInt(packetData) : dataTypes.ReadNextByte(packetData); + if (Enum.TryParse(effectId.ToString(), out effect)) + { + int amplifier = dataTypes.ReadNextByte(packetData); + int duration = dataTypes.ReadNextVarInt(packetData); + byte flags = dataTypes.ReadNextByte(packetData); + + bool hasFactorData = false; + Dictionary? factorCodec = null; + + if (protocolVersion >= MC_1_19_Version) + { + hasFactorData = dataTypes.ReadNextBool(packetData); + if (hasFactorData) + factorCodec = dataTypes.ReadNextNbt(packetData); + } + + handler.OnEntityEffect(entityid, effect, amplifier, duration, flags, hasFactorData, factorCodec); + } + } + break; + case PacketTypesIn.DestroyEntities: + if (handler.GetEntityHandlingEnabled()) + { + int entityCount = 1; // 1.17.0 has only one entity per packet + if (protocolVersion != MC_1_17_Version) + entityCount = dataTypes.ReadNextVarInt(packetData); // All other versions have a "count" field + int[] entityList = new int[entityCount]; + for (int i = 0; i < entityCount; i++) + { + entityList[i] = dataTypes.ReadNextVarInt(packetData); + } + handler.OnDestroyEntities(entityList); + } + break; + case PacketTypesIn.EntityPosition: + if (handler.GetEntityHandlingEnabled()) + { + int EntityID = dataTypes.ReadNextVarInt(packetData); + Double DeltaX = Convert.ToDouble(dataTypes.ReadNextShort(packetData)); + Double DeltaY = Convert.ToDouble(dataTypes.ReadNextShort(packetData)); + Double DeltaZ = Convert.ToDouble(dataTypes.ReadNextShort(packetData)); + bool OnGround = dataTypes.ReadNextBool(packetData); + DeltaX /= (128 * 32); + DeltaY /= (128 * 32); + DeltaZ /= (128 * 32); + handler.OnEntityPosition(EntityID, DeltaX, DeltaY, DeltaZ, OnGround); + } + break; + case PacketTypesIn.EntityPositionAndRotation: + if (handler.GetEntityHandlingEnabled()) + { + int EntityID = dataTypes.ReadNextVarInt(packetData); + Double DeltaX = Convert.ToDouble(dataTypes.ReadNextShort(packetData)); + Double DeltaY = Convert.ToDouble(dataTypes.ReadNextShort(packetData)); + Double DeltaZ = Convert.ToDouble(dataTypes.ReadNextShort(packetData)); + byte _yaw = dataTypes.ReadNextByte(packetData); + byte _pitch = dataTypes.ReadNextByte(packetData); + bool OnGround = dataTypes.ReadNextBool(packetData); + DeltaX /= (128 * 32); + DeltaY /= (128 * 32); + DeltaZ /= (128 * 32); + handler.OnEntityPosition(EntityID, DeltaX, DeltaY, DeltaZ, OnGround); + } + break; + case PacketTypesIn.EntityProperties: + if (handler.GetEntityHandlingEnabled()) + { + int EntityID = dataTypes.ReadNextVarInt(packetData); + int NumberOfProperties = protocolVersion >= MC_1_17_Version ? dataTypes.ReadNextVarInt(packetData) : dataTypes.ReadNextInt(packetData); + Dictionary keys = new(); + for (int i = 0; i < NumberOfProperties; i++) + { + string _key = dataTypes.ReadNextString(packetData); + Double _value = dataTypes.ReadNextDouble(packetData); + + List op0 = new(); + List op1 = new(); + List op2 = new(); + int NumberOfModifiers = dataTypes.ReadNextVarInt(packetData); + for (int j = 0; j < NumberOfModifiers; j++) + { + dataTypes.ReadNextUUID(packetData); + Double amount = dataTypes.ReadNextDouble(packetData); + byte operation = dataTypes.ReadNextByte(packetData); + switch (operation) + { + case 0: op0.Add(amount); break; + case 1: op1.Add(amount); break; + case 2: op2.Add(amount + 1); break; + } + } + if (op0.Count > 0) _value += op0.Sum(); + if (op1.Count > 0) _value *= 1 + op1.Sum(); + if (op2.Count > 0) _value *= op2.Aggregate((a, _x) => a * _x); + keys.Add(_key, _value); + } + handler.OnEntityProperties(EntityID, keys); + } + break; + case PacketTypesIn.EntityMetadata: + if (handler.GetEntityHandlingEnabled()) + { + int EntityID = dataTypes.ReadNextVarInt(packetData); + Dictionary metadata = dataTypes.ReadNextMetadata(packetData, itemPalette); + + int healthField; // See https://wiki.vg/Entity_metadata#Living_Entity + if (protocolVersion > MC_1_19_2_Version) + throw new NotImplementedException(Translations.exception_palette_healthfield); + else if (protocolVersion >= MC_1_17_Version) // 1.17 and above + healthField = 9; + else if (protocolVersion >= MC_1_14_Version) // 1.14 and above + healthField = 8; + else if (protocolVersion >= MC_1_10_Version) // 1.10 and above + healthField = 7; + else + throw new NotImplementedException(Translations.exception_palette_healthfield); + + if (metadata.TryGetValue(healthField, out object? healthObj) && healthObj != null && healthObj.GetType() == typeof(float)) + handler.OnEntityHealth(EntityID, (float)healthObj); + + handler.OnEntityMetadata(EntityID, metadata); + } + break; + case PacketTypesIn.EntityStatus: + if (handler.GetEntityHandlingEnabled()) + { + int entityId = dataTypes.ReadNextInt(packetData); + byte status = dataTypes.ReadNextByte(packetData); + handler.OnEntityStatus(entityId, status); + } + break; + case PacketTypesIn.TimeUpdate: + long WorldAge = dataTypes.ReadNextLong(packetData); + long TimeOfday = dataTypes.ReadNextLong(packetData); + handler.OnTimeUpdate(WorldAge, TimeOfday); + break; + case PacketTypesIn.EntityTeleport: + if (handler.GetEntityHandlingEnabled()) + { + int EntityID = dataTypes.ReadNextVarInt(packetData); + Double X = dataTypes.ReadNextDouble(packetData); + Double Y = dataTypes.ReadNextDouble(packetData); + Double Z = dataTypes.ReadNextDouble(packetData); + byte EntityYaw = dataTypes.ReadNextByte(packetData); + byte EntityPitch = dataTypes.ReadNextByte(packetData); + bool OnGround = dataTypes.ReadNextBool(packetData); + handler.OnEntityTeleport(EntityID, X, Y, Z, OnGround); + } + break; + case PacketTypesIn.UpdateHealth: + float health = dataTypes.ReadNextFloat(packetData); + int food; + if (protocolVersion >= MC_1_8_Version) + food = dataTypes.ReadNextVarInt(packetData); + else + food = dataTypes.ReadNextShort(packetData); + dataTypes.ReadNextFloat(packetData); // Food Saturation + handler.OnUpdateHealth(health, food); + break; + case PacketTypesIn.SetExperience: + float experiencebar = dataTypes.ReadNextFloat(packetData); + int totalexperience, level; + + if (protocolVersion >= MC_1_19_3_Version) + { + totalexperience = dataTypes.ReadNextVarInt(packetData); + level = dataTypes.ReadNextVarInt(packetData); + } + else + { + level = dataTypes.ReadNextVarInt(packetData); + totalexperience = dataTypes.ReadNextVarInt(packetData); + } + + handler.OnSetExperience(experiencebar, level, totalexperience); + break; + case PacketTypesIn.Explosion: + Location explosionLocation; + if (protocolVersion >= MC_1_19_3_Version) + explosionLocation = new(dataTypes.ReadNextDouble(packetData), dataTypes.ReadNextDouble(packetData), dataTypes.ReadNextDouble(packetData)); + else + explosionLocation = new(dataTypes.ReadNextFloat(packetData), dataTypes.ReadNextFloat(packetData), dataTypes.ReadNextFloat(packetData)); + + float explosionStrength = dataTypes.ReadNextFloat(packetData); + int explosionBlockCount = protocolVersion >= MC_1_17_Version + ? dataTypes.ReadNextVarInt(packetData) + : dataTypes.ReadNextInt(packetData); + + for (int i = 0; i < explosionBlockCount; i++) + dataTypes.ReadData(3, packetData); + + float playerVelocityX = dataTypes.ReadNextFloat(packetData); + float playerVelocityY = dataTypes.ReadNextFloat(packetData); + float playerVelocityZ = dataTypes.ReadNextFloat(packetData); + + handler.OnExplosion(explosionLocation, explosionStrength, explosionBlockCount); + break; + case PacketTypesIn.HeldItemChange: + byte slot = dataTypes.ReadNextByte(packetData); + handler.OnHeldItemChange(slot); + break; + case PacketTypesIn.ScoreboardObjective: + string objectivename = dataTypes.ReadNextString(packetData); + byte mode = dataTypes.ReadNextByte(packetData); + string objectivevalue = String.Empty; + int type2 = -1; + if (mode == 0 || mode == 2) + { + objectivevalue = dataTypes.ReadNextString(packetData); + type2 = dataTypes.ReadNextVarInt(packetData); + } + handler.OnScoreboardObjective(objectivename, mode, objectivevalue, type2); + break; + case PacketTypesIn.UpdateScore: + string entityname = dataTypes.ReadNextString(packetData); + int action3 = protocolVersion >= MC_1_18_2_Version ? dataTypes.ReadNextVarInt(packetData) - : dataTypes.ReadNextInt(packetData); - - for (int i = 0; i < explosionBlockCount; i++) - dataTypes.ReadData(3, packetData); - - float playerVelocityX = dataTypes.ReadNextFloat(packetData); - float playerVelocityY = dataTypes.ReadNextFloat(packetData); - float playerVelocityZ = dataTypes.ReadNextFloat(packetData); - - handler.OnExplosion(explosionLocation, explosionStrength, explosionBlockCount); - break; - case PacketTypesIn.HeldItemChange: - byte slot = dataTypes.ReadNextByte(packetData); - handler.OnHeldItemChange(slot); - break; - case PacketTypesIn.ScoreboardObjective: - string objectivename = dataTypes.ReadNextString(packetData); - byte mode = dataTypes.ReadNextByte(packetData); - string objectivevalue = String.Empty; - int type2 = -1; - if (mode == 0 || mode == 2) - { - objectivevalue = dataTypes.ReadNextString(packetData); - type2 = dataTypes.ReadNextVarInt(packetData); - } - handler.OnScoreboardObjective(objectivename, mode, objectivevalue, type2); - break; - case PacketTypesIn.UpdateScore: - string entityname = dataTypes.ReadNextString(packetData); - int action3 = protocolVersion >= MC_1_18_2_Version - ? dataTypes.ReadNextVarInt(packetData) - : dataTypes.ReadNextByte(packetData); - string objectivename2 = string.Empty; - int value = -1; - if (action3 != 1 || protocolVersion >= MC_1_8_Version) - objectivename2 = dataTypes.ReadNextString(packetData); - if (action3 != 1) - value = dataTypes.ReadNextVarInt(packetData); - handler.OnUpdateScore(entityname, action3, objectivename2, value); - break; - case PacketTypesIn.BlockChangedAck: - handler.OnBlockChangeAck(dataTypes.ReadNextVarInt(packetData)); - break; - case PacketTypesIn.BlockBreakAnimation: - if (handler.GetEntityHandlingEnabled() && handler.GetTerrainEnabled()) - { - int playerId = dataTypes.ReadNextVarInt(packetData); - Location blockLocation = dataTypes.ReadNextLocation(packetData); - byte stage = dataTypes.ReadNextByte(packetData); - handler.OnBlockBreakAnimation(playerId, blockLocation, stage); - } - break; - case PacketTypesIn.EntityAnimation: - if (handler.GetEntityHandlingEnabled()) - { - int playerId2 = dataTypes.ReadNextVarInt(packetData); - byte animation = dataTypes.ReadNextByte(packetData); - handler.OnEntityAnimation(playerId2, animation); - } - break; - default: - return false; //Ignored packet - } - return true; //Packet processed + : dataTypes.ReadNextByte(packetData); + string objectivename2 = string.Empty; + int value = -1; + if (action3 != 1 || protocolVersion >= MC_1_8_Version) + objectivename2 = dataTypes.ReadNextString(packetData); + if (action3 != 1) + value = dataTypes.ReadNextVarInt(packetData); + handler.OnUpdateScore(entityname, action3, objectivename2, value); + break; + case PacketTypesIn.BlockChangedAck: + handler.OnBlockChangeAck(dataTypes.ReadNextVarInt(packetData)); + break; + case PacketTypesIn.BlockBreakAnimation: + if (handler.GetEntityHandlingEnabled() && handler.GetTerrainEnabled()) + { + int playerId = dataTypes.ReadNextVarInt(packetData); + Location blockLocation = dataTypes.ReadNextLocation(packetData); + byte stage = dataTypes.ReadNextByte(packetData); + handler.OnBlockBreakAnimation(playerId, blockLocation, stage); + } + break; + case PacketTypesIn.EntityAnimation: + if (handler.GetEntityHandlingEnabled()) + { + int playerId2 = dataTypes.ReadNextVarInt(packetData); + byte animation = dataTypes.ReadNextByte(packetData); + handler.OnEntityAnimation(playerId2, animation); + } + break; + default: + return false; //Ignored packet + } + return true; //Packet processed +#if Release } catch (Exception innerException) { @@ -1986,6 +1999,7 @@ namespace MinecraftClient.Protocol.Handlers innerException.GetType()), innerException); } +#endif } /// diff --git a/MinecraftClient/Protocol/Handlers/Protocol18Terrain.cs b/MinecraftClient/Protocol/Handlers/Protocol18Terrain.cs index d144f37b..fc66edd0 100644 --- a/MinecraftClient/Protocol/Handlers/Protocol18Terrain.cs +++ b/MinecraftClient/Protocol/Handlers/Protocol18Terrain.cs @@ -264,9 +264,7 @@ namespace MinecraftClient.Protocol.Handlers int[] palette = new int[paletteLength]; for (int i = 0; i < paletteLength; i++) - { palette[i] = dataTypes.ReadNextVarInt(cache); - } // Bit mask covering bitsPerBlock bits // EG, if bitsPerBlock = 5, valueMask = 00011111 in binary