Minimal cleanup.

This commit is contained in:
Ottermandias 2024-01-07 14:42:16 +01:00
parent 3f8ac1e8d0
commit 2f6905cf35
4 changed files with 30 additions and 32 deletions

View file

@ -1,6 +1,5 @@
using OtterGui.Classes; using OtterGui.Classes;
using Penumbra.Api.Enums; using Penumbra.Api.Enums;
using Penumbra.GameData.Enums;
namespace Penumbra.Communication; namespace Penumbra.Communication;

View file

@ -56,11 +56,12 @@ public class ModelExporter
var names = new Dictionary<string, int>(); var names = new Dictionary<string, int>();
var joints = new List<NodeBuilder>(); var joints = new List<NodeBuilder>();
// Flatten out the bones across all the recieved skeletons, but retain a reference to the parent skeleton for lookups. // Flatten out the bones across all the received skeletons, but retain a reference to the parent skeleton for lookups.
var iterator = skeletons.SelectMany(skeleton => skeleton.Bones.Select(bone => (skeleton, bone))); var iterator = skeletons.SelectMany(skeleton => skeleton.Bones.Select(bone => (skeleton, bone)));
foreach (var (skeleton, bone) in iterator) foreach (var (skeleton, bone) in iterator)
{ {
if (names.ContainsKey(bone.Name)) continue; if (names.ContainsKey(bone.Name))
continue;
var node = new NodeBuilder(bone.Name); var node = new NodeBuilder(bone.Name);
names[bone.Name] = joints.Count; names[bone.Name] = joints.Count;

View file

@ -29,16 +29,17 @@ public sealed class ModelManager(IFramework framework, ActiveCollections collect
_tasks.Clear(); _tasks.Clear();
} }
public Task ExportToGltf(MdlFile mdl, IEnumerable<SklbFile>? sklbs, string outputPath) public Task ExportToGltf(MdlFile mdl, IEnumerable<SklbFile> sklbs, string outputPath)
=> Enqueue(new ExportToGltfAction(this, mdl, sklbs, outputPath)); => Enqueue(new ExportToGltfAction(this, mdl, sklbs, outputPath));
/// <summary> Try to find the .sklb paths for a .mdl file. </summary> /// <summary> Try to find the .sklb paths for a .mdl file. </summary>
/// <param name="mdlPath"> .mdl file to look up the skeletons for. </param> /// <param name="mdlPath"> .mdl file to look up the skeletons for. </param>
public string[]? ResolveSklbsForMdl(string mdlPath, EstManipulation[] estManipulations) /// <param name="estManipulations"> Modified extra skeleton template parameters. </param>
public string[] ResolveSklbsForMdl(string mdlPath, EstManipulation[] estManipulations)
{ {
var info = parser.GetFileInfo(mdlPath); var info = parser.GetFileInfo(mdlPath);
if (info.FileType is not FileType.Model) if (info.FileType is not FileType.Model)
return null; return [];
var baseSkeleton = GamePaths.Skeleton.Sklb.Path(info.GenderRace, "base", 1); var baseSkeleton = GamePaths.Skeleton.Sklb.Path(info.GenderRace, "base", 1);
@ -59,7 +60,7 @@ public sealed class ModelManager(IFramework framework, ActiveCollections collect
ObjectType.DemiHuman => [GamePaths.DemiHuman.Sklb.Path(info.PrimaryId)], ObjectType.DemiHuman => [GamePaths.DemiHuman.Sklb.Path(info.PrimaryId)],
ObjectType.Monster => [GamePaths.Monster.Sklb.Path(info.PrimaryId)], ObjectType.Monster => [GamePaths.Monster.Sklb.Path(info.PrimaryId)],
ObjectType.Weapon => [GamePaths.Weapon.Sklb.Path(info.PrimaryId)], ObjectType.Weapon => [GamePaths.Weapon.Sklb.Path(info.PrimaryId)],
_ => null, _ => [],
}; };
} }
@ -113,31 +114,38 @@ public sealed class ModelManager(IFramework framework, ActiveCollections collect
return task; return task;
} }
private class ExportToGltfAction(ModelManager manager, MdlFile mdl, IEnumerable<SklbFile>? sklbs, string outputPath) private class ExportToGltfAction(ModelManager manager, MdlFile mdl, IEnumerable<SklbFile> sklbs, string outputPath)
: IAction : IAction
{ {
public void Execute(CancellationToken cancel) public void Execute(CancellationToken cancel)
{ {
Penumbra.Log.Debug("Reading skeletons."); Penumbra.Log.Debug($"[GLTF Export] Exporting model to {outputPath}...");
Penumbra.Log.Debug("[GLTF Export] Reading skeletons...");
var xivSkeletons = BuildSkeletons(cancel); var xivSkeletons = BuildSkeletons(cancel);
Penumbra.Log.Debug("Converting model."); Penumbra.Log.Debug("[GLTF Export] Converting model...");
var model = ModelExporter.Export(mdl, xivSkeletons); var model = ModelExporter.Export(mdl, xivSkeletons);
Penumbra.Log.Debug("Building scene."); Penumbra.Log.Debug("[GLTF Export] Building scene...");
var scene = new SceneBuilder(); var scene = new SceneBuilder();
model.AddToScene(scene); model.AddToScene(scene);
Penumbra.Log.Debug("Saving."); Penumbra.Log.Debug("[GLTF Export] Saving...");
var gltfModel = scene.ToGltf2(); var gltfModel = scene.ToGltf2();
gltfModel.SaveGLTF(outputPath); gltfModel.SaveGLTF(outputPath);
Penumbra.Log.Debug("[GLTF Export] Done.");
} }
/// <summary> Attempt to read out the pertinent information from a .sklb. </summary> /// <summary> Attempt to read out the pertinent information from a .sklb. </summary>
private IEnumerable<XivSkeleton>? BuildSkeletons(CancellationToken cancel) private IEnumerable<XivSkeleton> BuildSkeletons(CancellationToken cancel)
{ {
if (sklbs == null) var havokTasks = sklbs
return null; .WithIndex()
.Select(CreateHavokTask)
.ToArray();
// Result waits automatically.
return havokTasks.Select(task => SkeletonConverter.FromXml(task.Result));
// The havok methods we're relying on for this conversion are a bit // The havok methods we're relying on for this conversion are a bit
// finicky at the best of times, and can outright cause a CTD if they // finicky at the best of times, and can outright cause a CTD if they
@ -146,16 +154,7 @@ public sealed class ModelManager(IFramework framework, ActiveCollections collect
Task<string> CreateHavokTask((SklbFile Sklb, int Index) pair) => Task<string> CreateHavokTask((SklbFile Sklb, int Index) pair) =>
manager._framework.RunOnTick( manager._framework.RunOnTick(
() => HavokConverter.HkxToXml(pair.Sklb.Skeleton), () => HavokConverter.HkxToXml(pair.Sklb.Skeleton),
delayTicks: pair.Index delayTicks: pair.Index, cancellationToken: cancel);
);
var havokTasks = sklbs
.WithIndex()
.Select(CreateHavokTask)
.ToArray();
Task.WaitAll(havokTasks, cancel);
return havokTasks.Select(task => SkeletonConverter.FromXml(task.Result));
} }
public bool Equals(IAction? other) public bool Equals(IAction? other)

View file

@ -86,31 +86,30 @@ public partial class ModEditWindow
.Where(subMod => subMod != option) .Where(subMod => subMod != option)
.Prepend(option) .Prepend(option)
.SelectMany(subMod => subMod.Manipulations) .SelectMany(subMod => subMod.Manipulations)
.Where(manipulation => manipulation.ManipulationType == MetaManipulation.Type.Est) .Where(manipulation => manipulation.ManipulationType is MetaManipulation.Type.Est)
.Select(manipulation => manipulation.Est) .Select(manipulation => manipulation.Est)
.ToArray(); .ToArray();
} }
/// <summary> Export model to an interchange format. </summary> /// <summary> Export model to an interchange format. </summary>
/// <param name="outputPath"> Disk path to save the resulting file to. </param> /// <param name="outputPath"> Disk path to save the resulting file to. </param>
/// <param name="mdlPath"> The game path of the model. </param>
public void Export(string outputPath, Utf8GamePath mdlPath) public void Export(string outputPath, Utf8GamePath mdlPath)
{ {
IEnumerable<SklbFile>? sklbs = null; IEnumerable<SklbFile> skeletons;
try try
{ {
var sklbPaths = _edit._models.ResolveSklbsForMdl(mdlPath.ToString(), GetCurrentEstManipulations()); var sklbPaths = _edit._models.ResolveSklbsForMdl(mdlPath.ToString(), GetCurrentEstManipulations());
sklbs = sklbPaths != null skeletons = sklbPaths.Select(ReadSklb).ToArray();
? sklbPaths.Select(ReadSklb).ToArray()
: null;
} }
catch (Exception exception) catch (Exception exception)
{ {
IoException = exception?.ToString(); IoException = exception.ToString();
return; return;
} }
PendingIo = true; PendingIo = true;
_edit._models.ExportToGltf(Mdl, sklbs, outputPath) _edit._models.ExportToGltf(Mdl, skeletons, outputPath)
.ContinueWith(task => .ContinueWith(task =>
{ {
IoException = task.Exception?.ToString(); IoException = task.Exception?.ToString();