Fix inventory handling across protocol versions

This commit is contained in:
Anon 2026-06-05 20:26:29 +02:00
parent 03e2e0d3fd
commit 5228670131
9 changed files with 364 additions and 89 deletions

View file

@ -118,9 +118,9 @@ namespace MinecraftClient.Protocol.Handlers.PacketPalettes
{ 0x00, PacketTypesOut.TeleportConfirm }, // (Wiki name: Confirm Teleportation)
{ 0x01, PacketTypesOut.QueryBlockNBT }, // (Wiki name: Query Block Entity Tag)
{ 0x02, PacketTypesOut.SetDifficulty }, // (Wiki name: Change Difficutly)
{ 0x03, PacketTypesOut.MessageAcknowledgment }, //
{ 0x04, PacketTypesOut.ChatCommand }, // Added in 1.19
{ 0x05, PacketTypesOut.ChatMessage }, // Changed in 1.19 (Completely changed) (Wiki name: Chat)
{ 0x03, PacketTypesOut.ChatCommand }, // Added in 1.19
{ 0x04, PacketTypesOut.ChatMessage }, // Changed in 1.19 (Completely changed) (Wiki name: Chat)
{ 0x05, PacketTypesOut.ChatPreview }, // Added in 1.19 (Wiki name: Chat Preview (serverbound))
{ 0x06, PacketTypesOut.ClientStatus }, // (Wiki name: Client Command)
{ 0x07, PacketTypesOut.ClientSettings }, // (Wiki name: Client Information)
{ 0x08, PacketTypesOut.TabComplete }, // (Wiki name: Command Suggestions Request)
@ -147,25 +147,24 @@ namespace MinecraftClient.Protocol.Handlers.PacketPalettes
{ 0x1D, PacketTypesOut.EntityAction }, // (Wiki name: Player Command)
{ 0x1E, PacketTypesOut.SteerVehicle }, // (Wiki name: Player Input)
{ 0x1F, PacketTypesOut.Pong }, // (Wiki name: Pong (play))
{ 0x20, PacketTypesOut.PlayerSession }, // Added in 1.19.3
{ 0x21, PacketTypesOut.SetDisplayedRecipe }, // (Wiki name: Recipe Book Change Settings)
{ 0x22, PacketTypesOut.SetRecipeBookState }, // (Wiki name: Recipe Book Seen Recipe)
{ 0x23, PacketTypesOut.NameItem }, // (Wiki name: Rename Item)
{ 0x24, PacketTypesOut.ResourcePackStatus }, // (Wiki name: Resource Pack (serverbound))
{ 0x25, PacketTypesOut.AdvancementTab }, // (Wiki name: Seen Advancements)
{ 0x26, PacketTypesOut.SelectTrade }, //
{ 0x27, PacketTypesOut.SetBeaconEffect }, // Changed in 1.19 (Added a "Secondary Effect Present" and "Secondary Effect" fields) (Wiki name: Set Beacon) - (No need to be implemented)
{ 0x28, PacketTypesOut.HeldItemChange }, // (Wiki name: Set Carried Item (serverbound))
{ 0x29, PacketTypesOut.UpdateCommandBlock }, // (Wiki name: Set Command Block)
{ 0x2A, PacketTypesOut.UpdateCommandBlockMinecart }, //
{ 0x2B, PacketTypesOut.CreativeInventoryAction }, // (Wiki name: Set Creative Mode Slot)
{ 0x2C, PacketTypesOut.UpdateJigsawBlock }, // (Wiki name: Set Jigsaw Block)
{ 0x2D, PacketTypesOut.UpdateStructureBlock }, // (Wiki name: Set Structure Block)
{ 0x2E, PacketTypesOut.UpdateSign }, // (Wiki name: Sign Update)
{ 0x2F, PacketTypesOut.Animation }, // (Wiki name: Swing)
{ 0x30, PacketTypesOut.Spectate }, // (Wiki name: Teleport To Entity)
{ 0x31, PacketTypesOut.PlayerBlockPlacement }, // Changed in 1.19 (Added a "Sequence" field) (Wiki name: Use Item On)
{ 0x32, PacketTypesOut.UseItem }, // Changed in 1.19 (Added a "Sequence" field) (Wiki name: Use Item)
{ 0x20, PacketTypesOut.SetDisplayedRecipe }, // (Wiki name: Recipe Book Change Settings)
{ 0x21, PacketTypesOut.SetRecipeBookState }, // (Wiki name: Recipe Book Seen Recipe)
{ 0x22, PacketTypesOut.NameItem }, // (Wiki name: Rename Item)
{ 0x23, PacketTypesOut.ResourcePackStatus }, // (Wiki name: Resource Pack (serverbound))
{ 0x24, PacketTypesOut.AdvancementTab }, // (Wiki name: Seen Advancements)
{ 0x25, PacketTypesOut.SelectTrade }, //
{ 0x26, PacketTypesOut.SetBeaconEffect }, // Changed in 1.19 (Added a "Secondary Effect Present" and "Secondary Effect" fields) (Wiki name: Set Beacon) - (No need to be implemented)
{ 0x27, PacketTypesOut.HeldItemChange }, // (Wiki name: Set Carried Item (serverbound))
{ 0x28, PacketTypesOut.UpdateCommandBlock }, // (Wiki name: Set Command Block)
{ 0x29, PacketTypesOut.UpdateCommandBlockMinecart }, //
{ 0x2A, PacketTypesOut.CreativeInventoryAction }, // (Wiki name: Set Creative Mode Slot)
{ 0x2B, PacketTypesOut.UpdateJigsawBlock }, // (Wiki name: Set Jigsaw Block)
{ 0x2C, PacketTypesOut.UpdateStructureBlock }, // (Wiki name: Set Structure Block)
{ 0x2D, PacketTypesOut.UpdateSign }, // (Wiki name: Sign Update)
{ 0x2E, PacketTypesOut.Animation }, // (Wiki name: Swing)
{ 0x2F, PacketTypesOut.Spectate }, // (Wiki name: Teleport To Entity)
{ 0x30, PacketTypesOut.PlayerBlockPlacement }, // Changed in 1.19 (Added a "Sequence" field) (Wiki name: Use Item On)
{ 0x31, PacketTypesOut.UseItem }, // Changed in 1.19 (Added a "Sequence" field) (Wiki name: Use Item)
};
protected override Dictionary<int, PacketTypesIn> GetListIn() => typeIn;

