diff --git a/MinecraftClient/Protocol/Handlers/DataTypes.cs b/MinecraftClient/Protocol/Handlers/DataTypes.cs index b8f894b6..0b82a810 100644 --- a/MinecraftClient/Protocol/Handlers/DataTypes.cs +++ b/MinecraftClient/Protocol/Handlers/DataTypes.cs @@ -358,6 +358,40 @@ namespace MinecraftClient.Protocol.Handlers ItemType type = itemPalette.FromId(ReadNextVarInt(cache)); byte itemCount = ReadNextByte(cache); Dictionary nbt = ReadNextNbt(cache); + + Console.WriteLine("Got ITEM NBT DATA: "); + Console.WriteLine("-----------------------------"); + + foreach (string x2 in GetNbtAsString(nbt, true)) + { + ConsoleIO.WriteLine(x2); + } + + Console.WriteLine("-----------------------------"); + + Console.WriteLine("-----------------------------"); + foreach (KeyValuePair i in nbt) + { + if (i.Value is object[]) + { + ConsoleIO.WriteLine(i.Key.ToString() + " = {"); + + foreach (object o in (object[])i.Value) + { + ConsoleIO.WriteLine("\t{"); + foreach (KeyValuePair o2 in ((Dictionary)o)) + { + ConsoleIO.WriteLine("\t\t" + o2.Key.ToString() + " = " + o2.Value.ToString() + ","); + } + ConsoleIO.WriteLine("\t},\n"); + } + + ConsoleIO.WriteLine("},\n"); + } + else ConsoleIO.WriteLine(i.Key.ToString() + " = " + i.Value.ToString() + ","); + } + Console.WriteLine("-----------------------------"); + return new Item(type, itemCount, nbt); } else return null; @@ -447,6 +481,7 @@ namespace MinecraftClient.Protocol.Handlers // NBT root name string rootName = Encoding.ASCII.GetString(ReadData(ReadNextUShort(cache), cache)); + if (!String.IsNullOrEmpty(rootName)) nbtData[""] = rootName; } @@ -703,10 +738,13 @@ namespace MinecraftClient.Protocol.Handlers // NBT root name string rootName = null; + if (nbt.ContainsKey("")) rootName = nbt[""] as string; + if (rootName == null) rootName = ""; + bytes.AddRange(GetUShort((ushort)rootName.Length)); bytes.AddRange(Encoding.ASCII.GetBytes(rootName)); } @@ -731,6 +769,227 @@ namespace MinecraftClient.Protocol.Handlers return bytes.ToArray(); } + public List GetNbtAsString(Dictionary nbt, bool root, string depth = "") + { + List strings = new List(); + + if (nbt == null || nbt.Count == 0) + { + strings.Add("TAG_End - No count or null"); + return strings; + } + + if (root) + { + // NBT root name + string rootName = null; + + if (nbt.ContainsKey("")) + rootName = nbt[""] as string; + + if (rootName == null) + rootName = ""; + + strings.Add("TAG_Compound('" + rootName + "'):"); + } + + foreach (var item in nbt) + { + // Skip NBT root name + if (item.Key == "" && root) + continue; + + int fieldType; + string fieldContent = GetNbtFieldAsAString(item.Value, out fieldType, depth); + strings.Add(GetNbtFieldTypeString(fieldType) + "('" + item.Key + "'):"); + strings.Add(depth + (fieldType == 10 ? "\t" : "") + fieldContent); + } + + strings.Add("TAG_End"); // TAG_End + return strings; + } + + private string GetNbtFieldAsAString(object obj, out int fieldType, string depth) + { + if (obj is byte) + { + fieldType = 1; // TAG_Byte + return ByteArrayToString(new byte[] { (byte)obj }); + } + else if (obj is short) + { + fieldType = 2; // TAG_Short + return "" + (short)obj; + } + else if (obj is int) + { + fieldType = 3; // TAG_Int + return "" + (int)obj; + } + else if (obj is long) + { + fieldType = 4; // TAG_Long + return "" + (long)obj; + } + else if (obj is float) + { + fieldType = 5; // TAG_Float + return "" + (float)obj; + } + else if (obj is double) + { + fieldType = 6; // TAG_Double + return "" + (double)obj; + } + else if (obj is byte[]) + { + fieldType = 7; // TAG_Byte_Array + return ByteArrayToString((byte[])obj); + } + else if (obj is string) + { + fieldType = 8; // TAG_String + return "'" + (string)obj + "'"; + } + else if (obj is object[]) + { + fieldType = 9; // TAG_List + + List list = new List((object[])obj); + int arrayLengthTotal = list.Count; + + // Treat empty list as TAG_Byte, length 0 + if (arrayLengthTotal == 0) + return "Empty List"; + + // Encode first list item, retain its type + int firstItemType; + string firstItemTypeString = list[0].GetType().Name; + string firstItemData = GetNbtFieldAsAString(list[0], out firstItemType, depth); + list.RemoveAt(0); + Console.WriteLine("Parsing a TAG_List it has a size of: " + arrayLengthTotal + " and type of: " + GetNbtFieldTypeString(firstItemType)); + + // Encode further list items, check they have the same type + int subsequentItemType; + List subsequentItems = new List(); + foreach (object item in list) + { + string _item = GetNbtFieldAsAString(item, out subsequentItemType, depth); + Console.WriteLine("Adding item to a list: " + _item); + subsequentItems.Add(_item); + + if (subsequentItemType != firstItemType) + throw new System.IO.InvalidDataException( + "GetNbt: Cannot encode object[] list with mixed types: " + firstItemTypeString + ", " + item.GetType().Name + " into NBT string!"); + } + + string itemsString = "" + GetNbtFieldTypeString(firstItemType) + "('" + firstItemData.Replace("\n", "").Trim() + "'): "; + + foreach (string listStr in subsequentItems) + { + itemsString += listStr; + } + + return itemsString; + } + else if (obj is Dictionary) + { + fieldType = 10; // TAG_Compound + + depth += "\t"; + List stringList = GetNbtAsString((Dictionary)obj, false, depth); + + string itemsString = ""; + + foreach (string listStr in stringList) + { + itemsString = depth + listStr; + itemsString += "\n"; + } + + return itemsString; + } + else if (obj is int[]) + { + fieldType = 11; // TAG_Int_Array + + int[] srcIntList = (int[])obj; + + string intListString = ""; + + foreach (int item in srcIntList) + { + intListString += item + ","; + } + + return intListString; + } + else if (obj is long[]) + { + fieldType = 12; // TAG_Long_Array + + long[] srcLongList = (long[])obj; + + string longListString = ""; + + foreach (int item in srcLongList) + { + longListString += item + ","; + } + + return longListString; + } + else + { + throw new System.IO.InvalidDataException("GetNbt: Cannot encode data type " + obj.GetType().Name + " into NBT string!"); + } + } + + private string GetNbtFieldTypeString(int fieldType) + { + if (fieldType == 0) + return "TAG_End"; + + if (fieldType == 1) + return "TAG_Byte"; + + if (fieldType == 2) + return "TAG_Short"; + + if (fieldType == 3) + return "TAG_Int"; + + if (fieldType == 4) + return "TAG_Long"; + + if (fieldType == 5) + return "TAG_Float"; + + if (fieldType == 6) + return "TAG_Double"; + + if (fieldType == 7) + return "TAG_Byte_Array"; + + if (fieldType == 8) + return "TAG_String"; + + if (fieldType == 9) + return "TAG_List"; + + if (fieldType == 10) + return "TAG_Compound"; + + if (fieldType == 11) + return "TAG_Int_Array"; + + if (fieldType == 11) + return "TAG_Long_Array"; + + throw new System.IO.InvalidDataException("Invalid Field Type provided: " + fieldType); + } + + /// /// Convert a single object into its NBT representation (internal) /// @@ -1007,10 +1266,10 @@ namespace MinecraftClient.Protocol.Handlers { // MC 1.13 and greater if (item == null || item.IsEmpty) - slotData.Add(0); // No item + slotData.AddRange(GetBool(false)); // No item else { - slotData.Add(1); // Item is present + slotData.AddRange(GetBool(true)); // Item is present slotData.AddRange(GetVarInt(itemPalette.ToId(item.Type))); slotData.Add((byte)item.Count); slotData.AddRange(GetNbt(item.NBT));