From f4ad24746ccd7e1b1a3864c026688eef98b6e2ab Mon Sep 17 00:00:00 2001 From: ReinforceZwei <39955851+ReinforceZwei@users.noreply.github.com> Date: Fri, 24 Mar 2023 19:46:25 +0800 Subject: [PATCH] Wire up entity metadata palette --- MinecraftClient/Mapping/EntityMetaDataType.cs | 1 + .../Mapping/EntityMetadataPalette.cs | 28 + .../EntityMetadataPalette1191.cs | 2 +- .../EntityMetadataPalette1193.cs | 2 +- .../Protocol/Handlers/DataTypes.cs | 523 +++++++----------- .../Protocol/Handlers/Protocol18.cs | 6 +- 6 files changed, 225 insertions(+), 337 deletions(-) diff --git a/MinecraftClient/Mapping/EntityMetaDataType.cs b/MinecraftClient/Mapping/EntityMetaDataType.cs index cb0fb85d..6bd3ce02 100644 --- a/MinecraftClient/Mapping/EntityMetaDataType.cs +++ b/MinecraftClient/Mapping/EntityMetaDataType.cs @@ -25,6 +25,7 @@ public enum EntityMetaDataType Pose, CatVariant, FrogVariant, + GlobalPosition, OptionalGlobalPosition, PaintingVariant, SnifferState, diff --git a/MinecraftClient/Mapping/EntityMetadataPalette.cs b/MinecraftClient/Mapping/EntityMetadataPalette.cs index 063ce383..a0738408 100644 --- a/MinecraftClient/Mapping/EntityMetadataPalette.cs +++ b/MinecraftClient/Mapping/EntityMetadataPalette.cs @@ -1,3 +1,6 @@ +using MinecraftClient.Mapping.EntityMetadataPalettes; +using MinecraftClient.Protocol.Handlers; +using System; using System.Collections.Generic; namespace MinecraftClient.Mapping; @@ -5,4 +8,29 @@ namespace MinecraftClient.Mapping; public abstract class EntityMetadataPalette { public abstract Dictionary GetEntityMetadataMappingsList(); + + public EntityMetaDataType GetDataType(int typeId) + { + return GetEntityMetadataMappingsList()[typeId]; + } + + public static EntityMetadataPalette GetPalette(int protocolVersion) + { + if (protocolVersion < Protocol18Handler.MC_1_9_1_Version) + return new EntityMetadataPalette19(); + else if (protocolVersion <= Protocol18Handler.MC_1_11_2_Version) + return new EntityMetadataPalette111(); + else if (protocolVersion <= Protocol18Handler.MC_1_13_2_Version) + return new EntityMetadataPalette113(); + else if (protocolVersion <= Protocol18Handler.MC_1_14_Version) + return new EntityMetadataPalette114(); + else if (protocolVersion <= Protocol18Handler.MC_1_19_2_Version) + return new EntityMetadataPalette1191(); + else if (protocolVersion <= Protocol18Handler.MC_1_19_3_Version) + return new EntityMetadataPalette1193(); + else if (protocolVersion <= Protocol18Handler.MC_1_19_4_Version) + return new EntityMetadataPalette1194(); + else + throw new NotImplementedException(); + } } \ No newline at end of file diff --git a/MinecraftClient/Mapping/EntityMetadataPalettes/EntityMetadataPalette1191.cs b/MinecraftClient/Mapping/EntityMetadataPalettes/EntityMetadataPalette1191.cs index 13216fa0..fdea2a62 100644 --- a/MinecraftClient/Mapping/EntityMetadataPalettes/EntityMetadataPalette1191.cs +++ b/MinecraftClient/Mapping/EntityMetadataPalettes/EntityMetadataPalette1191.cs @@ -27,7 +27,7 @@ public class EntityMetadataPalette1191 : EntityMetadataPalette { 18, EntityMetaDataType.Pose }, { 19, EntityMetaDataType.CatVariant }, { 20, EntityMetaDataType.FrogVariant }, - { 21, EntityMetaDataType.OptionalGlobalPosition }, + { 21, EntityMetaDataType.GlobalPosition }, { 22, EntityMetaDataType.PaintingVariant } }; diff --git a/MinecraftClient/Mapping/EntityMetadataPalettes/EntityMetadataPalette1193.cs b/MinecraftClient/Mapping/EntityMetadataPalettes/EntityMetadataPalette1193.cs index 3c4a5451..859cb4c5 100644 --- a/MinecraftClient/Mapping/EntityMetadataPalettes/EntityMetadataPalette1193.cs +++ b/MinecraftClient/Mapping/EntityMetadataPalettes/EntityMetadataPalette1193.cs @@ -28,7 +28,7 @@ public class EntityMetadataPalette1193 : EntityMetadataPalette { 19, EntityMetaDataType.Pose }, { 20, EntityMetaDataType.CatVariant }, { 21, EntityMetaDataType.FrogVariant }, - { 22, EntityMetaDataType.OptionalGlobalPosition }, + { 22, EntityMetaDataType.GlobalPosition }, { 23, EntityMetaDataType.PaintingVariant } }; diff --git a/MinecraftClient/Protocol/Handlers/DataTypes.cs b/MinecraftClient/Protocol/Handlers/DataTypes.cs index 84672875..ff2833f3 100644 --- a/MinecraftClient/Protocol/Handlers/DataTypes.cs +++ b/MinecraftClient/Protocol/Handlers/DataTypes.cs @@ -590,361 +590,216 @@ namespace MinecraftClient.Protocol.Handlers } //TODO: Refactor this to use new Entity Metadata Palettes - public Dictionary ReadNextMetadata(Queue cache, ItemPalette itemPalette) + public Dictionary ReadNextMetadata(Queue cache, ItemPalette itemPalette, EntityMetadataPalette metadataPalette) { + if (protocolversion <= Protocol18Handler.MC_1_8_Version) + throw new NotImplementedException(); // Require sepcial implementation + Dictionary data = new(); byte key = ReadNextByte(cache); while (key != 0xff) { - int type = ReadNextVarInt(cache); + int typeId = ReadNextVarInt(cache); + EntityMetaDataType type; + try + { + type = metadataPalette.GetDataType(typeId); + } + catch (KeyNotFoundException) + { + throw new System.IO.InvalidDataException("Unknown Metadata Type ID " + typeId + + ". Is this up to date for new MC Version?"); + } // Value's data type is depended on Type object? value = null; - // starting from 1.13, Optional Chat is inserted as number 5 in 1.13 and IDs after 5 got shifted. - // Increase type ID by 1 if - // - below 1.13 - // - type ID larger than 4 - if (protocolversion < Protocol18Handler.MC_1_13_Version) + switch (type) { - if (type > 4) - ++type; - } - - // Temporary - if (protocolversion >= Protocol18Handler.MC_1_19_3_Version) - { - switch (type) - { - case 0: // byte - value = ReadNextByte(cache); - break; - case 1: // VarInt - value = ReadNextVarInt(cache); - break; - case 2: // Long - value = ReadNextLong(cache); - break; - ; - case 3: // Float - value = ReadNextFloat(cache); - break; - case 4: // String + case EntityMetaDataType.Byte: // byte + value = ReadNextByte(cache); + break; + case EntityMetaDataType.VarInt: // VarInt + value = ReadNextVarInt(cache); + break; + case EntityMetaDataType.VarLong: // Long + value = ReadNextVarLong(cache); + break; + case EntityMetaDataType.Float: // Float + value = ReadNextFloat(cache); + break; + case EntityMetaDataType.String: // String + value = ReadNextString(cache); + break; + case EntityMetaDataType.Chat: // Chat + value = ReadNextString(cache); + break; + case EntityMetaDataType.OptionalChat: // Optional Chat + if (ReadNextBool(cache)) value = ReadNextString(cache); - break; - case 5: // Chat - value = ReadNextString(cache); - break; - case 6: // Optional Chat - if (ReadNextBool(cache)) - value = ReadNextString(cache); - break; - case 7: // Slot - value = ReadNextItemSlot(cache, itemPalette); - break; - case 8: // Boolean - value = ReadNextBool(cache); - break; - case 9: // Rotation (3x floats) - value = new List - { - ReadNextFloat(cache), - ReadNextFloat(cache), - ReadNextFloat(cache) - }; - break; - case 10: // Position + break; + case EntityMetaDataType.Slot: // Slot + value = ReadNextItemSlot(cache, itemPalette); + break; + case EntityMetaDataType.Boolean: // Boolean + value = ReadNextBool(cache); + break; + case EntityMetaDataType.Rotation: // Rotation (3x floats) + value = new List + { + ReadNextFloat(cache), + ReadNextFloat(cache), + ReadNextFloat(cache) + }; + break; + case EntityMetaDataType.Position: // Position + value = ReadNextLocation(cache); + break; + case EntityMetaDataType.OptionalPosition: // Optional Position + if (ReadNextBool(cache)) + { value = ReadNextLocation(cache); - break; - case 11: // Optional Position - if (ReadNextBool(cache)) - { - value = ReadNextLocation(cache); - } - - break; - case 12: // Direction (VarInt) - value = ReadNextVarInt(cache); - break; - case 13: // Optional UUID - if (ReadNextBool(cache)) - { - value = ReadNextUUID(cache); - } - - break; - case 14: // BlockID (VarInt) - value = ReadNextVarInt(cache); - break; - case 15: // Optional BlockID (VarInt) - value = ReadNextVarInt(cache); - break; - case 16: // NBT - value = ReadNextNbt(cache); - break; - case 17: // Particle - // Currently not handled. Reading data only - int ParticleID = ReadNextVarInt(cache); - // TODO: Go through wiki history and write for every version - // 1.19.3 - https://wiki.vg/index.php?title=Data_types&oldid=17986 - // 1.18 - https://wiki.vg/index.php?title=Data_types&oldid=17180 - // 1.17 - https://wiki.vg/index.php?title=Data_types&oldid=16740 - // 1.15 - https://wiki.vg/index.php?title=Data_types&oldid=15338 - // 1.13 - https://wiki.vg/index.php?title=Data_types&oldid=14271 - switch (ParticleID) - { - case 2: + } + break; + case EntityMetaDataType.Direction: // Direction (VarInt) + value = ReadNextVarInt(cache); + break; + case EntityMetaDataType.OptionalUuid: // Optional UUID + if (ReadNextBool(cache)) + { + value = ReadNextUUID(cache); + } + break; + case EntityMetaDataType.BlockId: // BlockID (VarInt) + value = ReadNextVarInt(cache); + break; + case EntityMetaDataType.OptionalBlockId: // Optional BlockID (VarInt) + value = ReadNextVarInt(cache); + break; + case EntityMetaDataType.Nbt: // NBT + value = ReadNextNbt(cache); + break; + case EntityMetaDataType.Particle: // Particle + // Currently not handled. Reading data only + int ParticleID = ReadNextVarInt(cache); + // TODO: Go through wiki history and write for every version + // 1.19.3 - https://wiki.vg/index.php?title=Data_types&oldid=17986 + // 1.18 - https://wiki.vg/index.php?title=Data_types&oldid=17180 + // 1.17 - https://wiki.vg/index.php?title=Data_types&oldid=16740 + // 1.15 - https://wiki.vg/index.php?title=Data_types&oldid=15338 + // 1.13 - https://wiki.vg/index.php?title=Data_types&oldid=14271 + switch (ParticleID) + { + case 2: + ReadNextVarInt(cache); + break; + case 3: + ReadNextVarInt(cache); + break; + case 14: + ReadNextFloat(cache); + ReadNextFloat(cache); + ReadNextFloat(cache); + ReadNextFloat(cache); + break; + case 15: + ReadNextFloat(cache); + ReadNextFloat(cache); + ReadNextFloat(cache); + ReadNextFloat(cache); + ReadNextFloat(cache); + ReadNextFloat(cache); + ReadNextFloat(cache); + break; + case 25: + ReadNextVarInt(cache); + break; + case 30: + ReadNextFloat(cache); + break; + case 39: + ReadNextItemSlot(cache, itemPalette); + break; + case 40: + string positionSourceType = ReadNextString(cache); + if (positionSourceType == "minecraft:block") + { + ReadNextLocation(cache); + } + else if (positionSourceType == "minecraft:entity") + { ReadNextVarInt(cache); - break; - case 3: - ReadNextVarInt(cache); - break; - case 14: ReadNextFloat(cache); - ReadNextFloat(cache); - ReadNextFloat(cache); - ReadNextFloat(cache); - break; - case 15: - ReadNextFloat(cache); - ReadNextFloat(cache); - ReadNextFloat(cache); - ReadNextFloat(cache); - ReadNextFloat(cache); - ReadNextFloat(cache); - ReadNextFloat(cache); - break; - case 25: - ReadNextVarInt(cache); - break; - case 30: - ReadNextFloat(cache); - break; - case 39: - ReadNextItemSlot(cache, itemPalette); - break; - case 40: - string positionSourceType = ReadNextString(cache); - if (positionSourceType == "minecraft:block") - { - ReadNextLocation(cache); - } - else if (positionSourceType == "minecraft:entity") - { - ReadNextVarInt(cache); - ReadNextFloat(cache); - } + } - ReadNextVarInt(cache); - break; - } + ReadNextVarInt(cache); + break; + } - break; - case 18: // Villager Data (3x VarInt) - value = new List - { - ReadNextVarInt(cache), - ReadNextVarInt(cache), - ReadNextVarInt(cache) - }; - break; - case 19: // Optional VarInt - if (ReadNextBool(cache)) - { - value = ReadNextVarInt(cache); - } - - break; - case 20: // Pose + break; + case EntityMetaDataType.VillagerData: // Villager Data (3x VarInt) + value = new List + { + ReadNextVarInt(cache), + ReadNextVarInt(cache), + ReadNextVarInt(cache) + }; + break; + case EntityMetaDataType.OptionalVarInt: // Optional VarInt + if (ReadNextBool(cache)) + { value = ReadNextVarInt(cache); - break; - case 21: // Cat Variant - value = ReadNextVarInt(cache); - break; - case 22: // Frog Varint - value = ReadNextVarInt(cache); - break; - case 23: // GlobalPos at 1.19.2+; Painting Variant at 1.19- - if (protocolversion <= Protocol18Handler.MC_1_19_Version) - { - value = ReadNextVarInt(cache); - } - else - { - // Dimension and blockPos, currently not in use - value = new Tuple(ReadNextString(cache), ReadNextLocation(cache)); - } - - break; - case 24: // Painting Variant - value = ReadNextVarInt(cache); - break; - case 25: // Sniffer state - value = ReadNextVarInt(cache); - break; - case 26: // Vector 3f - value = new List - { - ReadNextFloat(cache), - ReadNextFloat(cache), - ReadNextFloat(cache) - }; - break; - case 27: // Quaternion - value = new List - { - ReadNextFloat(cache), - ReadNextFloat(cache), - ReadNextFloat(cache), - ReadNextFloat(cache) - }; - break; - - default: - throw new System.IO.InvalidDataException("Unknown Metadata Type ID " + type + - ". Is this up to date for new MC Version?"); - } - - data[key] = value; - key = ReadNextByte(cache); + } + break; + case EntityMetaDataType.Pose: // Pose + value = ReadNextVarInt(cache); + break; + case EntityMetaDataType.CatVariant: // Cat Variant + value = ReadNextVarInt(cache); + break; + case EntityMetaDataType.FrogVariant: // Frog Varint + value = ReadNextVarInt(cache); + break; + case EntityMetaDataType.GlobalPosition: // GlobalPos + // Dimension and blockPos, currently not in use + value = new Tuple(ReadNextString(cache), ReadNextLocation(cache)); + break; + case EntityMetaDataType.OptionalGlobalPosition: + if (ReadNextBool(cache)) + { + value = new Tuple(ReadNextString(cache), ReadNextLocation(cache)); + } + break; + case EntityMetaDataType.PaintingVariant: // Painting Variant + value = ReadNextVarInt(cache); + break; + case EntityMetaDataType.SnifferState: // Sniffer state + value = ReadNextVarInt(cache); + break; + case EntityMetaDataType.Vector3: // Vector 3f + value = new List + { + ReadNextFloat(cache), + ReadNextFloat(cache), + ReadNextFloat(cache) + }; + break; + case EntityMetaDataType.Quaternion: // Quaternion + value = new List + { + ReadNextFloat(cache), + ReadNextFloat(cache), + ReadNextFloat(cache), + ReadNextFloat(cache) + }; + break; } - else - { - // This is backward compatible since new type is appended to the end - // Version upgrade note - // - Check type ID got shifted or not - // - Add new type if any - switch (type) - { - case 0: // byte - value = ReadNextByte(cache); - break; - case 1: // VarInt - value = ReadNextVarInt(cache); - break; - case 2: // Float - value = ReadNextFloat(cache); - break; - case 3: // String - value = ReadNextString(cache); - break; - case 4: // Chat - value = ReadNextString(cache); - break; - case 5: // Optional Chat - if (ReadNextBool(cache)) - value = ReadNextString(cache); - break; - case 6: // Slot - value = ReadNextItemSlot(cache, itemPalette); - break; - case 7: // Boolean - value = ReadNextBool(cache); - break; - case 8: // Rotation (3x floats) - value = new List - { - ReadNextFloat(cache), - ReadNextFloat(cache), - ReadNextFloat(cache) - }; - break; - case 9: // Position - value = ReadNextLocation(cache); - break; - case 10: // Optional Position - if (ReadNextBool(cache)) - { - value = ReadNextLocation(cache); - } - break; - case 11: // Direction (VarInt) - value = ReadNextVarInt(cache); - break; - case 12: // Optional UUID - if (ReadNextBool(cache)) - { - value = ReadNextUUID(cache); - } - - break; - case 13: // Optional BlockID (VarInt) - value = ReadNextVarInt(cache); - break; - case 14: // NBT - value = ReadNextNbt(cache); - break; - case 15: // Particle - int ParticleID = ReadNextVarInt(cache); - switch (ParticleID) - { - case 3: - ReadNextVarInt(cache); - break; - case 14: - ReadNextFloat(cache); - ReadNextFloat(cache); - ReadNextFloat(cache); - ReadNextFloat(cache); - break; - case 23: - ReadNextVarInt(cache); - break; - case 32: - ReadNextItemSlot(cache, itemPalette); - break; - } - - break; - case 16: // Villager Data (3x VarInt) - value = new List - { - ReadNextVarInt(cache), - ReadNextVarInt(cache), - ReadNextVarInt(cache) - }; - break; - case 17: // Optional VarInt - if (ReadNextBool(cache)) - { - value = ReadNextVarInt(cache); - } - - break; - case 18: // Pose - value = ReadNextVarInt(cache); - break; - case 19: // Cat Variant - value = ReadNextVarInt(cache); - break; - case 20: // Frog Varint - value = ReadNextVarInt(cache); - break; - case 21: // GlobalPos at 1.19.2+; Painting Variant at 1.19- - if (protocolversion <= Protocol18Handler.MC_1_19_Version) - value = ReadNextVarInt(cache); - else - { - // Dimension and blockPos, currently not in use - value = new Tuple(ReadNextString(cache), ReadNextLocation(cache)); - } - - break; - case 22: // Painting Variant - value = ReadNextVarInt(cache); - break; - default: - throw new System.IO.InvalidDataException("Unknown Metadata Type ID " + type + - ". Is this up to date for new MC Version?"); - } - - data[key] = value; - key = ReadNextByte(cache); - } + data[key] = value; + key = ReadNextByte(cache); } - + ConsoleIO.WriteLine($"Entity MetaData finished {data.Count}"); return data; } diff --git a/MinecraftClient/Protocol/Handlers/Protocol18.cs b/MinecraftClient/Protocol/Handlers/Protocol18.cs index 8143ea61..7485fdeb 100644 --- a/MinecraftClient/Protocol/Handlers/Protocol18.cs +++ b/MinecraftClient/Protocol/Handlers/Protocol18.cs @@ -86,6 +86,7 @@ namespace MinecraftClient.Protocol.Handlers readonly Protocol18Terrain pTerrain; readonly IMinecraftComHandler handler; readonly EntityPalette entityPalette; + readonly EntityMetadataPalette entityMetadataPalette; readonly ItemPalette itemPalette; readonly PacketTypePalette packetPalette; readonly SocketWrapper socketWrapper; @@ -179,6 +180,8 @@ namespace MinecraftClient.Protocol.Handlers else entityPalette = new EntityPalette112(); + entityMetadataPalette = EntityMetadataPalette.GetPalette(protocolVersion); + // Item palette if (protocolVersion > MC_1_19_4_Version && handler.GetInventoryEnabled()) throw new NotImplementedException(Translations.exception_palette_item); @@ -2132,8 +2135,9 @@ namespace MinecraftClient.Protocol.Handlers if (handler.GetEntityHandlingEnabled()) { int EntityID = dataTypes.ReadNextVarInt(packetData); - Dictionary metadata = dataTypes.ReadNextMetadata(packetData, itemPalette); + Dictionary metadata = dataTypes.ReadNextMetadata(packetData, itemPalette, entityMetadataPalette); + // Also make a palette for field? Will be a lot of work int healthField; // See https://wiki.vg/Entity_metadata#Living_Entity if (protocolVersion > MC_1_19_4_Version) throw new NotImplementedException(Translations.exception_palette_healthfield);