mirror of
https://github.com/bdunderscore/modular-avatar.git
synced 2025-04-24 21:38:59 +08:00
Merge remote-tracking branch 'bd/main' into enhancement/AddSubMenuCreatorModule
# Conflicts: # Packages/nadena.dev.modular-avatar/Editor/AvatarProcessor.cs
This commit is contained in:
commit
c2bca1ec25
@ -1,10 +1,10 @@
|
|||||||
{
|
{
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"com.unity.collab-proxy": "1.10.2",
|
"com.unity.collab-proxy": "1.10.2",
|
||||||
"com.unity.ide.rider": "3.0.16",
|
"com.unity.ide.rider": "3.0.17",
|
||||||
"com.unity.ide.visualstudio": "2.0.11",
|
"com.unity.ide.visualstudio": "2.0.17",
|
||||||
"com.unity.ide.vscode": "1.2.4",
|
"com.unity.ide.vscode": "1.2.5",
|
||||||
"com.unity.test-framework": "1.1.29",
|
"com.unity.test-framework": "1.1.33",
|
||||||
"com.unity.textmeshpro": "2.1.6",
|
"com.unity.textmeshpro": "2.1.6",
|
||||||
"com.unity.timeline": "1.2.18",
|
"com.unity.timeline": "1.2.18",
|
||||||
"com.unity.ugui": "1.0.0",
|
"com.unity.ugui": "1.0.0",
|
||||||
|
@ -23,6 +23,9 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
using UnityEditor;
|
using UnityEditor;
|
||||||
|
using UnityEngine;
|
||||||
|
using UnityEngine.SceneManagement;
|
||||||
|
using VRC.SDK3.Avatars.Components;
|
||||||
|
|
||||||
namespace nadena.dev.modular_avatar.core.editor
|
namespace nadena.dev.modular_avatar.core.editor
|
||||||
{
|
{
|
||||||
@ -45,10 +48,10 @@ namespace nadena.dev.modular_avatar.core.editor
|
|||||||
{
|
{
|
||||||
EditorApplication.playModeStateChanged += OnPlayModeStateChanged;
|
EditorApplication.playModeStateChanged += OnPlayModeStateChanged;
|
||||||
RuntimeUtil.OnDemandProcessAvatar = MaybeProcessAvatar;
|
RuntimeUtil.OnDemandProcessAvatar = MaybeProcessAvatar;
|
||||||
Menu.SetChecked(MENU_NAME, ModularAvatarSettings.applyOnPlay);
|
EditorApplication.delayCall += () => Menu.SetChecked(MENU_NAME, ModularAvatarSettings.applyOnPlay);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void MaybeProcessAvatar(RuntimeUtil.OnDemandSource source, AvatarTagComponent component)
|
private static void MaybeProcessAvatar(RuntimeUtil.OnDemandSource source, MonoBehaviour component)
|
||||||
{
|
{
|
||||||
if (ModularAvatarSettings.applyOnPlay && source == armedSource && component != null)
|
if (ModularAvatarSettings.applyOnPlay && source == armedSource && component != null)
|
||||||
{
|
{
|
||||||
|
@ -40,6 +40,12 @@ namespace nadena.dev.modular_avatar.core.editor
|
|||||||
// Place after EditorOnly processing (which runs at -1024) but hopefully before most other user callbacks
|
// Place after EditorOnly processing (which runs at -1024) but hopefully before most other user callbacks
|
||||||
public int callbackOrder => -25;
|
public int callbackOrder => -25;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Avoid recursive activation of avatar processing by suppressing starting processing while processing is
|
||||||
|
/// already in progress.
|
||||||
|
/// </summary>
|
||||||
|
private static bool nowProcessing = false;
|
||||||
|
|
||||||
public delegate void AvatarProcessorCallback(GameObject obj);
|
public delegate void AvatarProcessorCallback(GameObject obj);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -117,12 +123,16 @@ namespace nadena.dev.modular_avatar.core.editor
|
|||||||
|
|
||||||
public static void ProcessAvatar(GameObject avatarGameObject)
|
public static void ProcessAvatar(GameObject avatarGameObject)
|
||||||
{
|
{
|
||||||
|
if (nowProcessing) return;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
nowProcessing = true;
|
||||||
|
|
||||||
BoneDatabase.ResetBones();
|
BoneDatabase.ResetBones();
|
||||||
PathMappings.Clear();
|
PathMappings.Clear();
|
||||||
ClonedMenuMappings.Clear();
|
ClonedMenuMappings.Clear();
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// Sometimes people like to nest one avatar in another, when transplanting clothing. To avoid issues
|
// Sometimes people like to nest one avatar in another, when transplanting clothing. To avoid issues
|
||||||
// with inconsistently determining the avatar root, we'll go ahead and remove the extra sub-avatars
|
// with inconsistently determining the avatar root, we'll go ahead and remove the extra sub-avatars
|
||||||
// here.
|
// here.
|
||||||
@ -150,9 +160,13 @@ namespace nadena.dev.modular_avatar.core.editor
|
|||||||
PhysboneBlockerPass.Process(avatarGameObject);
|
PhysboneBlockerPass.Process(avatarGameObject);
|
||||||
|
|
||||||
AfterProcessing?.Invoke(avatarGameObject);
|
AfterProcessing?.Invoke(avatarGameObject);
|
||||||
|
|
||||||
|
FixupAnimatorDebugData(avatarGameObject);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
|
nowProcessing = false;
|
||||||
|
|
||||||
// Ensure that we clean up AvatarTagComponents after failed processing. This ensures we don't re-enter
|
// Ensure that we clean up AvatarTagComponents after failed processing. This ensures we don't re-enter
|
||||||
// processing from the Awake method on the unprocessed AvatarTagComponents
|
// processing from the Awake method on the unprocessed AvatarTagComponents
|
||||||
foreach (var component in avatarGameObject.GetComponentsInChildren<AvatarTagComponent>(true))
|
foreach (var component in avatarGameObject.GetComponentsInChildren<AvatarTagComponent>(true))
|
||||||
@ -162,7 +176,12 @@ namespace nadena.dev.modular_avatar.core.editor
|
|||||||
ClonedMenuMappings.Clear();
|
ClonedMenuMappings.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
FixupAnimatorDebugData(avatarGameObject);
|
var activator = avatarGameObject.GetComponent<AvatarActivator>();
|
||||||
|
if (activator != null)
|
||||||
|
{
|
||||||
|
UnityEngine.Object.DestroyImmediate(activator);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[SuppressMessage("ReSharper", "PossibleNullReferenceException")]
|
[SuppressMessage("ReSharper", "PossibleNullReferenceException")]
|
||||||
|
121
Packages/nadena.dev.modular-avatar/Runtime/Activator.cs
Normal file
121
Packages/nadena.dev.modular-avatar/Runtime/Activator.cs
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
#if UNITY_EDITOR
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using UnityEditor;
|
||||||
|
using UnityEditor.SceneManagement;
|
||||||
|
using UnityEngine;
|
||||||
|
using UnityEngine.SceneManagement;
|
||||||
|
using VRC.SDK3.Avatars.Components;
|
||||||
|
|
||||||
|
namespace nadena.dev.modular_avatar.core
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// This component is used to trigger MA processing upon entering play mode (prior to Av3Emu running).
|
||||||
|
/// We create it on a hidden object via AvatarTagObject's OnValidate, and it will proceed to add MAAvatarActivator
|
||||||
|
/// components to all avatar roots which contain MA components. This MAAvatarActivator component then performs MA
|
||||||
|
/// processing on Awake.
|
||||||
|
///
|
||||||
|
/// Note that we do not directly process the avatars from MAActivator. This is to avoid processing avatars that are
|
||||||
|
/// initially inactive in the scene (which can have high overhead if the user has a lot of inactive avatars in the
|
||||||
|
/// scene).
|
||||||
|
/// </summary>
|
||||||
|
[AddComponentMenu("")]
|
||||||
|
[ExecuteInEditMode]
|
||||||
|
[DefaultExecutionOrder(-9998)]
|
||||||
|
public class Activator : MonoBehaviour
|
||||||
|
{
|
||||||
|
private const string TAG_OBJECT_NAME = "ModularAvatarInternal_Activator";
|
||||||
|
|
||||||
|
private void Awake()
|
||||||
|
{
|
||||||
|
if (!RuntimeUtil.isPlaying || this == null) return;
|
||||||
|
|
||||||
|
var scene = gameObject.scene;
|
||||||
|
foreach (var root in scene.GetRootGameObjects())
|
||||||
|
{
|
||||||
|
foreach (var avatar in root.GetComponentsInChildren<VRCAvatarDescriptor>())
|
||||||
|
{
|
||||||
|
if (avatar.GetComponentInChildren<AvatarTagComponent>(true) != null)
|
||||||
|
{
|
||||||
|
avatar.gameObject.GetOrAddComponent<AvatarActivator>().hideFlags = HideFlags.HideInInspector;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool HasMAComponentsInScene()
|
||||||
|
{
|
||||||
|
var scene = gameObject.scene;
|
||||||
|
foreach (var root in scene.GetRootGameObjects())
|
||||||
|
{
|
||||||
|
if (root.GetComponentInChildren<AvatarTagComponent>(true) != null) return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnValidate()
|
||||||
|
{
|
||||||
|
EditorApplication.delayCall += () =>
|
||||||
|
{
|
||||||
|
if (this == null) return;
|
||||||
|
|
||||||
|
gameObject.hideFlags = HideFlags.HideInHierarchy;
|
||||||
|
if (!HasMAComponentsInScene())
|
||||||
|
{
|
||||||
|
var scene = gameObject.scene;
|
||||||
|
DestroyImmediate(gameObject);
|
||||||
|
EditorSceneManager.MarkSceneDirty(scene);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static void CreateIfNotPresent(Scene scene)
|
||||||
|
{
|
||||||
|
if (!scene.IsValid() || EditorSceneManager.IsPreviewScene(scene)) return;
|
||||||
|
if (EditorApplication.isPlayingOrWillChangePlaymode) return;
|
||||||
|
|
||||||
|
foreach (var root in scene.GetRootGameObjects())
|
||||||
|
{
|
||||||
|
if (root.GetComponent<Activator>() != null) return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var oldActiveScene = SceneManager.GetActiveScene();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
SceneManager.SetActiveScene(scene);
|
||||||
|
var gameObject = new GameObject(TAG_OBJECT_NAME);
|
||||||
|
gameObject.AddComponent<Activator>();
|
||||||
|
gameObject.hideFlags = HideFlags.HideInHierarchy;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
SceneManager.SetActiveScene(oldActiveScene);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[AddComponentMenu("")]
|
||||||
|
[ExecuteInEditMode]
|
||||||
|
[DefaultExecutionOrder(-9997)]
|
||||||
|
public class AvatarActivator : MonoBehaviour
|
||||||
|
{
|
||||||
|
private void Awake()
|
||||||
|
{
|
||||||
|
if (!RuntimeUtil.isPlaying || this == null) return;
|
||||||
|
RuntimeUtil.OnDemandProcessAvatar(RuntimeUtil.OnDemandSource.Awake, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Start()
|
||||||
|
{
|
||||||
|
if (!RuntimeUtil.isPlaying || this == null) return;
|
||||||
|
RuntimeUtil.OnDemandProcessAvatar(RuntimeUtil.OnDemandSource.Start, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Update()
|
||||||
|
{
|
||||||
|
DestroyImmediate(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
@ -0,0 +1,3 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: e41c5d0c41074360bc33887977722a4d
|
||||||
|
timeCreated: 1671337621
|
@ -22,7 +22,6 @@
|
|||||||
* SOFTWARE.
|
* SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
using System;
|
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
|
||||||
namespace nadena.dev.modular_avatar.core
|
namespace nadena.dev.modular_avatar.core
|
||||||
@ -44,5 +43,18 @@ namespace nadena.dev.modular_avatar.core
|
|||||||
if (!RuntimeUtil.isPlaying || this == null) return;
|
if (!RuntimeUtil.isPlaying || this == null) return;
|
||||||
RuntimeUtil.OnDemandProcessAvatar(RuntimeUtil.OnDemandSource.Start, this);
|
RuntimeUtil.OnDemandProcessAvatar(RuntimeUtil.OnDemandSource.Start, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void OnValidate()
|
||||||
|
{
|
||||||
|
if (RuntimeUtil.isPlaying) return;
|
||||||
|
|
||||||
|
RuntimeUtil.delayCall(() =>
|
||||||
|
{
|
||||||
|
if (this == null) return;
|
||||||
|
#if UNITY_EDITOR
|
||||||
|
Activator.CreateIfNotPresent(gameObject.scene);
|
||||||
|
#endif
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -49,7 +49,7 @@ namespace nadena.dev.modular_avatar.core
|
|||||||
Start
|
Start
|
||||||
}
|
}
|
||||||
|
|
||||||
public delegate void OnDemandProcessAvatarDelegate(OnDemandSource source, AvatarTagComponent component);
|
public delegate void OnDemandProcessAvatarDelegate(OnDemandSource source, MonoBehaviour component);
|
||||||
|
|
||||||
public static OnDemandProcessAvatarDelegate OnDemandProcessAvatar = (_m, _c) => { };
|
public static OnDemandProcessAvatarDelegate OnDemandProcessAvatar = (_m, _c) => { };
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "nadena.dev.modular-avatar",
|
"name": "nadena.dev.modular-avatar",
|
||||||
"displayName": "Modular Avatar",
|
"displayName": "Modular Avatar",
|
||||||
"version": "1.1.2",
|
"version": "1.2.0-rc0",
|
||||||
"unity": "2019.4",
|
"unity": "2019.4",
|
||||||
"description": "A suite of tools for assembling your avatar out of reusable components",
|
"description": "A suite of tools for assembling your avatar out of reusable components",
|
||||||
"author": {
|
"author": {
|
||||||
|
@ -24,7 +24,7 @@
|
|||||||
"url": "https://packages.unity.com"
|
"url": "https://packages.unity.com"
|
||||||
},
|
},
|
||||||
"com.unity.ide.rider": {
|
"com.unity.ide.rider": {
|
||||||
"version": "3.0.16",
|
"version": "3.0.17",
|
||||||
"depth": 0,
|
"depth": 0,
|
||||||
"source": "registry",
|
"source": "registry",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@ -33,7 +33,7 @@
|
|||||||
"url": "https://packages.unity.com"
|
"url": "https://packages.unity.com"
|
||||||
},
|
},
|
||||||
"com.unity.ide.visualstudio": {
|
"com.unity.ide.visualstudio": {
|
||||||
"version": "2.0.11",
|
"version": "2.0.17",
|
||||||
"depth": 0,
|
"depth": 0,
|
||||||
"source": "registry",
|
"source": "registry",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@ -42,7 +42,7 @@
|
|||||||
"url": "https://packages.unity.com"
|
"url": "https://packages.unity.com"
|
||||||
},
|
},
|
||||||
"com.unity.ide.vscode": {
|
"com.unity.ide.vscode": {
|
||||||
"version": "1.2.4",
|
"version": "1.2.5",
|
||||||
"depth": 0,
|
"depth": 0,
|
||||||
"source": "registry",
|
"source": "registry",
|
||||||
"dependencies": {},
|
"dependencies": {},
|
||||||
@ -63,7 +63,7 @@
|
|||||||
"url": "https://packages.unity.com"
|
"url": "https://packages.unity.com"
|
||||||
},
|
},
|
||||||
"com.unity.test-framework": {
|
"com.unity.test-framework": {
|
||||||
"version": "1.1.29",
|
"version": "1.1.33",
|
||||||
"depth": 0,
|
"depth": 0,
|
||||||
"source": "registry",
|
"source": "registry",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user