A simple data model representing one detected locomotion family for export. It stores names for the Folder and 2D blend nodes, a looping flag, a 3x3 blend animation grid and the ordered list of member animation file names.
#nullable enable annotations
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
namespace HumanoidRetargeter.Core.Target;
/// <summary>
/// One detected locomotion family to emit as a directional 2D blend: a <c>Folder</c> named by
/// the family stem grouping the member AnimFile entries plus one <c>2DBlend</c> node wired to
/// the citizen pose parameters (<c>move_x</c>/<c>move_y</c>). Produced by
/// <see cref="LocomotionSetDetector"/>; consumed by <see cref="VmdlWriter"/> and
/// <see cref="VmdlAugmenter"/>.
/// </summary>
public sealed class LocomotionSetSpec
{
/// <summary>Name of the Folder node grouping the family (the stem, collision-suffixed).</summary>
public required string FolderName { get; init; }
/// <summary>Name of the 2DBlend node (<c><stem>_2D</c>, collision-suffixed).</summary>
public required string BlendName { get; init; }
/// <summary>Looping flag of the 2DBlend node (true when every member loops; the shipped
/// locomotion blends are all looping).</summary>
public required bool Looping { get; init; }
/// <summary>
/// The 3×3 <c>blend_anim_list</c> grid, <c>[row][col]</c> with rows indexed by
/// <c>move_x</c> (−1, 0, +1) and columns by <c>move_y</c> (−1, 0, +1) — the exact shipped
/// citizen layout: row 0 = [SW, S, SE], row 1 = [W, center, E], row 2 = [NW, N, NE].
/// </summary>
public required string[][] BlendGrid { get; init; }
/// <summary>Names of the batch AnimFile entries grouped under the Folder, in canonical
/// direction order (N, NE, E, SE, S, SW, W, NW; absent diagonals skipped).</summary>
public required IReadOnlyList<string> MemberNames { get; init; }
}