feat: add packet palette, data components, and protocol fixes for MC 1.21.2

Packet Palette (Phase 2.1):
- Create PacketPalette1212.cs with complete ID mapping for protocol 768
  (131 clientbound + 60 serverbound play packets, plus config packets)
- Add new PacketTypesIn enum values: EntityPositionSync, MoveMinecartAlongTrack,
  PlayerRotation, RecipeBookAdd/Remove/Settings, SetCursorItem, SetHeldSlot,
  SetPlayerInventory
- Add new PacketTypesOut enum values: BundleItemSelected, ClientTickEnd
- Update PacketType18Handler routing for 1.21.2

Data Components (Phase 1.4):
- Create StructuredComponentsRegistry1212 with 67 components (was 57 in 1.21)
  reflecting the new 1.21.2 DataComponents ordering
- Implement 11 new component parsers: ConsumableComponent, UseRemainderComponent,
  UseCooldownComponent, DamageResistantComponent, EnchantableComponent,
  EquippableComponent, RepairableComponent, GliderComponent, TooltipStyleComponent,
  DeathProtectionComponent, ItemModelComponent
- Create FoodComponent1212 (simplified: nutrition/saturation/canAlwaysEat only;
  eatSeconds/effects/usingConvertsTo moved to consumable/use_remainder)
- Create SubComponentRegistry1212 and route in StructuredComponentsHandler

Protocol Fixes:
- Fix PlayerPositionAndLook packet for 1.21.2 (new format: teleportId first,
  added deltaMovement Vec3, flags as Int instead of Byte)
- Fix login success packet (remove strictErrorHandling read for >= 1.21.2)
- Fix ClientSettings/ClientInformation packet (add particleStatus VarInt)
- Add SetHeldSlot as alias for HeldItemChange in packet handler

Verified: MCC connects to 1.21.2 vanilla server, stays connected, chat works.
Made-with: Cursor
This commit is contained in:
BruceChen 2026-03-20 03:25:20 +08:00
parent df833ae2a8
commit 57a0dedb33
20 changed files with 953 additions and 33 deletions

View file

