From d743af015ed1f5c6cb6771d22f0e370c2f4713d7 Mon Sep 17 00:00:00 2001 From: bd_ Date: Mon, 18 Sep 2023 04:59:55 +0900 Subject: [PATCH 1/2] feat: implement NDMF integration --- CHANGELOG-PRERELEASE.md | 1 + Editor/OptimizerProcessor.cs | 3 +- Editor/OptimizerSession.cs | 11 +++ Editor/Processors/OptimizerPlugin.cs | 89 +++++++++++++++++++ Editor/Processors/OptimizerPlugin.cs.meta | 3 + Editor/Utils.cs | 10 ++- ...m.anatawa12.avatar-optimizer.editor.asmdef | 11 ++- .../Editor/ApplyOnPlayCallbackRegistry.cs | 4 +- .../ApplyOnPlay/Editor/ApplyOnPlayCaller.cs | 4 +- .../Editor/ApplyOnPlayConfiguration.cs | 4 +- .../Editor/IApplyOnPlayCallback.cs | 2 + Internal/ApplyOnPlay/Editor/ManualBake.cs | 2 + .../Editor/ManualBakeFinallizer.cs | 2 + .../Editor/RemoveEditorOnlyOnPlay.cs | 4 +- ...mizer.internal.apply-on-play.editor.asmdef | 7 +- .../ErrorReportingInitializerProcessor.cs | 11 ++- ...izer.internal.error-reporter.editor.asmdef | 8 +- 17 files changed, 162 insertions(+), 14 deletions(-) create mode 100644 Editor/Processors/OptimizerPlugin.cs create mode 100644 Editor/Processors/OptimizerPlugin.cs.meta diff --git a/CHANGELOG-PRERELEASE.md b/CHANGELOG-PRERELEASE.md index 72c8ada92..50b435374 100644 --- a/CHANGELOG-PRERELEASE.md +++ b/CHANGELOG-PRERELEASE.md @@ -8,6 +8,7 @@ The format is based on [Keep a Changelog]. ## [Unreleased] ### Added +- Support for [NDMF](https://ndmf.nadena.dev) integration [`#375`](https://github.com/anatawa12/AvatarOptimizer/pull/375) ### Changed diff --git a/Editor/OptimizerProcessor.cs b/Editor/OptimizerProcessor.cs index 9cdac04f4..6f4685127 100644 --- a/Editor/OptimizerProcessor.cs +++ b/Editor/OptimizerProcessor.cs @@ -1,4 +1,4 @@ - +#if !NADEMOFU using System; using System.Linq; using Anatawa12.ApplyOnPlay; @@ -175,3 +175,4 @@ private static void DoProcessObject(OptimizerSession session) } } } +#endif \ No newline at end of file diff --git a/Editor/OptimizerSession.cs b/Editor/OptimizerSession.cs index c03dbe5b1..8a50696ea 100644 --- a/Editor/OptimizerSession.cs +++ b/Editor/OptimizerSession.cs @@ -2,6 +2,10 @@ using System.Collections.Generic; using System.Linq; using Anatawa12.AvatarOptimizer.Processors; +#if NADEMOFU +using Anatawa12.AvatarOptimizer.ndmf; +using nadena.dev.ndmf; +#endif using UnityEditor; using UnityEngine; using Object = UnityEngine.Object; @@ -17,6 +21,13 @@ internal class OptimizerSession public ObjectMappingBuilder MappingBuilder { get; } public MeshInfo2Holder MeshInfo2Holder { get; private set; } = new MeshInfo2Holder(); + #if NADEMOFU + public static implicit operator OptimizerSession(BuildContext context) + { + return context.Extension().session; + } + #endif + public OptimizerSession(GameObject rootObject, bool addToAsset, bool isTest) : this(rootObject, addToAsset ? Utils.CreateAssetFile() : null, isTest) { diff --git a/Editor/Processors/OptimizerPlugin.cs b/Editor/Processors/OptimizerPlugin.cs new file mode 100644 index 000000000..2ea729bf2 --- /dev/null +++ b/Editor/Processors/OptimizerPlugin.cs @@ -0,0 +1,89 @@ +#if NADEMOFU +using System; +using Anatawa12.AvatarOptimizer.ErrorReporting; +using Anatawa12.AvatarOptimizer.ndmf; +using Anatawa12.AvatarOptimizer.Processors; +using nadena.dev.ndmf; +using nadena.dev.ndmf.builtin; + +[assembly: ExportsPlugin(typeof(OptimizerPlugin))] + +namespace Anatawa12.AvatarOptimizer.ndmf +{ + internal class OptimizerContext : IExtensionContext + { + private IDisposable buildReportScope; + internal OptimizerSession session; + + public void OnActivate(BuildContext context) + { + buildReportScope = BuildReport.ReportingOnAvatar(context.AvatarDescriptor); + session = new OptimizerSession(context.AvatarRootObject, false, false); + } + + public void OnDeactivate(BuildContext context) + { + session.MarkDirtyAll(); + buildReportScope.Dispose(); + } + } + + internal class OptimizerPlugin : Plugin + { + public override string DisplayName => "Anatawa12's Avatar Optimizer"; + + public override string QualifiedName => "com.anatawa12.avatar-optimizer"; + + protected override void Configure() + { + // Run early steps before EditorOnly objects are purged + InPhase(BuildPhase.Resolving) + .WithRequiredExtension(typeof(OptimizerContext), seq => + { + seq.Run("Early: UnusedBonesByReference", + ctx => new Processors.UnusedBonesByReferencesToolEarlyProcessor().Process(ctx) + ) + .Then.Run("Early: MakeChildren", + ctx => new Processors.MakeChildrenProcessor(early: true).Process(ctx) + ) + .BeforePass(RemoveEditorOnlyPass.Instance); + }); + + // Run everything else in the optimize phase + InPhase(BuildPhase.Optimizing) + .WithRequiredExtension(typeof(OptimizerContext), seq => + { + seq.Run("TraceAndOptimize", + ctx => + { + ctx.GetState().Process(ctx); + }) + .Then.Run("ClearEndpointPosition", + ctx => new Processors.ClearEndpointPositionProcessor().Process(ctx) + ) + .Then.Run("MergePhysBone", + ctx => new Processors.MergePhysBoneProcessor().Process(ctx) + ) + .Then.Run("EditSkinnedMeshComponent", + ctx => new Processors.EditSkinnedMeshComponentProcessor().Process(ctx) + ) + .Then.Run("MakeChildrenProcessor", + ctx => new Processors.MakeChildrenProcessor(early: false).Process(ctx) + ) + .Then.Run("TraceAndOptimize:ProcessLater", + ctx => ctx.GetState().ProcessLater(ctx)) + .Then.Run("MergeBoneProcessor", ctx => new Processors.MergeBoneProcessor().Process(ctx)) + .Then.Run("ApplyObjectMapping", + ctx => new Processors.ApplyObjectMapping().Apply(ctx) + ) + .Then.Run("SaveMeshInfo2", ctx => ((OptimizerSession) ctx).SaveMeshInfo2()); + }); + } + + protected override void OnUnhandledException(Exception e) + { + BuildReport.ReportInternalError(e); + } + } +} +#endif \ No newline at end of file diff --git a/Editor/Processors/OptimizerPlugin.cs.meta b/Editor/Processors/OptimizerPlugin.cs.meta new file mode 100644 index 000000000..8e4e60072 --- /dev/null +++ b/Editor/Processors/OptimizerPlugin.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 3509899322ab44619ca3b2c10e0e673c +timeCreated: 1694975631 \ No newline at end of file diff --git a/Editor/Utils.cs b/Editor/Utils.cs index a83b612c7..8f70cf7cd 100644 --- a/Editor/Utils.cs +++ b/Editor/Utils.cs @@ -5,7 +5,9 @@ using System.IO; using System.Linq; using System.Runtime.CompilerServices; +#if !NADEMOFU using Anatawa12.ApplyOnPlay; +#endif using JetBrains.Annotations; using UnityEditor; using UnityEngine; @@ -329,10 +331,10 @@ public static GameObject NewGameObject(string name, Transform parent) rootObject.transform.localScale = Vector3.one; return rootObject; } - + private const string TemporalDirPath = "Assets/9999-OptimizerGeneratedTemporalAssets"; private const string OutputDirPath = "Assets/AvatarOptimizerOutput"; - + public static void DeleteTemporalDirectory() { AssetDatabase.SaveAssets(); @@ -340,6 +342,7 @@ public static void DeleteTemporalDirectory() FileUtil.DeleteFileOrDirectory(TemporalDirPath); } +#if !NADEMOFU [CanBeNull] public static DummyObject CreateOutputAssetFile(GameObject avatarGameObject, ApplyReason reason) { @@ -352,6 +355,7 @@ public static DummyObject CreateOutputAssetFile(GameObject avatarGameObject, App return CreateOutputAssetFile(avatarGameObject); } } +#endif public static DummyObject CreateAssetFile() { @@ -391,7 +395,7 @@ private static string GetUniqueFileName(string name, string extension) if (PathIfNotExists($"{name} ({number}).{extension}") is string otherTry) return otherTry; } } - + public static IEnumerable<(T, T)> ZipWithNext(this IEnumerable enumerable) { using (var enumerator = enumerable.GetEnumerator()) diff --git a/Editor/com.anatawa12.avatar-optimizer.editor.asmdef b/Editor/com.anatawa12.avatar-optimizer.editor.asmdef index 004330a75..804ceb5cc 100644 --- a/Editor/com.anatawa12.avatar-optimizer.editor.asmdef +++ b/Editor/com.anatawa12.avatar-optimizer.editor.asmdef @@ -10,7 +10,8 @@ "GUID:2633ab9fa94544a69517fc9a1bc143c9", "GUID:b9880ca0b6584453a2627bd3c038759f", "GUID:8542dbf824204440a818dbc2377cb4d6", - "GUID:2665a8d13d1b3f18800f46e256720795" + "GUID:2665a8d13d1b3f18800f46e256720795", + "GUID:62ced99b048af7f4d8dfe4bed8373d76" ], "includePlatforms": [ "Editor" @@ -31,6 +32,12 @@ ], "autoReferenced": false, "defineConstraints": [], - "versionDefines": [], + "versionDefines": [ + { + "name": "nadena.dev.ndmf", + "expression": "0.4.0", + "define": "NADEMOFU" + } + ], "noEngineReferences": false } \ No newline at end of file diff --git a/Internal/ApplyOnPlay/Editor/ApplyOnPlayCallbackRegistry.cs b/Internal/ApplyOnPlay/Editor/ApplyOnPlayCallbackRegistry.cs index 03c60464c..ee0e7ab6a 100644 --- a/Internal/ApplyOnPlay/Editor/ApplyOnPlayCallbackRegistry.cs +++ b/Internal/ApplyOnPlay/Editor/ApplyOnPlayCallbackRegistry.cs @@ -1,3 +1,4 @@ +#if !NADEMOFU using System; using System.Collections.Generic; using System.Linq; @@ -101,4 +102,5 @@ private static void LogException(string message, params Exception[] exceptions) } } } -} \ No newline at end of file +} +#endif \ No newline at end of file diff --git a/Internal/ApplyOnPlay/Editor/ApplyOnPlayCaller.cs b/Internal/ApplyOnPlay/Editor/ApplyOnPlayCaller.cs index 96d361435..8f83c409a 100644 --- a/Internal/ApplyOnPlay/Editor/ApplyOnPlayCaller.cs +++ b/Internal/ApplyOnPlay/Editor/ApplyOnPlayCaller.cs @@ -1,3 +1,4 @@ +#if !NADEMOFU using System; using System.Diagnostics; using System.Linq; @@ -143,4 +144,5 @@ public static void CallManualBakeFinalizer(IManualBakeFinalizer[] finalizers, Ga } } } -} \ No newline at end of file +} +#endif \ No newline at end of file diff --git a/Internal/ApplyOnPlay/Editor/ApplyOnPlayConfiguration.cs b/Internal/ApplyOnPlay/Editor/ApplyOnPlayConfiguration.cs index 11059f9db..515e73650 100644 --- a/Internal/ApplyOnPlay/Editor/ApplyOnPlayConfiguration.cs +++ b/Internal/ApplyOnPlay/Editor/ApplyOnPlayConfiguration.cs @@ -1,3 +1,4 @@ +#if !NADEMOFU using System.Linq; using CustomLocalization4EditorExtension; using UnityEditor; @@ -64,4 +65,5 @@ private void OnGUI() GUILayout.EndHorizontal(); } } -} \ No newline at end of file +} +#endif \ No newline at end of file diff --git a/Internal/ApplyOnPlay/Editor/IApplyOnPlayCallback.cs b/Internal/ApplyOnPlay/Editor/IApplyOnPlayCallback.cs index ee76df431..b92fd8ef0 100644 --- a/Internal/ApplyOnPlay/Editor/IApplyOnPlayCallback.cs +++ b/Internal/ApplyOnPlay/Editor/IApplyOnPlayCallback.cs @@ -1,3 +1,4 @@ +#if !NADEMOFU using UnityEditor.Build; using UnityEngine; @@ -33,3 +34,4 @@ public enum ApplyReason ManualBake, } } +#endif \ No newline at end of file diff --git a/Internal/ApplyOnPlay/Editor/ManualBake.cs b/Internal/ApplyOnPlay/Editor/ManualBake.cs index 6e5e45b12..111e0da77 100644 --- a/Internal/ApplyOnPlay/Editor/ManualBake.cs +++ b/Internal/ApplyOnPlay/Editor/ManualBake.cs @@ -1,3 +1,4 @@ +#if !NADEMOFU using UnityEditor; using UnityEngine; using VRC.SDK3.Avatars.Components; @@ -45,3 +46,4 @@ private static void ExecuteManualBake() } } } +#endif \ No newline at end of file diff --git a/Internal/ApplyOnPlay/Editor/ManualBakeFinallizer.cs b/Internal/ApplyOnPlay/Editor/ManualBakeFinallizer.cs index ea76f10c8..aaf44a9d5 100644 --- a/Internal/ApplyOnPlay/Editor/ManualBakeFinallizer.cs +++ b/Internal/ApplyOnPlay/Editor/ManualBakeFinallizer.cs @@ -1,3 +1,4 @@ +#if !NADEMOFU using UnityEditor.Build; using UnityEngine; @@ -27,3 +28,4 @@ public interface IManualBakeFinalizer : IOrderedCallback void FinalizeManualBake(GameObject original, GameObject cloned); } } +#endif \ No newline at end of file diff --git a/Internal/ApplyOnPlay/Editor/RemoveEditorOnlyOnPlay.cs b/Internal/ApplyOnPlay/Editor/RemoveEditorOnlyOnPlay.cs index 875610e24..6596e46b5 100644 --- a/Internal/ApplyOnPlay/Editor/RemoveEditorOnlyOnPlay.cs +++ b/Internal/ApplyOnPlay/Editor/RemoveEditorOnlyOnPlay.cs @@ -1,3 +1,4 @@ +#if !NADEMOFU using UnityEngine; using Object = UnityEngine.Object; @@ -17,4 +18,5 @@ public bool ApplyOnPlay(GameObject avatarGameObject, ApplyReason reason) return true; } } -} \ No newline at end of file +} +#endif \ No newline at end of file diff --git a/Internal/ApplyOnPlay/Editor/com.anatawa12.avatar-optimizer.internal.apply-on-play.editor.asmdef b/Internal/ApplyOnPlay/Editor/com.anatawa12.avatar-optimizer.internal.apply-on-play.editor.asmdef index 155f5a192..7f8b0a9ca 100644 --- a/Internal/ApplyOnPlay/Editor/com.anatawa12.avatar-optimizer.internal.apply-on-play.editor.asmdef +++ b/Internal/ApplyOnPlay/Editor/com.anatawa12.avatar-optimizer.internal.apply-on-play.editor.asmdef @@ -21,8 +21,13 @@ "versionDefines": [ { "name": "nadena.dev.modular-avatar", - "expression": "[1.0.0,2.0.0)", + "expression": "[1.0.0,1.7.99999)", "define": "MODULAR_AVATAR" + }, + { + "name": "nadena.dev.ndmf", + "expression": "0.4.0", + "define": "NADEMOFU" } ], "noEngineReferences": false diff --git a/Internal/ErrorReporter/Editor/ErrorReportingInitializerProcessor.cs b/Internal/ErrorReporter/Editor/ErrorReportingInitializerProcessor.cs index 603545a69..d634c58de 100644 --- a/Internal/ErrorReporter/Editor/ErrorReportingInitializerProcessor.cs +++ b/Internal/ErrorReporter/Editor/ErrorReportingInitializerProcessor.cs @@ -1,22 +1,29 @@ using System.Collections.Generic; -using Anatawa12.ApplyOnPlay; using UnityEngine; using VRC.SDK3.Avatars.Components; using VRC.SDKBase.Editor.BuildPipeline; +#if !NADEMOFU +using Anatawa12.ApplyOnPlay; +#endif namespace Anatawa12.AvatarOptimizer.ErrorReporting { /// /// Initializes Error Reporting System /// - internal class ErrorReportingInitializerProcessor : IVRCSDKPreprocessAvatarCallback, IApplyOnPlayCallback, IManualBakeFinalizer + internal class ErrorReportingInitializerProcessor : IVRCSDKPreprocessAvatarCallback +#if !NADEMOFU + , IApplyOnPlayCallback, IManualBakeFinalizer +#endif { public int callbackOrder => int.MinValue; public string CallbackName => "Error Reporting Initialization"; public string CallbackId => "com.anatawa12.error-reporting"; +#if !NADEMOFU public bool ApplyOnPlay(GameObject avatarGameObject, ApplyReason reason) => OnPreprocessAvatar(avatarGameObject); +#endif public bool OnPreprocessAvatar(GameObject avatarGameObject) { diff --git a/Internal/ErrorReporter/Editor/com.anatawa12.avatar-optimizer.internal.error-reporter.editor.asmdef b/Internal/ErrorReporter/Editor/com.anatawa12.avatar-optimizer.internal.error-reporter.editor.asmdef index 726a9350d..93c4042e1 100644 --- a/Internal/ErrorReporter/Editor/com.anatawa12.avatar-optimizer.internal.error-reporter.editor.asmdef +++ b/Internal/ErrorReporter/Editor/com.anatawa12.avatar-optimizer.internal.error-reporter.editor.asmdef @@ -19,6 +19,12 @@ ], "autoReferenced": false, "defineConstraints": [], - "versionDefines": [], + "versionDefines": [ + { + "name": "nadena.dev.ndmf", + "expression": "[0.3.0,99999.0.0)", + "define": "NADEMOFU" + } + ], "noEngineReferences": false } \ No newline at end of file From 41369308b95ef7abe0c85f0e1e98db359c29b091 Mon Sep 17 00:00:00 2001 From: bd_ Date: Sun, 24 Sep 2023 17:20:12 +0900 Subject: [PATCH 2/2] chore: add CHANGELOG.md entry as well --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f8474d151..20682f696 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ The format is based on [Keep a Changelog]. ## [Unreleased] ### Added +- Support for [NDMF](https://ndmf.nadena.dev) integration [`#375`](https://github.com/anatawa12/AvatarOptimizer/pull/375) - Pre-building validation for MergeBone `#417` - There are some (rare) cases that are not supported by MergeBone. This adds warning for such case. - Validation error for self recursive MergeSkinnedMesh `#418`