diff --git a/PCK-Studio/External/Format/BlockBenchModel.cs b/PCK-Studio/External/Format/BlockBenchModel.cs index d8b9a0f0..4432c4d5 100644 --- a/PCK-Studio/External/Format/BlockBenchModel.cs +++ b/PCK-Studio/External/Format/BlockBenchModel.cs @@ -264,23 +264,6 @@ namespace PckStudio.External.Format rotation[2] = value.Z; } } - - [JsonProperty("pivot")] - private float[] pivot; - - [JsonIgnore] - public Vector3 Pivot - { - get => new Vector3(pivot?[0] ?? 0, pivot?[1] ?? 0, pivot?[2] ?? 0); - set - { - if (pivot is null || pivot.Length < 3) - pivot = new float[3]; - pivot[0] = value.X; - pivot[1] = value.Y; - pivot[2] = value.Z; - } - } [JsonProperty("uuid")] internal Guid Uuid; diff --git a/PCK-Studio/Internal/GameModelImporter.cs b/PCK-Studio/Internal/GameModelImporter.cs index a2da5407..de1df84b 100644 --- a/PCK-Studio/Internal/GameModelImporter.cs +++ b/PCK-Studio/Internal/GameModelImporter.cs @@ -12,6 +12,7 @@ using System.IO; using PckStudio.Internal.Json; using System.Collections.ObjectModel; using PckStudio.Properties; +using System.Diagnostics; namespace PckStudio.Internal { @@ -36,17 +37,8 @@ namespace PckStudio.Internal Vector3 transformAxis = new Vector3(1, 1, 0); - Outline GetOrCreateOutline(string partName) - { - if (!outliners.ContainsKey(partName)) - outliners.Add(partName, new Outline(partName)); - return outliners[partName]; - } - foreach (ModelPart part in modelInfo.Model.Parts.Values) { - //Outline outline = GetOrCreateOutline(part.Name); - var outline = new Outline(part.Name); Vector3 partTranslation = part.Translation; @@ -65,14 +57,59 @@ namespace PckStudio.Internal } outliners.Add(part.Name, outline); } + + if (!ModelTextureLocations.TryGetValue(modelInfo.Model.Name, out JsonModelMetaData modelMetaData)) + { + Trace.TraceError($"[{nameof(GameModelImporter)}:{nameof(ExportBlockBenchModel)}] Failed to get model meta data for '{modelInfo.Model.Name}'."); + return; + } + + TraverseChildren(modelMetaData.RootParts, ref outliners); blockBenchModel.Elements = elements.ToArray(); - blockBenchModel.Outliner = JArray.FromObject(outliners.Values); + blockBenchModel.Outliner = JArray.FromObject(outliners.Values.Where(value => modelMetaData.RootParts.Count == 0 || modelMetaData.RootParts.ContainsKey(value.Name))); - string content = JsonConvert.SerializeObject(blockBenchModel); + string content = JsonConvert.SerializeObject(blockBenchModel, Formatting.Indented); File.WriteAllText(fileName, content); } + private static void TraverseChildren(IReadOnlyDictionary keyValues, ref Dictionary outliners) + { + foreach (KeyValuePair item in keyValues) + { + if (!outliners.ContainsKey(item.Key)) + { + Debug.WriteLine($"{item.Key} not in {nameof(outliners)}."); + continue; + } + Outline partentOutline = outliners[item.Key]; + foreach (JToken child in item.Value) + { + if (child.Type == JTokenType.String && outliners.TryGetValue(child.ToString(), out Outline childOutline)) + { + childOutline.Rotation += -partentOutline.Rotation; + partentOutline.Children.Add(JToken.FromObject(childOutline)); + } + if (child.Type == JTokenType.Object) + { + IReadOnlyDictionary childKeyValues = child.ToObject>(); + TraverseChildren(childKeyValues, ref outliners); + foreach (var key in childKeyValues.Keys) + { + if (!outliners.ContainsKey(key)) + { + Debug.WriteLine($"{key} not in {nameof(outliners)}."); + continue; + } + childOutline = outliners[key]; + childOutline.Rotation += -partentOutline.Rotation; + partentOutline.Children.Add(JToken.FromObject(childOutline)); + } + } + } + } + } + private static Element CreateElement(ModelBox box, Vector3 origin, string name) { Vector3 pos = box.Position; diff --git a/PCK-Studio/Internal/Json/JsonModelMetaData.cs b/PCK-Studio/Internal/Json/JsonModelMetaData.cs index e6b60d2c..9a73c817 100644 --- a/PCK-Studio/Internal/Json/JsonModelMetaData.cs +++ b/PCK-Studio/Internal/Json/JsonModelMetaData.cs @@ -1,10 +1,12 @@ using System; using System.Collections.Generic; +using System.Collections.ObjectModel; using System.Linq; using System.Numerics; using System.Text; using System.Threading.Tasks; using Newtonsoft.Json; +using Newtonsoft.Json.Linq; namespace PckStudio.Internal.Json { @@ -13,7 +15,7 @@ namespace PckStudio.Internal.Json [JsonProperty("textureLocations", Required = Required.Always)] public string[] TextureLocations { get; set; } - //[JsonProperty("parents", NullValueHandling = NullValueHandling.Ignore, DefaultValueHandling = DefaultValueHandling.Populate)] - //public Dictionary ParentBones { get; set; } + [JsonProperty("root", NullValueHandling = NullValueHandling.Ignore)] + public ReadOnlyDictionary RootParts { get; set; } = new ReadOnlyDictionary(new Dictionary()); } } diff --git a/PCK-Studio/Resources/model/modelMetaData.json b/PCK-Studio/Resources/model/modelMetaData.json index 76c4cfa3..809cd0b8 100644 --- a/PCK-Studio/Resources/model/modelMetaData.json +++ b/PCK-Studio/Resources/model/modelMetaData.json @@ -1,13 +1,23 @@ -// TODO: Add parent detection - { "bat": { "textureLocations": [ "res/mob/bat" ], - "parents": { - "rightEar": "head", - "leftEar": "head" + "root": { + "head": [ + "rightEar", + "leftEar" + ], + "body": [ + { + "rightWing": [ + "rightWingTip" + ], + "leftWing": [ + "leftWingTip" + ] + } + ] } }, "bed": { @@ -19,7 +29,6 @@ "textureLocations": [ "res/mob/fire" ] - }, "boat": { "textureLocations": [ @@ -34,11 +43,7 @@ "chicken": { "textureLocations": [ "res/mob/chicken" - ], - "parents": { - "comb": "head", - "beak": "head" - } + ] }, "cow": { "textureLocations": [ @@ -58,28 +63,75 @@ "dolphin": { "textureLocations": [ "res/mob/dolphin" - ] + ], + "root": { + "body": [ + { "head": [ "nose" ] }, + "left_fin", + "right_fin", + "back_fin", + { "tail": [ "tail_fin" ] } + ] + } + // - body + // - head + // - nose + // - left_fin + // - right_fin + // - back_fin + // - tail + // - tail_fin }, "dragon": { "textureLocations": [ "res/mob/enderdragon/ender" - ] + ], + "root": { + "head": [ "jaw" ], + "body": [], + "wing": [ "wingtip" ], + "wing1": [ "wingtip1" ], + "rearleg": [ { "rearlegtip": [ "rearfoot" ] } ], + "rearleg1": [ { "rearlegtip1": [ "rearfoot1" ] } ], + "frontleg": [ { "frontlegtip": [ "frontfoot" ] } ], + "frontleg1": [ { "frontlegtip1": [ "frontfoot1" ] } ] + } + // TODO: Finish! + // - head + // - jaw + // - body + // - wing + // - wingtip + // - wing1 + // - wingtip1 + // - rearleg + // - rearlegtip + // - rearfoot + // - rearleg1 + // - rearlegtip1 + // - rearfoot1 + // - frontleg + // - frontlegtip + // - frontfoot + // - frontleg1 + // - frontlegtip1 + // - frontfoot1 }, "dragon_head": { "textureLocations": [ "res/mob/enderdragon/ender" - ] + ], + "root": { + "head": [ "jaw" ] + } + // - head + // - jaw }, "enderman": { "textureLocations": [ "res/mob/enderman" ] }, - "evoker": { - "textureLocations": [ - "res/mob/illager/evoker" - ] - }, "ghast": { "textureLocations": [ "res/mob/ghast", @@ -90,7 +142,15 @@ "textureLocations": [ "res/mob/guardian", "res/mob/guardian_elder" - ] + ], + "root": { + "head": [ + "eye", + { + "tailpart0": [ { "tailpart1": [ "tailpart2" ] } ] + } + ] + } }, "irongolem": { "textureLocations": [ @@ -116,6 +176,7 @@ "res/item/cart" ] }, + // the ocelot model is weird.. -miku "ocelot": { "textureLocations": [ "res/mob/ozelot" @@ -128,12 +189,29 @@ "res/mob/parrot/parrot_grey", "res/mob/parrot/parrot_red_blue", "res/mob/parrot/parrot_yellow_blue" - ] + ], + "root": { + "head": [ "head2", "beak1", "beak2", "feather" ], + "body": [], + "tail": [], + "wing0": [], + "wing1": [], + "leg0": [], + "leg1": [] + } }, "phantom": { "textureLocations": [ "res/mob/phantom" - ] + ], + "root": { + "body": [ + "head", + { "wing0": [ "wingtip0" ] }, + { "wing1": [ "wingtip1" ] }, + { "tail": [ "tailtip" ] } + ] + } }, "pig": { "textureLocations": [ @@ -165,12 +243,13 @@ }, "sheep": { "textureLocations": [ - "res/mob/sheep" + // locations not tested + "res/mob/sheep_fur" ] }, "sheep.sheared": { "textureLocations": [ - "" + "res/mob/sheep" ] }, "shulker": { @@ -234,12 +313,6 @@ "res/mob/sea_turtle" ] }, - "vex": { - "textureLocations": [ - "res/mob/illager/vex", - "res/mob/illager/vex_charging" - ] - }, "villager": { "textureLocations": [ "res/mob/villager/villager", @@ -255,6 +328,17 @@ "res/mob/witch" ] }, + "vex": { + "textureLocations": [ + "res/mob/illager/vex", + "res/mob/illager/vex_charging" + ] + }, + "evoker": { + "textureLocations": [ + "res/mob/illager/evoker" + ] + }, "vindicator": { "textureLocations": [ "res/mob/illager/vindicator" @@ -307,7 +391,20 @@ "res/mob/horse/horse_white", "res/mob/horse/horse_zombie", "res/mob/horse/mule" - ] + ], + "root": { + "Neck": [ { "Head": [ "UMouth", "Ear1", "Ear2", "MuleEarL", "MuleEarR", "SaddleMouthL", "SaddleMouthR", "HeadSaddle" ] } ], + "Body": [ "TailA", "Saddle" ], + "Mane": [], + "Leg1A": [], + "Leg2A": [], + "Leg3A": [], + "Leg4A": [], + "Bag1": [], + "Bag2": [], + "SaddleMouthLine": [], + "SaddleMouthLineR": [] + } }, "cat": { "textureLocations": [ @@ -316,11 +413,6 @@ "res/mob/cat_siamese" ] }, - "cod": { - "textureLocations": [ - "res/mob/fish/cod" - ] - }, "zombie.drowned": { "textureLocations": [ "res/mob/zombie/drowned" @@ -336,7 +428,12 @@ null ] }, - "pufferfish.large": { + "cod": { + "textureLocations": [ + "res/mob/fish/cod" + ] + }, + "pufferfish.small": { "textureLocations": [ "res/mob/fish/pufferfish" ] @@ -346,7 +443,7 @@ "res/mob/fish/pufferfish" ] }, - "pufferfish.small": { + "pufferfish.large": { "textureLocations": [ "res/mob/fish/pufferfish" ]