@ -0,0 +1,243 @@
using System.Collections.Generic;
namespace MinecraftClient.Protocol.Handlers.PacketPalettes;
public class PacketPalette1212 : PacketTypePalette
{
private readonly Dictionary<int, PacketTypesIn> typeIn = new()
{
{ 0x00, PacketTypesIn.Bundle }, // Bundle delimiter
{ 0x01, PacketTypesIn.SpawnEntity }, // Add Entity
{ 0x02, PacketTypesIn.SpawnExperienceOrb }, // Add Experience Orb
{ 0x03, PacketTypesIn.EntityAnimation }, // Animate
{ 0x04, PacketTypesIn.Statistics }, // Award Stats
{ 0x05, PacketTypesIn.BlockChangedAck }, // Block Changed Ack
{ 0x06, PacketTypesIn.BlockBreakAnimation }, // Block Destruction
{ 0x07, PacketTypesIn.BlockEntityData }, // Block Entity Data
{ 0x08, PacketTypesIn.BlockAction }, // Block Event
{ 0x09, PacketTypesIn.BlockChange }, // Block Update
{ 0x0A, PacketTypesIn.BossBar }, // Boss Event
{ 0x0B, PacketTypesIn.ServerDifficulty }, // Change Difficulty
{ 0x0C, PacketTypesIn.ChunkBatchFinished }, // Chunk Batch Finished
{ 0x0D, PacketTypesIn.ChunkBatchStarted }, // Chunk Batch Start
{ 0x0E, PacketTypesIn.ChunksBiomes }, // Chunks Biomes
{ 0x0F, PacketTypesIn.ClearTiles }, // Clear Titles
{ 0x10, PacketTypesIn.TabComplete }, // Command Suggestions
{ 0x11, PacketTypesIn.DeclareCommands }, // Commands
{ 0x12, PacketTypesIn.CloseWindow }, // Container Close
{ 0x13, PacketTypesIn.WindowItems }, // Container Set Content
{ 0x14, PacketTypesIn.WindowProperty }, // Container Set Data
{ 0x15, PacketTypesIn.SetSlot }, // Container Set Slot
{ 0x16, PacketTypesIn.CookieRequest }, // Cookie Request
{ 0x17, PacketTypesIn.SetCooldown }, // Cooldown
{ 0x18, PacketTypesIn.ChatSuggestions }, // Custom Chat Completions
{ 0x19, PacketTypesIn.PluginMessage }, // Custom Payload
{ 0x1A, PacketTypesIn.DamageEvent }, // Damage Event
{ 0x1B, PacketTypesIn.DebugSample }, // Debug Sample
{ 0x1C, PacketTypesIn.HideMessage }, // Delete Chat
{ 0x1D, PacketTypesIn.Disconnect }, // Disconnect
{ 0x1E, PacketTypesIn.ProfilelessChatMessage }, // Disguised Chat
{ 0x1F, PacketTypesIn.EntityStatus }, // Entity Event
{ 0x20, PacketTypesIn.EntityPositionSync }, // Entity Position Sync (new in 1.21.2)
{ 0x21, PacketTypesIn.Explosion }, // Explode
{ 0x22, PacketTypesIn.UnloadChunk }, // Forget Level Chunk
{ 0x23, PacketTypesIn.ChangeGameState }, // Game Event
{ 0x24, PacketTypesIn.OpenHorseWindow }, // Horse Screen Open
{ 0x25, PacketTypesIn.HurtAnimation }, // Hurt Animation
{ 0x26, PacketTypesIn.InitializeWorldBorder }, // Initialize Border
{ 0x27, PacketTypesIn.KeepAlive }, // Keep Alive
{ 0x28, PacketTypesIn.ChunkData }, // Level Chunk With Light
{ 0x29, PacketTypesIn.Effect }, // Level Event
{ 0x2A, PacketTypesIn.Particle }, // Level Particles
{ 0x2B, PacketTypesIn.UpdateLight }, // Light Update
{ 0x2C, PacketTypesIn.JoinGame }, // Login
{ 0x2D, PacketTypesIn.MapData }, // Map Item Data
{ 0x2E, PacketTypesIn.TradeList }, // Merchant Offers
{ 0x2F, PacketTypesIn.EntityPosition }, // Move Entity Pos
{ 0x30, PacketTypesIn.EntityPositionAndRotation }, // Move Entity Pos Rot
{ 0x31, PacketTypesIn.MoveMinecartAlongTrack }, // Move Minecart Along Track (new in 1.21.2)
{ 0x32, PacketTypesIn.EntityRotation }, // Move Entity Rot
{ 0x33, PacketTypesIn.VehicleMove }, // Move Vehicle
{ 0x34, PacketTypesIn.OpenBook }, // Open Book
{ 0x35, PacketTypesIn.OpenWindow }, // Open Screen
{ 0x36, PacketTypesIn.OpenSignEditor }, // Open Sign Editor
{ 0x37, PacketTypesIn.Ping }, // Ping
{ 0x38, PacketTypesIn.PingResponse }, // Pong Response
{ 0x39, PacketTypesIn.CraftRecipeResponse }, // Place Ghost Recipe
{ 0x3A, PacketTypesIn.PlayerAbilities }, // Player Abilities
{ 0x3B, PacketTypesIn.ChatMessage }, // Player Chat
{ 0x3C, PacketTypesIn.EndCombatEvent }, // Player Combat End
{ 0x3D, PacketTypesIn.EnterCombatEvent }, // Player Combat Enter
{ 0x3E, PacketTypesIn.DeathCombatEvent }, // Player Combat Kill
{ 0x3F, PacketTypesIn.PlayerRemove }, // Player Info Remove
{ 0x40, PacketTypesIn.PlayerInfo }, // Player Info Update
{ 0x41, PacketTypesIn.FacePlayer }, // Player Look At
{ 0x42, PacketTypesIn.PlayerPositionAndLook }, // Player Position
{ 0x43, PacketTypesIn.PlayerRotation }, // Player Rotation (new in 1.21.2)
{ 0x44, PacketTypesIn.RecipeBookAdd }, // Recipe Book Add (new in 1.21.2, replaces UnlockRecipes)
{ 0x45, PacketTypesIn.RecipeBookRemove }, // Recipe Book Remove (new in 1.21.2)
{ 0x46, PacketTypesIn.RecipeBookSettings }, // Recipe Book Settings (new in 1.21.2)
{ 0x47, PacketTypesIn.DestroyEntities }, // Remove Entities
{ 0x48, PacketTypesIn.RemoveEntityEffect }, // Remove Mob Effect
{ 0x49, PacketTypesIn.ResetScore }, // Reset Score
{ 0x4A, PacketTypesIn.RemoveResourcePack }, // Resource Pack Pop
{ 0x4B, PacketTypesIn.ResourcePackSend }, // Resource Pack Push
{ 0x4C, PacketTypesIn.Respawn }, // Respawn
{ 0x4D, PacketTypesIn.EntityHeadLook }, // Rotate Head
{ 0x4E, PacketTypesIn.MultiBlockChange }, // Section Blocks Update
{ 0x4F, PacketTypesIn.SelectAdvancementTab }, // Select Advancements Tab
{ 0x50, PacketTypesIn.ServerData }, // Server Data
{ 0x51, PacketTypesIn.ActionBar }, // Set Action Bar Text
{ 0x52, PacketTypesIn.WorldBorderCenter }, // Set Border Center
{ 0x53, PacketTypesIn.WorldBorderLerpSize }, // Set Border Lerp Size
{ 0x54, PacketTypesIn.WorldBorderSize }, // Set Border Size
{ 0x55, PacketTypesIn.WorldBorderWarningDelay }, // Set Border Warning Delay
{ 0x56, PacketTypesIn.WorldBorderWarningReach }, // Set Border Warning Distance
{ 0x57, PacketTypesIn.Camera }, // Set Camera
{ 0x58, PacketTypesIn.UpdateViewPosition }, // Set Chunk Cache Center
{ 0x59, PacketTypesIn.UpdateViewDistance }, // Set Chunk Cache Radius
{ 0x5A, PacketTypesIn.SetCursorItem }, // Set Cursor Item (new in 1.21.2)
{ 0x5B, PacketTypesIn.SpawnPosition }, // Set Default Spawn Position
{ 0x5C, PacketTypesIn.DisplayScoreboard }, // Set Display Objective
{ 0x5D, PacketTypesIn.EntityMetadata }, // Set Entity Data
{ 0x5E, PacketTypesIn.AttachEntity }, // Set Entity Link
{ 0x5F, PacketTypesIn.EntityVelocity }, // Set Entity Motion
{ 0x60, PacketTypesIn.EntityEquipment }, // Set Equipment
{ 0x61, PacketTypesIn.SetExperience }, // Set Experience
{ 0x62, PacketTypesIn.UpdateHealth }, // Set Health
{ 0x63, PacketTypesIn.SetHeldSlot }, // Set Held Slot (new in 1.21.2, replaces HeldItemChange)
{ 0x64, PacketTypesIn.ScoreboardObjective }, // Set Objective
{ 0x65, PacketTypesIn.SetPassengers }, // Set Passengers
{ 0x66, PacketTypesIn.SetPlayerInventory }, // Set Player Inventory (new in 1.21.2)
{ 0x67, PacketTypesIn.Teams }, // Set Player Team
{ 0x68, PacketTypesIn.UpdateScore }, // Set Score
{ 0x69, PacketTypesIn.UpdateSimulationDistance }, // Set Simulation Distance
{ 0x6A, PacketTypesIn.SetTitleSubTitle }, // Set Subtitle Text
{ 0x6B, PacketTypesIn.TimeUpdate }, // Set Time
{ 0x6C, PacketTypesIn.SetTitleText }, // Set Title Text
{ 0x6D, PacketTypesIn.SetTitleTime }, // Set Titles Animation
{ 0x6E, PacketTypesIn.EntitySoundEffect }, // Sound Entity
{ 0x6F, PacketTypesIn.SoundEffect }, // Sound
{ 0x70, PacketTypesIn.StartConfiguration }, // Start Configuration
{ 0x71, PacketTypesIn.StopSound }, // Stop Sound
{ 0x72, PacketTypesIn.StoreCookie }, // Store Cookie
{ 0x73, PacketTypesIn.SystemChat }, // System Chat
{ 0x74, PacketTypesIn.PlayerListHeaderAndFooter }, // Tab List
{ 0x75, PacketTypesIn.NBTQueryResponse }, // Tag Query
{ 0x76, PacketTypesIn.CollectItem }, // Take Item Entity
{ 0x77, PacketTypesIn.EntityTeleport }, // Teleport Entity
{ 0x78, PacketTypesIn.SetTickingState }, // Ticking State
{ 0x79, PacketTypesIn.StepTick }, // Ticking Step
{ 0x7A, PacketTypesIn.Transfer }, // Transfer
{ 0x7B, PacketTypesIn.Advancements }, // Update Advancements
{ 0x7C, PacketTypesIn.EntityProperties }, // Update Attributes
{ 0x7D, PacketTypesIn.EntityEffect }, // Update Mob Effect
{ 0x7E, PacketTypesIn.DeclareRecipes }, // Update Recipes
{ 0x7F, PacketTypesIn.Tags }, // Update Tags
{ 0x80, PacketTypesIn.ProjectilePower }, // Projectile Power
{ 0x81, PacketTypesIn.CustomReportDetails }, // Custom Report Details
{ 0x82, PacketTypesIn.ServerLinks } // Server Links
};
private readonly Dictionary<int, PacketTypesOut> typeOut = new()
{
{ 0x00, PacketTypesOut.TeleportConfirm }, // Accept Teleportation
{ 0x01, PacketTypesOut.QueryBlockNBT }, // Block Entity Tag Query
{ 0x02, PacketTypesOut.BundleItemSelected }, // Bundle Item Selected (new in 1.21.2)
{ 0x03, PacketTypesOut.SetDifficulty }, // Change Difficulty
{ 0x04, PacketTypesOut.MessageAcknowledgment }, // Chat Ack
{ 0x05, PacketTypesOut.ChatCommand }, // Chat Command
{ 0x06, PacketTypesOut.SignedChatCommand }, // Chat Command Signed
{ 0x07, PacketTypesOut.ChatMessage }, // Chat
{ 0x08, PacketTypesOut.PlayerSession }, // Chat Session Update
{ 0x09, PacketTypesOut.ChunkBatchReceived }, // Chunk Batch Received
{ 0x0A, PacketTypesOut.ClientStatus }, // Client Command
{ 0x0B, PacketTypesOut.ClientTickEnd }, // Client Tick End (new in 1.21.2)
{ 0x0C, PacketTypesOut.ClientSettings }, // Client Information
{ 0x0D, PacketTypesOut.TabComplete }, // Command Suggestion
{ 0x0E, PacketTypesOut.AcknowledgeConfiguration }, // Configuration Acknowledged
{ 0x0F, PacketTypesOut.ClickWindowButton }, // Container Button Click
{ 0x10, PacketTypesOut.ClickWindow }, // Container Click
{ 0x11, PacketTypesOut.CloseWindow }, // Container Close
{ 0x12, PacketTypesOut.ChangeContainerSlotState }, // Container Slot State Changed
{ 0x13, PacketTypesOut.CookieResponse }, // Cookie Response
{ 0x14, PacketTypesOut.PluginMessage }, // Custom Payload
{ 0x15, PacketTypesOut.DebugSampleSubscription }, // Debug Sample Subscription
{ 0x16, PacketTypesOut.EditBook }, // Edit Book
{ 0x17, PacketTypesOut.EntityNBTRequest }, // Entity Tag Query
{ 0x18, PacketTypesOut.InteractEntity }, // Interact
{ 0x19, PacketTypesOut.GenerateStructure }, // Jigsaw Generate
{ 0x1A, PacketTypesOut.KeepAlive }, // Keep Alive
{ 0x1B, PacketTypesOut.LockDifficulty }, // Lock Difficulty
{ 0x1C, PacketTypesOut.PlayerPosition }, // Move Player Pos
{ 0x1D, PacketTypesOut.PlayerPositionAndRotation }, // Move Player Pos Rot
{ 0x1E, PacketTypesOut.PlayerRotation }, // Move Player Rot
{ 0x1F, PacketTypesOut.PlayerMovement }, // Move Player Status Only
{ 0x20, PacketTypesOut.VehicleMove }, // Move Vehicle
{ 0x21, PacketTypesOut.SteerBoat }, // Paddle Boat
{ 0x22, PacketTypesOut.PickItem }, // Pick Item
{ 0x23, PacketTypesOut.PingRequest }, // Ping Request
{ 0x24, PacketTypesOut.CraftRecipeRequest }, // Place Recipe
{ 0x25, PacketTypesOut.PlayerAbilities }, // Player Abilities
{ 0x26, PacketTypesOut.PlayerDigging }, // Player Action
{ 0x27, PacketTypesOut.EntityAction }, // Player Command
{ 0x28, PacketTypesOut.SteerVehicle }, // Player Input
{ 0x29, PacketTypesOut.Pong }, // Pong
{ 0x2A, PacketTypesOut.SetDisplayedRecipe }, // Recipe Book Change Settings
{ 0x2B, PacketTypesOut.SetRecipeBookState }, // Recipe Book Seen Recipe
{ 0x2C, PacketTypesOut.NameItem }, // Rename Item
{ 0x2D, PacketTypesOut.ResourcePackStatus }, // Resource Pack
{ 0x2E, PacketTypesOut.AdvancementTab }, // Seen Advancements
{ 0x2F, PacketTypesOut.SelectTrade }, // Select Trade
{ 0x30, PacketTypesOut.SetBeaconEffect }, // Set Beacon
{ 0x31, PacketTypesOut.HeldItemChange }, // Set Carried Item
{ 0x32, PacketTypesOut.UpdateCommandBlock }, // Set Command Block
{ 0x33, PacketTypesOut.UpdateCommandBlockMinecart }, // Set Command Minecart
{ 0x34, PacketTypesOut.CreativeInventoryAction }, // Set Creative Mode Slot
{ 0x35, PacketTypesOut.UpdateJigsawBlock }, // Set Jigsaw Block
{ 0x36, PacketTypesOut.UpdateStructureBlock }, // Set Structure Block
{ 0x37, PacketTypesOut.UpdateSign }, // Sign Update
{ 0x38, PacketTypesOut.Animation }, // Swing
{ 0x39, PacketTypesOut.Spectate }, // Teleport To Entity
{ 0x3A, PacketTypesOut.PlayerBlockPlacement }, // Use Item On
{ 0x3B, PacketTypesOut.UseItem }, // Use Item
};
private readonly Dictionary<int, ConfigurationPacketTypesIn> configurationTypesIn = new()
{
{ 0x00, ConfigurationPacketTypesIn.CookieRequest },
{ 0x01, ConfigurationPacketTypesIn.PluginMessage },
{ 0x02, ConfigurationPacketTypesIn.Disconnect },
{ 0x03, ConfigurationPacketTypesIn.FinishConfiguration },
{ 0x04, ConfigurationPacketTypesIn.KeepAlive },
{ 0x05, ConfigurationPacketTypesIn.Ping },
{ 0x06, ConfigurationPacketTypesIn.ResetChat },
{ 0x07, ConfigurationPacketTypesIn.RegistryData },
{ 0x08, ConfigurationPacketTypesIn.RemoveResourcePack },
{ 0x09, ConfigurationPacketTypesIn.ResourcePack },
{ 0x0A, ConfigurationPacketTypesIn.StoreCookie },
{ 0x0B, ConfigurationPacketTypesIn.Transfer },
{ 0x0C, ConfigurationPacketTypesIn.FeatureFlags },
{ 0x0D, ConfigurationPacketTypesIn.UpdateTags },
{ 0x0E, ConfigurationPacketTypesIn.KnownDataPacks },
{ 0x0F, ConfigurationPacketTypesIn.CustomReportDetails },
{ 0x10, ConfigurationPacketTypesIn.ServerLinks }
};
private readonly Dictionary<int, ConfigurationPacketTypesOut> configurationTypesOut = new()
{
{ 0x00, ConfigurationPacketTypesOut.ClientInformation },
{ 0x01, ConfigurationPacketTypesOut.CookieResponse },
{ 0x02, ConfigurationPacketTypesOut.PluginMessage },
{ 0x03, ConfigurationPacketTypesOut.FinishConfiguration },
{ 0x04, ConfigurationPacketTypesOut.KeepAlive },
{ 0x05, ConfigurationPacketTypesOut.Pong },
{ 0x06, ConfigurationPacketTypesOut.ResourcePackResponse },
{ 0x07, ConfigurationPacketTypesOut.KnownDataPacks }
};
protected override Dictionary<int, PacketTypesIn> GetListIn() => typeIn;
protected override Dictionary<int, PacketTypesOut> GetListOut() => typeOut;
protected override Dictionary<int, ConfigurationPacketTypesIn> GetConfigurationListIn() => configurationTypesIn!;
protected override Dictionary<int, ConfigurationPacketTypesOut> GetConfigurationListOut() => configurationTypesOut!;
}

