Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Attach stuff #8

Merged
merged 19 commits into from
Aug 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 0 additions & 3 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -1,3 +0,0 @@
[submodule "FFXIVClientStructs"]
path = FFXIVClientStructs
url = https://github.com/aers/FFXIVClientStructs.git
1 change: 0 additions & 1 deletion FFXIVClientStructs
Submodule FFXIVClientStructs deleted from a6c867
30 changes: 0 additions & 30 deletions Meddle.sln
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,10 @@ VisualStudioVersion = 17.8.34309.116
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Meddle.Plugin", "Meddle\Meddle.Plugin\Meddle.Plugin.csproj", "{ABA6105F-84F8-421E-9365-4D19416FC850}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FFXIVClientStructs", "FFXIVClientStructs\FFXIVClientStructs\FFXIVClientStructs.csproj", "{13C16D26-657B-4EC2-90F2-365125403E2D}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Meddle.Utils", "Meddle\Meddle.Utils\Meddle.Utils.csproj", "{AF561495-196F-4076-AA2B-0415E7F85B8E}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Meddle.UI.InteropPlugin", "Meddle\Meddle.UI.InteropPlugin\Meddle.UI.InteropPlugin.csproj", "{F056F9E7-B1D1-4220-8B51-D180855D1EDA}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Meddle.UI", "Meddle\Meddle.UI\Meddle.UI.csproj", "{853D0E4A-A38F-42DF-A2A1-10A1240773DC}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FFXIVClientStructs.Generators", "FFXIVClientStructs\FFXIVClientStructs.Generators\FFXIVClientStructs.Generators.csproj", "{F428CB69-6B3C-4C30-AA47-2F69B07FBD5F}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "InteropGenerator", "FFXIVClientStructs\InteropGenerator\InteropGenerator.csproj", "{965F3CEF-32C7-41EA-AFC9-7AC55FA4BE21}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "InteropGenerator.Runtime", "FFXIVClientStructs\InteropGenerator.Runtime\InteropGenerator.Runtime.csproj", "{AFB41DF8-3B49-4B35-8704-6810454971A0}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand All @@ -29,34 +19,14 @@ Global
{ABA6105F-84F8-421E-9365-4D19416FC850}.Debug|Any CPU.Build.0 = Debug|Any CPU
{ABA6105F-84F8-421E-9365-4D19416FC850}.Release|Any CPU.ActiveCfg = Release|Any CPU
{ABA6105F-84F8-421E-9365-4D19416FC850}.Release|Any CPU.Build.0 = Release|Any CPU
{13C16D26-657B-4EC2-90F2-365125403E2D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{13C16D26-657B-4EC2-90F2-365125403E2D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{13C16D26-657B-4EC2-90F2-365125403E2D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{13C16D26-657B-4EC2-90F2-365125403E2D}.Release|Any CPU.Build.0 = Release|Any CPU
{AF561495-196F-4076-AA2B-0415E7F85B8E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{AF561495-196F-4076-AA2B-0415E7F85B8E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{AF561495-196F-4076-AA2B-0415E7F85B8E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{AF561495-196F-4076-AA2B-0415E7F85B8E}.Release|Any CPU.Build.0 = Release|Any CPU
{F056F9E7-B1D1-4220-8B51-D180855D1EDA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F056F9E7-B1D1-4220-8B51-D180855D1EDA}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F056F9E7-B1D1-4220-8B51-D180855D1EDA}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F056F9E7-B1D1-4220-8B51-D180855D1EDA}.Release|Any CPU.Build.0 = Release|Any CPU
{853D0E4A-A38F-42DF-A2A1-10A1240773DC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{853D0E4A-A38F-42DF-A2A1-10A1240773DC}.Debug|Any CPU.Build.0 = Debug|Any CPU
{853D0E4A-A38F-42DF-A2A1-10A1240773DC}.Release|Any CPU.ActiveCfg = Release|Any CPU
{853D0E4A-A38F-42DF-A2A1-10A1240773DC}.Release|Any CPU.Build.0 = Release|Any CPU
{F428CB69-6B3C-4C30-AA47-2F69B07FBD5F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F428CB69-6B3C-4C30-AA47-2F69B07FBD5F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F428CB69-6B3C-4C30-AA47-2F69B07FBD5F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F428CB69-6B3C-4C30-AA47-2F69B07FBD5F}.Release|Any CPU.Build.0 = Release|Any CPU
{965F3CEF-32C7-41EA-AFC9-7AC55FA4BE21}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{965F3CEF-32C7-41EA-AFC9-7AC55FA4BE21}.Debug|Any CPU.Build.0 = Debug|Any CPU
{965F3CEF-32C7-41EA-AFC9-7AC55FA4BE21}.Release|Any CPU.ActiveCfg = Release|Any CPU
{965F3CEF-32C7-41EA-AFC9-7AC55FA4BE21}.Release|Any CPU.Build.0 = Release|Any CPU
{AFB41DF8-3B49-4B35-8704-6810454971A0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{AFB41DF8-3B49-4B35-8704-6810454971A0}.Debug|Any CPU.Build.0 = Debug|Any CPU
{AFB41DF8-3B49-4B35-8704-6810454971A0}.Release|Any CPU.ActiveCfg = Release|Any CPU
{AFB41DF8-3B49-4B35-8704-6810454971A0}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down
3 changes: 3 additions & 0 deletions Meddle/Meddle.Plugin/Meddle.Plugin.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,9 @@
<Reference Include="OtterTex">
<HintPath>..\Meddle.Utils\Lib\OtterTex.dll</HintPath>
</Reference>
<Reference Include="FFXIVClientStructs">
<HintPath>$(DalamudLibPath)FFXIVClientStructs.dll</HintPath>
</Reference>
</ItemGroup>

<ItemGroup>
Expand Down
23 changes: 23 additions & 0 deletions Meddle/Meddle.Plugin/Models/AttachSet.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
using Meddle.Plugin.Models.Skeletons;
using SharpGLTF.Transforms;

namespace Meddle.Plugin.Models;

public class AttachSet
{
public AttachSet(
string id, ParsedAttach attach, ParsedSkeleton ownerSkeleton, AffineTransform transform, string? ownerId)
{
Id = id;
Attach = attach;
OwnerSkeleton = ownerSkeleton;
Transform = transform;
OwnerId = ownerId;
}

public string Id { get; set; }
public string? OwnerId { get; set; }
public ParsedAttach Attach { get; set; }
public ParsedSkeleton OwnerSkeleton { get; set; }
public AffineTransform Transform { get; set; }
}
34 changes: 25 additions & 9 deletions Meddle/Meddle.Plugin/Models/Groups.cs
Original file line number Diff line number Diff line change
@@ -1,24 +1,40 @@
using System.Numerics;
using Meddle.Plugin.Skeleton;
using Meddle.Plugin.Models.Skeletons;
using Meddle.Utils.Export;
using Meddle.Utils.Files;
using SharpGLTF.Transforms;

namespace Meddle.Plugin.Models;

public record CharacterGroup(
Meddle.Utils.Export.CustomizeParameter CustomizeParams,
CustomizeParameter CustomizeParams,
CustomizeData CustomizeData,
GenderRace GenderRace,
MdlFileGroup[] MdlGroups,
Skeleton.Skeleton Skeleton,
ParsedSkeleton Skeleton,
AttachedModelGroup[] AttachedModelGroups);

public record AttachedModelGroup(Attach Attach, MdlFileGroup[] MdlGroups, Skeleton.Skeleton Skeleton);
public record MdlFileGroup(string CharacterPath, string Path, DeformerGroup? DeformerGroup, MdlFile MdlFile, MtrlFileGroup[] MtrlFiles, Model.ShapeAttributeGroup? ShapeAttributeGroup);
public record MtrlFileGroup(string MdlPath, string Path, MtrlFile MtrlFile, string ShpkPath, ShpkFile ShpkFile, TexResourceGroup[] TexFiles);
public record AttachedModelGroup(ParsedAttach Attach, MdlFileGroup[] MdlGroups, ParsedSkeleton Skeleton);

public record MdlFileGroup(
string CharacterPath,
string Path,
DeformerGroup? DeformerGroup,
MdlFile MdlFile,
MtrlFileGroup[] MtrlFiles,
Model.ShapeAttributeGroup? ShapeAttributeGroup);

public record MtrlFileGroup(
string MdlPath,
string Path,
MtrlFile MtrlFile,
string ShpkPath,
ShpkFile ShpkFile,
TexResourceGroup[] TexFiles);

public record TexResourceGroup(string MtrlPath, string Path, TextureResource Resource);

public record SklbFileGroup(string Path, SklbFile File);

public record Resource(string MdlPath, Vector3 Position, Quaternion Rotation, Vector3 Scale);

public record DeformerGroup(string Path, ushort RaceSexId, ushort DeformerId);
public record AnimationFrameData(DateTime Time, Skeleton.Skeleton Skeleton, AffineTransform Transform, AttachedSkeleton[] Attachments);
public record AttachedSkeleton(string AttachId, Skeleton.Skeleton Skeleton, Attach Attach);
35 changes: 35 additions & 0 deletions Meddle/Meddle.Plugin/Models/Skeletons/HkSkeleton.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
using System.Text.Json.Serialization;
using FFXIVClientStructs.Havok.Animation.Rig;
using FFXIVClientStructs.Interop;
using Meddle.Utils.Skeletons;

namespace Meddle.Plugin.Models.Skeletons;

public class ParsedHkaSkeleton
{
public unsafe ParsedHkaSkeleton(Pointer<hkaSkeleton> skeleton) : this(skeleton.Value) { }

public unsafe ParsedHkaSkeleton(hkaSkeleton* skeleton)
{
var boneNames = new List<string?>();
var boneParents = new List<short>();
var referencePose = new List<Transform>();

for (var i = 0; i < skeleton->Bones.Length; ++i)
{
boneNames.Add(skeleton->Bones[i].Name.String);
boneParents.Add(skeleton->ParentIndices[i]);
referencePose.Add(new Transform(skeleton->ReferencePose[i]));
}

BoneNames = boneNames;
BoneParents = boneParents;
ReferencePose = referencePose;
}

public IReadOnlyList<string?> BoneNames { get; }
public IReadOnlyList<short> BoneParents { get; }

[JsonIgnore]
public IReadOnlyList<Transform> ReferencePose { get; }
}
91 changes: 91 additions & 0 deletions Meddle/Meddle.Plugin/Models/Skeletons/ParsedAttach.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
using Meddle.Plugin.Models.Structs;
using Meddle.Utils.Skeletons;

namespace Meddle.Plugin.Models.Skeletons;

public unsafe class ParsedAttach
{
public ParsedAttach(Attach attach)
{
// 0 => Root
// 3 => Fashion Accessories
// 4 => Weapon
ExecuteType = attach.ExecuteType;
AttachmentCount = attach.AttachmentCount;
switch (ExecuteType)
{
case 0:
// nothing to do here
return;
case 3:
{
if (attach.OwnerCharacter->Skeleton != null)
OwnerSkeleton = new ParsedSkeleton(attach.OwnerCharacter->Skeleton);
TargetSkeleton = new ParsedSkeleton(attach.TargetSkeleton);
AttachmentCount = attach.AttachmentCount;
if (attach.AttachmentCount != 0)
{
var transform = attach.SkeletonBoneAttachments[0];
OffsetTransform = new Transform(transform.ChildTransform);
PartialSkeletonIdx = transform.BoneIndexMask.SkeletonIdx;

var ownerSkeleton = (Skeleton*)attach.OwnerCharacter->Skeleton;

Skeleton.Bone? foundBone = null;
var foundBoneIdx = 0;
for (var i = 0; i < ownerSkeleton->AttachBoneCount; i++)
{
var bone = ownerSkeleton->AttachBonesSpan[i];
if (bone.BoneIndex == transform.BoneIndexMask.BoneIdx)
{
foundBone = bone;
foundBoneIdx = i;
break;
}
}

if (foundBone == null)
{
// should default but gonna throw for now
throw new InvalidOperationException("Bone not found");
}

var boneMask = ownerSkeleton->BoneMasksSpan[foundBoneIdx];
// some case for if boneMask == -1 but meh
PartialSkeletonIdx = boneMask.SkeletonIdx;
BoneIdx = boneMask.BoneIdx;
}

break;
}
case 4:
{
OwnerSkeleton = new ParsedSkeleton(attach.OwnerSkeleton);
TargetSkeleton = new ParsedSkeleton(attach.TargetSkeleton);
AttachmentCount = attach.AttachmentCount;
if (attach.AttachmentCount != 0)
{
var att = attach.SkeletonBoneAttachments[0];
OffsetTransform = new Transform(att.ChildTransform);

PartialSkeletonIdx = att.BoneIndexMask.SkeletonIdx;
BoneIdx = att.BoneIndexMask.BoneIdx;
}

break;
}
default:
{
throw new NotImplementedException($"Unsupported Execute Type: {ExecuteType}, please report this");
}
}
}

public int AttachmentCount { get; }
public int ExecuteType { get; }
public ParsedSkeleton? TargetSkeleton { get; }
public ParsedSkeleton? OwnerSkeleton { get; }
public Transform? OffsetTransform { get; }
public byte PartialSkeletonIdx { get; }
public uint BoneIdx { get; }
}
46 changes: 46 additions & 0 deletions Meddle/Meddle.Plugin/Models/Skeletons/ParsedPartialSkeleton.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
using FFXIVClientStructs.FFXIV.Client.Graphics.Render;
using FFXIVClientStructs.Interop;

namespace Meddle.Plugin.Models.Skeletons;

public class ParsedPartialSkeleton
{
public unsafe ParsedPartialSkeleton(Pointer<PartialSkeleton> partialSkeleton) :
this(partialSkeleton.Value) { }

public unsafe ParsedPartialSkeleton(PartialSkeleton* partialSkeleton)
{
if (partialSkeleton->SkeletonResourceHandle != null)
{
HkSkeleton = new ParsedHkaSkeleton(partialSkeleton->SkeletonResourceHandle->HavokSkeleton);
HandlePath = partialSkeleton->SkeletonResourceHandle->FileName.ToString();
}

BoneCount = StructExtensions.GetBoneCount(partialSkeleton);
ConnectedBoneIndex = partialSkeleton->ConnectedBoneIndex;

var poses = new List<ParsedHkaPose>();
for (var i = 0; i < partialSkeleton->HavokPoses.Length; ++i)
{
var pose = partialSkeleton->GetHavokPose(i);
if (pose != null)
{
if (pose->Skeleton != partialSkeleton->SkeletonResourceHandle->HavokSkeleton)
{
throw new ArgumentException(
$"Pose is not the same as the skeleton {(nint)pose->Skeleton:X16} != {(nint)partialSkeleton->SkeletonResourceHandle->HavokSkeleton:X16}");
}

poses.Add(new ParsedHkaPose(pose));
}
}

Poses = poses;
}

public string? HandlePath { get; }
public ParsedHkaSkeleton? HkSkeleton { get; }
public IReadOnlyList<ParsedHkaPose> Poses { get; }
public int ConnectedBoneIndex { get; }
public uint BoneCount { get; }
}
32 changes: 32 additions & 0 deletions Meddle/Meddle.Plugin/Models/Skeletons/ParsedSkeleton.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
using FFXIVClientStructs.FFXIV.Client.Graphics.Render;
using FFXIVClientStructs.Interop;
using Meddle.Utils.Skeletons;

namespace Meddle.Plugin.Models.Skeletons;

public class ParsedSkeleton
{
public unsafe ParsedSkeleton(Pointer<Skeleton> skeleton) : this(skeleton.Value) { }

public unsafe ParsedSkeleton(Skeleton* skeleton)
{
Transform = new Transform(skeleton->Transform);
var partialSkeletons = new List<ParsedPartialSkeleton>();
for (var i = 0; i < skeleton->PartialSkeletonCount; ++i)
{
try
{
partialSkeletons.Add(new ParsedPartialSkeleton(&skeleton->PartialSkeletons[i]));
}
catch (Exception e)
{
throw new Exception($"Failed to load partial skeleton {i}/{skeleton->PartialSkeletonCount}", e);
}
}

PartialSkeletons = partialSkeletons;
}

public Transform Transform { get; }
public IReadOnlyList<ParsedPartialSkeleton> PartialSkeletons { get; }
}
34 changes: 34 additions & 0 deletions Meddle/Meddle.Plugin/Models/Skeletons/SkeletonPose.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
using System.Text.Json.Serialization;
using FFXIVClientStructs.Havok.Animation.Rig;
using FFXIVClientStructs.Interop;
using Meddle.Plugin.Utils;
using Meddle.Utils.Skeletons;

namespace Meddle.Plugin.Models.Skeletons;

public class ParsedHkaPose
{
public unsafe ParsedHkaPose(Pointer<hkaPose> pose) : this(pose.Value) { }

public unsafe ParsedHkaPose(hkaPose* pose)
{
var transforms = new List<Transform>();

var boneCount = pose->LocalPose.Length;
for (var i = 0; i < boneCount; ++i)
{
var localSpace = PoseUtil.AccessBoneLocalSpace(pose, i);
if (localSpace == null)
{
throw new Exception("Failed to access bone local space");
}

transforms.Add(new Transform(*localSpace));
}

Pose = transforms;
}

[JsonIgnore]
public IReadOnlyList<Transform> Pose { get; }
}
Loading
Loading