diff --git a/MinecraftClient/Protocol/Handlers/PacketPalettes/PacketPalette1212.cs b/MinecraftClient/Protocol/Handlers/PacketPalettes/PacketPalette1212.cs new file mode 100644 index 00000000..76deae7e --- /dev/null +++ b/MinecraftClient/Protocol/Handlers/PacketPalettes/PacketPalette1212.cs @@ -0,0 +1,243 @@ +using System.Collections.Generic; + +namespace MinecraftClient.Protocol.Handlers.PacketPalettes; + +public class PacketPalette1212 : PacketTypePalette + { + private readonly Dictionary 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 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 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 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 GetListIn() => typeIn; + protected override Dictionary GetListOut() => typeOut; + protected override Dictionary GetConfigurationListIn() => configurationTypesIn!; + protected override Dictionary GetConfigurationListOut() => configurationTypesOut!; + } diff --git a/MinecraftClient/Protocol/Handlers/PacketType18Handler.cs b/MinecraftClient/Protocol/Handlers/PacketType18Handler.cs index 7d80d4ee..9141627b 100644 --- a/MinecraftClient/Protocol/Handlers/PacketType18Handler.cs +++ b/MinecraftClient/Protocol/Handlers/PacketType18Handler.cs @@ -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); diff --git a/MinecraftClient/Protocol/Handlers/PacketTypesIn.cs b/MinecraftClient/Protocol/Handlers/PacketTypesIn.cs index d3feabb7..19d72455 100644 --- a/MinecraftClient/Protocol/Handlers/PacketTypesIn.cs +++ b/MinecraftClient/Protocol/Handlers/PacketTypesIn.cs @@ -1,4 +1,4 @@ -namespace MinecraftClient.Protocol.Handlers +namespace MinecraftClient.Protocol.Handlers { /// /// 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 diff --git a/MinecraftClient/Protocol/Handlers/PacketTypesOut.cs b/MinecraftClient/Protocol/Handlers/PacketTypesOut.cs index 1149a71f..9512024a 100644 --- a/MinecraftClient/Protocol/Handlers/PacketTypesOut.cs +++ b/MinecraftClient/Protocol/Handlers/PacketTypesOut.cs @@ -1,4 +1,4 @@ -namespace MinecraftClient.Protocol.Handlers +namespace MinecraftClient.Protocol.Handlers { /// /// 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, // diff --git a/MinecraftClient/Protocol/Handlers/Protocol18.cs b/MinecraftClient/Protocol/Handlers/Protocol18.cs index 13b86408..1b1cb1fe 100644 --- a/MinecraftClient/Protocol/Handlers/Protocol18.cs +++ b/MinecraftClient/Protocol/Handlers/Protocol18.cs @@ -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) diff --git a/MinecraftClient/Protocol/Handlers/StructuredComponents/Components/1_21_2/ConsumableComponent.cs b/MinecraftClient/Protocol/Handlers/StructuredComponents/Components/1_21_2/ConsumableComponent.cs new file mode 100644 index 00000000..ad931c61 --- /dev/null +++ b/MinecraftClient/Protocol/Handlers/StructuredComponents/Components/1_21_2/ConsumableComponent.cs @@ -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 Effects { get; set; } = new(); + + public override void Parse(Queue 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 data) + { + var payload = new List(); + switch (effectTypeId) + { + case 0: // apply_effects: List + 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 + 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 + var sound = (SoundEventSubComponent)subComponentRegistry.ParseSubComponent(SubComponents.SoundEvent, data); + payload.AddRange(sound.Serialize()); + break; + } + return payload.ToArray(); + } + + private byte[] ReadMobEffectInstance(Queue data) + { + var result = new List(); + var effectId = dataTypes.ReadNextVarInt(data); + result.AddRange(DataTypes.GetVarInt(effectId)); + result.AddRange(ReadMobEffectDetails(data)); + return result.ToArray(); + } + + private byte[] ReadMobEffectDetails(Queue data) + { + var result = new List(); + 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 data) + { + var result = new List(); + 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 Serialize() + { + var data = new List(); + 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(data); + } + + public record ConsumeEffectData(int EffectTypeId, byte[] Payload); +} diff --git a/MinecraftClient/Protocol/Handlers/StructuredComponents/Components/1_21_2/DamageResistantComponent.cs b/MinecraftClient/Protocol/Handlers/StructuredComponents/Components/1_21_2/DamageResistantComponent.cs new file mode 100644 index 00000000..25592d2f --- /dev/null +++ b/MinecraftClient/Protocol/Handlers/StructuredComponents/Components/1_21_2/DamageResistantComponent.cs @@ -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 data) + { + Types = dataTypes.ReadNextString(data); + } + + public override Queue Serialize() + { + var data = new List(); + data.AddRange(DataTypes.GetString(Types)); + return new Queue(data); + } +} diff --git a/MinecraftClient/Protocol/Handlers/StructuredComponents/Components/1_21_2/DeathProtectionComponent.cs b/MinecraftClient/Protocol/Handlers/StructuredComponents/Components/1_21_2/DeathProtectionComponent.cs new file mode 100644 index 00000000..36c59690 --- /dev/null +++ b/MinecraftClient/Protocol/Handlers/StructuredComponents/Components/1_21_2/DeathProtectionComponent.cs @@ -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 DeathEffects { get; set; } = new(); + + public override void Parse(Queue 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 data) + { + var payload = new List(); + 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 data) + { + var result = new List(); + result.AddRange(DataTypes.GetVarInt(dataTypes.ReadNextVarInt(data))); + result.AddRange(ReadMobEffectDetails(data)); + return result.ToArray(); + } + + private byte[] ReadMobEffectDetails(Queue data) + { + var result = new List(); + 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 data) + { + var result = new List(); + 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 Serialize() + { + var data = new List(); + data.AddRange(DataTypes.GetVarInt(DeathEffects.Count)); + foreach (var effect in DeathEffects) + { + data.AddRange(DataTypes.GetVarInt(effect.EffectTypeId)); + data.AddRange(effect.Payload); + } + return new Queue(data); + } + + public record ConsumeEffectData(int EffectTypeId, byte[] Payload); +} diff --git a/MinecraftClient/Protocol/Handlers/StructuredComponents/Components/1_21_2/EnchantableComponent.cs b/MinecraftClient/Protocol/Handlers/StructuredComponents/Components/1_21_2/EnchantableComponent.cs new file mode 100644 index 00000000..4ef63563 --- /dev/null +++ b/MinecraftClient/Protocol/Handlers/StructuredComponents/Components/1_21_2/EnchantableComponent.cs @@ -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 data) + { + Value = dataTypes.ReadNextVarInt(data); + } + + public override Queue Serialize() + { + var data = new List(); + data.AddRange(DataTypes.GetVarInt(Value)); + return new Queue(data); + } +} diff --git a/MinecraftClient/Protocol/Handlers/StructuredComponents/Components/1_21_2/EquippableComponent.cs b/MinecraftClient/Protocol/Handlers/StructuredComponents/Components/1_21_2/EquippableComponent.cs new file mode 100644 index 00000000..c63e3f4d --- /dev/null +++ b/MinecraftClient/Protocol/Handlers/StructuredComponents/Components/1_21_2/EquippableComponent.cs @@ -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? AllowedEntitiesIds { get; set; } + public bool Dispensable { get; set; } + public bool Swappable { get; set; } + public bool DamageOnHurt { get; set; } + + public override void Parse(Queue 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(); + 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 Serialize() + { + var data = new List(); + 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(data); + } +} diff --git a/MinecraftClient/Protocol/Handlers/StructuredComponents/Components/1_21_2/FoodComponent1212.cs b/MinecraftClient/Protocol/Handlers/StructuredComponents/Components/1_21_2/FoodComponent1212.cs new file mode 100644 index 00000000..1832234d --- /dev/null +++ b/MinecraftClient/Protocol/Handlers/StructuredComponents/Components/1_21_2/FoodComponent1212.cs @@ -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 data) + { + Nutrition = dataTypes.ReadNextVarInt(data); + Saturation = dataTypes.ReadNextFloat(data); + CanAlwaysEat = dataTypes.ReadNextBool(data); + } + + public override Queue Serialize() + { + var data = new List(); + data.AddRange(DataTypes.GetVarInt(Nutrition)); + data.AddRange(DataTypes.GetFloat(Saturation)); + data.AddRange(DataTypes.GetBool(CanAlwaysEat)); + return new Queue(data); + } +} diff --git a/MinecraftClient/Protocol/Handlers/StructuredComponents/Components/1_21_2/GliderComponent.cs b/MinecraftClient/Protocol/Handlers/StructuredComponents/Components/1_21_2/GliderComponent.cs new file mode 100644 index 00000000..1aa739d0 --- /dev/null +++ b/MinecraftClient/Protocol/Handlers/StructuredComponents/Components/1_21_2/GliderComponent.cs @@ -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); diff --git a/MinecraftClient/Protocol/Handlers/StructuredComponents/Components/1_21_2/ItemModelComponent.cs b/MinecraftClient/Protocol/Handlers/StructuredComponents/Components/1_21_2/ItemModelComponent.cs new file mode 100644 index 00000000..65cdac8c --- /dev/null +++ b/MinecraftClient/Protocol/Handlers/StructuredComponents/Components/1_21_2/ItemModelComponent.cs @@ -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 data) + { + Identifier = dataTypes.ReadNextString(data); + } + + public override Queue Serialize() + { + var data = new List(); + data.AddRange(DataTypes.GetString(Identifier)); + return new Queue(data); + } +} diff --git a/MinecraftClient/Protocol/Handlers/StructuredComponents/Components/1_21_2/RepairableComponent.cs b/MinecraftClient/Protocol/Handlers/StructuredComponents/Components/1_21_2/RepairableComponent.cs new file mode 100644 index 00000000..08dcb91c --- /dev/null +++ b/MinecraftClient/Protocol/Handlers/StructuredComponents/Components/1_21_2/RepairableComponent.cs @@ -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? ItemIds { get; set; } + + public override void Parse(Queue data) + { + Type = dataTypes.ReadNextVarInt(data); + if (Type == 0) + { + TagName = dataTypes.ReadNextString(data); + } + else + { + ItemIds = new List(); + for (var i = 0; i < Type - 1; i++) + ItemIds.Add(dataTypes.ReadNextVarInt(data)); + } + } + + public override Queue Serialize() + { + var data = new List(); + 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(data); + } +} diff --git a/MinecraftClient/Protocol/Handlers/StructuredComponents/Components/1_21_2/TooltipStyleComponent.cs b/MinecraftClient/Protocol/Handlers/StructuredComponents/Components/1_21_2/TooltipStyleComponent.cs new file mode 100644 index 00000000..aed0af34 --- /dev/null +++ b/MinecraftClient/Protocol/Handlers/StructuredComponents/Components/1_21_2/TooltipStyleComponent.cs @@ -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 data) + { + Identifier = dataTypes.ReadNextString(data); + } + + public override Queue Serialize() + { + var data = new List(); + data.AddRange(DataTypes.GetString(Identifier)); + return new Queue(data); + } +} diff --git a/MinecraftClient/Protocol/Handlers/StructuredComponents/Components/1_21_2/UseCooldownComponent.cs b/MinecraftClient/Protocol/Handlers/StructuredComponents/Components/1_21_2/UseCooldownComponent.cs new file mode 100644 index 00000000..60f175c6 --- /dev/null +++ b/MinecraftClient/Protocol/Handlers/StructuredComponents/Components/1_21_2/UseCooldownComponent.cs @@ -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 data) + { + Seconds = dataTypes.ReadNextFloat(data); + HasCooldownGroup = dataTypes.ReadNextBool(data); + if (HasCooldownGroup) + CooldownGroup = dataTypes.ReadNextString(data); + } + + public override Queue Serialize() + { + var data = new List(); + data.AddRange(DataTypes.GetFloat(Seconds)); + data.AddRange(DataTypes.GetBool(HasCooldownGroup)); + if (HasCooldownGroup && CooldownGroup != null) + data.AddRange(DataTypes.GetString(CooldownGroup)); + return new Queue(data); + } +} diff --git a/MinecraftClient/Protocol/Handlers/StructuredComponents/Components/1_21_2/UseRemainderComponent.cs b/MinecraftClient/Protocol/Handlers/StructuredComponents/Components/1_21_2/UseRemainderComponent.cs new file mode 100644 index 00000000..ead551aa --- /dev/null +++ b/MinecraftClient/Protocol/Handlers/StructuredComponents/Components/1_21_2/UseRemainderComponent.cs @@ -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 data) + { + ConvertInto = dataTypes.ReadNextItemSlot(data, ItemPalette); + } + + public override Queue Serialize() + { + var data = new List(); + data.AddRange(dataTypes.GetItemSlot(ConvertInto, ItemPalette)); + return new Queue(data); + } +} diff --git a/MinecraftClient/Protocol/Handlers/StructuredComponents/Registries/StructuredComponentsRegistry1212.cs b/MinecraftClient/Protocol/Handlers/StructuredComponents/Registries/StructuredComponentsRegistry1212.cs new file mode 100644 index 00000000..361cbfae --- /dev/null +++ b/MinecraftClient/Protocol/Handlers/StructuredComponents/Registries/StructuredComponentsRegistry1212.cs @@ -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(0, "minecraft:custom_data"); + RegisterComponent(1, "minecraft:max_stack_size"); + RegisterComponent(2, "minecraft:max_damage"); + RegisterComponent(3, "minecraft:damage"); + RegisterComponent(4, "minecraft:unbreakable"); + RegisterComponent(5, "minecraft:custom_name"); + RegisterComponent(6, "minecraft:item_name"); + RegisterComponent(7, "minecraft:item_model"); + RegisterComponent(8, "minecraft:lore"); + RegisterComponent(9, "minecraft:rarity"); + RegisterComponent(10, "minecraft:enchantments"); + RegisterComponent(11, "minecraft:can_place_on"); + RegisterComponent(12, "minecraft:can_break"); + RegisterComponent(13, "minecraft:attribute_modifiers"); + RegisterComponent(14, "minecraft:custom_model_data"); + RegisterComponent(15, "minecraft:hide_additional_tooltip"); + RegisterComponent(16, "minecraft:hide_tooltip"); + RegisterComponent(17, "minecraft:repair_cost"); + RegisterComponent(18, "minecraft:creative_slot_lock"); + RegisterComponent(19, "minecraft:enchantment_glint_override"); + RegisterComponent(20, "minecraft:intangible_projectile"); + RegisterComponent(21, "minecraft:food"); + RegisterComponent(22, "minecraft:consumable"); + RegisterComponent(23, "minecraft:use_remainder"); + RegisterComponent(24, "minecraft:use_cooldown"); + RegisterComponent(25, "minecraft:damage_resistant"); + RegisterComponent(26, "minecraft:tool"); + RegisterComponent(27, "minecraft:enchantable"); + RegisterComponent(28, "minecraft:equippable"); + RegisterComponent(29, "minecraft:repairable"); + RegisterComponent(30, "minecraft:glider"); + RegisterComponent(31, "minecraft:tooltip_style"); + RegisterComponent(32, "minecraft:death_protection"); + RegisterComponent(33, "minecraft:stored_enchantments"); + RegisterComponent(34, "minecraft:dyed_color"); + RegisterComponent(35, "minecraft:map_color"); + RegisterComponent(36, "minecraft:map_id"); + RegisterComponent(37, "minecraft:map_decorations"); + RegisterComponent(38, "minecraft:map_post_processing"); + RegisterComponent(39, "minecraft:charged_projectiles"); + RegisterComponent(40, "minecraft:bundle_contents"); + RegisterComponent(41, "minecraft:potion_contents"); + RegisterComponent(42, "minecraft:suspicious_stew_effects"); + RegisterComponent(43, "minecraft:writable_book_content"); + RegisterComponent(44, "minecraft:written_book_content"); + RegisterComponent(45, "minecraft:trim"); + RegisterComponent(46, "minecraft:debug_stick_state"); + RegisterComponent(47, "minecraft:entity_data"); + RegisterComponent(48, "minecraft:bucket_entity_data"); + RegisterComponent(49, "minecraft:block_entity_data"); + RegisterComponent(50, "minecraft:instrument"); + RegisterComponent(51, "minecraft:ominous_bottle_amplifier"); + RegisterComponent(52, "minecraft:jukebox_playable"); + RegisterComponent(53, "minecraft:recipes"); + RegisterComponent(54, "minecraft:lodestone_tracker"); + RegisterComponent(55, "minecraft:firework_explosion"); + RegisterComponent(56, "minecraft:fireworks"); + RegisterComponent(57, "minecraft:profile"); + RegisterComponent(58, "minecraft:note_block_sound"); + RegisterComponent(59, "minecraft:banner_patterns"); + RegisterComponent(60, "minecraft:base_color"); + RegisterComponent(61, "minecraft:pot_decorations"); + RegisterComponent(62, "minecraft:container"); + RegisterComponent(63, "minecraft:block_state"); + RegisterComponent(64, "minecraft:bees"); + RegisterComponent(65, "minecraft:lock"); + RegisterComponent(66, "minecraft:container_loot"); + } +} diff --git a/MinecraftClient/Protocol/Handlers/StructuredComponents/Registries/Subcomponents/SubComponentRegistry1212.cs b/MinecraftClient/Protocol/Handlers/StructuredComponents/Registries/Subcomponents/SubComponentRegistry1212.cs new file mode 100644 index 00000000..ba5df821 --- /dev/null +++ b/MinecraftClient/Protocol/Handlers/StructuredComponents/Registries/Subcomponents/SubComponentRegistry1212.cs @@ -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) + { + } +} diff --git a/MinecraftClient/Protocol/Handlers/StructuredComponents/StructuredComponentsHandler.cs b/MinecraftClient/Protocol/Handlers/StructuredComponents/StructuredComponentsHandler.cs index 2fd0cb82..9729e5f4 100644 --- a/MinecraftClient/Protocol/Handlers/StructuredComponents/StructuredComponentsHandler.cs +++ b/MinecraftClient/Protocol/Handlers/StructuredComponents/StructuredComponentsHandler.cs @@ -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!") };