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.prefix)
|
||||||
&& string.IsNullOrEmpty(target.suffix))
|
&& string.IsNullOrEmpty(target.suffix))
|
||||||
{
|
{
|
||||||
// We only infer if targeting the armature (below the Hips bone)
|
target.InferPrefixSuffix();
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
* SOFTWARE.
|
* SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
#if UNITY_EDITOR
|
#if UNITY_EDITOR
|
||||||
@ -186,5 +187,36 @@ namespace net.fushizen.modular_avatar.core
|
|||||||
|
|
||||||
return correspondingParent.Find(prefix + xform.name + suffix);
|
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