KINDNICK_URP/Assets/External/VRM/Editor/SpringBone/VRMSpringBoneValidator.cs
2025-04-25 21:14:54 +09:00

114 lines
4.4 KiB
C#

using System.Collections.Generic;
using System.Linq;
using UniGLTF;
using UnityEngine;
namespace VRM
{
static class VRMSpringBoneValidator
{
// https://github.com/vrm-c/UniVRM/issues/474
public static IEnumerable<Validation> Validate(GameObject root)
{
if (root == null)
{
yield break;
}
var hierarchy = root.GetComponentsInChildren<Transform>(true);
Dictionary<Transform, List<VRMSpringBone>> rootMap = new Dictionary<Transform, List<VRMSpringBone>>();
foreach (var sb in root.GetComponentsInChildren<VRMSpringBone>())
{
for (int i = 0; i < sb.RootBones.Count; ++i)
{
var springRoot = sb.RootBones[i];
if (springRoot == null)
{
yield return Validation.Error($"[VRMSpringBone]{sb.name}.RootBones[{i}] is null", ValidationContext.Create(sb));
continue;
}
if (!hierarchy.Contains(springRoot))
{
yield return Validation.Error($"[VRMSpringBone]{sb.name}.RootBones[{i}] is out of hierarchy", ValidationContext.Create(sb));
continue;
}
if (!springRoot.transform.EnableForExport())
{
yield return Validation.Error($"[VRMSpringBone]{sb.name}.RootBones[{i}] is not active", ValidationContext.Create(sb));
continue;
}
if (!rootMap.TryGetValue(springRoot, out List<VRMSpringBone> list))
{
list = new List<VRMSpringBone>();
rootMap.Add(springRoot, list);
}
list.Add(sb);
}
if (sb.ColliderGroups != null)
{
for (int i = 0; i < sb.ColliderGroups.Length; ++i)
{
var c = sb.ColliderGroups[i];
if (c == null)
{
yield return Validation.Error($"{sb.name}.ColliderGroups[{i}] is null");
continue;
}
if (!hierarchy.Contains(c.transform))
{
yield return Validation.Error($"{sb.name}.ColliderGroups[{i}] is out of hierarchy");
continue;
}
foreach (var x in c.Validate())
{
yield return x;
}
}
}
}
foreach (var kv in rootMap)
{
if (kv.Value.Count > 1)
{
// * GameObjectが複数回ルートとして指定されてる(SpringBoneが同じでも別でも)
var list = string.Join(", ", kv.Value.Select(x => string.IsNullOrEmpty(x.m_comment) ? x.name : x.m_comment));
yield return Validation.Warning($"{kv.Key} found multiple. {list}");
}
var rootInRootMap = new Dictionary<Transform, List<Transform>>();
foreach (var child in kv.Key.GetComponentsInChildren<Transform>())
{
// * Rootから子をだどって、別のRootが現れる
if (child == kv.Key)
{
continue;
}
if (!rootMap.ContainsKey(child))
{
continue;
}
if (!rootInRootMap.TryGetValue(kv.Key, out List<Transform> rootInRoot))
{
rootInRoot = new List<Transform>();
rootInRootMap.Add(kv.Key, rootInRoot);
}
rootInRoot.Add(child);
}
foreach (var rootList in rootInRootMap)
{
var list = string.Join(", ", rootList.Value.Select(x => x.name));
yield return Validation.Warning($"{rootList.Key} hierarchy contains other root: {list}");
}
}
}
}
}