Update modelMetaData part hierarchy structure

This commit is contained in:
miku-666
2024-09-22 13:53:45 +02:00
parent 9339a60545
commit 288e6718b4
3 changed files with 237 additions and 131 deletions

View File

@@ -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<string, Outline> outliners = new Dictionary<string, Outline>(5);
List<Element> elements = new List<Element>(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<Outline> outlines = ConvertToOutlines(modelInfo.Model, Vector3.Zero, modelMetaData.RootParts, elements.AddRange);
blockBenchModel.Elements = elements.ToArray();
IEnumerable<Outline> 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<string, JArray> keyValues, ref Dictionary<string, Outline> outliners)
private Outline[] ConvertToOutlines(Model model, Vector3 parentRotation, IReadOnlyCollection<ModelMetaDataPart> keyValues, Action<Element[]> addElements, int depth = 0)
{
foreach (KeyValuePair<string, JArray> 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<Outline> outlines = new List<Outline>();
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<string, JArray> childKeyValues = child.ToObject<ReadOnlyDictionary<string, JArray>>();
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;

View File

@@ -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<ModelMetaDataPart>();
}
internal class JsonModelMetaData
{
[JsonProperty("textureLocations", Required = Required.Always)]
public string[] TextureLocations { get; set; }
[JsonProperty("root", NullValueHandling = NullValueHandling.Ignore)]
public ReadOnlyDictionary<string, JArray> RootParts { get; set; } = new ReadOnlyDictionary<string, JArray>(new Dictionary<string, JArray>());
[JsonProperty("parts", NullValueHandling = NullValueHandling.Ignore)]
public ModelMetaDataPart[] RootParts { get; set; }
}
}

View File

@@ -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": [