View file

@ -0,0 +1,127 @@
using System.Collections.Generic;
namespace MinecraftClient.Protocol.Handlers.PacketPalettes
{
public class PacketPalette19 : PacketTypePalette
{
private readonly Dictionary<int, PacketTypesIn> typeIn = new()
{
{ 0x00, PacketTypesIn.SpawnEntity },
{ 0x01, PacketTypesIn.SpawnExperienceOrb },
{ 0x02, PacketTypesIn.SpawnWeatherEntity },
{ 0x03, PacketTypesIn.SpawnLivingEntity },
{ 0x04, PacketTypesIn.SpawnPainting },
{ 0x05, PacketTypesIn.SpawnPlayer },
{ 0x06, PacketTypesIn.EntityAnimation },
{ 0x07, PacketTypesIn.Statistics },
{ 0x08, PacketTypesIn.BlockBreakAnimation },
{ 0x09, PacketTypesIn.BlockEntityData },
{ 0x0A, PacketTypesIn.BlockAction },
{ 0x0B, PacketTypesIn.BlockChange },
{ 0x0C, PacketTypesIn.BossBar },
{ 0x0D, PacketTypesIn.ServerDifficulty },
{ 0x0E, PacketTypesIn.TabComplete },
{ 0x0F, PacketTypesIn.ChatMessage },
{ 0x10, PacketTypesIn.MultiBlockChange },
{ 0x11, PacketTypesIn.WindowConfirmation },
{ 0x12, PacketTypesIn.CloseWindow },
{ 0x13, PacketTypesIn.OpenWindow },
{ 0x14, PacketTypesIn.WindowItems },
{ 0x15, PacketTypesIn.WindowProperty },
{ 0x16, PacketTypesIn.SetSlot },
{ 0x17, PacketTypesIn.SetCooldown },
{ 0x18, PacketTypesIn.PluginMessage },
{ 0x19, PacketTypesIn.NamedSoundEffect },
{ 0x1A, PacketTypesIn.Disconnect },
{ 0x1B, PacketTypesIn.EntityStatus },
{ 0x1C, PacketTypesIn.Explosion },
{ 0x1D, PacketTypesIn.UnloadChunk },
{ 0x1E, PacketTypesIn.ChangeGameState },
{ 0x1F, PacketTypesIn.KeepAlive },
{ 0x20, PacketTypesIn.ChunkData },
{ 0x21, PacketTypesIn.Effect },
{ 0x22, PacketTypesIn.Particle },
{ 0x23, PacketTypesIn.JoinGame },
{ 0x24, PacketTypesIn.MapData },
{ 0x25, PacketTypesIn.EntityPosition },
{ 0x26, PacketTypesIn.EntityPositionAndRotation },
{ 0x27, PacketTypesIn.EntityRotation },
{ 0x28, PacketTypesIn.EntityMovement },
{ 0x29, PacketTypesIn.VehicleMove },
{ 0x2A, PacketTypesIn.OpenSignEditor },
{ 0x2B, PacketTypesIn.PlayerAbilities },
{ 0x2C, PacketTypesIn.CombatEvent },
{ 0x2D, PacketTypesIn.PlayerInfo },
{ 0x2E, PacketTypesIn.PlayerPositionAndLook },
{ 0x2F, PacketTypesIn.UseBed },
{ 0x30, PacketTypesIn.DestroyEntities },
{ 0x31, PacketTypesIn.RemoveEntityEffect },
{ 0x32, PacketTypesIn.ResourcePackSend },
{ 0x33, PacketTypesIn.Respawn },
{ 0x34, PacketTypesIn.EntityHeadLook },
{ 0x35, PacketTypesIn.WorldBorder },
{ 0x36, PacketTypesIn.Camera },
{ 0x37, PacketTypesIn.HeldItemChange },
{ 0x38, PacketTypesIn.DisplayScoreboard },
{ 0x39, PacketTypesIn.EntityMetadata },
{ 0x3A, PacketTypesIn.AttachEntity },
{ 0x3B, PacketTypesIn.EntityVelocity },
{ 0x3C, PacketTypesIn.EntityEquipment },
{ 0x3D, PacketTypesIn.SetExperience },
{ 0x3E, PacketTypesIn.UpdateHealth },
{ 0x3F, PacketTypesIn.ScoreboardObjective },
{ 0x40, PacketTypesIn.SetPassengers },
{ 0x41, PacketTypesIn.Teams },
{ 0x42, PacketTypesIn.UpdateScore },
{ 0x43, PacketTypesIn.SpawnPosition },
{ 0x44, PacketTypesIn.TimeUpdate },
{ 0x45, PacketTypesIn.Title },
{ 0x46, PacketTypesIn.UpdateSign },
{ 0x47, PacketTypesIn.SoundEffect },
{ 0x48, PacketTypesIn.PlayerListHeaderAndFooter },
{ 0x49, PacketTypesIn.CollectItem },
{ 0x4A, PacketTypesIn.EntityTeleport },
{ 0x4B, PacketTypesIn.EntityProperties },
{ 0x4C, PacketTypesIn.EntityEffect },
};
private readonly Dictionary<int, PacketTypesOut> typeOut = new()
{
{ 0x00, PacketTypesOut.TeleportConfirm },
{ 0x01, PacketTypesOut.TabComplete },
{ 0x02, PacketTypesOut.ChatMessage },
{ 0x03, PacketTypesOut.ClientStatus },
{ 0x04, PacketTypesOut.ClientSettings },
{ 0x05, PacketTypesOut.WindowConfirmation },
{ 0x06, PacketTypesOut.EnchantItem },
{ 0x07, PacketTypesOut.ClickWindow },
{ 0x08, PacketTypesOut.CloseWindow },
{ 0x09, PacketTypesOut.PluginMessage },
{ 0x0A, PacketTypesOut.InteractEntity },
{ 0x0B, PacketTypesOut.KeepAlive },
{ 0x0C, PacketTypesOut.PlayerPosition },
{ 0x0D, PacketTypesOut.PlayerPositionAndRotation },
{ 0x0E, PacketTypesOut.PlayerRotation },
{ 0x0F, PacketTypesOut.PlayerMovement },
{ 0x10, PacketTypesOut.VehicleMove },
{ 0x11, PacketTypesOut.SteerBoat },
{ 0x12, PacketTypesOut.PlayerAbilities },
{ 0x13, PacketTypesOut.PlayerDigging },
{ 0x14, PacketTypesOut.EntityAction },
{ 0x15, PacketTypesOut.SteerVehicle },
{ 0x16, PacketTypesOut.ResourcePackStatus },
{ 0x17, PacketTypesOut.HeldItemChange },
{ 0x18, PacketTypesOut.CreativeInventoryAction },
{ 0x19, PacketTypesOut.UpdateSign },
{ 0x1A, PacketTypesOut.Animation },
{ 0x1B, PacketTypesOut.Spectate },
{ 0x1C, PacketTypesOut.PlayerBlockPlacement },
{ 0x1D, PacketTypesOut.UseItem },
};
protected override Dictionary<int, PacketTypesIn> GetListIn() => typeIn;
protected override Dictionary<int, PacketTypesOut> GetListOut() => typeOut;
protected override Dictionary<int, ConfigurationPacketTypesIn> GetConfigurationListIn() => new();
protected override Dictionary<int, ConfigurationPacketTypesOut> GetConfigurationListOut() => new();
}
}

