Merge pull request #2940: Add Minecraft 1.21.9/1.21.10 (Protocol 773) Support

Add Minecraft 1.21.9/1.21.10 (Protocol 773) Support
This commit is contained in:
BruceChen 2026-03-21 15:35:06 +08:00 committed by GitHub
commit c5537c0444
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
25 changed files with 5305 additions and 161 deletions

View file

@ -16,6 +16,38 @@ Systematic workflow for updating Minecraft Console Client to support a new Minec
java -jar MinecraftDecompiler.jar --version <ver> --side SERVER \
--decompile --output <ver>-remapped.jar --decompiled-output <ver>-decompiled
```
- A test server of the target version in `$MCC_SERVERS/` (see `mcc-dev-workflow` skill)
## Step 0: Generate Server Reports (CRITICAL since 1.21.9)
**Before** analyzing decompiled source, generate authoritative registry data from the server jar:
```bash
cd /tmp && java -DbundlerMainClass=net.minecraft.data.Main \
-jar $MCC_SERVERS/<version>-Vanilla/server.jar \
--reports --output /tmp/mc_reports
```
This produces `/tmp/mc_reports/reports/` containing:
- `registries.json` — all registries with **actual protocol_id** for each entry
- `blocks.json` — all blocks with **block state IDs**
- `packets.json` — packet protocol definitions
**Why this matters**: Since MC 1.21.9, some items and blocks are registered outside `Items.java`/`Blocks.java` field declarations (via block registration callbacks or other paths). The decompiled source alone will **miss** these entries. The server data generator is the only authoritative source for protocol IDs.
### Validation check
Compare server registry counts against decompiled source counts:
```bash
python3 -c "
import json
with open('/tmp/mc_reports/reports/registries.json') as f:
data = json.load(f)
for reg in ['minecraft:item', 'minecraft:entity_type', 'minecraft:block']:
print(f'{reg}: {len(data[reg][\"entries\"])} entries')
"
```
If server counts differ from decompiled Java source counts, the palette **must** be generated from server data, not from Java source.
## Step 1: Run Registry Diff
@ -33,18 +65,50 @@ This compares five registries and reports which need palette updates:
| DataComponents.java | `StructuredComponents/StructuredComponentsRegistryXXX.cs` | New/reordered components |
| EntityDataSerializers.java | `EntityMetadataPalettes/EntityMetadataPaletteXXX.cs` | New/reordered serializer types |
**Important**: diff_registries.py compares decompiled Java source. If Step 0 revealed count mismatches, the diff output may undercount. Always cross-reference with server registries.json.
## Step 2: Generate Updated Palettes
For registries marked "PALETTE UPDATE NEEDED":
### Item Palette
**Preferred method** (accurate since 1.21.9):
```bash
python3 $MCC_REPO/tools/gen_item_palette.py --from-registry /tmp/mc_reports/reports/registries.json <suffix>
# e.g., gen_item_palette.py --from-registry /tmp/mc_reports/reports/registries.json 1219
```
**Legacy method** (works for versions where Items.java has all items):
```bash
python3 $MCC_REPO/tools/gen_item_palette.py <new_ver> <suffix>
# e.g., gen_item_palette.py 1.21.1 121
```
- If new items are reported missing from `ItemType.cs`, add them to the enum in alphabetical order.
- The script auto-generates the C# palette file.
### Block Palette
**Preferred method** (accurate since 1.21.9):
```bash
python3 $MCC_REPO/tools/gen_block_palette.py /tmp/mc_reports/reports/blocks.json <suffix>
# e.g., gen_block_palette.py /tmp/mc_reports/reports/blocks.json 1219
```
**Legacy method** (manual creation from decompiled Blocks.java): Follow the pattern of existing palette files, using `register("name", ...)` call order from the decompiled source. Only reliable when Blocks.java contains all blocks.
If new blocks are reported missing from `Material.cs`, add them to the enum in alphabetical order.
### Entity Palette
```bash
python3 $MCC_REPO/tools/gen_entity_palette.py /tmp/mc_reports/reports/registries.json <suffix>
# e.g., gen_entity_palette.py /tmp/mc_reports/reports/registries.json 1219
```
If new entity types are reported missing from `EntityType.cs`, add them to the enum in alphabetical order.
### Entity Metadata Palette
```bash
python3 $MCC_REPO/tools/gen_entity_metadata_palette.py <new_ver> <suffix>
@ -55,9 +119,6 @@ python3 $MCC_REPO/tools/gen_entity_metadata_palette.py <new_ver> <suffix>
2. MCC's `EntityMetaDataType.cs` enum
3. `DataTypes.cs` read logic (add a `case` to consume the correct bytes)
### Entity/Block Palettes
No generator script yet — these change rarely. When needed, manually create by following the pattern of existing palette files, using `register("name", ...)` call order from the decompiled source.
### DataComponents / StructuredComponents
Compare `DataComponents.java` registration order. If new components appear, update `StructuredComponentsRegistryXXX.cs`. For new component types, implement corresponding reader in `StructuredComponents/Components/`.
@ -72,10 +133,31 @@ After creating palette files, update version selection logic:
| Block | `Protocol18.cs``blockPalette` initialization |
| EntityMetadata | `EntityMetadataPalette.cs``GetPalette()` switch |
| DataComponents | `StructuredComponentsRegistry.cs` → factory/routing |
| Packet | `PacketType18Handler.cs``GetTypeHandler()` switch |
Pattern: add a new `>= MC_X_Y_Z_Version => new XxxPaletteXYZ()` case.
## Step 4: Check Variant Encoding Changes
Also update:
- `Protocol18.cs`: add `MC_X_Y_Z_Version = <protocol_number>` constant
- `Protocol18.cs`: update all `> MC_prev_Version` upper-bound checks to `> MC_X_Y_Z_Version`
- `ProtocolHandler.cs`: add version string → protocol mapping, protocol → version mapping, add to supported list
- `Program.cs`: update `MCHighestVersion`
## Step 4: Check Packet Changes
Compare `GameProtocols.java` and `ConfigurationProtocols.java` between versions.
Common patterns:
- **New clientbound packets inserted mid-list**: All subsequent packet IDs shift. Requires a new `PacketPalette` class.
- **New packets appended at end**: Only need to add new enum values and entries in the palette.
- **Packet renames** (same slot): Update MCC's packet type enum name but no ID change.
When packet changes are detected:
1. Add new packet type enum values to `PacketTypesIn.cs`, `PacketTypesOut.cs`, `ConfigurationPacketTypesIn.cs`, `ConfigurationPacketTypesOut.cs`
2. Create new `PacketPaletteXXX.cs` based on the previous one, adjusting IDs
3. Update `PacketType18Handler.cs` routing
## Step 5: Check Variant Encoding Changes
For entity types that use variant serializers (Cat, Wolf, Frog, Painting), check if the codec changed between versions by inspecting:
@ -85,18 +167,26 @@ For entity types that use variant serializers (Cat, Wolf, Frog, Painting), check
- `ByteBufCodecs.holder()` → wire format: `VarInt(id+1)` for registered, `VarInt(0) + inline_data` for direct
- If codec changed, update `DataTypes.cs` entity metadata reading logic accordingly.
## Step 5: Handle New EntityDataSerializer Types
## Step 6: Handle New EntityDataSerializer Types
When new serializer types are added (detected in Step 1):
1. Add enum value to `EntityMetaDataType.cs` with XML doc comment
2. Add read logic in `DataTypes.cs` `ReadNextMetadata()`:
- Determine byte consumption from the decompiled codec
- Examples: VarInt read, list of particles, etc.
- Simple enum types (like CopperGolemState, WeatheringCopperState): `ReadNextVarInt(cache)`
- Composite types (like ResolvableProfile): analyze the STREAM_CODEC chain in decompiled source
3. Create the new palette file (Step 2)
4. Update palette routing (Step 3)
## Step 6: Compile and Verify
## Step 7: Check SpawnEntity / Other Packet Format Changes
Compare key packet codec classes between versions. Known changes:
- **1.21.9+**: `SpawnEntity` velocity fields changed from `short / 8000.0` to `LpVec3` format (VarLong-packed fixed-point). Gate reading in `DataTypes.ReadNextEntity()` by version.
When in doubt, compare the relevant packet class (e.g. `ClientboundAddEntityPacket.java`) between versions.
## Step 8: Compile and Verify
```bash
dotnet build $MCC_REPO/MinecraftClient.sln -c Release
@ -104,27 +194,53 @@ dotnet build $MCC_REPO/MinecraftClient.sln -c Release
Then connect to a test server of the target version (see `mcc-dev-workflow` skill) and verify:
- Successful connection
- `/give` new items → check inventory
- Summon entities (especially variant types) → no metadata parse errors
- Particle effects → no crashes
- `/give` new items → check inventory for correct identification
- `/give` existing items (diamond_sword, etc.) → verify no ID shift
- Summon new entities → check type and health
- Summon variant entities (wolf, cat, frog) → no metadata parse errors
- Place new blocks → `dig` reports correct block type
- Teleport to distant chunks → terrain loads without errors
- Chat commands work normally
**Always verify basic existing items first** (e.g. diamond_sword) to catch palette ID shift bugs early. If an existing item shows as the wrong type, the palette is using wrong protocol IDs.
## Key Source Files Reference
| Decompiled Java Source | Purpose |
|----------------------|---------|
| `world/item/Items.java` | Item registry (field declaration order = ID) |
| `world/item/Items.java` | Item registry (field declaration order ≈ ID, **but not always since 1.21.9**) |
| `world/entity/EntityType.java` | Entity type registry (`register()` call order = ID) |
| `world/level/block/Blocks.java` | Block registry (`register()` call order = ID) |
| `world/level/block/Blocks.java` | Block registry (`register()` call order ≈ ID, **but not always since 1.21.9**) |
| `core/component/DataComponents.java` | Data component registry |
| `network/syncher/EntityDataSerializers.java` | Entity metadata type registry (static block order = ID) |
| `network/protocol/game/GameProtocols.java` | Play packet registration order (= packet IDs) |
| `network/protocol/configuration/ConfigurationProtocols.java` | Config packet registration order |
| Server Data Generator Output | Purpose |
|-----|---------|
| `registries.json` | **Authoritative** protocol_id for all registries |
| `blocks.json` | **Authoritative** block state IDs |
| `packets.json` | Packet protocol definitions |
## Common Pitfalls
- **ID order matters**: IDs are determined by declaration/registration order, not alphabetical. Always use the decompiled source as ground truth.
- **Source field order ≠ runtime registry ID (since 1.21.9)**: Some items/blocks are registered via callbacks (e.g., block items registered by `Blocks.java` during block registration) rather than in `Items.java` field declarations. Always validate palette counts against server `registries.json`. If counts differ, **use server data generator output instead of decompiled source**.
- **ID order matters**: IDs are determined by registration order, not alphabetical. Always use server data generator as ground truth.
- **Cross-version jumps**: When MCC skips versions (e.g., 1.20.4→1.20.6), registries from ALL intermediate versions may have changed. Always diff against the actual last-supported version, not the latest palette.
- **EntityMetadata type shifts**: A single new serializer type shifts all subsequent IDs, causing widespread metadata parse failures. Symptoms: entity rendering glitches, disconnections, or silent data corruption.
- **CUT_STANDSTONE_SLAB**: This is an intentional typo in Minecraft source (should be SANDSTONE). MCC's `ItemType.cs` uses `CutSandstoneSlab` — the gen script handles this via the OVERRIDES dict.
- **Item/block renames across versions**: Some items/blocks get renamed (e.g., `DRY_SHORT_GRASS``SHORT_DRY_GRASS`, `CHAIN``IRON_CHAIN`). Keep old enum values for backward compatibility with older palettes, and add new ones for the new version.
- **Packet ID cascading shifts**: Even one inserted mid-list clientbound packet shifts ALL subsequent IDs. Always create a new PacketPalette for protocol changes.
- **Test existing items first**: After palette changes, always verify existing items (diamond_sword, stone, etc.) before testing new ones. If they show as wrong items, the palette has a systemic ID offset bug.
## Reusable Scripts
All scripts are in `$MCC_REPO/tools/`. See `tools/README.md` for detailed usage.
| Script | Purpose | Input |
|--------|---------|-------|
| `diff_registries.py` | Compare registries between versions | Decompiled source |
| `gen_item_palette.py` | Generate ItemPalette C# | Decompiled source OR registries.json |
| `gen_block_palette.py` | Generate BlockPalette C# | blocks.json |
| `gen_entity_palette.py` | Generate EntityPalette C# | registries.json |
| `gen_entity_metadata_palette.py` | Generate EntityMetadataPalette C# | Decompiled source |

File diff suppressed because it is too large Load diff

View file

@ -26,6 +26,7 @@ namespace MinecraftClient.Inventory
AcaciaPlanks,
AcaciaPressurePlate,
AcaciaSapling,
AcaciaShelf,
AcaciaSign,
AcaciaSlab,
AcaciaStairs,
@ -72,6 +73,7 @@ namespace MinecraftClient.Inventory
BambooPlanks,
BambooPressurePlate,
BambooRaft,
BambooShelf,
BambooSign,
BambooSlab,
BambooStairs,
@ -103,6 +105,7 @@ namespace MinecraftClient.Inventory
BirchPlanks,
BirchPressurePlate,
BirchSapling,
BirchShelf,
BirchSign,
BirchSlab,
BirchStairs,
@ -110,19 +113,19 @@ namespace MinecraftClient.Inventory
BirchWood,
BlackBanner,
BlackBed,
BlackBundle,
BlackCandle,
BlackCarpet,
BlackConcrete,
BlackConcretePowder,
BlackDye,
BlackGlazedTerracotta,
BlackHarness,
BlackShulkerBox,
BlackStainedGlass,
BlackStainedGlassPane,
BlackTerracotta,
BlackWool,
BlackBundle,
BlackHarness,
Blackstone,
BlackstoneSlab,
BlackstoneStairs,
@ -134,13 +137,15 @@ namespace MinecraftClient.Inventory
BlazeSpawnEgg,
BlueBanner,
BlueBed,
BlueBundle,
BlueCandle,
BlueCarpet,
BlueConcrete,
BlueConcretePowder,
BlueDye,
BlueEgg, // blue egg
BlueEgg,
BlueGlazedTerracotta,
BlueHarness,
BlueIce,
BlueOrchid,
BlueShulkerBox,
@ -148,8 +153,6 @@ namespace MinecraftClient.Inventory
BlueStainedGlassPane,
BlueTerracotta,
BlueWool,
BlueBundle,
BlueHarness,
BoggedSpawnEgg,
BoltArmorTrimSmithingTemplate,
Bone,
@ -175,13 +178,15 @@ namespace MinecraftClient.Inventory
Bricks,
BrownBanner,
BrownBed,
BrownBundle,
BrownCandle,
BrownCarpet,
BrownConcrete,
BrownConcretePowder,
BrownDye,
BrownEgg, // brown egg
BrownEgg,
BrownGlazedTerracotta,
BrownHarness,
BrownMushroom,
BrownMushroomBlock,
BrownShulkerBox,
@ -189,8 +194,6 @@ namespace MinecraftClient.Inventory
BrownStainedGlassPane,
BrownTerracotta,
BrownWool,
BrownBundle,
BrownHarness,
Brush,
BubbleCoral,
BubbleCoralBlock,
@ -199,9 +202,9 @@ namespace MinecraftClient.Inventory
BuddingAmethyst,
Bundle,
BurnPotterySherd,
Bush, // bush
Bush,
Cactus,
CactusFlower, // cactus flower
CactusFlower,
Cake,
Calcite,
CalibratedSculkSensor,
@ -234,6 +237,7 @@ namespace MinecraftClient.Inventory
CherryPlanks,
CherryPressurePlate,
CherrySapling,
CherryShelf,
CherrySign,
CherrySlab,
CherryStairs,
@ -295,12 +299,30 @@ namespace MinecraftClient.Inventory
CookedRabbit,
CookedSalmon,
Cookie,
CopperAxe,
CopperBars,
CopperBlock,
CopperBoots,
CopperBulb,
CopperChain,
CopperChest,
CopperChestplate,
CopperDoor,
CopperGolemSpawnEgg,
CopperGolemStatue,
CopperGrate,
CopperHelmet,
CopperHoe,
CopperHorseArmor,
CopperIngot,
CopperLantern,
CopperLeggings,
CopperNugget,
CopperOre,
CopperPickaxe,
CopperShovel,
CopperSword,
CopperTorch,
CopperTrapdoor,
Cornflower,
CowSpawnEgg,
@ -327,6 +349,7 @@ namespace MinecraftClient.Inventory
CrimsonPlanks,
CrimsonPressurePlate,
CrimsonRoots,
CrimsonShelf,
CrimsonSign,
CrimsonSlab,
CrimsonStairs,
@ -343,19 +366,19 @@ namespace MinecraftClient.Inventory
CutSandstoneSlab,
CyanBanner,
CyanBed,
CyanBundle,
CyanCandle,
CyanCarpet,
CyanConcrete,
CyanConcretePowder,
CyanDye,
CyanGlazedTerracotta,
CyanHarness,
CyanShulkerBox,
CyanStainedGlass,
CyanStainedGlassPane,
CyanTerracotta,
CyanWool,
CyanBundle,
CyanHarness,
DamagedAnvil,
Dandelion,
DangerPotterySherd,
@ -371,6 +394,7 @@ namespace MinecraftClient.Inventory
DarkOakPlanks,
DarkOakPressurePlate,
DarkOakSapling,
DarkOakShelf,
DarkOakSign,
DarkOakSlab,
DarkOakStairs,
@ -448,8 +472,8 @@ namespace MinecraftClient.Inventory
DripstoneBlock,
Dropper,
DrownedSpawnEgg,
DryShortGrass, // dry short grass
DryTallGrass, // dry tall grass
DryShortGrass,
DryTallGrass,
DuneArmorTrimSmithingTemplate,
EchoShard,
Egg,
@ -480,13 +504,19 @@ namespace MinecraftClient.Inventory
ExplorerPotterySherd,
ExposedChiseledCopper,
ExposedCopper,
ExposedCopperBars,
ExposedCopperBulb,
ExposedCopperChain,
ExposedCopperChest,
ExposedCopperDoor,
ExposedCopperGolemStatue,
ExposedCopperGrate,
ExposedCopperLantern,
ExposedCopperTrapdoor,
ExposedCutCopper,
ExposedCutCopperSlab,
ExposedCutCopperStairs,
ExposedLightningRod,
EyeArmorTrimSmithingTemplate,
Farmland,
Feather,
@ -498,7 +528,7 @@ namespace MinecraftClient.Inventory
FireCoral,
FireCoralBlock,
FireCoralFan,
FireflyBush, // firefly bush
FireflyBush,
FireworkRocket,
FireworkStar,
FishingRod,
@ -559,34 +589,34 @@ namespace MinecraftClient.Inventory
Gravel,
GrayBanner,
GrayBed,
GrayBundle,
GrayCandle,
GrayCarpet,
GrayConcrete,
GrayConcretePowder,
GrayDye,
GrayGlazedTerracotta,
GrayHarness,
GrayShulkerBox,
GrayStainedGlass,
GrayStainedGlassPane,
GrayTerracotta,
GrayWool,
GrayBundle,
GrayHarness,
GreenBanner,
GreenBed,
GreenBundle,
GreenCandle,
GreenCarpet,
GreenConcrete,
GreenConcretePowder,
GreenDye,
GreenGlazedTerracotta,
GreenHarness,
GreenShulkerBox,
GreenStainedGlass,
GreenStainedGlassPane,
GreenTerracotta,
GreenWool,
GreenBundle,
GreenHarness,
Grindstone,
GuardianSpawnEgg,
Gunpowder,
@ -627,6 +657,7 @@ namespace MinecraftClient.Inventory
IronBars,
IronBlock,
IronBoots,
IronChain,
IronChestplate,
IronDoor,
IronGolemSpawnEgg,
@ -657,6 +688,7 @@ namespace MinecraftClient.Inventory
JunglePlanks,
JunglePressurePlate,
JungleSapling,
JungleShelf,
JungleSign,
JungleSlab,
JungleStairs,
@ -673,7 +705,7 @@ namespace MinecraftClient.Inventory
LargeFern,
LavaBucket,
Lead,
LeafLitter, // leaf litter
LeafLitter,
Leather,
LeatherBoots,
LeatherChestplate,
@ -685,34 +717,34 @@ namespace MinecraftClient.Inventory
Light,
LightBlueBanner,
LightBlueBed,
LightBlueBundle,
LightBlueCandle,
LightBlueCarpet,
LightBlueConcrete,
LightBlueConcretePowder,
LightBlueDye,
LightBlueGlazedTerracotta,
LightBlueHarness,
LightBlueShulkerBox,
LightBlueStainedGlass,
LightBlueStainedGlassPane,
LightBlueTerracotta,
LightBlueWool,
LightBlueBundle,
LightBlueHarness,
LightGrayBanner,
LightGrayBed,
LightGrayBundle,
LightGrayCandle,
LightGrayCarpet,
LightGrayConcrete,
LightGrayConcretePowder,
LightGrayDye,
LightGrayGlazedTerracotta,
LightGrayHarness,
LightGrayShulkerBox,
LightGrayStainedGlass,
LightGrayStainedGlassPane,
LightGrayTerracotta,
LightGrayWool,
LightGrayBundle,
LightGrayHarness,
LightWeightedPressurePlate,
LightningRod,
Lilac,
@ -720,19 +752,19 @@ namespace MinecraftClient.Inventory
LilyPad,
LimeBanner,
LimeBed,
LimeBundle,
LimeCandle,
LimeCarpet,
LimeConcrete,
LimeConcretePowder,
LimeDye,
LimeGlazedTerracotta,
LimeHarness,
LimeShulkerBox,
LimeStainedGlass,
LimeStainedGlassPane,
LimeTerracotta,
LimeWool,
LimeBundle,
LimeHarness,
LingeringPotion,
LlamaSpawnEgg,
Lodestone,
@ -740,19 +772,19 @@ namespace MinecraftClient.Inventory
Mace,
MagentaBanner,
MagentaBed,
MagentaBundle,
MagentaCandle,
MagentaCarpet,
MagentaConcrete,
MagentaConcretePowder,
MagentaDye,
MagentaGlazedTerracotta,
MagentaHarness,
MagentaShulkerBox,
MagentaStainedGlass,
MagentaStainedGlassPane,
MagentaTerracotta,
MagentaWool,
MagentaBundle,
MagentaHarness,
MagmaBlock,
MagmaCream,
MagmaCubeSpawnEgg,
@ -769,6 +801,7 @@ namespace MinecraftClient.Inventory
MangrovePressurePlate,
MangrovePropagule,
MangroveRoots,
MangroveShelf,
MangroveSign,
MangroveSlab,
MangroveStairs,
@ -868,6 +901,7 @@ namespace MinecraftClient.Inventory
OakPlanks,
OakPressurePlate,
OakSapling,
OakShelf,
OakSign,
OakSlab,
OakStairs,
@ -882,30 +916,36 @@ namespace MinecraftClient.Inventory
OpenEyeblossom,
OrangeBanner,
OrangeBed,
OrangeBundle,
OrangeCandle,
OrangeCarpet,
OrangeConcrete,
OrangeConcretePowder,
OrangeDye,
OrangeGlazedTerracotta,
OrangeHarness,
OrangeShulkerBox,
OrangeStainedGlass,
OrangeStainedGlassPane,
OrangeTerracotta,
OrangeTulip,
OrangeWool,
OrangeBundle,
OrangeHarness,
OxeyeDaisy,
OxidizedChiseledCopper,
OxidizedCopper,
OxidizedCopperBars,
OxidizedCopperBulb,
OxidizedCopperChain,
OxidizedCopperChest,
OxidizedCopperDoor,
OxidizedCopperGolemStatue,
OxidizedCopperGrate,
OxidizedCopperLantern,
OxidizedCopperTrapdoor,
OxidizedCutCopper,
OxidizedCutCopperSlab,
OxidizedCutCopperStairs,
OxidizedLightningRod,
PackedIce,
PackedMud,
Painting,
@ -924,6 +964,7 @@ namespace MinecraftClient.Inventory
PaleOakPlanks,
PaleOakPressurePlate,
PaleOakSapling,
PaleOakShelf,
PaleOakSign,
PaleOakSlab,
PaleOakStairs,
@ -945,12 +986,14 @@ namespace MinecraftClient.Inventory
PillagerSpawnEgg,
PinkBanner,
PinkBed,
PinkBundle,
PinkCandle,
PinkCarpet,
PinkConcrete,
PinkConcretePowder,
PinkDye,
PinkGlazedTerracotta,
PinkHarness,
PinkPetals,
PinkShulkerBox,
PinkStainedGlass,
@ -958,8 +1001,6 @@ namespace MinecraftClient.Inventory
PinkTerracotta,
PinkTulip,
PinkWool,
PinkBundle,
PinkHarness,
Piston,
PitcherPlant,
PitcherPod,
@ -1022,19 +1063,19 @@ namespace MinecraftClient.Inventory
PumpkinSeeds,
PurpleBanner,
PurpleBed,
PurpleBundle,
PurpleCandle,
PurpleCarpet,
PurpleConcrete,
PurpleConcretePowder,
PurpleDye,
PurpleGlazedTerracotta,
PurpleHarness,
PurpleShulkerBox,
PurpleStainedGlass,
PurpleStainedGlassPane,
PurpleTerracotta,
PurpleWool,
PurpleBundle,
PurpleHarness,
PurpurBlock,
PurpurPillar,
PurpurSlab,
@ -1062,12 +1103,14 @@ namespace MinecraftClient.Inventory
RecoveryCompass,
RedBanner,
RedBed,
RedBundle,
RedCandle,
RedCarpet,
RedConcrete,
RedConcretePowder,
RedDye,
RedGlazedTerracotta,
RedHarness,
RedMushroom,
RedMushroomBlock,
RedNetherBrickSlab,
@ -1085,8 +1128,6 @@ namespace MinecraftClient.Inventory
RedTerracotta,
RedTulip,
RedWool,
RedBundle,
RedHarness,
Redstone,
RedstoneBlock,
RedstoneLamp,
@ -1097,10 +1138,10 @@ namespace MinecraftClient.Inventory
RepeatingCommandBlock,
ResinBlock,
ResinBrick,
ResinBricks,
ResinBrickSlab,
ResinBrickStairs,
ResinBrickWall,
ResinBricks,
ResinClump,
RespawnAnchor,
RibArmorTrimSmithingTemplate,
@ -1133,6 +1174,7 @@ namespace MinecraftClient.Inventory
SheepSpawnEgg,
ShelterPotterySherd,
Shield,
ShortDryGrass,
ShortGrass,
Shroomlight,
ShulkerBox,
@ -1197,6 +1239,7 @@ namespace MinecraftClient.Inventory
SprucePlanks,
SprucePressurePlate,
SpruceSapling,
SpruceShelf,
SpruceSign,
SpruceSlab,
SpruceStairs,
@ -1258,11 +1301,12 @@ namespace MinecraftClient.Inventory
SweetBerries,
TadpoleBucket,
TadpoleSpawnEgg,
TallDryGrass,
TallGrass,
Target,
Terracotta,
TestBlock, // test block
TestInstanceBlock, // test instance block
TestBlock,
TestInstanceBlock,
TideArmorTrimSmithingTemplate,
TintedGlass,
TippedArrow,
@ -1319,6 +1363,7 @@ namespace MinecraftClient.Inventory
WarpedPlanks,
WarpedPressurePlate,
WarpedRoots,
WarpedShelf,
WarpedSign,
WarpedSlab,
WarpedStairs,
@ -1327,73 +1372,103 @@ namespace MinecraftClient.Inventory
WarpedWartBlock,
WaterBucket,
WaxedChiseledCopper,
WaxedCopperBars,
WaxedCopperBlock,
WaxedCopperBulb,
WaxedCopperChain,
WaxedCopperChest,
WaxedCopperDoor,
WaxedCopperGolemStatue,
WaxedCopperGrate,
WaxedCopperLantern,
WaxedCopperTrapdoor,
WaxedCutCopper,
WaxedCutCopperSlab,
WaxedCutCopperStairs,
WaxedExposedChiseledCopper,
WaxedExposedCopper,
WaxedExposedCopperBars,
WaxedExposedCopperBulb,
WaxedExposedCopperChain,
WaxedExposedCopperChest,
WaxedExposedCopperDoor,
WaxedExposedCopperGolemStatue,
WaxedExposedCopperGrate,
WaxedExposedCopperLantern,
WaxedExposedCopperTrapdoor,
WaxedExposedCutCopper,
WaxedExposedCutCopperSlab,
WaxedExposedCutCopperStairs,
WaxedExposedLightningRod,
WaxedLightningRod,
WaxedOxidizedChiseledCopper,
WaxedOxidizedCopper,
WaxedOxidizedCopperBars,
WaxedOxidizedCopperBulb,
WaxedOxidizedCopperChain,
WaxedOxidizedCopperChest,
WaxedOxidizedCopperDoor,
WaxedOxidizedCopperGolemStatue,
WaxedOxidizedCopperGrate,
WaxedOxidizedCopperLantern,
WaxedOxidizedCopperTrapdoor,
WaxedOxidizedCutCopper,
WaxedOxidizedCutCopperSlab,
WaxedOxidizedCutCopperStairs,
WaxedOxidizedLightningRod,
WaxedWeatheredChiseledCopper,
WaxedWeatheredCopper,
WaxedWeatheredCopperBars,
WaxedWeatheredCopperBulb,
WaxedWeatheredCopperChain,
WaxedWeatheredCopperChest,
WaxedWeatheredCopperDoor,
WaxedWeatheredCopperGolemStatue,
WaxedWeatheredCopperGrate,
WaxedWeatheredCopperLantern,
WaxedWeatheredCopperTrapdoor,
WaxedWeatheredCutCopper,
WaxedWeatheredCutCopperSlab,
WaxedWeatheredCutCopperStairs,
WaxedWeatheredLightningRod,
WayfinderArmorTrimSmithingTemplate,
WeatheredChiseledCopper,
WeatheredCopper,
WeatheredCopperBars,
WeatheredCopperBulb,
WeatheredCopperChain,
WeatheredCopperChest,
WeatheredCopperDoor,
WeatheredCopperGolemStatue,
WeatheredCopperGrate,
WeatheredCopperLantern,
WeatheredCopperTrapdoor,
WeatheredCutCopper,
WeatheredCutCopperSlab,
WeatheredCutCopperStairs,
WeatheredLightningRod,
WeepingVines,
WetSponge,
Wheat,
WheatSeeds,
WhiteBanner,
WhiteBed,
WhiteBundle,
WhiteCandle,
WhiteCarpet,
WhiteConcrete,
WhiteConcretePowder,
WhiteDye,
WhiteGlazedTerracotta,
WhiteHarness,
WhiteShulkerBox,
WhiteStainedGlass,
WhiteStainedGlassPane,
WhiteTerracotta,
WhiteTulip,
WhiteWool,
WhiteBundle,
WhiteHarness,
WildArmorTrimSmithingTemplate,
Wildflowers, // wildflowers
Wildflowers,
WindCharge,
WitchSpawnEgg,
WitherRose,
@ -1411,19 +1486,19 @@ namespace MinecraftClient.Inventory
WrittenBook,
YellowBanner,
YellowBed,
YellowBundle,
YellowCandle,
YellowCarpet,
YellowConcrete,
YellowConcretePowder,
YellowDye,
YellowGlazedTerracotta,
YellowHarness,
YellowShulkerBox,
YellowStainedGlass,
YellowStainedGlassPane,
YellowTerracotta,
YellowWool,
YellowBundle,
YellowHarness,
ZoglinSpawnEgg,
ZombieHead,
ZombieHorseSpawnEgg,

File diff suppressed because it is too large Load diff

View file

@ -98,11 +98,23 @@ public enum EntityMetaDataType
/// </summary>
ArmadilloState,
/// <summary>
/// VarInt (1.21.9+)
/// </summary>
CopperGolemState,
/// <summary>
/// VarInt (1.21.9+)
/// </summary>
WeatheringCopperState,
/// <summary>
/// Float x3
/// </summary>
Vector3,
/// <summary>
/// Float x4
/// </summary>
Quaternion
Quaternion,
/// <summary>
/// Either&lt;GameProfile, Partial&gt; + PlayerSkin.Patch (1.21.9+)
/// </summary>
ResolvableProfile
}

View file

@ -24,7 +24,8 @@ public abstract class EntityMetadataPalette
<= Protocol18Handler.MC_1_19_3_Version => new EntityMetadataPalette1193(), // 1.19.3
< Protocol18Handler.MC_1_20_6_Version => new EntityMetadataPalette1194(), // 1.19.4 - 1.20.4
<= Protocol18Handler.MC_1_21_4_Version => new EntityMetadataPalette1206(), // 1.20.6 - 1.21.4
<= Protocol18Handler.MC_1_21_7_Version => new EntityMetadataPalette1215(), // 1.21.5 - 1.21.7
<= Protocol18Handler.MC_1_21_7_Version => new EntityMetadataPalette1215(), // 1.21.5 - 1.21.8
<= Protocol18Handler.MC_1_21_9_Version => new EntityMetadataPalette1219(), // 1.21.9 - 1.21.10
_ => throw new NotImplementedException()
};
}

View file

@ -0,0 +1,52 @@
using System.Collections.Generic;
namespace MinecraftClient.Mapping.EntityMetadataPalettes;
public class EntityMetadataPalette1219 : EntityMetadataPalette
{
private readonly Dictionary<int, EntityMetaDataType> entityMetadataMappings = new()
{
{ 0, EntityMetaDataType.Byte },
{ 1, EntityMetaDataType.VarInt },
{ 2, EntityMetaDataType.VarLong },
{ 3, EntityMetaDataType.Float },
{ 4, EntityMetaDataType.String },
{ 5, EntityMetaDataType.Chat },
{ 6, EntityMetaDataType.OptionalChat },
{ 7, EntityMetaDataType.Slot },
{ 8, EntityMetaDataType.Boolean },
{ 9, EntityMetaDataType.Rotation },
{ 10, EntityMetaDataType.Position },
{ 11, EntityMetaDataType.OptionalPosition },
{ 12, EntityMetaDataType.Direction },
{ 13, EntityMetaDataType.OptionalLivingEntityReference },
{ 14, EntityMetaDataType.BlockId },
{ 15, EntityMetaDataType.OptionalBlockId },
{ 16, EntityMetaDataType.Particle },
{ 17, EntityMetaDataType.Particles },
{ 18, EntityMetaDataType.VillagerData },
{ 19, EntityMetaDataType.OptionalVarInt },
{ 20, EntityMetaDataType.Pose },
{ 21, EntityMetaDataType.CatVariant },
{ 22, EntityMetaDataType.CowVariant },
{ 23, EntityMetaDataType.WolfVariant },
{ 24, EntityMetaDataType.WolfSoundVariant },
{ 25, EntityMetaDataType.FrogVariant },
{ 26, EntityMetaDataType.PigVariant },
{ 27, EntityMetaDataType.ChickenVariant },
{ 28, EntityMetaDataType.OptionalGlobalPosition },
{ 29, EntityMetaDataType.PaintingVariant },
{ 30, EntityMetaDataType.SnifferState },
{ 31, EntityMetaDataType.ArmadilloState },
{ 32, EntityMetaDataType.CopperGolemState },
{ 33, EntityMetaDataType.WeatheringCopperState },
{ 34, EntityMetaDataType.Vector3 },
{ 35, EntityMetaDataType.Quaternion },
{ 36, EntityMetaDataType.ResolvableProfile },
};
public override Dictionary<int, EntityMetaDataType> GetEntityMetadataMappingsList()
{
return entityMetadataMappings;
}
}

View file

@ -0,0 +1,171 @@
using System.Collections.Generic;
namespace MinecraftClient.Mapping.EntityPalettes
{
public class EntityPalette1219 : EntityPalette
{
private static readonly Dictionary<int, EntityType> mappings = new();
static EntityPalette1219()
{
mappings[0] = EntityType.AcaciaBoat;
mappings[1] = EntityType.AcaciaChestBoat;
mappings[2] = EntityType.Allay;
mappings[3] = EntityType.AreaEffectCloud;
mappings[4] = EntityType.Armadillo;
mappings[5] = EntityType.ArmorStand;
mappings[6] = EntityType.Arrow;
mappings[7] = EntityType.Axolotl;
mappings[8] = EntityType.BambooChestRaft;
mappings[9] = EntityType.BambooRaft;
mappings[10] = EntityType.Bat;
mappings[11] = EntityType.Bee;
mappings[12] = EntityType.BirchBoat;
mappings[13] = EntityType.BirchChestBoat;
mappings[14] = EntityType.Blaze;
mappings[15] = EntityType.BlockDisplay;
mappings[16] = EntityType.Bogged;
mappings[17] = EntityType.Breeze;
mappings[18] = EntityType.BreezeWindCharge;
mappings[19] = EntityType.Camel;
mappings[20] = EntityType.Cat;
mappings[21] = EntityType.CaveSpider;
mappings[22] = EntityType.CherryBoat;
mappings[23] = EntityType.CherryChestBoat;
mappings[24] = EntityType.ChestMinecart;
mappings[25] = EntityType.Chicken;
mappings[26] = EntityType.Cod;
mappings[27] = EntityType.CopperGolem;
mappings[28] = EntityType.CommandBlockMinecart;
mappings[29] = EntityType.Cow;
mappings[30] = EntityType.Creaking;
mappings[31] = EntityType.Creeper;
mappings[32] = EntityType.DarkOakBoat;
mappings[33] = EntityType.DarkOakChestBoat;
mappings[34] = EntityType.Dolphin;
mappings[35] = EntityType.Donkey;
mappings[36] = EntityType.DragonFireball;
mappings[37] = EntityType.Drowned;
mappings[38] = EntityType.Egg;
mappings[39] = EntityType.ElderGuardian;
mappings[40] = EntityType.Enderman;
mappings[41] = EntityType.Endermite;
mappings[42] = EntityType.EnderDragon;
mappings[43] = EntityType.EnderPearl;
mappings[44] = EntityType.EndCrystal;
mappings[45] = EntityType.Evoker;
mappings[46] = EntityType.EvokerFangs;
mappings[47] = EntityType.ExperienceBottle;
mappings[48] = EntityType.ExperienceOrb;
mappings[49] = EntityType.EyeOfEnder;
mappings[50] = EntityType.FallingBlock;
mappings[51] = EntityType.Fireball;
mappings[52] = EntityType.FireworkRocket;
mappings[53] = EntityType.Fox;
mappings[54] = EntityType.Frog;
mappings[55] = EntityType.FurnaceMinecart;
mappings[56] = EntityType.Ghast;
mappings[57] = EntityType.HappyGhast;
mappings[58] = EntityType.Giant;
mappings[59] = EntityType.GlowItemFrame;
mappings[60] = EntityType.GlowSquid;
mappings[61] = EntityType.Goat;
mappings[62] = EntityType.Guardian;
mappings[63] = EntityType.Hoglin;
mappings[64] = EntityType.HopperMinecart;
mappings[65] = EntityType.Horse;
mappings[66] = EntityType.Husk;
mappings[67] = EntityType.Illusioner;
mappings[68] = EntityType.Interaction;
mappings[69] = EntityType.IronGolem;
mappings[70] = EntityType.Item;
mappings[71] = EntityType.ItemDisplay;
mappings[72] = EntityType.ItemFrame;
mappings[73] = EntityType.JungleBoat;
mappings[74] = EntityType.JungleChestBoat;
mappings[75] = EntityType.LeashKnot;
mappings[76] = EntityType.LightningBolt;
mappings[77] = EntityType.Llama;
mappings[78] = EntityType.LlamaSpit;
mappings[79] = EntityType.MagmaCube;
mappings[80] = EntityType.MangroveBoat;
mappings[81] = EntityType.MangroveChestBoat;
mappings[82] = EntityType.Mannequin;
mappings[83] = EntityType.Marker;
mappings[84] = EntityType.Minecart;
mappings[85] = EntityType.Mooshroom;
mappings[86] = EntityType.Mule;
mappings[87] = EntityType.OakBoat;
mappings[88] = EntityType.OakChestBoat;
mappings[89] = EntityType.Ocelot;
mappings[90] = EntityType.OminousItemSpawner;
mappings[91] = EntityType.Painting;
mappings[92] = EntityType.PaleOakBoat;
mappings[93] = EntityType.PaleOakChestBoat;
mappings[94] = EntityType.Panda;
mappings[95] = EntityType.Parrot;
mappings[96] = EntityType.Phantom;
mappings[97] = EntityType.Pig;
mappings[98] = EntityType.Piglin;
mappings[99] = EntityType.PiglinBrute;
mappings[100] = EntityType.Pillager;
mappings[101] = EntityType.PolarBear;
mappings[102] = EntityType.SplashPotion;
mappings[103] = EntityType.LingeringPotion;
mappings[104] = EntityType.Pufferfish;
mappings[105] = EntityType.Rabbit;
mappings[106] = EntityType.Ravager;
mappings[107] = EntityType.Salmon;
mappings[108] = EntityType.Sheep;
mappings[109] = EntityType.Shulker;
mappings[110] = EntityType.ShulkerBullet;
mappings[111] = EntityType.Silverfish;
mappings[112] = EntityType.Skeleton;
mappings[113] = EntityType.SkeletonHorse;
mappings[114] = EntityType.Slime;
mappings[115] = EntityType.SmallFireball;
mappings[116] = EntityType.Sniffer;
mappings[117] = EntityType.Snowball;
mappings[118] = EntityType.SnowGolem;
mappings[119] = EntityType.SpawnerMinecart;
mappings[120] = EntityType.SpectralArrow;
mappings[121] = EntityType.Spider;
mappings[122] = EntityType.SpruceBoat;
mappings[123] = EntityType.SpruceChestBoat;
mappings[124] = EntityType.Squid;
mappings[125] = EntityType.Stray;
mappings[126] = EntityType.Strider;
mappings[127] = EntityType.Tadpole;
mappings[128] = EntityType.TextDisplay;
mappings[129] = EntityType.Tnt;
mappings[130] = EntityType.TntMinecart;
mappings[131] = EntityType.TraderLlama;
mappings[132] = EntityType.Trident;
mappings[133] = EntityType.TropicalFish;
mappings[134] = EntityType.Turtle;
mappings[135] = EntityType.Vex;
mappings[136] = EntityType.Villager;
mappings[137] = EntityType.Vindicator;
mappings[138] = EntityType.WanderingTrader;
mappings[139] = EntityType.Warden;
mappings[140] = EntityType.WindCharge;
mappings[141] = EntityType.Witch;
mappings[142] = EntityType.Wither;
mappings[143] = EntityType.WitherSkeleton;
mappings[144] = EntityType.WitherSkull;
mappings[145] = EntityType.Wolf;
mappings[146] = EntityType.Zoglin;
mappings[147] = EntityType.Zombie;
mappings[148] = EntityType.ZombieHorse;
mappings[149] = EntityType.ZombieVillager;
mappings[150] = EntityType.ZombifiedPiglin;
mappings[151] = EntityType.Player;
mappings[152] = EntityType.FishingBobber;
}
protected override Dictionary<int, EntityType> GetDict()
{
return mappings;
}
}
}

View file

@ -44,6 +44,7 @@ namespace MinecraftClient.Mapping
Chicken,
Cod,
CommandBlockMinecart,
CopperGolem,
Cow,
Creaking,
CreakingTransient,
@ -99,6 +100,7 @@ namespace MinecraftClient.Mapping
MagmaCube,
MangroveBoat,
MangroveChestBoat,
Mannequin,
Marker,
Minecart,
Mooshroom,

View file

@ -24,6 +24,7 @@ namespace MinecraftClient.Mapping
AcaciaPlanks,
AcaciaPressurePlate,
AcaciaSapling,
AcaciaShelf,
AcaciaSign,
AcaciaSlab,
AcaciaStairs,
@ -60,6 +61,7 @@ namespace MinecraftClient.Mapping
BambooPlanks,
BambooPressurePlate,
BambooSapling,
BambooShelf,
BambooSign,
BambooSlab,
BambooStairs,
@ -87,6 +89,7 @@ namespace MinecraftClient.Mapping
BirchPlanks,
BirchPressurePlate,
BirchSapling,
BirchShelf,
BirchSign,
BirchSlab,
BirchStairs,
@ -162,9 +165,9 @@ namespace MinecraftClient.Mapping
BubbleCoralFan,
BubbleCoralWallFan,
BuddingAmethyst,
Bush, // bush
Bush,
Cactus,
CactusFlower, // cactus_flower
CactusFlower,
Cake,
Calcite,
CalibratedSculkSensor,
@ -190,6 +193,7 @@ namespace MinecraftClient.Mapping
CherryPlanks,
CherryPressurePlate,
CherrySapling,
CherryShelf,
CherrySign,
CherrySlab,
CherryStairs,
@ -232,12 +236,19 @@ namespace MinecraftClient.Mapping
Comparator,
Composter,
Conduit,
CopperBars,
CopperBlock,
CopperBulb,
CopperChain,
CopperChest,
CopperDoor,
CopperGolemStatue,
CopperGrate,
CopperLantern,
CopperOre,
CopperTorch,
CopperTrapdoor,
CopperWallTorch,
Cornflower,
CrackedDeepslateBricks,
CrackedDeepslateTiles,
@ -260,6 +271,7 @@ namespace MinecraftClient.Mapping
CrimsonPlanks,
CrimsonPressurePlate,
CrimsonRoots,
CrimsonShelf,
CrimsonSign,
CrimsonSlab,
CrimsonStairs,
@ -301,6 +313,7 @@ namespace MinecraftClient.Mapping
DarkOakPlanks,
DarkOakPressurePlate,
DarkOakSapling,
DarkOakShelf,
DarkOakSign,
DarkOakSlab,
DarkOakStairs,
@ -383,13 +396,19 @@ namespace MinecraftClient.Mapping
EnderChest,
ExposedChiseledCopper,
ExposedCopper,
ExposedCopperBars,
ExposedCopperBulb,
ExposedCopperChain,
ExposedCopperChest,
ExposedCopperDoor,
ExposedCopperGolemStatue,
ExposedCopperGrate,
ExposedCopperLantern,
ExposedCopperTrapdoor,
ExposedCutCopper,
ExposedCutCopperSlab,
ExposedCutCopperStairs,
ExposedLightningRod,
Farmland,
Fern,
Fire,
@ -397,7 +416,7 @@ namespace MinecraftClient.Mapping
FireCoralBlock,
FireCoralFan,
FireCoralWallFan,
FireflyBush, // firefly_bush
FireflyBush,
FletchingTable,
FlowerPot,
FloweringAzalea,
@ -468,6 +487,7 @@ namespace MinecraftClient.Mapping
InfestedStoneBricks,
IronBars,
IronBlock,
IronChain,
IronDoor,
IronOre,
IronTrapdoor,
@ -484,6 +504,7 @@ namespace MinecraftClient.Mapping
JunglePlanks,
JunglePressurePlate,
JungleSapling,
JungleShelf,
JungleSign,
JungleSlab,
JungleStairs,
@ -501,7 +522,7 @@ namespace MinecraftClient.Mapping
LargeFern,
Lava,
LavaCauldron,
LeafLitter, // leaf_litter
LeafLitter,
Lectern,
Lever,
Light,
@ -580,6 +601,7 @@ namespace MinecraftClient.Mapping
MangrovePressurePlate,
MangrovePropagule,
MangroveRoots,
MangroveShelf,
MangroveSign,
MangroveSlab,
MangroveStairs,
@ -633,6 +655,7 @@ namespace MinecraftClient.Mapping
OakPlanks,
OakPressurePlate,
OakSapling,
OakShelf,
OakSign,
OakSlab,
OakStairs,
@ -662,13 +685,19 @@ namespace MinecraftClient.Mapping
OxeyeDaisy,
OxidizedChiseledCopper,
OxidizedCopper,
OxidizedCopperBars,
OxidizedCopperBulb,
OxidizedCopperChain,
OxidizedCopperChest,
OxidizedCopperDoor,
OxidizedCopperGolemStatue,
OxidizedCopperGrate,
OxidizedCopperLantern,
OxidizedCopperTrapdoor,
OxidizedCutCopper,
OxidizedCutCopperSlab,
OxidizedCutCopperStairs,
OxidizedLightningRod,
PackedIce,
PackedMud,
PaleHangingMoss,
@ -684,6 +713,7 @@ namespace MinecraftClient.Mapping
PaleOakPlanks,
PaleOakPressurePlate,
PaleOakSapling,
PaleOakShelf,
PaleOakSign,
PaleOakSlab,
PaleOakStairs,
@ -884,7 +914,7 @@ namespace MinecraftClient.Mapping
SeaLantern,
SeaPickle,
Seagrass,
ShortDryGrass, // short_dry_grass
ShortDryGrass,
ShortGrass,
Shroomlight,
ShulkerBox,
@ -930,6 +960,7 @@ namespace MinecraftClient.Mapping
SprucePlanks,
SprucePressurePlate,
SpruceSapling,
SpruceShelf,
SpruceSign,
SpruceSlab,
SpruceStairs,
@ -978,13 +1009,13 @@ namespace MinecraftClient.Mapping
SuspiciousGravel,
SuspiciousSand,
SweetBerryBush,
TallDryGrass, // tall_dry_grass
TallDryGrass,
TallGrass,
TallSeagrass,
Target,
Terracotta,
TestBlock, // test_block
TestInstanceBlock, // test_instance_block
TestBlock,
TestInstanceBlock,
TintedGlass,
Tnt,
Torch,
@ -1025,6 +1056,7 @@ namespace MinecraftClient.Mapping
WarpedPlanks,
WarpedPressurePlate,
WarpedRoots,
WarpedShelf,
WarpedSign,
WarpedSlab,
WarpedStairs,
@ -1036,50 +1068,80 @@ namespace MinecraftClient.Mapping
Water,
WaterCauldron,
WaxedChiseledCopper,
WaxedCopperBars,
WaxedCopperBlock,
WaxedCopperBulb,
WaxedCopperChain,
WaxedCopperChest,
WaxedCopperDoor,
WaxedCopperGolemStatue,
WaxedCopperGrate,
WaxedCopperLantern,
WaxedCopperTrapdoor,
WaxedCutCopper,
WaxedCutCopperSlab,
WaxedCutCopperStairs,
WaxedExposedChiseledCopper,
WaxedExposedCopper,
WaxedExposedCopperBars,
WaxedExposedCopperBulb,
WaxedExposedCopperChain,
WaxedExposedCopperChest,
WaxedExposedCopperDoor,
WaxedExposedCopperGolemStatue,
WaxedExposedCopperGrate,
WaxedExposedCopperLantern,
WaxedExposedCopperTrapdoor,
WaxedExposedCutCopper,
WaxedExposedCutCopperSlab,
WaxedExposedCutCopperStairs,
WaxedExposedLightningRod,
WaxedLightningRod,
WaxedOxidizedChiseledCopper,
WaxedOxidizedCopper,
WaxedOxidizedCopperBars,
WaxedOxidizedCopperBulb,
WaxedOxidizedCopperChain,
WaxedOxidizedCopperChest,
WaxedOxidizedCopperDoor,
WaxedOxidizedCopperGolemStatue,
WaxedOxidizedCopperGrate,
WaxedOxidizedCopperLantern,
WaxedOxidizedCopperTrapdoor,
WaxedOxidizedCutCopper,
WaxedOxidizedCutCopperSlab,
WaxedOxidizedCutCopperStairs,
WaxedOxidizedLightningRod,
WaxedWeatheredChiseledCopper,
WaxedWeatheredCopper,
WaxedWeatheredCopperBars,
WaxedWeatheredCopperBulb,
WaxedWeatheredCopperChain,
WaxedWeatheredCopperChest,
WaxedWeatheredCopperDoor,
WaxedWeatheredCopperGolemStatue,
WaxedWeatheredCopperGrate,
WaxedWeatheredCopperLantern,
WaxedWeatheredCopperTrapdoor,
WaxedWeatheredCutCopper,
WaxedWeatheredCutCopperSlab,
WaxedWeatheredCutCopperStairs,
WaxedWeatheredLightningRod,
WeatheredChiseledCopper,
WeatheredCopper,
WeatheredCopperBars,
WeatheredCopperBulb,
WeatheredCopperChain,
WeatheredCopperChest,
WeatheredCopperDoor,
WeatheredCopperGolemStatue,
WeatheredCopperGrate,
WeatheredCopperLantern,
WeatheredCopperTrapdoor,
WeatheredCutCopper,
WeatheredCutCopperSlab,
WeatheredCutCopperStairs,
WeatheredLightningRod,
WeepingVines,
WeepingVinesPlant,
WetSponge,
@ -1099,7 +1161,7 @@ namespace MinecraftClient.Mapping
WhiteTulip,
WhiteWallBanner,
WhiteWool,
Wildflowers, // wildflowers
Wildflowers,
WitherRose,
WitherSkeletonSkull,
WitherSkeletonWallSkull,

View file

@ -46,7 +46,7 @@ namespace MinecraftClient
public const string Version = MCHighestVersion;
public const string MCLowestVersion = "1.4.6";
public const string MCHighestVersion = "1.21.8";
public const string MCHighestVersion = "1.21.10";
public static readonly string? BuildInfo = null;
private static Tuple<Thread, CancellationTokenSource>? offlinePrompt = null;

View file

@ -21,6 +21,7 @@ public enum ConfigurationPacketTypesIn
UpdateTags,
ClearDialog, // Added in 1.21.6
ShowDialog, // Added in 1.21.6
CodeOfConduct, // Added in 1.21.9
Unknown
}

View file

@ -11,6 +11,7 @@ public enum ConfigurationPacketTypesOut
CookieResponse,
KnownDataPacks,
CustomClickAction, // Added in 1.21.6
AcceptCodeOfConduct, // Added in 1.21.9
Unknown
}

View file

@ -559,11 +559,32 @@ namespace MinecraftClient.Protocol.Handlers
int data = -1;
byte entityPitch, entityYaw;
if (living)
if (protocolversion >= Protocol18Handler.MC_1_21_9_Version)
{
// 1.21.9+: LpVec3 movement before angles, unified format
ReadNextLpVec3(cache); // Movement (LpVec3)
entityPitch = ReadNextByte(cache); // xRot
entityYaw = ReadNextByte(cache); // yRot
ReadNextByte(cache); // yHeadRot
data = ReadNextVarInt(cache); // Data
}
else if (living)
{
entityYaw = ReadNextByte(cache); // Yaw
entityPitch = ReadNextByte(cache); // Pitch
entityPitch = ReadNextByte(cache); // Head Pitch
// Velocity (3 shorts)
if (protocolversion < Protocol18Handler.MC_1_9_Version)
{
// no velocity for living entities in <1.9
}
else
{
ReadNextShort(cache);
ReadNextShort(cache);
ReadNextShort(cache);
}
}
else
{
@ -577,9 +598,8 @@ namespace MinecraftClient.Protocol.Handlers
data = protocolversion >= Protocol18Handler.MC_1_19_Version
? ReadNextVarInt(cache)
: ReadNextInt(cache);
}
// In 1.8 those 3 fields for Velocity are optional
// Velocity (3 shorts)
if (protocolversion < Protocol18Handler.MC_1_9_Version)
{
if (data != 0)
@ -595,6 +615,7 @@ namespace MinecraftClient.Protocol.Handlers
ReadNextShort(cache);
ReadNextShort(cache);
}
}
return new Entity(entityID, entityType, new Location(entityX, entityY, entityZ), entityYaw, entityPitch,
data);
@ -907,6 +928,13 @@ namespace MinecraftClient.Protocol.Handlers
case EntityMetaDataType.ArmadilloState: // Armadillo state (1.20.6+)
value = ReadNextVarInt(cache);
break;
case EntityMetaDataType.CopperGolemState: // Copper Golem state (1.21.9+)
case EntityMetaDataType.WeatheringCopperState: // Weathering Copper state (1.21.9+)
value = ReadNextVarInt(cache);
break;
case EntityMetaDataType.ResolvableProfile: // ResolvableProfile (1.21.9+)
ReadNextResolvableProfile(cache);
break;
case EntityMetaDataType.Vector3: // Vector 3f
value = new List<float>
{
@ -938,6 +966,76 @@ namespace MinecraftClient.Protocol.Handlers
}
}
/// <summary>
/// Read an LpVec3 (low-precision vec3) from the cache (1.21.9+).
/// Variable-length encoding: first byte 0 = zero vector; otherwise
/// 2 bytes + 4 bytes (6 total), plus an optional VarInt continuation.
/// </summary>
public void ReadNextLpVec3(Queue<byte> cache)
{
int first = ReadNextByte(cache);
if (first == 0)
return;
ReadNextByte(cache); // second byte
ReadData(4, cache); // uint32
if ((first & 4) == 4) // continuation bit set
ReadNextVarInt(cache);
}
/// <summary>
/// Consume bytes for a ResolvableProfile (1.21.9+).
/// Wire: Either(GameProfile, Partial) + PlayerSkin.Patch
/// </summary>
private void ReadNextResolvableProfile(Queue<byte> cache)
{
bool isFullProfile = ReadNextBool(cache); // Either flag: true=GameProfile, false=Partial
if (isFullProfile)
{
ReadNextUUID(cache); // UUID
ReadNextString(cache); // player name (max 16 chars)
ReadGameProfileProperties(cache);
}
else
{
// Partial: optional name, optional UUID, properties
if (ReadNextBool(cache))
ReadNextString(cache); // optional player name
if (ReadNextBool(cache))
ReadNextUUID(cache); // optional UUID
ReadGameProfileProperties(cache);
}
// PlayerSkin.Patch: 4 optional fields
// body (optional ResourceLocation string)
if (ReadNextBool(cache))
ReadNextString(cache);
// cape
if (ReadNextBool(cache))
ReadNextString(cache);
// elytra
if (ReadNextBool(cache))
ReadNextString(cache);
// model (optional bool: true=SLIM, false=WIDE)
if (ReadNextBool(cache))
ReadNextBool(cache);
}
/// <summary>
/// Read GameProfile properties (PropertyMap): VarInt count, then per entry:
/// name string, value string, optional signature string.
/// </summary>
private void ReadGameProfileProperties(Queue<byte> cache)
{
int count = ReadNextVarInt(cache);
for (int i = 0; i < count; i++)
{
ReadNextString(cache); // property name
ReadNextString(cache); // property value
if (ReadNextBool(cache)) // has signature?
ReadNextString(cache); // signature
}
}
/// <summary>
/// Currently not handled. Reading data only
/// </summary>

View file

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

@ -48,8 +48,9 @@ namespace MinecraftClient.Protocol.Handlers
{
PacketTypePalette p = protocol switch
{
> Protocol18Handler.MC_1_21_7_Version => throw new NotImplementedException(Translations
> Protocol18Handler.MC_1_21_9_Version => throw new NotImplementedException(Translations
.exception_palette_packet),
<= Protocol18Handler.MC_1_21_9_Version and > Protocol18Handler.MC_1_21_7_Version => new PacketPalette1219(),
<= Protocol18Handler.MC_1_21_7_Version and > Protocol18Handler.MC_1_21_5_Version => new PacketPalette1216(),
<= Protocol18Handler.MC_1_21_5_Version and > Protocol18Handler.MC_1_21_4_Version => new PacketPalette1215(),
<= Protocol18Handler.MC_1_21_4_Version and > Protocol18Handler.MC_1_21_2_Version => new PacketPalette1214(),

View file

@ -164,5 +164,10 @@ namespace MinecraftClient.Protocol.Handlers
Waypoint, // Added in 1.21.6
ClearDialog, // Added in 1.21.6
ShowDialog, // Added in 1.21.6
DebugBlockValue, // Added in 1.21.9
DebugChunkValue, // Added in 1.21.9
DebugEntityValue, // Added in 1.21.9
DebugEvent, // Added in 1.21.9
GameTestHighlightPos, // Added in 1.21.9
}
}

View file

@ -78,6 +78,7 @@ namespace MinecraftClient.Protocol.Handlers
internal const int MC_1_21_5_Version = 770;
internal const int MC_1_21_6_Version = 771;
internal const int MC_1_21_7_Version = 772;
internal const int MC_1_21_9_Version = 773;
private int compression_treshold = -1;
private int autocomplete_transaction_id = 0;
@ -129,21 +130,21 @@ namespace MinecraftClient.Protocol.Handlers
lastSeenMessagesCollector = protocolVersion >= MC_1_19_3_Version ? new(20) : new(5);
chunkBatchStartTime = GetNanos();
if (handler.GetTerrainEnabled() && protocolVersion > MC_1_21_7_Version)
if (handler.GetTerrainEnabled() && protocolVersion > MC_1_21_9_Version)
{
log.Error($"§c{Translations.extra_terrainandmovement_disabled}");
handler.SetTerrainEnabled(false);
}
if (handler.GetInventoryEnabled() &&
protocolVersion is < MC_1_8_Version or > MC_1_21_7_Version)
protocolVersion is < MC_1_8_Version or > MC_1_21_9_Version)
{
log.Error($"§c{Translations.extra_inventory_disabled}");
handler.SetInventoryEnabled(false);
}
if (handler.GetEntityHandlingEnabled() &&
protocolVersion is < MC_1_8_Version or > MC_1_21_7_Version)
protocolVersion is < MC_1_8_Version or > MC_1_21_9_Version)
{
log.Error($"§c{Translations.extra_entity_disabled}");
handler.SetEntityHandlingEnabled(false);
@ -152,9 +153,10 @@ namespace MinecraftClient.Protocol.Handlers
Block.Palette = protocolVersion switch
{
// Block palette
> MC_1_21_7_Version when handler.GetTerrainEnabled() =>
> MC_1_21_9_Version when handler.GetTerrainEnabled() =>
throw new NotImplementedException(Translations.exception_palette_block),
>= MC_1_21_6_Version => new Palette1216(), // 1.21.7 blocks unchanged, reuse 1216
>= MC_1_21_9_Version => new Palette1219(),
>= MC_1_21_6_Version => new Palette1216(), // 1.21.7/1.21.8 blocks unchanged, reuse 1216
>= MC_1_21_5_Version => new Palette1215(),
>= MC_1_21_4_Version => new Palette1214(),
>= MC_1_21_2_Version => new Palette1212(),
@ -175,9 +177,10 @@ namespace MinecraftClient.Protocol.Handlers
entityPalette = protocolVersion switch
{
// Entity palette
> MC_1_21_7_Version when handler.GetEntityHandlingEnabled() =>
> MC_1_21_9_Version when handler.GetEntityHandlingEnabled() =>
throw new NotImplementedException(Translations.exception_palette_entity),
>= MC_1_21_6_Version => new EntityPalette1216(), // 1.21.7 entities unchanged, reuse 1216
>= MC_1_21_9_Version => new EntityPalette1219(),
>= MC_1_21_6_Version => new EntityPalette1216(), // 1.21.7/1.21.8 entities unchanged, reuse 1216
>= MC_1_21_5_Version => new EntityPalette1215(),
>= MC_1_21_4_Version => new EntityPalette1214(),
>= MC_1_21_2_Version => new EntityPalette1212(),
@ -202,8 +205,9 @@ namespace MinecraftClient.Protocol.Handlers
itemPalette = protocolVersion switch
{
// Item palette
> MC_1_21_7_Version when handler.GetInventoryEnabled() =>
> MC_1_21_9_Version when handler.GetInventoryEnabled() =>
throw new NotImplementedException(Translations.exception_palette_item),
>= MC_1_21_9_Version => new ItemPalette1219(),
>= MC_1_21_7_Version => new ItemPalette1217(),
>= MC_1_21_6_Version => new ItemPalette1216(),
>= MC_1_21_5_Version => new ItemPalette1215(),
@ -2661,7 +2665,7 @@ namespace MinecraftClient.Protocol.Handlers
// Also make a palette for field? Will be a lot of work
var healthField = protocolVersion switch
{
> MC_1_21_7_Version => throw new NotImplementedException(Translations
> MC_1_21_9_Version => throw new NotImplementedException(Translations
.exception_palette_healthfield),
// 1.17 and above
>= MC_1_17_Version => 9,

View file

@ -154,7 +154,7 @@ namespace MinecraftClient.Protocol
{
4, 5, 47, 107, 108, 109, 110, 210, 315, 316, 335, 338, 340, 393, 401, 404, 477, 480, 485, 490, 498, 573,
575, 578, 735, 736, 751, 753, 754, 755, 756, 757, 758, 759, 760, 761, 762, 763, 764, 765, 766, 767, 768,
769, 770, 771, 772
769, 770, 771, 772, 773
};
if (Array.IndexOf(suppoertedVersionsProtocol18, protocolVersion) > -1)
@ -365,6 +365,9 @@ namespace MinecraftClient.Protocol
case "1.21.7":
case "1.21.8":
return 772;
case "1.21.9":
case "1.21.10":
return 773;
default:
return 0;
}
@ -451,6 +454,7 @@ namespace MinecraftClient.Protocol
770 => "1.21.5",
771 => "1.21.6",
772 => "1.21.7",
773 => "1.21.9",
_ => "0.0"
};
}

View file

@ -2,46 +2,115 @@
Scripts for analyzing Minecraft version differences and generating MCC palette files.
Requires: Python 3.10+, decompiled MC server source in `MinecraftOfficial/<version>-decompiled/`.
Requires: Python 3.10+
## Decompiling a new MC version
## Data Sources
Two types of data can be used as input:
| Source | How to Get | Authoritative? |
|--------|-----------|---------------|
| Decompiled Java source | `MinecraftDecompiler.jar``MinecraftOfficial/<ver>-decompiled/` | Mostly (see caveat below) |
| Server data reports | `java -DbundlerMainClass=net.minecraft.data.Main -jar server.jar --reports` | **Yes** |
**Important since MC 1.21.9**: Some items and blocks are registered outside `Items.java`/`Blocks.java` field declarations (via block registration callbacks). In these cases, the decompiled source undercounts entries. **Always use server data reports** for item and block palettes when available.
### Decompiling a new MC version
```bash
cd MinecraftOfficial
java -jar MinecraftDecompiler.jar --version 1.21.4 --side SERVER \
--decompile --output 1.21.4-remapped.jar --decompiled-output 1.21.4-decompiled
java -jar MinecraftDecompiler.jar --version 1.21.9 --side SERVER \
--decompile --output 1.21.9-remapped.jar --decompiled-output 1.21.9-decompiled
```
### Generating server data reports
```bash
cd /tmp
java -DbundlerMainClass=net.minecraft.data.Main \
-jar /path/to/server.jar \
--reports --output /tmp/mc_reports
```
This generates:
- `/tmp/mc_reports/reports/registries.json` — all registries with protocol IDs
- `/tmp/mc_reports/reports/blocks.json` — all blocks with block state IDs
- `/tmp/mc_reports/reports/packets.json` — packet protocol definitions
## diff_registries.py — Compare registries between versions
Compares Items, EntityTypes, Blocks, DataComponents, and EntityDataSerializers between two MC versions. Reports whether each palette needs updating, lists added/removed entries, and shows ID shift statistics.
```bash
python3 tools/diff_registries.py 1.20.6 1.21.1
# Basic comparison (decompiled source only)
python3 tools/diff_registries.py 1.21.8 1.21.9
# With cross-validation against server registries.json (recommended)
python3 tools/diff_registries.py 1.21.8 1.21.9 --registry /tmp/mc_reports/reports/registries.json
```
The `--registry` flag enables cross-validation: compares the count and set of entries found in decompiled Java source against the server's authoritative registry. Any mismatches indicate that palette generation must use server data instead of Java source.
Output indicates for each registry:
- **IDENTICAL** → reuse existing palette
- **PALETTE UPDATE NEEDED** → create new palette file + update version routing
- **Count MISMATCH** (with --registry) → server has entries not in Java source
## gen_item_palette.py — Generate ItemPalette C# file
Reads `Items.java` field declaration order to generate a complete `ItemPaletteXXX.cs`.
Two modes:
```bash
# Preferred: from server registries.json (accurate since 1.21.9)
python3 tools/gen_item_palette.py --from-registry /tmp/mc_reports/reports/registries.json 1219
# Legacy: from decompiled Items.java
python3 tools/gen_item_palette.py 1.21.1 121
# → MinecraftClient/Inventory/ItemPalettes/ItemPalette121.cs
```
Also validates each item name against `ItemType.cs` and warns about missing enum values.
Output: `MinecraftClient/Inventory/ItemPalettes/ItemPalette<suffix>.cs`
Validates each item name against `ItemType.cs` and warns about missing enum values. Add missing values to `ItemType.cs` in alphabetical order before compiling.
## gen_block_palette.py — Generate BlockPalette C# file
```bash
python3 tools/gen_block_palette.py /tmp/mc_reports/reports/blocks.json 1219
# → MinecraftClient/Mapping/BlockPalettes/Palette1219.cs
```
Generates a complete block palette with block state ID ranges from the server's `blocks.json`. Validates against `Material.cs` and warns about missing enum values.
## gen_entity_palette.py — Generate EntityPalette C# file
```bash
python3 tools/gen_entity_palette.py /tmp/mc_reports/reports/registries.json 1219
# → MinecraftClient/Mapping/EntityPalettes/EntityPalette1219.cs
```
Generates entity type palette from server's `registries.json`. Validates against `EntityType.cs` and warns about missing enum values.
## gen_entity_metadata_palette.py — Generate EntityMetadataPalette C# file
Reads `EntityDataSerializers.java` static block registration order to generate `EntityMetadataPaletteXXX.cs`.
```bash
python3 tools/gen_entity_metadata_palette.py 1.20.6 1206
# → MinecraftClient/Mapping/EntityMetadataPalettes/EntityMetadataPalette1206.cs
python3 tools/gen_entity_metadata_palette.py 1.21.9 1219
# → MinecraftClient/Mapping/EntityMetadataPalettes/EntityMetadataPalette1219.cs
```
The script maps Java field names to MCC's `EntityMetaDataType` enum. If a new serializer type appears that isn't in the mapping table, it will warn you to update both the script's `FIELD_TO_ENUM` dict and MCC's `EntityMetaDataType.cs` enum.
Reads `EntityDataSerializers.java` static block registration order. Maps Java field names to MCC's `EntityMetaDataType` enum. If a new serializer type appears that isn't in the mapping table, it will warn you to update:
1. The script's `FIELD_TO_ENUM` dict
2. MCC's `EntityMetaDataType.cs` enum
3. `DataTypes.cs` ReadNextMetadata() read logic
## Recommended workflow
1. Generate server reports (Step 0)
2. Run `diff_registries.py --registry` to identify changes and validate source completeness
3. For each registry needing update:
- Items: `gen_item_palette.py --from-registry`
- Blocks: `gen_block_palette.py`
- Entities: `gen_entity_palette.py`
- Metadata: `gen_entity_metadata_palette.py`
4. Add any missing enum values to `ItemType.cs`, `Material.cs`, `EntityType.cs`, `EntityMetaDataType.cs`
5. Update version routing (see SKILL.md)
6. Build and test

View file

@ -6,12 +6,19 @@ Compares Items, EntityTypes, Blocks, DataComponents, and EntityDataSerializers
to determine which MCC palettes need updating for a new MC version.
Usage:
python3 tools/diff_registries.py <old_version> <new_version>
python3 tools/diff_registries.py <old_version> <new_version> [--registry <registries.json>]
Example:
Examples:
python3 tools/diff_registries.py 1.20.6 1.21.1
python3 tools/diff_registries.py 1.21.8 1.21.9 --registry /tmp/mc_reports/reports/registries.json
The optional --registry flag cross-validates decompiled source counts against
the server's authoritative registries.json (generated via --reports).
Since MC 1.21.9, some items/blocks are registered outside Items.java/Blocks.java,
making this cross-validation essential for detecting hidden entries.
"""
import json
import re
import sys
import os
@ -65,7 +72,7 @@ def extract_static_register_order(filepath: Path) -> list[str]:
return results
def compare_lists(old: list[str], new: list[str], label: str):
def compare_lists(old: list[str], new: list[str], label: str) -> bool:
"""Compare two ordered lists and report differences."""
set_old, set_new = set(old), set(new)
added = sorted(set_new - set_old)
@ -117,7 +124,46 @@ def compare_lists(old: list[str], new: list[str], label: str):
return True
def diff_items(old_dir: Path, new_dir: Path):
def cross_validate(registry_data: dict, java_entries: list[str], registry_key: str,
label: str, convert_fn=None):
"""Cross-validate Java source entries against server registries.json."""
reg = registry_data.get(registry_key, {}).get("entries", {})
server_names = set()
for key in reg:
name = key.removeprefix("minecraft:")
server_names.add(name)
if convert_fn:
java_names = set(convert_fn(n) for n in java_entries)
else:
java_names = set(n.lower() for n in java_entries)
server_count = len(server_names)
java_count = len(java_names)
print(f"\n --- Cross-validation: {label} ---")
print(f" Java source: {java_count} entries, Server registry: {server_count} entries")
if server_count == java_count:
print(f" ✓ Counts match — Java source is complete")
else:
diff = server_count - java_count
print(f" ⚠ Count MISMATCH: server has {diff:+d} entries vs Java source")
extra_in_server = server_names - java_names
extra_in_java = java_names - server_names
if extra_in_server:
print(f" In server but NOT in Java source ({len(extra_in_server)}):")
for n in sorted(extra_in_server):
pid = reg[f"minecraft:{n}"]["protocol_id"]
print(f" [{pid}] {n}")
print(f" ⚠ MUST use --from-registry / server data to generate palette!")
if extra_in_java:
print(f" In Java source but NOT in server ({len(extra_in_java)}):")
for n in sorted(extra_in_java):
print(f" {n}")
def diff_items(old_dir: Path, new_dir: Path, registry_data: dict | None = None):
old_f = find_java_file(old_dir, "net/minecraft/world/item/Items.java")
new_f = find_java_file(new_dir, "net/minecraft/world/item/Items.java")
if not old_f or not new_f:
@ -128,8 +174,12 @@ def diff_items(old_dir: Path, new_dir: Path):
new = extract_field_names(new_f, pattern)
compare_lists(old, new, "Items.java (Item registry)")
if registry_data:
cross_validate(registry_data, new, "minecraft:item", "Items",
convert_fn=lambda n: n.lower())
def diff_entity_types(old_dir: Path, new_dir: Path):
def diff_entity_types(old_dir: Path, new_dir: Path, registry_data: dict | None = None):
old_f = find_java_file(old_dir, "net/minecraft/world/entity/EntityType.java")
new_f = find_java_file(new_dir, "net/minecraft/world/entity/EntityType.java")
if not old_f or not new_f:
@ -139,8 +189,12 @@ def diff_entity_types(old_dir: Path, new_dir: Path):
new = extract_register_multiline(new_f)
compare_lists(old, new, "EntityType.java (Entity registry)")
if registry_data:
cross_validate(registry_data, new, "minecraft:entity_type", "EntityType",
convert_fn=lambda n: n)
def diff_blocks(old_dir: Path, new_dir: Path):
def diff_blocks(old_dir: Path, new_dir: Path, registry_data: dict | None = None):
old_f = find_java_file(old_dir, "net/minecraft/world/level/block/Blocks.java")
new_f = find_java_file(new_dir, "net/minecraft/world/level/block/Blocks.java")
if not old_f or not new_f:
@ -150,6 +204,10 @@ def diff_blocks(old_dir: Path, new_dir: Path):
new = extract_register_multiline(new_f)
compare_lists(old, new, "Blocks.java (Block registry)")
if registry_data:
cross_validate(registry_data, new, "minecraft:block", "Blocks",
convert_fn=lambda n: n)
def diff_data_components(old_dir: Path, new_dir: Path):
old_f = find_java_file(old_dir, "net/minecraft/core/component/DataComponents.java")
@ -183,11 +241,23 @@ def diff_entity_data_serializers(old_dir: Path, new_dir: Path):
def main():
if len(sys.argv) != 3:
# Parse arguments
args = sys.argv[1:]
registry_path = None
if "--registry" in args:
idx = args.index("--registry")
if idx + 1 >= len(args):
print("Error: --registry requires a path argument")
sys.exit(1)
registry_path = Path(args[idx + 1])
args = args[:idx] + args[idx + 2:]
if len(args) != 2:
print(__doc__)
sys.exit(1)
old_ver, new_ver = sys.argv[1], sys.argv[2]
old_ver, new_ver = args[0], args[1]
old_dir = DECOMPILED_ROOT / f"{old_ver}-decompiled"
new_dir = DECOMPILED_ROOT / f"{new_ver}-decompiled"
@ -199,13 +269,22 @@ def main():
f"--output {v}-remapped.jar --decompiled-output {v}-decompiled")
sys.exit(1)
registry_data = None
if registry_path:
if not registry_path.exists():
print(f"Error: {registry_path} not found")
sys.exit(1)
with open(registry_path) as f:
registry_data = json.load(f)
print(f"Loaded server registries.json for cross-validation")
print(f"Comparing MC {old_ver}{new_ver}")
print(f"Old: {old_dir}")
print(f"New: {new_dir}")
diff_items(old_dir, new_dir)
diff_entity_types(old_dir, new_dir)
diff_blocks(old_dir, new_dir)
diff_items(old_dir, new_dir, registry_data)
diff_entity_types(old_dir, new_dir, registry_data)
diff_blocks(old_dir, new_dir, registry_data)
diff_data_components(old_dir, new_dir)
diff_entity_data_serializers(old_dir, new_dir)
@ -215,6 +294,10 @@ def main():
print(" Review each section above. For any marked 'PALETTE UPDATE NEEDED',")
print(" create a new palette file in MCC and update the version routing.")
print(" For 'IDENTICAL' sections, the existing palette can be reused.")
if registry_data:
print("\n Cross-validation was performed against server registries.json.")
print(" If any count mismatches were found, use server data generator output")
print(" (--from-registry) instead of decompiled Java source for palette generation.")
if __name__ == "__main__":

119
tools/gen_block_palette.py Normal file
View file

@ -0,0 +1,119 @@
#!/usr/bin/env python3
"""
Generate an MCC BlockPalette C# file from server-generated blocks.json.
The blocks.json file is generated by running:
java -DbundlerMainClass=net.minecraft.data.Main -jar server.jar --reports
Usage:
python3 tools/gen_block_palette.py <blocks.json> <suffix>
Example:
python3 tools/gen_block_palette.py /tmp/mc_reports/reports/blocks.json 1219
# Generates Palette1219.cs
"""
import json
import re
import sys
from pathlib import Path
OUTPUT_DIR = (Path(__file__).resolve().parent.parent /
"MinecraftClient" / "Mapping" / "BlockPalettes")
MATERIAL_CS = OUTPUT_DIR.parent / "Material.cs"
def mc_name_to_csharp(mc_name: str) -> str:
"""Convert minecraft:snake_case to PascalCase C# enum name."""
name = mc_name.removeprefix("minecraft:")
return "".join(word.capitalize() for word in name.split("_"))
def load_known_materials() -> set[str]:
known = set()
if MATERIAL_CS.exists():
with open(MATERIAL_CS) as f:
for line in f:
m = re.match(r'\s+(\w+),?\s*$', line)
if m:
known.add(m.group(1))
return known
def main():
if len(sys.argv) != 3:
print(__doc__)
sys.exit(1)
blocks_json = Path(sys.argv[1])
class_suffix = sys.argv[2]
if not blocks_json.exists():
print(f"Error: {blocks_json} not found")
sys.exit(1)
with open(blocks_json) as f:
data = json.load(f)
# Build (min_state, max_state, cs_name) for each block, sorted by min_state
block_ranges = []
for block_key, block_info in data.items():
cs_name = mc_name_to_csharp(block_key)
states = block_info.get("states", [])
state_ids = [s["id"] for s in states]
if state_ids:
block_ranges.append((min(state_ids), max(state_ids), cs_name))
block_ranges.sort(key=lambda x: x[0])
print(f"Loaded {len(block_ranges)} blocks from {blocks_json}")
max_state = max(r[1] for r in block_ranges)
print(f"State ID range: 0 - {max_state}")
known_materials = load_known_materials()
missing = [cs for _, _, cs in block_ranges if known_materials and cs not in known_materials]
if missing:
print(f"\nWARNING: {len(missing)} blocks not found in Material.cs enum:")
for cs_name in missing:
print(f" {cs_name}")
print("\nYou need to add these to Material.cs before the palette will compile.")
print("Insert them in alphabetical order within the enum.")
class_name = f"Palette{class_suffix}"
output_path = OUTPUT_DIR / f"{class_name}.cs"
lines = [
"using System.Collections.Generic;",
"",
"namespace MinecraftClient.Mapping.BlockPalettes",
"{",
f" public class {class_name} : BlockPalette",
" {",
" private static readonly Dictionary<int, Material> materials = new();",
"",
f" static {class_name}()",
" {",
]
for min_s, max_s, cs_name in block_ranges:
lines.append(f" for (int i = {min_s}; i <= {max_s}; i++)")
lines.append(f" materials[i] = Material.{cs_name};")
lines += [
" }",
"",
" protected override Dictionary<int, Material> GetDict()",
" {",
" return materials;",
" }",
" }",
"}",
"",
]
output_path.write_text("\n".join(lines))
print(f"Generated {output_path} with {len(block_ranges)} blocks ({max_state + 1} total states)")
if __name__ == "__main__":
main()

View file

@ -57,8 +57,11 @@ FIELD_TO_ENUM = {
"PAINTING_VARIANT": "PaintingVariant",
"SNIFFER_STATE": "SnifferState",
"ARMADILLO_STATE": "ArmadilloState",
"COPPER_GOLEM_STATE": "CopperGolemState",
"WEATHERING_COPPER_STATE": "WeatheringCopperState",
"VECTOR3": "Vector3",
"QUATERNION": "Quaternion",
"RESOLVABLE_PROFILE": "ResolvableProfile",
}

111
tools/gen_entity_palette.py Normal file
View file

@ -0,0 +1,111 @@
#!/usr/bin/env python3
"""
Generate an MCC EntityPalette C# file from server-generated registries.json.
The registries.json file is generated by running:
java -DbundlerMainClass=net.minecraft.data.Main -jar server.jar --reports
Usage:
python3 tools/gen_entity_palette.py <registries.json> <suffix>
Example:
python3 tools/gen_entity_palette.py /tmp/mc_reports/reports/registries.json 1219
# Generates EntityPalette1219.cs
"""
import json
import re
import sys
from pathlib import Path
OUTPUT_DIR = (Path(__file__).resolve().parent.parent /
"MinecraftClient" / "Mapping" / "EntityPalettes")
ENTITY_TYPE_CS = OUTPUT_DIR.parent / "EntityType.cs"
def mc_name_to_csharp(mc_name: str) -> str:
"""Convert minecraft:snake_case to PascalCase C# enum name."""
name = mc_name.removeprefix("minecraft:")
return "".join(word.capitalize() for word in name.split("_"))
def load_known_entity_types() -> set[str]:
known = set()
if ENTITY_TYPE_CS.exists():
with open(ENTITY_TYPE_CS) as f:
for line in f:
m = re.match(r'\s+(\w+),?\s*$', line)
if m:
known.add(m.group(1))
return known
def main():
if len(sys.argv) != 3:
print(__doc__)
sys.exit(1)
registry_path = Path(sys.argv[1])
class_suffix = sys.argv[2]
if not registry_path.exists():
print(f"Error: {registry_path} not found")
sys.exit(1)
with open(registry_path) as f:
data = json.load(f)
entities_reg = data.get("minecraft:entity_type", {}).get("entries", {})
mappings = []
for entity_key, info in entities_reg.items():
pid = info["protocol_id"]
cs_name = mc_name_to_csharp(entity_key)
mappings.append((pid, cs_name))
mappings.sort(key=lambda x: x[0])
print(f"Loaded {len(mappings)} entity types from {registry_path}")
known = load_known_entity_types()
missing = [cs for _, cs in mappings if known and cs not in known]
if missing:
print(f"\nWARNING: {len(missing)} entity types not found in EntityType.cs enum:")
for cs_name in missing:
print(f" {cs_name}")
print("\nYou need to add these to EntityType.cs before the palette will compile.")
print("Insert them in alphabetical order within the enum.")
class_name = f"EntityPalette{class_suffix}"
output_path = OUTPUT_DIR / f"{class_name}.cs"
lines = [
"using System.Collections.Generic;",
"",
"namespace MinecraftClient.Mapping.EntityPalettes",
"{",
f" public class {class_name} : EntityPalette",
" {",
" private static readonly Dictionary<int, EntityType> mappings = new();",
"",
f" static {class_name}()",
" {",
]
for pid, cs_name in mappings:
lines.append(f" mappings[{pid}] = EntityType.{cs_name};")
lines += [
" }",
"",
" protected override Dictionary<int, EntityType> GetDict()",
" {",
" return mappings;",
" }",
" }",
"}",
"",
]
output_path.write_text("\n".join(lines))
print(f"Generated {output_path} with {len(mappings)} entity types")
if __name__ == "__main__":
main()

View file

@ -1,36 +1,43 @@
#!/usr/bin/env python3
"""
Generate an MCC ItemPalette C# file from decompiled Items.java.
Generate an MCC ItemPalette C# file.
Reads public static final Item field declarations (which define item IDs
by declaration order) and generates a complete C# palette class.
Supports two input modes:
1. Server registry (preferred since 1.21.9):
python3 tools/gen_item_palette.py --from-registry /tmp/mc_reports/reports/registries.json <suffix>
Usage:
python3 tools/gen_item_palette.py <mc_version> <class_suffix>
2. Decompiled Items.java (legacy):
python3 tools/gen_item_palette.py <mc_version> <suffix>
Example:
python3 tools/gen_item_palette.py 1.21.1 121
# Generates ItemPalette121.cs
The --from-registry mode uses the server's authoritative protocol_id assignments,
which is required since MC 1.21.9 where some items are registered outside Items.java.
The <class_suffix> determines the class name (ItemPalette<suffix>) and
should match MCC's naming convention (e.g., 121 for 1.21, 1206 for 1.20.6).
The <suffix> determines the class name (ItemPalette<suffix>) and should match MCC's
naming convention (e.g., 121 for 1.21, 1219 for 1.21.9).
"""
import json
import re
import sys
from pathlib import Path
DECOMPILED_ROOT = Path(__file__).resolve().parent.parent / "MinecraftOfficial"
OUTPUT_DIR = Path(__file__).resolve().parent.parent / "MinecraftClient" / "Inventory" / "ItemPalettes"
ITEM_TYPE_CS = OUTPUT_DIR.parent / "ItemType.cs"
# Java field name → C# ItemType enum name
# Most conversions are automatic (SCREAMING_SNAKE → PascalCase).
# Add manual overrides here for irregular names.
OVERRIDES = {
"CUT_STANDSTONE_SLAB": "CutSandstoneSlab", # Mojang typo in source
}
def mc_name_to_csharp(mc_name: str) -> str:
"""Convert minecraft:snake_case to PascalCase C# enum name."""
name = mc_name.removeprefix("minecraft:")
if name.upper() in OVERRIDES:
return OVERRIDES[name.upper()]
return "".join(word.capitalize() for word in name.split("_"))
def java_to_csharp_name(java_name: str) -> str:
"""Convert SCREAMING_SNAKE_CASE Java field name to PascalCase C# enum name."""
if java_name in OVERRIDES:
@ -38,52 +45,81 @@ def java_to_csharp_name(java_name: str) -> str:
return "".join(word.capitalize() for word in java_name.lower().split("_"))
def main():
if len(sys.argv) != 3:
print(__doc__)
sys.exit(1)
def load_known_enums() -> set[str]:
known = set()
if ITEM_TYPE_CS.exists():
with open(ITEM_TYPE_CS) as f:
for line in f:
m = re.match(r'\s+(\w+),?\s*$', line)
if m and m.group(1) not in ("Null", "Unknown"):
known.add(m.group(1))
return known
mc_version = sys.argv[1]
class_suffix = sys.argv[2]
def items_from_registry(registry_path: Path) -> list[tuple[int, str]]:
"""Load items from server registries.json, returns sorted (protocol_id, cs_name) pairs."""
with open(registry_path) as f:
data = json.load(f)
items_reg = data.get("minecraft:item", {}).get("entries", {})
result = []
for item_key, info in items_reg.items():
pid = info["protocol_id"]
cs_name = mc_name_to_csharp(item_key)
result.append((pid, cs_name))
result.sort(key=lambda x: x[0])
return result
def items_from_java(mc_version: str) -> list[tuple[int, str]]:
"""Load items from decompiled Items.java field declaration order."""
version_dir = DECOMPILED_ROOT / f"{mc_version}-decompiled"
items_java = version_dir / "net" / "minecraft" / "world" / "item" / "Items.java"
if not items_java.exists():
print(f"Error: {items_java} not found")
sys.exit(1)
pattern = re.compile(r'\s+public static final Item (\w+)\s*=')
field_names = []
result = []
with open(items_java) as f:
for line in f:
m = pattern.match(line)
if m:
field_names.append(m.group(1))
idx = len(result)
cs_name = java_to_csharp_name(m.group(1))
result.append((idx, cs_name))
return result
print(f"Found {len(field_names)} items in MC {mc_version}")
# Verify enum name conversion against existing ItemType.cs
item_type_cs = OUTPUT_DIR.parent / "ItemType.cs"
known_enums = set()
if item_type_cs.exists():
with open(item_type_cs) as f:
for line in f:
m = re.match(r'\s+(\w+),?\s*$', line)
if m and m.group(1) not in ("Null", "Unknown"):
known_enums.add(m.group(1))
def main():
if len(sys.argv) < 3:
print(__doc__)
sys.exit(1)
missing = []
mappings = []
for i, name in enumerate(field_names):
cs_name = java_to_csharp_name(name)
mappings.append((i, cs_name))
if known_enums and cs_name not in known_enums:
missing.append((i, name, cs_name))
from_registry = sys.argv[1] == "--from-registry"
if from_registry:
if len(sys.argv) != 4:
print("Usage: gen_item_palette.py --from-registry <registries.json> <suffix>")
sys.exit(1)
registry_path = Path(sys.argv[2])
class_suffix = sys.argv[3]
if not registry_path.exists():
print(f"Error: {registry_path} not found")
sys.exit(1)
mappings = items_from_registry(registry_path)
print(f"Loaded {len(mappings)} items from {registry_path}")
else:
mc_version = sys.argv[1]
class_suffix = sys.argv[2]
mappings = items_from_java(mc_version)
print(f"Found {len(mappings)} items in MC {mc_version} Items.java")
known_enums = load_known_enums()
missing = [(pid, cs) for pid, cs in mappings if known_enums and cs not in known_enums]
if missing:
print(f"\nWARNING: {len(missing)} items not found in ItemType.cs enum:")
for idx, java_name, cs_name in missing:
print(f" [{idx}] {java_name} -> {cs_name}")
for pid, cs_name in missing:
print(f" [{pid}] {cs_name}")
print("\nYou need to add these to ItemType.cs before the palette will compile.")
print("Insert them in alphabetical order within the enum.")
@ -102,8 +138,8 @@ def main():
f" static {class_name}()",
" {",
]
for idx, cs_name in mappings:
lines.append(f" mappings[{idx}] = ItemType.{cs_name};")
for pid, cs_name in mappings:
lines.append(f" mappings[{pid}] = ItemType.{cs_name};")
lines += [
" }",
"",