From 288e6718b4a242dbbbeb6a8267713de3c3b9bdd4 Mon Sep 17 00:00:00 2001 From: miku-666 <74728189+NessieHax@users.noreply.github.com> Date: Sun, 22 Sep 2024 13:53:45 +0200 Subject: [PATCH] Update modelMetaData part hierarchy structure --- PCK-Studio/Internal/GameModelImporter.cs | 87 +++--- PCK-Studio/Internal/Json/JsonModelMetaData.cs | 13 +- PCK-Studio/Resources/model/modelMetaData.json | 268 +++++++++++++----- 3 files changed, 237 insertions(+), 131 deletions(-) diff --git a/PCK-Studio/Internal/GameModelImporter.cs b/PCK-Studio/Internal/GameModelImporter.cs index 237e7d89..8c6a6aa8 100644 --- a/PCK-Studio/Internal/GameModelImporter.cs +++ b/PCK-Studio/Internal/GameModelImporter.cs @@ -62,7 +62,6 @@ namespace PckStudio.Internal BlockBenchModel blockBenchModel = BlockBenchModel.Create(BlockBenchFormatInfos.BedrockEntity, modelInfo.Model.Name, modelInfo.Model.TextureSize, modelInfo.Textures.Select(nt => (Texture)nt)); blockBenchModel.ModelIdentifier = modelInfo.Model.Name; - Dictionary outliners = new Dictionary(5); List elements = new List(modelInfo.Model.PartCount); if (!ModelMetaData.TryGetValue(modelInfo.Model.Name, out JsonModelMetaData modelMetaData)) @@ -71,28 +70,9 @@ namespace PckStudio.Internal return; } - foreach (ModelPart part in modelInfo.Model.GetParts()) - { - Debug.Assert(!outliners.ContainsKey(part.Name), $"'{part.Name}' is already present."); - var outline = new Outline(part.Name); - - Vector3 partTranslation = part.Translation; - outline.Origin = TransformSpace(partTranslation, Vector3.Zero, bbModelTransformAxis); - outline.Origin += _heightOffset; - - Vector3 rotation = part.Rotation; - outline.Rotation = rotation * TransformSpace(Vector3.One, Vector3.Zero, bbModelTransformAxis); - - Element[] elements1 = part.GetBoxes().Select(box => ToElement(part.Name, box, partTranslation)).ToArray(); - elements.AddRange(elements1); - outline.Children.Add(elements1.Select(element => element.Uuid)); - outliners.Add(part.Name, outline); - } - - TraverseChildren(modelMetaData.RootParts, ref outliners); + IEnumerable outlines = ConvertToOutlines(modelInfo.Model, Vector3.Zero, modelMetaData.RootParts, elements.AddRange); blockBenchModel.Elements = elements.ToArray(); - IEnumerable outlines = outliners.Values.Where(value => modelMetaData.RootParts.Count == 0 || modelMetaData.RootParts.ContainsKey(value.Name)); if (ExportSettings.CreateModelOutline) outlines = new Outline[1] { @@ -113,44 +93,49 @@ namespace PckStudio.Internal return element; } - // TODO: return a new object instead of modifying a reference. (make immutable) -miku - private static void TraverseChildren(IReadOnlyDictionary keyValues, ref Dictionary outliners) + private Outline[] ConvertToOutlines(Model model, Vector3 parentRotation, IReadOnlyCollection keyValues, Action addElements, int depth = 0) { - foreach (KeyValuePair item in keyValues) + Outline CreateOutline(ModelPart modelPart) { - if (!outliners.ContainsKey(item.Key)) + Outline outline = new Outline(modelPart.Name); + + Vector3 partTranslation = modelPart.Translation; + outline.Origin = TransformSpace(partTranslation, Vector3.Zero, bbModelTransformAxis); + outline.Origin += _heightOffset; + + Vector3 rotation = modelPart.Rotation; + outline.Rotation = rotation * TransformSpace(Vector3.One, Vector3.Zero, bbModelTransformAxis); + outline.Rotation += parentRotation; + + Element[] elements1 = modelPart.GetBoxes().Select(box => ToElement(modelPart.Name, box, partTranslation)).ToArray(); + addElements(elements1); + + outline.Children.Add(elements1.Select(element => element.Uuid).ToArray()); + return outline; + } + + if (depth == 0 && keyValues.Count == 0) { - Debug.WriteLine($"{nameof(item.Key)}: '{item.Key}' not in {nameof(outliners)}."); + return model.GetParts().Select(CreateOutline).ToArray(); + } + + List outlines = new List(); + foreach (ModelMetaDataPart item in keyValues) + { + if (!model.TryGetPart(item.Name, out ModelPart modelPart)) + { + Debug.WriteLine($"{nameof(item.Name)}: '{item.Name}' not in {nameof(model)}."); 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($"{nameof(key)}: '{key}' not in {nameof(outliners)}."); - continue; - } - childOutline = outliners[key]; - childOutline.Rotation -= partentOutline.Rotation; - partentOutline.Children.Add(JToken.FromObject(childOutline)); - } - } - } + Outline partentOutline = CreateOutline(modelPart); + JToken[] s = ConvertToOutlines(model, modelPart.Rotation, item.Children, addElements, depth + 1).Select(JToken.FromObject).ToArray(); + partentOutline.Children.Add(s); + outlines.Add(partentOutline); } + return outlines.ToArray(); } + private static Element CreateElement(string name, ModelBox box, Vector3 origin, Vector3 translationUnit, Vector3 offset) { Vector3 pos = box.Position; diff --git a/PCK-Studio/Internal/Json/JsonModelMetaData.cs b/PCK-Studio/Internal/Json/JsonModelMetaData.cs index 9a73c817..dd4e2bfc 100644 --- a/PCK-Studio/Internal/Json/JsonModelMetaData.cs +++ b/PCK-Studio/Internal/Json/JsonModelMetaData.cs @@ -10,12 +10,21 @@ using Newtonsoft.Json.Linq; namespace PckStudio.Internal.Json { + internal class ModelMetaDataPart + { + [JsonProperty("name", Required = Required.Always)] + public string Name { get; set; } + + [JsonProperty("children", NullValueHandling = NullValueHandling.Ignore, DefaultValueHandling = DefaultValueHandling.Ignore)] + public ModelMetaDataPart[] Children { get; set; } = Array.Empty(); + } + internal class JsonModelMetaData { [JsonProperty("textureLocations", Required = Required.Always)] public string[] TextureLocations { get; set; } - [JsonProperty("root", NullValueHandling = NullValueHandling.Ignore)] - public ReadOnlyDictionary RootParts { get; set; } = new ReadOnlyDictionary(new Dictionary()); + [JsonProperty("parts", NullValueHandling = NullValueHandling.Ignore)] + public ModelMetaDataPart[] RootParts { get; set; } } } diff --git a/PCK-Studio/Resources/model/modelMetaData.json b/PCK-Studio/Resources/model/modelMetaData.json index 10085096..d0d6af8c 100644 --- a/PCK-Studio/Resources/model/modelMetaData.json +++ b/PCK-Studio/Resources/model/modelMetaData.json @@ -3,22 +3,32 @@ "textureLocations": [ "res/mob/bat" ], - "root": { - "head": [ - "rightEar", - "leftEar" - ], - "body": [ - { - "rightWing": [ - "rightWingTip" - ], - "leftWing": [ - "leftWingTip" - ] - } - ] - } + "parts": [ + { + "name": "head", + "children": [ + { "name": "rightEar" }, + { "name": "leftEar" } + ] + }, + { + "name": "body", + "children": [ + { + "name": "rightWing", + "children": [ + { "name": "rightWingTip" } + ] + }, + { + "name": "leftWing", + "children": [ + { "name": "leftWingTip" } + ] + } + ] + } + ] }, "bed": { "textureLocations": [ @@ -64,40 +74,90 @@ "textureLocations": [ "res/mob/dolphin" ], - "root": { - "body": [ - { - "head": [ "nose" ], - "tail": [ "tail_fin" ] - }, - "left_fin", - "right_fin", - "back_fin" - ] - } + "parts": [ + { + "name": "body", + "children": [ + { + "name": "head", + "children": [ + { "name": "nose" }, + { "name": "tail_fin" } + ] + }, + { "name": "right_fin" }, + { "name": "left_fin" }, + { "name": "back_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" ] } ] - } + "parts": [ + { + "name": "head", + "children": [ { "name": "jaw" } ] + }, + { "name": "body" }, + { + "name": "wing", + "children": [ { "name": "wingtip" } ] + }, + { + "name": "wing1", + "children": [ { "name": "wingtip1" } ] + }, + { + "name": "rearleg", + "children": [ + { + "name": "rearlegtip", + "children": [ { "name": "rearfoot" } ] + } + ] + }, + { + "name": "rearleg1", + "children": [ + { + "name": "rearlegtip1", + "children": [ { "name": "rearfoot1" } ] + } + ] + }, + { + "name": "frontleg", + "children": [ + { + "name": "frontlegtip", + "children": [ { "name": "frontfoot" } ] + } + ] + }, + { + "name": "frontleg1", + "children": [ + { + "name": "frontlegtip1", + "children": [ { "name": "frontfoot1" } ] + } + ] + } + ] }, "dragon_head": { "textureLocations": [ "res/mob/enderdragon/ender" ], - "root": { - "head": [ "jaw" ] - } + "parts": [ + { + "name": "head", + "children": [ { "name": "jaw" } ] + } + ] }, "enderman": { "textureLocations": [ @@ -115,14 +175,23 @@ "res/mob/guardian", "res/mob/guardian_elder" ], - "root": { - "head": [ - "eye", - { - "tailpart0": [ { "tailpart1": [ "tailpart2" ] } ] - } - ] - } + "parts": [ + { + "name": "head", + "children": [ + { "name": "eye" }, + { + "name": "tailpart0", + "children": [ + { + "name": "tailpart1", + "children": [ { "name": "tailpart2" } ] + } + ] + } + ] + } + ] }, "irongolem": { "textureLocations": [ @@ -167,28 +236,48 @@ "res/mob/parrot/parrot_red_blue", "res/mob/parrot/parrot_yellow_blue" ], - "root": { - "head": [ "head2", "beak1", "beak2", "feather" ], - "body": [], - "tail": [], - "wing0": [], - "wing1": [], - "leg0": [], - "leg1": [] - } + "parts": [ + { + "name": "head", + "children": [ + { "name": "head2" }, + { "name": "beak1" }, + { "name": "beak2" }, + { "name": "feather" } + ] + }, + { "name": "body" }, + { "name": "tail" }, + { "name": "wing0" }, + { "name": "wing1" }, + { "name": "leg0" }, + { "name": "leg1" } + ] }, "phantom": { "textureLocations": [ "res/mob/phantom" ], - "root": { - "body": [ - "head", - { "wing0": [ "wingtip0" ] }, - { "wing1": [ "wingtip1" ] }, - { "tail": [ "tailtip" ] } - ] - } + "parts": [ + { + "name": "body", + "children": [ + { "name": "head" }, + { + "name": "wing0", + "children": [ { "name": "wingtip0" } ] + }, + { + "name": "wing1", + "children": [ { "name": "wingtip1" } ] + }, + { + "name": "tail", + "children": [ { "name": "tailtip" } ] + } + ] + } + ] }, "pig": { "textureLocations": [ @@ -369,19 +458,42 @@ "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": [] - } + "parts": [ + { + "name": "Neck", + "children": [ + { + "name": "Head", + "children": [ + { "name": "HeadSaddle" }, + { "name": "UMouth" }, + { "name": "Ear1" }, + { "name": "Ear2" }, + { "name": "MuleEarL" }, + { "name": "MuleEarR" }, + { "name": "SaddleMouthL" }, + { "name": "SaddleMouthR" } + ] + } + ] + }, + { + "name": "Body", + "children": [ + { "name": "TailA" }, + { "name": "Saddle" } + ] + }, + { "name": "Mane" }, + { "name": "Leg1A" }, + { "name": "Leg2A" }, + { "name": "Leg3A" }, + { "name": "Leg4A" }, + { "name": "Bag1" }, + { "name": "Bag2" }, + { "name": "SaddleMouthLine" }, + { "name": "SaddleMouthLineR" } + ] }, "cat": { "textureLocations": [