From 16579b502292ecae884b2fc4cf93a8e912c66c8c Mon Sep 17 00:00:00 2001 From: miku-666 <74728189+NessieHax@users.noreply.github.com> Date: Mon, 19 Aug 2024 18:12:22 +0200 Subject: [PATCH] SkinModelImporter - Fix offset detection when importing --- PCK-Studio/Internal/SkinModelImporter.cs | 96 ++++++++++++++---------- 1 file changed, 58 insertions(+), 38 deletions(-) diff --git a/PCK-Studio/Internal/SkinModelImporter.cs b/PCK-Studio/Internal/SkinModelImporter.cs index 1a978d7c..084217ef 100644 --- a/PCK-Studio/Internal/SkinModelImporter.cs +++ b/PCK-Studio/Internal/SkinModelImporter.cs @@ -92,12 +92,30 @@ namespace PckStudio.Internal modelInfo.ANIM = modelInfo.ANIM.SetFlag(SkinAnimFlag.RESOLUTION_64x64, modelInfo.Texture.Size.Width == modelInfo.Texture.Size.Height); } - IEnumerable boxes = ReadOutliner(blockBenchModel.Outliner, null, blockBenchModel.Elements); - modelInfo.AdditionalBoxes.AddRange(boxes.Where(box => !SkinBOX.KnownHashes.ContainsKey(box.GetHashCode()))); + IEnumerable partOffsets = blockBenchModel.Outliner + .Where(token => token.Type == JTokenType.Object && SkinBOX.IsValidType(TryConvertToSkinBoxType(token.ToObject().Name))) + .Select(token => token.ToObject()) + .Select(outline => new SkinPartOffset(TryConvertToSkinBoxType(outline.Name), -GetOffsetFromOrigin(TryConvertToSkinBoxType(outline.Name), outline.Origin).Y)) + .Where(offset => offset.Value != 0f); + modelInfo.PartOffsets.AddRange(partOffsets); + + SkinBOX ApplyOffset(SkinBOX box) + { + SkinPartOffset offset = modelInfo.PartOffsets.FirstOrDefault(offset => offset.Type == (box.IsOverlayPart() ? box.GetBaseType() : box.Type)); + return string.IsNullOrEmpty(offset.Type) ? box : new SkinBOX(box.Type, box.Pos - (Vector3.UnitY * offset.Value), box.Size, box.UV, box.HideWithArmor, box.Mirror, box.Scale); + } + + IEnumerable convertedBoxes = + ReadOutliner(null, blockBenchModel.Outliner, blockBenchModel.Elements) + .Select(ApplyOffset); + + IEnumerable customBoxes = convertedBoxes.Where(box => !SkinBOX.KnownHashes.ContainsKey(box.GetHashCode())); + + modelInfo.AdditionalBoxes.AddRange(customBoxes); + // check for know boxes and filter them out - - SkinAnimMask mask = (SkinAnimMask)boxes + SkinAnimMask mask = (SkinAnimMask)convertedBoxes .Where(box => SkinBOX.KnownHashes.ContainsKey(box.GetHashCode()) && Enum.IsDefined(typeof(SkinAnimMask), (1 >> (int)SkinBOX.KnownHashes[box.GetHashCode()]))) .Select(box => SkinBOX.KnownHashes[box.GetHashCode()]) .Select(i => 1 << (int)i) @@ -111,29 +129,29 @@ namespace PckStudio.Internal return modelInfo; } - private static IEnumerable ReadOutliner(JArray ouliner, string outlineName, IReadOnlyCollection elements) + private static IEnumerable ReadOutliner(string parentName, JArray oulineChildren, IReadOnlyCollection elements) { - IEnumerable boxes = ouliner + IEnumerable boxes = oulineChildren .Where(token => token.Type == JTokenType.String && Guid.TryParse(token.ToString(), out Guid elementUuid) && elements.Any(e => e.Uuid == elementUuid)) .Select(token => elements.First(e => Guid.Parse(token.ToString()) == e.Uuid)) - .Where(element => element.Type == "cube" && element.UseBoxUv && element.Export && SkinBOX.IsValidType(TryConvertToSkinBoxType(outlineName ?? element.Name))) - .Select(element => LoadElement(element, TryConvertToSkinBoxType(outlineName ?? element.Name), Vector3.Zero)); + .Where(element => element.Type == "cube" && element.UseBoxUv && element.Export && SkinBOX.IsValidType(TryConvertToSkinBoxType(parentName ?? element.Name))) + .Select(element => LoadElement(element, TryConvertToSkinBoxType(parentName ?? element.Name))); - IEnumerable childOutlines = ouliner + IEnumerable childOutlines = oulineChildren .Where(token => token.Type == JTokenType.Object) .Select(token => token.ToObject()); foreach (Outline childOutline in childOutlines) { - boxes = boxes.Concat(ReadOutliner(childOutline.Children, childOutline.Name, elements)); + boxes = boxes.Concat(ReadOutliner(parentName ?? childOutline.Name, childOutline.Children, elements)); } return boxes; } - private static SkinBOX LoadElement(Element element, string outlineName, Vector3 offset) + private static SkinBOX LoadElement(Element element, string outlineName) { var boundingBox = new Rendering.BoundingBox(element.From, element.To); - Vector3 pos = boundingBox.Start - offset; + Vector3 pos = boundingBox.Start; Vector3 size = boundingBox.Volume; Vector2 uv = element.UvOffset; @@ -148,7 +166,7 @@ namespace PckStudio.Internal internal static void ExportBlockBenchModel(string fileName, SkinModelInfo modelInfo) { Image exportTexture = FixTexture(modelInfo); - BlockBenchModel blockBenchModel = BlockBenchModel.Create(BlockBenchFormatInfos.Free, Path.GetFileNameWithoutExtension(fileName), new Size(64, exportTexture.Width == exportTexture.Height ? 64 : 32), [exportTexture]); + BlockBenchModel blockBenchModel = BlockBenchModel.Create(BlockBenchFormatInfos.BedrockEntity, Path.GetFileNameWithoutExtension(fileName), new Size(64, exportTexture.Width == exportTexture.Height ? 64 : 32), [exportTexture]); Dictionary outliners = new Dictionary(5); List elements = new List(modelInfo.AdditionalBoxes.Count); @@ -157,12 +175,14 @@ namespace PckStudio.Internal void AddElement(SkinBOX box) { - Vector3 offset = GetOffset(box.Type, ref offsetLookUp, modelInfo.PartOffsets); - if (!outliners.ContainsKey(box.Type)) + string offsetType = box.IsOverlayPart() ? box.GetBaseType() : box.Type; + + Vector3 offset = GetOffsetForPart(offsetType, ref offsetLookUp, modelInfo.PartOffsets); + if (!outliners.ContainsKey(offsetType)) { - outliners.Add(box.Type, new Outline(box.Type) + outliners.Add(offsetType, new Outline(offsetType) { - Origin = GetSkinBoxPivot(box.Type, new Vector3(1, 1, 0)) + offset + Origin = GetSkinBoxPivot(offsetType, new Vector3(1, 1, 0)) + offset }); } @@ -172,7 +192,7 @@ namespace PckStudio.Internal element.To += offset; elements.Add(element); - outliners[box.Type].Children.Add(element.Uuid); + outliners[offsetType].Children.Add(element.Uuid); } ANIM2BOX(modelInfo.ANIM, AddElement); @@ -279,7 +299,7 @@ namespace PckStudio.Internal if (!SkinBOX.IsValidType(boxType)) continue; - Vector3 offset = GetModelOffsetAndAddToModelInfo(boxType, bone.Pivot); + Vector3 offset = GetOffsetFromOrigin(boxType, bone.Pivot); if (offset.Y != 0f) modelInfo.PartOffsets.Add(new SkinPartOffset(boxType, -offset.Y)); @@ -312,7 +332,7 @@ namespace PckStudio.Internal void AddElement(SkinBOX box) { - Vector3 offset = GetOffset(box.Type, ref offsetLookUp, modelInfo.PartOffsets); + Vector3 offset = GetOffsetForPart(box.Type, ref offsetLookUp, modelInfo.PartOffsets); if (!bones.ContainsKey(box.Type)) { @@ -462,15 +482,30 @@ namespace PckStudio.Internal }; } - private static Vector3 GetModelOffsetAndAddToModelInfo(string boxType, Vector3 origin) + private static Vector3 GetOffsetFromOrigin(string boxType, Vector3 origin) { - Vector3 partTranslation = ModelPartSpecifics.GetPositioningInfo(boxType).Translation; + Vector3 partTranslation = ModelPartSpecifics.GetPositioningInfo(boxType).Pivot; Vector3 offset = partTranslation - ((Vector3.UnitY * 24f) - origin); if (offset.X != 0f || offset.Z != 0f) - Trace.TraceWarning($"[{nameof(SkinModelImporter)}:{nameof(LoadElement)}] Warning: skin part({boxType}) offsets only support horizontal offsets."); + Trace.TraceWarning($"[{nameof(SkinModelImporter)}:{nameof(GetOffsetFromOrigin)}] Warning: skin part({boxType}) offsets only support horizontal offsets."); return offset * Vector3.UnitY; } + private static Vector3 GetOffsetForPart(string offsetType, ref Dictionary offsetLookUp, IEnumerable partOffsets) + { + if (offsetLookUp.ContainsKey(offsetType)) + { + return -offsetLookUp[offsetType].Value * Vector3.UnitY; + } + if (partOffsets.Any(o => o.Type == offsetType)) + { + SkinPartOffset partOffset = partOffsets.First(o => o.Type == offsetType); + offsetLookUp.Add(offsetType, partOffset); + return -partOffset.Value * Vector3.UnitY; + } + return Vector3.Zero; + } + private static Image FixTexture(SkinModelInfo modelInfo) { return FixTexture(modelInfo.Texture, modelInfo.AdditionalBoxes.Where(box => !(box.Size == Vector3.One || box.Size == Vector3.Zero)).Select(box => @@ -509,21 +544,6 @@ namespace PckStudio.Internal return result; } - private static Vector3 GetOffset(string name, ref Dictionary offsetLookUp, IEnumerable partOffsets) - { - if (offsetLookUp.ContainsKey(name)) - { - return -offsetLookUp[name].Value * Vector3.UnitY; - } - if (partOffsets.Any(o => o.Type == name)) - { - SkinPartOffset partOffset = partOffsets.First(o => o.Type == name); - offsetLookUp.Add(name, partOffset); - return -partOffset.Value * Vector3.UnitY; - } - return Vector3.Zero; - } - private static Vector3 GetSkinBoxPivot(string partName, Vector3 translationUnit) { return TransformSpace(ModelPartSpecifics.GetPositioningInfo(partName).Pivot, Vector3.Zero, translationUnit) + (24f * Vector3.UnitY);