mirror of
https://github.com/bdunderscore/modular-avatar.git
synced 2025-03-09 23:34:56 +08:00
Add a context menu setup option for outfits
This commit is contained in:
parent
c40647e433
commit
76d2adefd3
@ -0,0 +1,80 @@
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace net.fushizen.modular_avatar.core.editor
|
||||
{
|
||||
public class EasySetupOutfit
|
||||
{
|
||||
private const int PRIORITY = 49;
|
||||
|
||||
[MenuItem("GameObject/[ModularAvatar] Setup Outfit", false, PRIORITY)]
|
||||
static void SetupOutfit(MenuCommand cmd)
|
||||
{
|
||||
if (!FindBones(cmd.context,
|
||||
out var avatarRoot, out var avatarHips, out var outfitHips)
|
||||
) return;
|
||||
|
||||
var avatarArmature = avatarHips.transform.parent;
|
||||
var outfitArmature = outfitHips.transform.parent;
|
||||
|
||||
var merge = Undo.AddComponent<ModularAvatarMergeArmature>(outfitArmature.gameObject);
|
||||
merge.mergeTarget.referencePath = RuntimeUtil.RelativePath(avatarRoot, avatarArmature.gameObject);
|
||||
merge.InferPrefixSuffix();
|
||||
}
|
||||
|
||||
[MenuItem("GameObject/[ModularAvatar] Setup Outfit", true, PRIORITY)]
|
||||
static bool ValidateSetupOutfit()
|
||||
{
|
||||
foreach (var obj in Selection.objects)
|
||||
{
|
||||
if (!FindBones(obj, out var _, out var _, out var outfitHips)
|
||||
|| outfitHips.transform.parent.GetComponent<ModularAvatarMergeArmature>() != null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static bool FindBones(Object obj, out GameObject avatarRoot, out GameObject avatarHips,
|
||||
out GameObject outfitHips)
|
||||
{
|
||||
avatarHips = outfitHips = null;
|
||||
var outfitRoot = obj as GameObject;
|
||||
avatarRoot = outfitRoot != null
|
||||
? RuntimeUtil.FindAvatarInParents(outfitRoot.transform)?.gameObject
|
||||
: null;
|
||||
if (outfitRoot == null || avatarRoot == null) return false;
|
||||
|
||||
var avatarAnimator = avatarRoot.GetComponent<Animator>();
|
||||
if (avatarAnimator == null) return false;
|
||||
|
||||
avatarHips = avatarAnimator.GetBoneTransform(HumanBodyBones.Hips)?.gameObject;
|
||||
if (avatarHips == null) return false;
|
||||
|
||||
var outfitAnimator = outfitRoot.GetComponent<Animator>();
|
||||
if (outfitAnimator != null)
|
||||
{
|
||||
outfitHips = outfitAnimator.GetBoneTransform(HumanBodyBones.Hips)?.gameObject;
|
||||
}
|
||||
|
||||
if (outfitHips == null)
|
||||
{
|
||||
// Heuristic search - usually there'll be root -> Armature -> (single child) Hips
|
||||
foreach (Transform child in outfitRoot.transform)
|
||||
{
|
||||
if (child.childCount == 1)
|
||||
{
|
||||
if (child.GetChild(0).name.Contains(avatarHips.name))
|
||||
{
|
||||
outfitHips = child.GetChild(0).gameObject;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return avatarHips != null && outfitHips != null;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ce0a55eae40b424084cb91f80f6276c2
|
||||
timeCreated: 1664935971
|
@ -22,33 +22,7 @@ namespace net.fushizen.modular_avatar.core.editor
|
||||
&& string.IsNullOrEmpty(target.prefix)
|
||||
&& string.IsNullOrEmpty(target.suffix))
|
||||
{
|
||||
// We only infer if targeting the armature (below the Hips bone)
|
||||
var rootAnimator = RuntimeUtil.FindAvatarInParents(target.transform)?.GetComponent<Animator>();
|
||||
if (rootAnimator == null) return;
|
||||
|
||||
var hips = rootAnimator.GetBoneTransform(HumanBodyBones.Hips);
|
||||
if (hips == null || hips.transform.parent != target.mergeTargetObject.transform) return;
|
||||
|
||||
// We also require that the attached object has exactly one child (presumably the hips)
|
||||
if (target.transform.childCount != 1) return;
|
||||
|
||||
// Infer the prefix and suffix by comparing the names of the mergeTargetObject's hips with the child of the
|
||||
// GameObject we're attached to.
|
||||
var baseName = hips.name;
|
||||
var mergeName = target.transform.GetChild(0).name;
|
||||
|
||||
var prefixLength = mergeName.IndexOf(baseName, StringComparison.InvariantCulture);
|
||||
if (prefixLength < 0) return;
|
||||
|
||||
var suffixLength = mergeName.Length - prefixLength - baseName.Length;
|
||||
|
||||
target.prefix = mergeName.Substring(0, prefixLength);
|
||||
target.suffix = mergeName.Substring(mergeName.Length - suffixLength);
|
||||
|
||||
if (!string.IsNullOrEmpty(target.prefix) || !string.IsNullOrEmpty(target.suffix))
|
||||
{
|
||||
RuntimeUtil.MarkDirty(target);
|
||||
}
|
||||
target.InferPrefixSuffix();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -22,6 +22,7 @@
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
#if UNITY_EDITOR
|
||||
@ -186,5 +187,36 @@ namespace net.fushizen.modular_avatar.core
|
||||
|
||||
return correspondingParent.Find(prefix + xform.name + suffix);
|
||||
}
|
||||
|
||||
public void InferPrefixSuffix()
|
||||
{
|
||||
// We only infer if targeting the armature (below the Hips bone)
|
||||
var rootAnimator = RuntimeUtil.FindAvatarInParents(transform)?.GetComponent<Animator>();
|
||||
if (rootAnimator == null) return;
|
||||
|
||||
var hips = rootAnimator.GetBoneTransform(HumanBodyBones.Hips);
|
||||
if (hips == null || hips.transform.parent != mergeTargetObject.transform) return;
|
||||
|
||||
// We also require that the attached object has exactly one child (presumably the hips)
|
||||
if (transform.childCount != 1) return;
|
||||
|
||||
// Infer the prefix and suffix by comparing the names of the mergeTargetObject's hips with the child of the
|
||||
// GameObject we're attached to.
|
||||
var baseName = hips.name;
|
||||
var mergeName = transform.GetChild(0).name;
|
||||
|
||||
var prefixLength = mergeName.IndexOf(baseName, StringComparison.InvariantCulture);
|
||||
if (prefixLength < 0) return;
|
||||
|
||||
var suffixLength = mergeName.Length - prefixLength - baseName.Length;
|
||||
|
||||
prefix = mergeName.Substring(0, prefixLength);
|
||||
suffix = mergeName.Substring(mergeName.Length - suffixLength);
|
||||
|
||||
if (!string.IsNullOrEmpty(prefix) || !string.IsNullOrEmpty(suffix))
|
||||
{
|
||||
RuntimeUtil.MarkDirty(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user