Further Protocol Adaptation for 1.20.6 / 1.21 / 1.21.2#2930
Merged
BruceChenQAQ merged 41 commits intoMCCTeam:masterfrom Mar 20, 2026
Merged
Further Protocol Adaptation for 1.20.6 / 1.21 / 1.21.2#2930BruceChenQAQ merged 41 commits intoMCCTeam:masterfrom
BruceChenQAQ merged 41 commits intoMCCTeam:masterfrom
Conversation
…/1.20.6 Fix session cache serializer failure
When MCC runs in non-interactive terminals (e.g. CI runners, IDE embedded shells, piped input), several Console APIs throw exceptions because there is no real console attached. Changes: - Program.cs: Wrap Console.KeyAvailable / Console.ReadKey in HandleFailure() with try-catch so MCC does not crash on startup failure in headless environments. - Chunk.cs: Wrap Console.BufferWidth / BufferHeight in try-catch with fallback values (120x50) to prevent exceptions when rendering chunk maps without a console buffer. - Map.cs: Same treatment for the map rendering path - use safe fallback values when Console.BufferWidth/Height are unavailable. - ReplayHandler.cs: Replace Array.Reverse() (returns void in newer .NET) with .AsEnumerable().Reverse() to fix compilation with .NET 10 SDK where the void return breaks the fluent chain. Made-with: Cursor
The 1.20.6 EntityProperties packet sends attribute IDs as VarInts instead of strings. The existing mapping dictionary had three issues: 1. IDs 5/6/7 used the wrong prefix "generic." but the official 1.20.6 registry uses "player." for these attributes: - 5: player.block_break_speed (was generic.block_break_speed) - 6: player.block_interaction_range (was generic.block_interaction_range) - 7: player.entity_interaction_range (was generic.entity_interaction_range) 2. IDs 22-24 (submerged_mining_speed, sweeping_damage_ratio, water_movement_efficiency) do not exist in the 1.20.6 attribute registry — they were introduced in 1.21. Their presence could cause incorrect attribute resolution. 3. Direct dictionary indexing (attributeDictionary[id]) throws KeyNotFoundException if the server sends an unknown attribute ID, crashing the packet handler. Replaced with TryGetValue and a safe fallback to "unknown". Made-with: Cursor
Two critical issues in the 1.20.6 configuration phase that could cause connection instability and packet desync: 1. RegistryData: The handler used an early `break` when it encountered a registryId other than "minecraft:dimension_type" or "minecraft:chat_type". This skipped reading the remaining entries for that registry, leaving unconsumed data in the packet buffer. Subsequent packet reads would start at the wrong offset, causing cascading parse failures and eventual disconnection. Fix: Always read all entries (entryId + hasData + optional NBT) for every registry, regardless of whether we process it. For dimension_type entries, if the server sends inline NBT data (i.e. non-vanilla dimensions from mods/datapacks), parse and store the dimension directly via World.StoreOneDimension(). Only fall back to hardcoded defaults when no dimension data was received. 2. KnownDataPacks: The client echoed back ALL packs the server listed, including non-vanilla ones. This told the server "I have these packs cached" when the client actually did not, so the server would skip sending full registry data for those packs. The result: incomplete registries for modded/datapack content. Fix: Filter the response to only include packs with the "minecraft" namespace. Non-vanilla packs are omitted, forcing the server to send their full registry data inline. Also adds supporting methods to World.cs: - SetDimensionIdMap(): Store VarInt ID -> dimension name mapping from RegistryData entries (needed by JoinGame/Respawn) - GetDimensionNameById(): Look up dimension name by numeric ID - HasAnyDimension(): Check if any dimensions were loaded from server-provided data Made-with: Cursor
The JoinGame and Respawn packet handlers for 1.20.6+ used hardcoded switch expressions to map dimension type VarInt IDs to names: 0 => overworld, 1 => overworld_caves, 2 => the_end, 3 => the_nether This only works for vanilla servers with exactly 4 default dimensions. Modded servers (Forge/Fabric/NeoForge) or servers with custom datapacks can register additional dimensions with IDs beyond 0-3, causing the switch to fall through to the default "overworld" for any non-vanilla dimension. This means players in modded dimensions would have incorrect world parameters (height, lighting, etc.). Fix: Replace both hardcoded switch expressions with World.GetDimensionNameById(), which looks up the VarInt ID in the dimension ID map populated during the RegistryData phase. Also fixes two pre-existing issues in the SetDimension dispatch: - JoinGame (pre-1.20.2 path): The `case < MC_1_20_6_Version` guard was technically correct within its enclosing `if` block, but changed to `default` for clarity and future-proofing. - Respawn: The `case <= MC_1_20_6_Version` guard excluded protocol versions above 766 (e.g. 1.21 / protocol 767), meaning SetDimension was never called for those versions. Changed to `default` so all versions >= 1.19 properly update the dimension. Made-with: Cursor
…alization In 1.20.6+, items use structured components instead of NBT for metadata. Previously, ReadNextItemSlot parsed the components but never stored them on the Item instance, leaving DisplayName/Lores/Damage/Enchantments all empty. GetItemSlot also still used the pre-1.20.6 format (bool + VarInt + byte + NBT), causing the server to reject any item operation packets. Changes: Item.cs: - Add List<StructuredComponent>? Components field to hold the raw component list for round-trip serialization - DisplayName property: read from CustomNameComponent (with ItemNameComponent as fallback) when Components is present - Lores property: read from LoreNameComponent1206 when Components is present - Damage property: read from DamageComponent when Components is present - Add EnchantmentList property: read from EnchantmentsComponent (covers both normal and StoredEnchantmentsComponent for enchanted books) - ToFullString(): use EnchantmentList with EnchantmentMapping for display when available, fall back to NBT path for older versions - Add CloneWithCount() method that preserves both NBT and Components DataTypes.cs - ReadNextItemSlot: - Assign parsed strcturedComponentsToAdd to item.Components DataTypes.cs - GetItemSlot: - Add 1.20.6+ branch: write VarInt(count) + VarInt(itemId) + component counts + serialized components (using each component's TypeId and Serialize() method) - Empty slot sends VarInt(0) per the 1.20.6 protocol spec StructuredComponent.cs: - Add int TypeId property (default -1) to store the registry type ID assigned during parsing, enabling round-trip serialization StructuredComponentRegistry.cs: - Set component.TypeId = id after instantiation in ParseComponent() McClient.cs: - Replace manual Item constructor calls (new Item(type, count, nbt)) with Item.CloneWithCount() to preserve Components during inventory operations like slot moves, stack splits, and right-click placement Made-with: Cursor
FileInputBot (ChatBots/FileInputBot.cs): - New ChatBot that monitors a text file (default: mcc_input.txt) for commands, enabling MCC control from Cursor Shell or any non-interactive environment where stdin is not available - Activated by setting MCC_FILE_INPUT env var (e.g. MCC_FILE_INPUT=1) - Polls every ~500ms for new lines appended to the file - Lines starting with "/" are sent as server chat/commands - Other lines are executed as MCC internal commands (same as console input) - File path overridable via MCC_INPUT_FILE env var McClient.cs: - Load FileInputBot when MCC_FILE_INPUT environment variable is set ChatParser.cs - NbtToString: - Fix InvalidCastException when NBT "text" or nameless root tag values are Int32 instead of String (happens with 1.20.6 SystemChat packets containing numeric values in the chat component tree) - Replace direct (string) casts with ?.ToString() ?? string.Empty Made-with: Cursor
In 1.20.6+, EntityProperties packets reference attributes by VarInt registry IDs instead of string names. Previously, a hardcoded dictionary of 22 attribute entries (matching the vanilla 1.20.6 registry) was used to map these IDs back to names. This works for vanilla servers but would fail silently for modded servers that add custom attributes — any unknown ID would be reported as "unknown". This commit replaces the hardcoded attribute dictionary with dynamic registry parsing, following the same pattern already used for dimension_type and chat_type registries: - World.cs: Add static `attributeIdMap` field, `SetAttributeIdMap()` and `GetAttributeNameById()` methods for storing/querying attribute names by their VarInt registry IDs. - Protocol18.cs (RegistryData handler): When the server sends a `minecraft:attribute` registry during the Configuration phase, parse all entries and store the ID→name mapping. The `minecraft:` prefix is stripped from entry names to match the format used in EntityProperties packets (e.g. "minecraft:generic.armor" → "generic.armor"). - Protocol18.cs (EntityProperties handler): Remove the hardcoded 22-entry `attributeDictionary` and use `World.GetAttributeNameById()` instead. Unknown IDs still fall back to "unknown" for safety. Also closes issue MCCTeam#4 (Disconnect packet extra boolean) — verified that both Play and Configuration phase Disconnect handlers already use `ReadNextChat()` (NBT format since 1.20.4+), matching the 1.20.6 protocol spec. No code changes needed; updated tracking document to mark as closed. Made-with: Cursor
After the previous commit (99ac3d0) moved attribute lookup from a hardcoded dictionary to the dynamic RegistryData, MCC would crash immediately upon joining a vanilla 1.20.6 server with: System.ArgumentException: An item with the same key has already been added. Key: unknown Root cause: When KnownDataPacks negotiation tells the server that MCC already has the "minecraft" data pack, the server skips sending RegistryData for registries it considers "known" — including minecraft:attribute. This left the dynamic attribute map empty, so every VarInt attribute ID resolved to "unknown". The EntityProperties packet often contains multiple attributes (e.g. armor, max_health, movement_speed), and `keys.Add("unknown", ...)` on the second "unknown" attribute threw ArgumentException. Two fixes applied: 1. World.GetAttributeNameById(): When the dynamic attribute map is empty (server didn't send the registry), automatically load the vanilla 1.20.6 default attribute order (22 entries matching Attributes.java registration order). This mirrors the pattern used for dimensions where defaults are loaded when RegistryData is not sent. If a modded server sends a custom attribute registry, the dynamic map takes precedence. 2. Protocol18.cs EntityProperties handler: Change `keys.Add(propertyKey, propertyValue2)` to `keys[propertyKey] = propertyValue2` to tolerate duplicate keys defensively, in case an unknown attribute ID still appears. Tested: MCC now connects to a vanilla 1.20.6 offline-mode server, stays online for 6+ minutes with no crashes or disconnections. Verified: chat messages received, inventory listing (item names/counts correct), entity detection, TPS query, and health query all work correctly. Made-with: Cursor
Audited all 58 StructuredComponent subclasses against the official Minecraft
1.20.6 decompiled source to verify Parse()/Serialize() symmetry. Found and
fixed four bugs across four components:
1. ContainerComponent: Parse() skipped null item slots (empty slots in a
container) but Serialize() looped NumberOfItems times using Items[i],
causing IndexOutOfRangeException when any slot was empty. The official
ItemContainerContents uses OPTIONAL_STREAM_CODEC which serializes empty
slots as VarInt(0). Fixed: Parse now stores all slots including nulls,
Serialize uses Items.Count and iterates all entries. GetItemSlot(null)
correctly writes VarInt(0) for empty slots.
2. ChargedProjectilesComponent: Used Items.OfType<Item>() in Serialize()
which silently dropped null entries, causing the serialized count to
differ from the written VarInt header. The official ChargedProjectiles
uses STREAM_CODEC (non-optional, no empty slots allowed). Fixed: Items
list is now List<Item> (non-nullable), Parse defensively skips nulls,
Serialize writes Items.Count matching the actual list.
3. BundleContentsComponent: Same issue as ChargedProjectilesComponent.
Applied the same fix pattern.
4. FoodComponentComponent: Two type mismatches vs the official
FoodProperties.DIRECT_STREAM_CODEC:
- Saturation was declared as bool and read with ReadNextBool (1 byte),
but the protocol sends it as float (4 bytes). This caused all
subsequent fields in the component to be read at wrong offsets,
corrupting CanAlwaysEat, SecondsToEat, and the effects list.
- NumberOfEffects was serialized with GetFloat() instead of GetVarInt(),
writing 4 bytes of IEEE 754 float instead of a variable-length integer.
Fixed both Parse and Serialize to use correct types.
Also removed redundant NumberOfItems/NumberOfEffects fields from components
where the count is derivable from the list length, and replaced
ArgumentNullException with cleaner patterns.
Tested end-to-end on vanilla 1.20.6 server: item receiving (diamond_sword,
golden_apple, diamond_pickaxe), inventory slot movement (click to pick up
and place), and inventory listing all work correctly with no server-side
protocol errors.
Made-with: Cursor
… 1.20.6 Both components had incorrect Parse/Serialize implementations that would cause packet deserialization misalignment when encountered in-game. PotionContentsComponent (3 bugs): - Serialize unconditionally wrote VarInt(PotionId) and Int(CustomColor) even when HasPotionId/HasCustomColor was false. The official format (PotionContents.STREAM_CODEC) uses Optional encoding: Bool(hasValue) followed by the value only when true. The extra bytes caused all subsequent fields in the packet to be read at wrong offsets. - Serialize omitted the VarInt(count) prefix for the custom effects list. The official codec uses ByteBufCodecs.list() which always writes a VarInt count header before the list elements. - Also fixed typo: PotiononId -> PotionId. InstrumentComponent (3 bugs): - The official Instrument.STREAM_CODEC uses ByteBufCodecs.holder() which encodes as VarInt(holderId): 0 = inline data, N>0 = registry ref (N-1). The SoundEvent field inside uses the same holder pattern. The old code unconditionally read SoundName (ResourceLocation) and HasFixedRange/ FixedRange even when SoundEventHolderId != 0 (registry reference case has no inline data). - UseDuration was read/written as Float, but the official codec uses ByteBufCodecs.VAR_INT. This caused a 4-byte vs variable-length mismatch that would shift all subsequent data. - HasFixedRange was read unconditionally when SoundEventHolderId == 0, but FixedRange was also read unconditionally. The official SoundEvent DIRECT_STREAM_CODEC uses Optional<Float> encoding: Bool(hasValue) followed by Float only when true. These components are used for potion items and goat horns respectively. Verified against official 1.20.6 decompiled source: - net.minecraft.world.item.alchemy.PotionContents (STREAM_CODEC) - net.minecraft.world.item.Instrument (STREAM_CODEC/DIRECT_STREAM_CODEC) - net.minecraft.sounds.SoundEvent (STREAM_CODEC/DIRECT_STREAM_CODEC) - net.minecraft.network.codec.ByteBufCodecs (holder/optional/list) Made-with: Cursor
EnchantmentsComponent (used by both regular and stored enchantments) was directly casting the registry VarInt ID to the Enchantments enum via (Enchantments)id. However, the Enchantments enum is ordered alphabetically (AquaAffinity=0, BaneOfArthropods=1, ..., Sharpness=32) while the 1.20.6 registry uses a completely different order (protection=0, fire_protection=1, ..., sharpness=13). This caused all enchantment names to display incorrectly (e.g. Sharpness V shown as "Unknown Enchantment with ID: 32"). Changes: - Parse now uses EnchantmentMapping.GetEnchantmentByRegistryId1206() to properly map registry IDs to enum values via the existing 1.20.6+ mapping table - Serialize now uses EnchantmentMapping.GetRegistryId1206ByEnchantment() to convert enum values back to registry IDs (reverse lookup) - Fixed translation key prefix: "Enchantments.minecraft." (wrong) -> "enchantment.minecraft." (matches en_us.json resource keys) - Fixed 3 long-standing typos in the Enchantments enum that prevented translation lookup from matching resource keys: - DepthStrieder -> DepthStrider (depth_strieder vs depth_strider) - Efficency -> Efficiency (efficency vs efficiency) - Loyality -> Loyalty (loyality vs loyalty) Verified on vanilla 1.20.6 server: items with sharpness, efficiency, unbreaking, fortune, mending, and bane_of_arthropods all display correct localized names (锋利, 效率, 耐久, 时运, 经验修补, 节肢杀手). Made-with: Cursor
…nent, WrittenBookContent, and NBT serialization Audited all 8 high-complexity structured components against official 1.20.6 decompiled STREAM_CODEC definitions. Found and fixed bugs in 3 components plus a systemic NBT serialization issue: TrimComponent (ID 35): - Serialize had TrimPatternType and ShowInTooltip incorrectly nested inside the TrimMaterialType==0 branch; moved them outside to match Parse logic - Description fields (TrimMaterial.description, TrimPattern.description) were read/written as String but official codec uses ComponentSerialization (NBT Tag format); changed to ReadNextNbt/GetNbt ProfileComponent (ID 46): - Serialize was missing the HasUniqueId Bool prefix before UUID - Serialize only wrote properties when count > 0 but omitted the VarInt count prefix entirely when empty; now always writes VarInt count WrittenBookContentComponent (ID 34): - Page content uses Filterable<Component> where Component is NBT-encoded via ComponentSerialization.STREAM_CODEC, not plain String; changed Parse to use ReadNextNbt and Serialize to use GetNbt - Added RawContentNbt/FilteredContentNbt fields to BookPage record for round-trip NBT preservation - Removed unnecessary ChatParser.ParseText on title (it's a plain string) DataTypes.GetNbt: - Added TAG_String root support for 1.20.4+ (chat components like "Page 1" are encoded as TAG_String, not TAG_Compound) - Fixed root name handling: versions >= 1.20.2 omit the root compound name, but GetNbt was unconditionally writing it Components confirmed correct (no changes needed): - FoodComponentComponent (ID 20), ToolComponent (ID 22), InstrumentComponent (ID 40), PotionContentsComponent (ID 31), AttributeModifiersComponent (ID 12) Made-with: Cursor
…SubComponent serialization Audited all 8 batch-2 components (enchantments, stored_enchantments, can_place_on, can_break, lodestone_tracker, firework_explosion, fireworks, banner_patterns, suspicious_stew_effects, bees) against official 1.20.6 decompiled STREAM_CODEC definitions. Found and fixed 3 bugs in BlockPredicate/PropertySubComponent: 1. BlockPredicateSubcomponent.Serialize(): missing HasNbt bool write. Parse reads the bool but Serialize skipped writing it, causing all subsequent fields to be offset by one byte. 2. BlockPredicateSubcomponent.Serialize(): missing Properties list count VarInt write. Parse reads VarInt count before iterating, but Serialize only wrote the elements without the preceding count. 3. PropertySubComponent: RangedMatcher min/max values must use Optional encoding (Bool prefix + conditional String), matching the official ByteBufCodecs.either(ExactMatcher, RangedMatcher) where RangedMatcher uses ByteBufCodecs.optional(STRING_UTF8) for both min and max fields. Previously read/wrote plain Strings unconditionally. Remaining 6 components (enchantments, stored_enchantments, lodestone_tracker, firework_explosion, fireworks, banner_patterns, suspicious_stew_effects, bees) verified correct — no changes needed. Made-with: Cursor
…ponent type correction Audited all 14 simple binary components (batch 3): max_stack_size, max_damage, damage, unbreakable, rarity, custom_model_data, repair_cost, enchantment_glint_override, ominous_bottle_amplifier, dyed_color, map_color, map_id, map_post_processing, base_color. Found and fixed 1 bug: - EnchantmentGlintOverrideComponent: was reading/writing VarInt but the official STREAM_CODEC uses ByteBufCodecs.BOOL (single byte boolean). Changed property type from int to bool, Parse from ReadNextVarInt to ReadNextBool, and Serialize from GetVarInt to GetBool. All other 13 components matched the official 1.20.6 STREAM_CODEC definitions exactly. Verified in-game: connected to 1.20.6 vanilla server, received items with enchantment_glint_override=true/false, dyed_color, map_color, map_id, base_color, unbreakable, rarity, custom_model_data, repair_cost, damage, max_damage. All parsed and serialized correctly with no errors. Made-with: Cursor
…use NBT encoding In 1.20.6+, ComponentSerialization.STREAM_CODEC uses ByteBufCodecs.fromCodecWithRegistries (NBT tag format), not plain string. The previous implementation incorrectly used ReadNextString/GetString for custom_name (5), item_name (6), and lore (7) components. Fixed all three to use ReadNextNbt/GetNbt, preserving raw NBT data for round-trip serialization while still extracting readable text via ChatParser.ParseText(Dictionary). Other batch 4 components (custom_data, entity_data, bucket_entity_data, block_entity_data, debug_stick_state, map_decorations, recipes, lock, container_loot, intangible_projectile — all NBT; hide_additional_tooltip, hide_tooltip, fire_resistant, creative_slot_lock — all Unit/Empty; note_block_sound — ResourceLocation string) were verified correct. Made-with: Cursor
… fields
Audited batch 5 components (ChargedProjectiles, BundleContents, Container,
WritableBookContent, BlockState, PotDecorations) against official 1.20.6
decompiled STREAM_CODEC definitions. All network encodings were correct.
Removed redundant NumberOfItems/NumberOfPages/NumberOfProperties fields from
ContainerComponent, WritableBlookContentComponent, BlockStateComponent, and
PotDecorationsComponent. Serialize now uses the actual collection .Count
instead of a potentially stale cached value, matching the pattern already
used by ContainerComponent's Serialize and other components.
Also modernized loop style (foreach with deconstruction where applicable)
and fixed a typo in an exception message ("setialize" -> "serialize").
Made-with: Cursor
Add ItemPalette121.cs with item ID mappings for MC 1.21 (protocol 767). Add three new music disc entries to ItemType enum: MusicDiscCreator, MusicDiscCreatorMusicBox, and MusicDiscPrecipice, introduced in 1.21. Made-with: Cursor
…pdate - Add AttributeSubComponent121 that uses ResourceLocation(string) instead of UUID+Name, matching the 1.21 attribute modifier wire format change. Register it in SubComponentRegistry121 via new ReplaceSubComponent method. - Add ProjectilePower packet handler: reads 1 double (accelerationPower) for 1.21+, or 3 doubles (xPower/yPower/zPower) for 1.20.6. - Add CustomReportDetails and ServerLinks packet handlers in both Play and Configuration phases, consuming all fields to prevent byte offset errors on 1.21 servers. Made-with: Cursor
Fix the Explosion packet handler that was truncating reads at the knockback fields, leaving BlockInteraction, particles, and SoundEvent bytes unconsumed for 1.20.4+. The old commented-out code had three bugs: conditional particle read (should always read both small and large), reading SoundEvent as a plain string (it's a Holder<SoundEvent> encoded as VarInt id + optional inline DIRECT_STREAM_CODEC), and an incorrect fixedRange version gate. Verified against decompiled ClientboundExplodePacket from both 1.20.6 and 1.21.1 — the wire format is identical across versions. Update LoadDefaultAttributes() fallback to match the 1.21.1 registry order (31 attributes), adding 9 new entries: burning_time, explosion_knockback_resistance, mining_efficiency, movement_efficiency, oxygen_bonus, sneaking_speed, submerged_mining_speed, sweeping_damage_ratio, and water_movement_efficiency. This fallback is only used when the server omits the attribute RegistryData packet. Made-with: Cursor
…a parsing 1.20.6 introduced three new EntityDataSerializer types compared to 1.20.4: - PARTICLES (id 18) - list of particles, inserted after PARTICLE - WOLF_VARIANT (id 23) - wolf variant holder, inserted after CAT_VARIANT - ARMADILLO_STATE (id 28) - armadillo state, inserted after SNIFFER_STATE These insertions shifted subsequent serializer IDs, causing the 1.19.4 palette (EntityMetadataPalette1194) to misidentify metadata types on 1.20.6+ servers. This could lead to incorrect byte consumption and potential packet parse failures when entities with affected metadata types (e.g. wolves, armadillos, area effect clouds with particles) were present. Changes: - Add Particles, WolfVariant, ArmadilloState to EntityMetaDataType enum - Create EntityMetadataPalette1206 with correct 31-entry ID mapping - Route 1.20.6+ to the new palette in EntityMetadataPalette.GetPalette() - Add read logic for the three new types in DataTypes.cs Verified on 1.21.1 vanilla server: cat, wolf, frog, armadillo, painting entities all spawn without metadata parse errors. Made-with: Cursor
Add tools/ directory with Python scripts for comparing Minecraft version registries and generating MCC palette files: - diff_registries.py: Compare Items/EntityTypes/Blocks/DataComponents/ EntityDataSerializers between two decompiled MC versions, reporting which palettes need updating with ID shift analysis. - gen_item_palette.py: Generate ItemPaletteXXX.cs from Items.java field declaration order, with name validation against ItemType.cs. - gen_entity_metadata_palette.py: Generate EntityMetadataPaletteXXX.cs from EntityDataSerializers.java registration order. - README.md: Usage documentation for all scripts. Made-with: Cursor
…mapping issues for 1.21 - SpawnEntity packet handler now registers non-player entities via OnSpawnEntity for protocol >= 1.20.2 (previously only players were tracked, causing 'entity near' to find nothing) - PlaceBlock gains lookAtBlock option that sends a position/rotation update before the block placement packet, fixing containers not opening via useblock - Enchantment registry IDs are now dynamically parsed from server RegistryData (minecraft:enchantment), fixing incorrect enchantment name display in 1.21 - AttributeModifiersComponent uses base SubComponent type to avoid InvalidCastException when parsing 1.21-specific attribute subcomponents Made-with: Cursor
Add item, entity, block, and metadata palettes for Minecraft 1.21.2: - ItemPalette1212: 1375 items (42 new: pale oak set, colored bundles, creaking heart/spawn egg, banner patterns) - EntityPalette1212: 150 entity types (boats split into per-wood-type entries, generic boat/chest_boat removed; added creaking, creaking_transient, pale oak boats) - Palette1212 (blocks): 1084 block types with state IDs generated from official 1.21.2 data reports (24 new pale oak blocks, creaking heart, pale moss variants) - EntityMetadataPalette: reuses 1206 (serializers unchanged in 1.21.2) Updated version infrastructure: - Protocol18.cs: MC_1_21_2_Version = 768, palette switch routing - ProtocolHandler.cs: version mapping 1.21.2 <-> 768 - Program.cs: MCHighestVersion bumped to 1.21.2 - ItemType.cs, EntityType.cs, Material.cs: new enum entries Note: packet palette, structured components, and protocol handler changes for 1.21.2 are not yet implemented — this commit covers palette/registry groundwork only. Made-with: Cursor
…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
…ntity support The previous commits added palette files, packet IDs, and structured components for MC 1.21.2 (protocol 768), but terrain/inventory/entity features were still disabled at runtime because the version guards in the constructor checked > MC_1_21_Version (767) instead of > MC_1_21_2_Version (768). This commit completes the 1.21.2 adaptation with the following changes: - Update feature-disable guards from > MC_1_21_Version to > MC_1_21_2_Version so terrain, inventory, and entity handling are enabled for protocol 768 - Update healthField metadata index guard to > MC_1_21_2_Version - Handle container ID encoding change: byte -> VarInt for 1.21.2+ in both clientbound reads (CloseWindow, WindowItems, WindowProperty, SetSlot) and serverbound sends (ClickWindow, CloseWindow) - Handle EntityTeleport format change: 1.21.2 uses PositionMoveRotation (pos + delta + float angles) + relative flags bitmask (int) + onGround - Handle TimeUpdate format change: 1.21.2 appends a tickDayTime boolean - Add handlers for new 1.21.2 packets: EntityPositionSync, PlayerRotation, SetCursorItem, SetPlayerInventory, MoveMinecartAlongTrack, and RecipeBookAdd/Remove/Settings (ignored, MCC doesn't track recipes) Tested: successful connection to 1.21.2 vanilla server with inventory, entity tracking, and chat all working correctly. Made-with: Cursor
Collaborator
Author
|
@milutinke I’m going to merge this commit first. The entity- and inventory-related tests didn’t crash, and then I’ll move on to working on adapting the next version. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Further Protocol Adaptation for 1.20.6 / 1.21 / 1.21.2
Building on top of @milutinke's foundational work in #2820, this branch contains 25 additional commits that fix critical protocol bugs, complete the Structured Components system, and extend support through MC 1.21.2 (protocol 768).
All three versions (1.20.6, 1.21, 1.21.2) have been tested on vanilla servers — terrain rendering, inventory operations, and entity tracking are all working.
What was done
1. Critical Fixes for 1.20.6 Protocol Correctness
minecraft:dimension_type/minecraft:chat_type/minecraft:attributeare properly stored for runtime use.namespace == "minecraft"packs, so the server sends full registry data for modded/custom data packs instead of assuming the client already has them.World.GetDimensionNameById()). Affects both JoinGame and Respawn packets.generic.block_break_speed→player.block_break_speed) and removed 1.21-only entries that don't exist in 1.20.6. Changed dictionary access toTryGetValueto preventKeyNotFoundExceptioncrashes on unknown IDs.minecraft:attributeregistry sent by the server, with a vanilla fallback when the server omits it (due to KnownDataPacks).InvalidCastExceptionwhen NBT "text" field isInt32instead ofStringin 1.20.6 SystemChat packets.2. Structured Components — Full Audit & Serialization Fixes
Audited all 58 component subclasses against the official 1.20.6 decompiled server code. Fixed 12+ serialization bugs across 5 batches:
NumberOfItems, causingIndexOutOfRangeException. Fixed to preserve empty slots perOPTIONAL_STREAM_CODEC.OfType<Item>()dropped nulls, causing serialization count mismatch. Fixed with non-nullableList<Item>.boolinstead offloat(3-byte offset);NumberOfEffectsserialization usedGetFloatinstead ofGetVarInt.VarIntcount prefix for effects list.UseDurationwasFloatinstead ofVarInt;FixedRangeoptional encoding was incorrect.3. Item ↔ Structured Components Integration
Itemclass extended withComponentsfield preserving the parsed component list.DisplayName,Lores,Damage,EnchantmentListproperties that read from components.GetItemSlotnow correctly serializes item slots with components for 1.20.6+ (writesaddCount+removeCount+ component data).CloneWithCount()preserves components during inventory operations.EnchantmentMappingfor 1.20.6+.4. MC 1.21 (Protocol 767) Completion
ItemPalette121with new music disc item types.AttributeSubComponentfor 1.21 (modifier ID changed from UUID to string identifier).EntityMetadataPalette1206for correct entity metadata parsing on 1.20.6+.5. MC 1.21.2 (Protocol 768) — New
PacketPalette1212,ItemPalette1212,Palette1212(blocks),EntityPalette1212.StructuredComponentsRegistry1212with 10 new data components:Consumable,UseRemainder,UseCooldown,DamageResistant,Enchantable,Equippable,Repairable,Glider,TooltipStyle,DeathProtection,ItemModel,FoodComponent(1.21.2 variant).Protocol18.csfor 1.21.2 packet handling differences (terrain, inventory, entity).6. Tooling & Infrastructure
tools/diff_registries.py,tools/gen_item_palette.py,tools/gen_entity_metadata_palette.py).FileInputBotfor non-interactive terminal debugging (reads commands frommcc_input.txt).Testing
Tested on vanilla offline-mode servers for all three versions:
Inventory operations tested: viewing items (correct names, counts, enchantments), slot clicking, item moving.
Known Limitations