View file

@ -56,6 +56,7 @@ namespace MinecraftClient.Protocol.Handlers
<= Protocol18Handler.MC_1_21_5_Version and > Protocol18Handler.MC_1_21_4_Version => new PacketPalette1215(),
<= Protocol18Handler.MC_1_21_4_Version and > Protocol18Handler.MC_1_21_2_Version => new PacketPalette1214(),
<= Protocol18Handler.MC_1_8_Version => new PacketPalette17(),
<= Protocol18Handler.MC_1_9_2_Version => new PacketPalette19(),
<= Protocol18Handler.MC_1_11_2_Version => new PacketPalette110(),
<= Protocol18Handler.MC_1_12_Version => new PacketPalette112(),
<= Protocol18Handler.MC_1_12_2_Version => new PacketPalette1122(),

View file

@ -146,7 +146,7 @@ namespace MinecraftClient.Protocol.Handlers
UpdateHealth, //
UpdateLight, //
UpdateScore, //
UpdateSign, // For 1.8 or below
UpdateSign, // For 1.8 or below, and 1.9-1.9.2
UpdateSimulationDistance, //
UpdateViewDistance, //
UpdateViewPosition, //

View file

@ -45,6 +45,7 @@ namespace MinecraftClient.Protocol.Handlers
internal const int MC_1_8_Version = 47;
internal const int MC_1_9_Version = 107;
internal const int MC_1_9_1_Version = 108;
internal const int MC_1_9_2_Version = 109;
internal const int MC_1_10_Version = 210;
internal const int MC_1_11_Version = 315;
internal const int MC_1_11_2_Version = 316;
@ -835,15 +836,15 @@ namespace MinecraftClient.Protocol.Handlers
dimensionTypeName =
dataTypes.ReadNextString(packetData); // Dimension Type: Identifier
break;
case >= MC_1_16_2_Version:
dimensionType =
dataTypes.ReadNextNbt(
packetData); // Dimension Type: NBT Tag Compound
break;
default:
dataTypes.ReadNextString(packetData);
break;
}
case >= MC_1_16_2_Version:
dimensionType =
dataTypes.ReadNextNbt(
packetData); // Dimension Type: NBT Tag Compound
break;
default:
dimensionTypeName = dataTypes.ReadNextString(packetData);
break;
}
currentDimension = 0;
break;
@ -1408,14 +1409,14 @@ namespace MinecraftClient.Protocol.Handlers
dimensionTypeNameRespawn =
dataTypes.ReadNextString(packetData); // Dimension Type: Identifier
break;
case >= MC_1_16_2_Version:
dimensionTypeRespawn =
dataTypes.ReadNextNbt(packetData); // Dimension Type: NBT Tag Compound
break;
default:
dataTypes.ReadNextString(packetData);
break;
}
case >= MC_1_16_2_Version:
dimensionTypeRespawn =
dataTypes.ReadNextNbt(packetData); // Dimension Type: NBT Tag Compound
break;
default:
dimensionTypeNameRespawn = dataTypes.ReadNextString(packetData);
break;
}
currentDimension = 0;
}
@ -4027,6 +4028,21 @@ namespace MinecraftClient.Protocol.Handlers
int blockEntityCount = dataTypes.ReadNextVarInt(packetData);
for (int i = 0; i < blockEntityCount; i++)
{
if (protocolVersion < MC_1_18_1_Version)
{
Dictionary<string, object>? blockEntityNbt = dataTypes.ReadNextNbt(packetData);
if (blockEntityNbt.TryGetValue("x", out var nbtX)
&& blockEntityNbt.TryGetValue("y", out var nbtY)
&& blockEntityNbt.TryGetValue("z", out var nbtZ))
{
handler.OnBlockEntityData(
new Location(Convert.ToInt32(nbtX), Convert.ToInt32(nbtY), Convert.ToInt32(nbtZ)),
blockEntityNbt);
}
continue;
}
int packedXZ = dataTypes.ReadNextByte(packetData);
int y = dataTypes.ReadNextShort(packetData);
dataTypes.ReadNextVarInt(packetData); // Block entity type registry id
@ -5616,7 +5632,7 @@ namespace MinecraftClient.Protocol.Handlers
private static byte ToLegacyBlockPlacementCursor(float cursor)
{
return (byte)Math.Clamp((int)(cursor * 16.0f), 0, byte.MaxValue);
return (byte)Math.Clamp((int)(cursor * 16.0f), 0, 15);
}
public bool SendHeldItemChange(short slot)
@ -5752,16 +5768,11 @@ namespace MinecraftClient.Protocol.Handlers
switch (protocolVersion)
{
// 1.18+
case >= MC_1_18_1_Version:
// 1.17.1+
case >= MC_1_17_1_Version:
packet.AddRange(DataTypes.GetVarInt(stateId)); // State ID
packet.AddRange(dataTypes.GetShort((short)slotId)); // Slot ID
break;
// 1.17.1
case MC_1_17_1_Version:
packet.AddRange(dataTypes.GetShort((short)slotId)); // Slot ID
packet.AddRange(DataTypes.GetVarInt(stateId)); // State ID
break;
// Older
default:
packet.AddRange(dataTypes.GetShort((short)slotId)); // Slot ID