View file

@ -1,4 +1,4 @@
using System;
using System;
using MinecraftClient.Protocol.Handlers.PacketPalettes;
namespace MinecraftClient.Protocol.Handlers
@ -48,7 +48,7 @@ namespace MinecraftClient.Protocol.Handlers
{
PacketTypePalette p = protocol switch
{
> Protocol18Handler.MC_1_21_Version => throw new NotImplementedException(Translations
> Protocol18Handler.MC_1_21_2_Version => throw new NotImplementedException(Translations
.exception_palette_packet),
<= Protocol18Handler.MC_1_8_Version => new PacketPalette17(),
<= Protocol18Handler.MC_1_11_2_Version => new PacketPalette110(),
@ -69,7 +69,8 @@ namespace MinecraftClient.Protocol.Handlers
<= Protocol18Handler.MC_1_20_2_Version => new PacketPalette1202(),
<= Protocol18Handler.MC_1_20_4_Version => new PacketPalette1204(),
<= Protocol18Handler.MC_1_20_6_Version => new PacketPalette1206(),
_ => new PacketPalette121()
<= Protocol18Handler.MC_1_21_Version => new PacketPalette121(),
_ => new PacketPalette1212()
};
p.SetForgeEnabled(forgeEnabled);

View file

@ -1,4 +1,4 @@
namespace MinecraftClient.Protocol.Handlers
namespace MinecraftClient.Protocol.Handlers
{
/// <summary>
/// Incoming packet types
@ -51,6 +51,7 @@
EntityMovement, //
EntityPosition, //
EntityPositionAndRotation, //
EntityPositionSync, // Added in 1.21.2
EntityProperties, //
EntityRotation, //
EntitySoundEffect, //
@ -58,6 +59,7 @@
EntityTeleport, //
EntityVelocity, //
Explosion, //
MoveMinecartAlongTrack, // Added in 1.21.2
FacePlayer, //
FeatureFlags, // Added in 1.19.3
HeldItemChange, //
@ -84,6 +86,7 @@
PlayerListHeaderAndFooter, //
PlayerRemove, // Added in 1.19.3 (Not used)
PlayerPositionAndLook, //
PlayerRotation, // Added in 1.21.2
PluginMessage, //
ProfilelessChatMessage, // Added in 1.19.3
ProjectilePower, // Added in 1.20.6
@ -92,6 +95,9 @@
ResetScore, // Added in 1.20.3
ResourcePackSend, //
Respawn, //
RecipeBookAdd, // Added in 1.21.2 (replaces UnlockRecipes)
RecipeBookRemove, // Added in 1.21.2
RecipeBookSettings, // Added in 1.21.2
ScoreboardObjective, //
SelectAdvancementTab, //
ServerData, // Added in 1.19
@ -99,9 +105,12 @@
ServerLinks, // Added in 1.21 (Not used)
SetCompression, // For 1.8 or below
SetCooldown, //
SetCursorItem, // Added in 1.21.2
SetDisplayChatPreview, // Added in 1.19
SetExperience, //
SetHeldSlot, // Added in 1.21.2 (replaces HeldItemChange clientbound)
SetPassengers, //
SetPlayerInventory, // Added in 1.21.2
SetSlot, //
SetTickingState, // Added in 1.20.3
StepTick, // Added in 1.20.3

View file

@ -1,4 +1,4 @@
namespace MinecraftClient.Protocol.Handlers
namespace MinecraftClient.Protocol.Handlers
{
/// <summary>
/// Outgoing packet types
@ -8,6 +8,7 @@
AcknowledgeConfiguration, // Added in 1.20.2
AdvancementTab, //
Animation, //
BundleItemSelected, // Added in 1.21.2
ChangeContainerSlotState, // Added in 1.20.3
ChatCommand, // Added in 1.19
ChatMessage, //
@ -17,6 +18,7 @@
ClickWindowButton, //
ClientSettings, //
ClientStatus, //
ClientTickEnd, // Added in 1.21.2
CloseWindow, //
CraftRecipeRequest, //
CreativeInventoryAction, //

View file

@ -1411,18 +1411,40 @@ namespace MinecraftClient.Protocol.Handlers
break;
case PacketTypesIn.PlayerPositionAndLook:
{
// These always need to be read, since we need the field after them for teleport confirm
var location = new Location(
dataTypes.ReadNextDouble(packetData), // X
dataTypes.ReadNextDouble(packetData), // Y
dataTypes.ReadNextDouble(packetData) // Z
);
int teleportId;
Location location;
float yaw, pitch;
int locMask;
var yaw = dataTypes.ReadNextFloat(packetData);
var pitch = dataTypes.ReadNextFloat(packetData);
var locMask = dataTypes.ReadNextByte(packetData);
if (protocolVersion >= MC_1_21_2_Version)
{
teleportId = dataTypes.ReadNextVarInt(packetData);
location = new Location(
dataTypes.ReadNextDouble(packetData), // X
dataTypes.ReadNextDouble(packetData), // Y
dataTypes.ReadNextDouble(packetData) // Z
);
dataTypes.ReadNextDouble(packetData); // Delta X
dataTypes.ReadNextDouble(packetData); // Delta Y
dataTypes.ReadNextDouble(packetData); // Delta Z
yaw = dataTypes.ReadNextFloat(packetData);
pitch = dataTypes.ReadNextFloat(packetData);
locMask = dataTypes.ReadNextInt(packetData); // Int flags (was Byte before 1.21.2)
}
else
{
location = new Location(
dataTypes.ReadNextDouble(packetData), // X
dataTypes.ReadNextDouble(packetData), // Y
dataTypes.ReadNextDouble(packetData) // Z
);
yaw = dataTypes.ReadNextFloat(packetData);
pitch = dataTypes.ReadNextFloat(packetData);
locMask = dataTypes.ReadNextByte(packetData);
teleportId = protocolVersion >= MC_1_9_Version
? dataTypes.ReadNextVarInt(packetData) : -1;
}
// entity handling require player pos for distance calculating
if (handler.GetTerrainEnabled() || handler.GetEntityHandlingEnabled())
{
if (protocolVersion >= MC_1_8_Version)
@ -1434,24 +1456,11 @@ namespace MinecraftClient.Protocol.Handlers
}
}
if (protocolVersion >= MC_1_9_Version)
if (teleportId >= 0)
{
var teleportId = dataTypes.ReadNextVarInt(packetData);
if (teleportId < 0)
{
yaw = LastYaw;
pitch = LastPitch;
}
else
{
LastYaw = yaw;
LastPitch = pitch;
}
LastYaw = yaw;
LastPitch = pitch;
handler.UpdateLocation(location, yaw, pitch);
// Teleport confirm packet
SendPacket(PacketTypesOut.TeleportConfirm, DataTypes.GetVarInt(teleportId));
if (Config.Main.Advanced.TemporaryFixBadpacket)
@ -2723,6 +2732,7 @@ namespace MinecraftClient.Protocol.Handlers
handler.OnExplosion(explosionLocation, explosionStrength, explosionBlockCount);
break;
case PacketTypesIn.HeldItemChange:
case PacketTypesIn.SetHeldSlot:
handler.OnHeldItemChange(dataTypes.ReadNextByte(packetData)); // Slot
break;
case PacketTypesIn.ScoreboardObjective:
@ -3251,8 +3261,8 @@ namespace MinecraftClient.Protocol.Handlers
}
}
// Strict Error Handling (Ignored)
if (protocolVersion >= MC_1_20_6_Version)
// Strict Error Handling (removed in 1.21.2)
if (protocolVersion >= MC_1_20_6_Version && protocolVersion < MC_1_21_2_Version)
dataTypes.ReadNextBool(packetData);
currentState = protocolVersion < MC_1_20_2_Version
@ -3844,6 +3854,9 @@ namespace MinecraftClient.Protocol.Handlers
if (protocolVersion >= MC_1_18_1_Version)
fields.Add(1); // 1.18 and above - Allow server listings
if (protocolVersion >= MC_1_21_2_Version)
fields.AddRange(DataTypes.GetVarInt(0)); // 1.21.2+ Particle status: 0=All, 1=Decreased, 2=Minimal
SendPacket(PacketTypesOut.ClientSettings, fields);
}
catch (SocketException)

View file

@ -0,0 +1,129 @@
using System.Collections.Generic;
using MinecraftClient.Inventory.ItemPalettes;
using MinecraftClient.Protocol.Handlers.StructuredComponents.Components.Subcomponents;
using MinecraftClient.Protocol.Handlers.StructuredComponents.Components.Subcomponents._1_21;
using MinecraftClient.Protocol.Handlers.StructuredComponents.Core;
namespace MinecraftClient.Protocol.Handlers.StructuredComponents.Components._1_21_2;
public class ConsumableComponent(DataTypes dataTypes, ItemPalette itemPalette, SubComponentRegistry subComponentRegistry)
: StructuredComponent(dataTypes, itemPalette, subComponentRegistry)
{
public float ConsumeSeconds { get; set; }
public int Animation { get; set; }
public SoundEventSubComponent? Sound { get; set; }
public bool HasConsumeParticles { get; set; }
public List<ConsumeEffectData> Effects { get; set; } = new();
public override void Parse(Queue<byte> data)
{
ConsumeSeconds = dataTypes.ReadNextFloat(data);
Animation = dataTypes.ReadNextVarInt(data);
Sound = (SoundEventSubComponent)subComponentRegistry.ParseSubComponent(SubComponents.SoundEvent, data);
HasConsumeParticles = dataTypes.ReadNextBool(data);
var effectCount = dataTypes.ReadNextVarInt(data);
for (var i = 0; i < effectCount; i++)
{
var effectTypeId = dataTypes.ReadNextVarInt(data);
var effectData = ReadConsumeEffectPayload(effectTypeId, data);
Effects.Add(new ConsumeEffectData(effectTypeId, effectData));
}
}
private byte[] ReadConsumeEffectPayload(int effectTypeId, Queue<byte> data)
{
var payload = new List<byte>();
switch (effectTypeId)
{
case 0: // apply_effects: List<MobEffectInstance> + probability(float)
var effectCount = dataTypes.ReadNextVarInt(data);
payload.AddRange(DataTypes.GetVarInt(effectCount));
for (var i = 0; i < effectCount; i++)
payload.AddRange(ReadMobEffectInstance(data));
payload.AddRange(DataTypes.GetFloat(dataTypes.ReadNextFloat(data)));
break;
case 1: // remove_effects: HolderSet<MobEffect>
payload.AddRange(ReadHolderSet(data));
break;
case 2: // clear_all_effects: empty
break;
case 3: // teleport_randomly: float diameter
payload.AddRange(DataTypes.GetFloat(dataTypes.ReadNextFloat(data)));
break;
case 4: // play_sound: Holder<SoundEvent>
var sound = (SoundEventSubComponent)subComponentRegistry.ParseSubComponent(SubComponents.SoundEvent, data);
payload.AddRange(sound.Serialize());
break;
}
return payload.ToArray();
}
private byte[] ReadMobEffectInstance(Queue<byte> data)
{
var result = new List<byte>();
var effectId = dataTypes.ReadNextVarInt(data);
result.AddRange(DataTypes.GetVarInt(effectId));
result.AddRange(ReadMobEffectDetails(data));
return result.ToArray();
}
private byte[] ReadMobEffectDetails(Queue<byte> data)
{
var result = new List<byte>();
var amplifier = dataTypes.ReadNextVarInt(data);
result.AddRange(DataTypes.GetVarInt(amplifier));
var duration = dataTypes.ReadNextVarInt(data);
result.AddRange(DataTypes.GetVarInt(duration));
var ambient = dataTypes.ReadNextBool(data);
result.AddRange(DataTypes.GetBool(ambient));
var showParticles = dataTypes.ReadNextBool(data);
result.AddRange(DataTypes.GetBool(showParticles));
var showIcon = dataTypes.ReadNextBool(data);
result.AddRange(DataTypes.GetBool(showIcon));
var hasHiddenEffect = dataTypes.ReadNextBool(data);
result.AddRange(DataTypes.GetBool(hasHiddenEffect));
if (hasHiddenEffect)
result.AddRange(ReadMobEffectDetails(data));
return result.ToArray();
}
private byte[] ReadHolderSet(Queue<byte> data)
{
var result = new List<byte>();
var type = dataTypes.ReadNextVarInt(data);
result.AddRange(DataTypes.GetVarInt(type));
if (type == 0)
{
var tagName = dataTypes.ReadNextString(data);
result.AddRange(DataTypes.GetString(tagName));
}
else
{
for (var i = 0; i < type - 1; i++)
{
var id = dataTypes.ReadNextVarInt(data);
result.AddRange(DataTypes.GetVarInt(id));
}
}
return result.ToArray();
}
public override Queue<byte> Serialize()
{
var data = new List<byte>();
data.AddRange(DataTypes.GetFloat(ConsumeSeconds));
data.AddRange(DataTypes.GetVarInt(Animation));
if (Sound != null) data.AddRange(Sound.Serialize());
data.AddRange(DataTypes.GetBool(HasConsumeParticles));
data.AddRange(DataTypes.GetVarInt(Effects.Count));
foreach (var effect in Effects)
{
data.AddRange(DataTypes.GetVarInt(effect.EffectTypeId));
data.AddRange(effect.Payload);
}
return new Queue<byte>(data);
}
public record ConsumeEffectData(int EffectTypeId, byte[] Payload);
}

View file

@ -0,0 +1,23 @@
using System.Collections.Generic;
using MinecraftClient.Inventory.ItemPalettes;
using MinecraftClient.Protocol.Handlers.StructuredComponents.Core;
namespace MinecraftClient.Protocol.Handlers.StructuredComponents.Components._1_21_2;
public class DamageResistantComponent(DataTypes dataTypes, ItemPalette itemPalette, SubComponentRegistry subComponentRegistry)
: StructuredComponent(dataTypes, itemPalette, subComponentRegistry)
{
public string Types { get; set; } = null!;
public override void Parse(Queue<byte> data)
{
Types = dataTypes.ReadNextString(data);
}
public override Queue<byte> Serialize()
{
var data = new List<byte>();
data.AddRange(DataTypes.GetString(Types));
return new Queue<byte>(data);
}
}

View file

@ -0,0 +1,106 @@
using System.Collections.Generic;
using MinecraftClient.Inventory.ItemPalettes;
using MinecraftClient.Protocol.Handlers.StructuredComponents.Components.Subcomponents;
using MinecraftClient.Protocol.Handlers.StructuredComponents.Components.Subcomponents._1_21;
using MinecraftClient.Protocol.Handlers.StructuredComponents.Core;
namespace MinecraftClient.Protocol.Handlers.StructuredComponents.Components._1_21_2;
public class DeathProtectionComponent(DataTypes dataTypes, ItemPalette itemPalette, SubComponentRegistry subComponentRegistry)
: StructuredComponent(dataTypes, itemPalette, subComponentRegistry)
{
public List<ConsumeEffectData> DeathEffects { get; set; } = new();
public override void Parse(Queue<byte> data)
{
var effectCount = dataTypes.ReadNextVarInt(data);
for (var i = 0; i < effectCount; i++)
{
var effectTypeId = dataTypes.ReadNextVarInt(data);
var effectData = ReadConsumeEffectPayload(effectTypeId, data);
DeathEffects.Add(new ConsumeEffectData(effectTypeId, effectData));
}
}
private byte[] ReadConsumeEffectPayload(int effectTypeId, Queue<byte> data)
{
var payload = new List<byte>();
switch (effectTypeId)
{
case 0: // apply_effects
var effectCount = dataTypes.ReadNextVarInt(data);
payload.AddRange(DataTypes.GetVarInt(effectCount));
for (var i = 0; i < effectCount; i++)
payload.AddRange(ReadMobEffectInstance(data));
payload.AddRange(DataTypes.GetFloat(dataTypes.ReadNextFloat(data)));
break;
case 1: // remove_effects
payload.AddRange(ReadHolderSet(data));
break;
case 2: // clear_all_effects
break;
case 3: // teleport_randomly
payload.AddRange(DataTypes.GetFloat(dataTypes.ReadNextFloat(data)));
break;
case 4: // play_sound
var sound = (SoundEventSubComponent)subComponentRegistry.ParseSubComponent(SubComponents.SoundEvent, data);
payload.AddRange(sound.Serialize());
break;
}
return payload.ToArray();
}
private byte[] ReadMobEffectInstance(Queue<byte> data)
{
var result = new List<byte>();
result.AddRange(DataTypes.GetVarInt(dataTypes.ReadNextVarInt(data)));
result.AddRange(ReadMobEffectDetails(data));
return result.ToArray();
}
private byte[] ReadMobEffectDetails(Queue<byte> data)
{
var result = new List<byte>();
result.AddRange(DataTypes.GetVarInt(dataTypes.ReadNextVarInt(data)));
result.AddRange(DataTypes.GetVarInt(dataTypes.ReadNextVarInt(data)));
result.AddRange(DataTypes.GetBool(dataTypes.ReadNextBool(data)));
result.AddRange(DataTypes.GetBool(dataTypes.ReadNextBool(data)));
result.AddRange(DataTypes.GetBool(dataTypes.ReadNextBool(data)));
var hasHidden = dataTypes.ReadNextBool(data);
result.AddRange(DataTypes.GetBool(hasHidden));
if (hasHidden)
result.AddRange(ReadMobEffectDetails(data));
return result.ToArray();
}
private byte[] ReadHolderSet(Queue<byte> data)
{
var result = new List<byte>();
var type = dataTypes.ReadNextVarInt(data);
result.AddRange(DataTypes.GetVarInt(type));
if (type == 0)
{
result.AddRange(DataTypes.GetString(dataTypes.ReadNextString(data)));
}
else
{
for (var i = 0; i < type - 1; i++)
result.AddRange(DataTypes.GetVarInt(dataTypes.ReadNextVarInt(data)));
}
return result.ToArray();
}
public override Queue<byte> Serialize()
{
var data = new List<byte>();
data.AddRange(DataTypes.GetVarInt(DeathEffects.Count));
foreach (var effect in DeathEffects)
{
data.AddRange(DataTypes.GetVarInt(effect.EffectTypeId));
data.AddRange(effect.Payload);
}
return new Queue<byte>(data);
}
public record ConsumeEffectData(int EffectTypeId, byte[] Payload);
}

View file

@ -0,0 +1,23 @@
using System.Collections.Generic;
using MinecraftClient.Inventory.ItemPalettes;
using MinecraftClient.Protocol.Handlers.StructuredComponents.Core;
namespace MinecraftClient.Protocol.Handlers.StructuredComponents.Components._1_21_2;
public class EnchantableComponent(DataTypes dataTypes, ItemPalette itemPalette, SubComponentRegistry subComponentRegistry)
: StructuredComponent(dataTypes, itemPalette, subComponentRegistry)
{
public int Value { get; set; }
public override void Parse(Queue<byte> data)
{
Value = dataTypes.ReadNextVarInt(data);
}
public override Queue<byte> Serialize()
{
var data = new List<byte>();
data.AddRange(DataTypes.GetVarInt(Value));
return new Queue<byte>(data);
}
}

View file

@ -0,0 +1,94 @@
using System.Collections.Generic;
using MinecraftClient.Inventory.ItemPalettes;
using MinecraftClient.Protocol.Handlers.StructuredComponents.Components.Subcomponents;
using MinecraftClient.Protocol.Handlers.StructuredComponents.Components.Subcomponents._1_21;
using MinecraftClient.Protocol.Handlers.StructuredComponents.Core;
namespace MinecraftClient.Protocol.Handlers.StructuredComponents.Components._1_21_2;
public class EquippableComponent(DataTypes dataTypes, ItemPalette itemPalette, SubComponentRegistry subComponentRegistry)
: StructuredComponent(dataTypes, itemPalette, subComponentRegistry)
{
public int Slot { get; set; }
public SoundEventSubComponent? EquipSound { get; set; }
public bool HasModel { get; set; }
public string? Model { get; set; }
public bool HasCameraOverlay { get; set; }
public string? CameraOverlay { get; set; }
public bool HasAllowedEntities { get; set; }
public int AllowedEntitiesType { get; set; }
public string? AllowedEntitiesTag { get; set; }
public List<int>? AllowedEntitiesIds { get; set; }
public bool Dispensable { get; set; }
public bool Swappable { get; set; }
public bool DamageOnHurt { get; set; }
public override void Parse(Queue<byte> data)
{
Slot = dataTypes.ReadNextVarInt(data);
EquipSound = (SoundEventSubComponent)subComponentRegistry.ParseSubComponent(SubComponents.SoundEvent, data);
HasModel = dataTypes.ReadNextBool(data);
if (HasModel)
Model = dataTypes.ReadNextString(data);
HasCameraOverlay = dataTypes.ReadNextBool(data);
if (HasCameraOverlay)
CameraOverlay = dataTypes.ReadNextString(data);
HasAllowedEntities = dataTypes.ReadNextBool(data);
if (HasAllowedEntities)
{
AllowedEntitiesType = dataTypes.ReadNextVarInt(data);
if (AllowedEntitiesType == 0)
{
AllowedEntitiesTag = dataTypes.ReadNextString(data);
}
else
{
AllowedEntitiesIds = new List<int>();
for (var i = 0; i < AllowedEntitiesType - 1; i++)
AllowedEntitiesIds.Add(dataTypes.ReadNextVarInt(data));
}
}
Dispensable = dataTypes.ReadNextBool(data);
Swappable = dataTypes.ReadNextBool(data);
DamageOnHurt = dataTypes.ReadNextBool(data);
}
public override Queue<byte> Serialize()
{
var data = new List<byte>();
data.AddRange(DataTypes.GetVarInt(Slot));
if (EquipSound != null) data.AddRange(EquipSound.Serialize());
data.AddRange(DataTypes.GetBool(HasModel));
if (HasModel && Model != null)
data.AddRange(DataTypes.GetString(Model));
data.AddRange(DataTypes.GetBool(HasCameraOverlay));
if (HasCameraOverlay && CameraOverlay != null)
data.AddRange(DataTypes.GetString(CameraOverlay));
data.AddRange(DataTypes.GetBool(HasAllowedEntities));
if (HasAllowedEntities)
{
data.AddRange(DataTypes.GetVarInt(AllowedEntitiesType));
if (AllowedEntitiesType == 0 && AllowedEntitiesTag != null)
{
data.AddRange(DataTypes.GetString(AllowedEntitiesTag));
}
else if (AllowedEntitiesIds != null)
{
foreach (var id in AllowedEntitiesIds)
data.AddRange(DataTypes.GetVarInt(id));
}
}
data.AddRange(DataTypes.GetBool(Dispensable));
data.AddRange(DataTypes.GetBool(Swappable));
data.AddRange(DataTypes.GetBool(DamageOnHurt));
return new Queue<byte>(data);
}
}

View file

@ -0,0 +1,29 @@
using System.Collections.Generic;
using MinecraftClient.Inventory.ItemPalettes;
using MinecraftClient.Protocol.Handlers.StructuredComponents.Core;
namespace MinecraftClient.Protocol.Handlers.StructuredComponents.Components._1_21_2;
public class FoodComponent1212(DataTypes dataTypes, ItemPalette itemPalette, SubComponentRegistry subComponentRegistry)
: StructuredComponent(dataTypes, itemPalette, subComponentRegistry)
{
public int Nutrition { get; set; }
public float Saturation { get; set; }
public bool CanAlwaysEat { get; set; }
public override void Parse(Queue<byte> data)
{
Nutrition = dataTypes.ReadNextVarInt(data);
Saturation = dataTypes.ReadNextFloat(data);
CanAlwaysEat = dataTypes.ReadNextBool(data);
}
public override Queue<byte> Serialize()
{
var data = new List<byte>();
data.AddRange(DataTypes.GetVarInt(Nutrition));
data.AddRange(DataTypes.GetFloat(Saturation));
data.AddRange(DataTypes.GetBool(CanAlwaysEat));
return new Queue<byte>(data);
}
}

View file

@ -0,0 +1,8 @@
using MinecraftClient.Inventory.ItemPalettes;
using MinecraftClient.Protocol.Handlers.StructuredComponents.Components;
using MinecraftClient.Protocol.Handlers.StructuredComponents.Core;
namespace MinecraftClient.Protocol.Handlers.StructuredComponents.Components._1_21_2;
public class GliderComponent(DataTypes dataTypes, ItemPalette itemPalette, SubComponentRegistry subComponentRegistry)
: EmptyComponent(dataTypes, itemPalette, subComponentRegistry);

View file

@ -0,0 +1,23 @@
using System.Collections.Generic;
using MinecraftClient.Inventory.ItemPalettes;
using MinecraftClient.Protocol.Handlers.StructuredComponents.Core;
namespace MinecraftClient.Protocol.Handlers.StructuredComponents.Components._1_21_2;
public class ItemModelComponent(DataTypes dataTypes, ItemPalette itemPalette, SubComponentRegistry subComponentRegistry)
: StructuredComponent(dataTypes, itemPalette, subComponentRegistry)
{
public string Identifier { get; set; } = null!;
public override void Parse(Queue<byte> data)
{
Identifier = dataTypes.ReadNextString(data);
}
public override Queue<byte> Serialize()
{
var data = new List<byte>();
data.AddRange(DataTypes.GetString(Identifier));
return new Queue<byte>(data);
}
}

View file

@ -0,0 +1,44 @@
using System.Collections.Generic;
using MinecraftClient.Inventory.ItemPalettes;
using MinecraftClient.Protocol.Handlers.StructuredComponents.Core;
namespace MinecraftClient.Protocol.Handlers.StructuredComponents.Components._1_21_2;
public class RepairableComponent(DataTypes dataTypes, ItemPalette itemPalette, SubComponentRegistry subComponentRegistry)
: StructuredComponent(dataTypes, itemPalette, subComponentRegistry)
{
public int Type { get; set; }
public string? TagName { get; set; }
public List<int>? ItemIds { get; set; }
public override void Parse(Queue<byte> data)
{
Type = dataTypes.ReadNextVarInt(data);
if (Type == 0)
{
TagName = dataTypes.ReadNextString(data);
}
else
{
ItemIds = new List<int>();
for (var i = 0; i < Type - 1; i++)
ItemIds.Add(dataTypes.ReadNextVarInt(data));
}
}
public override Queue<byte> Serialize()
{
var data = new List<byte>();
data.AddRange(DataTypes.GetVarInt(Type));
if (Type == 0 && TagName != null)
{
data.AddRange(DataTypes.GetString(TagName));
}
else if (ItemIds != null)
{
foreach (var id in ItemIds)
data.AddRange(DataTypes.GetVarInt(id));
}
return new Queue<byte>(data);
}
}

View file

@ -0,0 +1,23 @@
using System.Collections.Generic;
using MinecraftClient.Inventory.ItemPalettes;
using MinecraftClient.Protocol.Handlers.StructuredComponents.Core;
namespace MinecraftClient.Protocol.Handlers.StructuredComponents.Components._1_21_2;
public class TooltipStyleComponent(DataTypes dataTypes, ItemPalette itemPalette, SubComponentRegistry subComponentRegistry)
: StructuredComponent(dataTypes, itemPalette, subComponentRegistry)
{
public string Identifier { get; set; } = null!;
public override void Parse(Queue<byte> data)
{
Identifier = dataTypes.ReadNextString(data);
}
public override Queue<byte> Serialize()
{
var data = new List<byte>();
data.AddRange(DataTypes.GetString(Identifier));
return new Queue<byte>(data);
}
}

View file

@ -0,0 +1,31 @@
using System.Collections.Generic;
using MinecraftClient.Inventory.ItemPalettes;
using MinecraftClient.Protocol.Handlers.StructuredComponents.Core;
namespace MinecraftClient.Protocol.Handlers.StructuredComponents.Components._1_21_2;
public class UseCooldownComponent(DataTypes dataTypes, ItemPalette itemPalette, SubComponentRegistry subComponentRegistry)
: StructuredComponent(dataTypes, itemPalette, subComponentRegistry)
{
public float Seconds { get; set; }
public bool HasCooldownGroup { get; set; }
public string? CooldownGroup { get; set; }
public override void Parse(Queue<byte> data)
{
Seconds = dataTypes.ReadNextFloat(data);
HasCooldownGroup = dataTypes.ReadNextBool(data);
if (HasCooldownGroup)
CooldownGroup = dataTypes.ReadNextString(data);
}
public override Queue<byte> Serialize()
{
var data = new List<byte>();
data.AddRange(DataTypes.GetFloat(Seconds));
data.AddRange(DataTypes.GetBool(HasCooldownGroup));
if (HasCooldownGroup && CooldownGroup != null)
data.AddRange(DataTypes.GetString(CooldownGroup));
return new Queue<byte>(data);
}
}

View file

@ -0,0 +1,24 @@
using System.Collections.Generic;
using MinecraftClient.Inventory;
using MinecraftClient.Inventory.ItemPalettes;
using MinecraftClient.Protocol.Handlers.StructuredComponents.Core;
namespace MinecraftClient.Protocol.Handlers.StructuredComponents.Components._1_21_2;
public class UseRemainderComponent(DataTypes dataTypes, ItemPalette itemPalette, SubComponentRegistry subComponentRegistry)
: StructuredComponent(dataTypes, itemPalette, subComponentRegistry)
{
public Item? ConvertInto { get; set; }
public override void Parse(Queue<byte> data)
{
ConvertInto = dataTypes.ReadNextItemSlot(data, ItemPalette);
}
public override Queue<byte> Serialize()
{
var data = new List<byte>();
data.AddRange(dataTypes.GetItemSlot(ConvertInto, ItemPalette));
return new Queue<byte>(data);
}
}

View file

@ -0,0 +1,82 @@
using MinecraftClient.Inventory.ItemPalettes;
using MinecraftClient.Protocol.Handlers.StructuredComponents.Components._1_20_6;
using MinecraftClient.Protocol.Handlers.StructuredComponents.Components._1_21;
using MinecraftClient.Protocol.Handlers.StructuredComponents.Components._1_21_2;
using MinecraftClient.Protocol.Handlers.StructuredComponents.Core;
namespace MinecraftClient.Protocol.Handlers.StructuredComponents.Registries;
public class StructuredComponentsRegistry1212 : StructuredComponentRegistry
{
public StructuredComponentsRegistry1212(DataTypes dataTypes, ItemPalette itemPalette, SubComponentRegistry subComponentRegistry)
: base(dataTypes, itemPalette, subComponentRegistry)
{
RegisterComponent<CustomDataComponent>(0, "minecraft:custom_data");
RegisterComponent<MaxStackSizeComponent>(1, "minecraft:max_stack_size");
RegisterComponent<MaxDamageComponent>(2, "minecraft:max_damage");
RegisterComponent<DamageComponent>(3, "minecraft:damage");
RegisterComponent<UnbrekableComponent1206>(4, "minecraft:unbreakable");
RegisterComponent<CustomNameComponent>(5, "minecraft:custom_name");
RegisterComponent<ItemNameComponent>(6, "minecraft:item_name");
RegisterComponent<ItemModelComponent>(7, "minecraft:item_model");
RegisterComponent<LoreNameComponent1206>(8, "minecraft:lore");
RegisterComponent<RarityComponent>(9, "minecraft:rarity");
RegisterComponent<EnchantmentsComponent>(10, "minecraft:enchantments");
RegisterComponent<CanPlaceOnComponent>(11, "minecraft:can_place_on");
RegisterComponent<CanBreakComponent>(12, "minecraft:can_break");
RegisterComponent<AttributeModifiersComponent>(13, "minecraft:attribute_modifiers");
RegisterComponent<CustomModelDataComponent>(14, "minecraft:custom_model_data");
RegisterComponent<HideAdditionalTooltipComponent>(15, "minecraft:hide_additional_tooltip");
RegisterComponent<HideTooltipComponent>(16, "minecraft:hide_tooltip");
RegisterComponent<RepairCostComponent>(17, "minecraft:repair_cost");
RegisterComponent<CreativeSlotLockComponent>(18, "minecraft:creative_slot_lock");
RegisterComponent<EnchantmentGlintOverrideComponent>(19, "minecraft:enchantment_glint_override");
RegisterComponent<IntangibleProjectileComponent>(20, "minecraft:intangible_projectile");
RegisterComponent<FoodComponent1212>(21, "minecraft:food");
RegisterComponent<ConsumableComponent>(22, "minecraft:consumable");
RegisterComponent<UseRemainderComponent>(23, "minecraft:use_remainder");
RegisterComponent<UseCooldownComponent>(24, "minecraft:use_cooldown");
RegisterComponent<DamageResistantComponent>(25, "minecraft:damage_resistant");
RegisterComponent<ToolComponent>(26, "minecraft:tool");
RegisterComponent<EnchantableComponent>(27, "minecraft:enchantable");
RegisterComponent<EquippableComponent>(28, "minecraft:equippable");
RegisterComponent<RepairableComponent>(29, "minecraft:repairable");
RegisterComponent<GliderComponent>(30, "minecraft:glider");
RegisterComponent<TooltipStyleComponent>(31, "minecraft:tooltip_style");
RegisterComponent<DeathProtectionComponent>(32, "minecraft:death_protection");
RegisterComponent<StoredEnchantmentsComponent>(33, "minecraft:stored_enchantments");
RegisterComponent<DyeColorComponent>(34, "minecraft:dyed_color");
RegisterComponent<MapColorComponent>(35, "minecraft:map_color");
RegisterComponent<MapIdComponent>(36, "minecraft:map_id");
RegisterComponent<MapDecorationsComponent>(37, "minecraft:map_decorations");
RegisterComponent<MapPostProcessingComponent>(38, "minecraft:map_post_processing");
RegisterComponent<ChargedProjectilesComponent>(39, "minecraft:charged_projectiles");
RegisterComponent<BundleContentsComponent>(40, "minecraft:bundle_contents");
RegisterComponent<PotionContentsComponent>(41, "minecraft:potion_contents");
RegisterComponent<SuspiciousStewEffectsComponent>(42, "minecraft:suspicious_stew_effects");
RegisterComponent<WritableBlookContentComponent>(43, "minecraft:writable_book_content");
RegisterComponent<WrittenBlookContentComponent>(44, "minecraft:written_book_content");
RegisterComponent<TrimComponent>(45, "minecraft:trim");
RegisterComponent<DebugStickStateComponent>(46, "minecraft:debug_stick_state");
RegisterComponent<EntityDataComponent>(47, "minecraft:entity_data");
RegisterComponent<BucketEntityDataComponent>(48, "minecraft:bucket_entity_data");
RegisterComponent<BlockEntityDataComponent>(49, "minecraft:block_entity_data");
RegisterComponent<InstrumentComponent>(50, "minecraft:instrument");
RegisterComponent<OmniousBottleAmplifierComponent>(51, "minecraft:ominous_bottle_amplifier");
RegisterComponent<JukeBoxPlayableComponent>(52, "minecraft:jukebox_playable");
RegisterComponent<RecipesComponent>(53, "minecraft:recipes");
RegisterComponent<LodestoneTrackerComponent>(54, "minecraft:lodestone_tracker");
RegisterComponent<FireworkExplosionComponent>(55, "minecraft:firework_explosion");
RegisterComponent<FireworksComponent>(56, "minecraft:fireworks");
RegisterComponent<ProfileComponent>(57, "minecraft:profile");
RegisterComponent<NoteBlockSoundComponent>(58, "minecraft:note_block_sound");
RegisterComponent<BannerPatternsComponent>(59, "minecraft:banner_patterns");
RegisterComponent<BaseColorComponent>(60, "minecraft:base_color");
RegisterComponent<PotDecorationsComponent>(61, "minecraft:pot_decorations");
RegisterComponent<ContainerComponent>(62, "minecraft:container");
RegisterComponent<BlockStateComponent>(63, "minecraft:block_state");
RegisterComponent<BeesComponent>(64, "minecraft:bees");
RegisterComponent<LockComponent>(65, "minecraft:lock");
RegisterComponent<ContainerLootComponent>(66, "minecraft:container_loot");
}
}

View file

@ -0,0 +1,11 @@
using MinecraftClient.Protocol.Handlers.StructuredComponents.Components.Subcomponents._1_21;
using MinecraftClient.Protocol.Handlers.StructuredComponents.Core;
namespace MinecraftClient.Protocol.Handlers.StructuredComponents.Registries.Subcomponents;
public class SubComponentRegistry1212 : SubComponentRegistry121
{
public SubComponentRegistry1212(DataTypes dataTypes) : base(dataTypes)
{
}
}

View file

@ -21,6 +21,7 @@ public class StructuredComponentsHandler
{
Protocol18Handler.MC_1_20_6_Version => typeof(SubComponentRegistry1206),
Protocol18Handler.MC_1_21_Version => typeof(SubComponentRegistry121),
>= Protocol18Handler.MC_1_21_2_Version => typeof(SubComponentRegistry1212),
_ => throw new NotSupportedException($"Protocol version {protocolVersion} is not supported for subcomponent registries!")
};
@ -32,6 +33,7 @@ public class StructuredComponentsHandler
{
Protocol18Handler.MC_1_20_6_Version => typeof(StructuredComponentsRegistry1206),
Protocol18Handler.MC_1_21_Version => typeof(StructuredComponentsRegistry121),
>= Protocol18Handler.MC_1_21_2_Version => typeof(StructuredComponentsRegistry1212),
_ => throw new NotSupportedException($"Protocol version {protocolVersion} is not supported for structured component registries!")
};