From 20f37b6c6cdb14bfcff3a6de3c9a1a85a3eb053f Mon Sep 17 00:00:00 2001 From: yum Date: Wed, 19 Feb 2025 01:00:04 -0800 Subject: Begin NDMF integration It mostly works. Weight parameter is being set to 0 which is causing it to not work. Easy enough to fix! TODO: * animations should stay in memory, never save to disk unless debugging * YOTS_weight param should be set to 1 * Generally clean up, so much "if null keep going" bullshit --- YOTSNDMFGenerator.cs | 91 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 91 insertions(+) create mode 100644 YOTSNDMFGenerator.cs (limited to 'YOTSNDMFGenerator.cs') diff --git a/YOTSNDMFGenerator.cs b/YOTSNDMFGenerator.cs new file mode 100644 index 0000000..7ea20c8 --- /dev/null +++ b/YOTSNDMFGenerator.cs @@ -0,0 +1,91 @@ +using UnityEngine; +using nadena.dev.ndmf; +using nadena.dev.ndmf.VRChat; +using nadena.dev.ndmf.localization; +using VRC.SDK3.Avatars.ScriptableObjects; +using UnityEditor; +using System; +using System.Collections.Generic; + +[assembly: ExportsPlugin(typeof(YOTS.YOTSNDMFGenerator))] + +namespace YOTS +{ + public class YOTSNDMFGenerator : Plugin + { + private readonly Localizer localizer = new Localizer("en-us", () => new List<(string, Func)> + { + ("en-us", key => key) // Simple pass-through for English + }); + + public override string DisplayName => "YOTS Animator Generator"; + + protected override void Configure() + { + // Use a different pass name in play mode to indicate temporary processing. + InPhase(BuildPhase.Transforming) + .Run("Generate YOTS Animator", ctx => { + // ctx is a BuildContext + // https://ndmf.nadena.dev/api/nadena.dev.ndmf.BuildContext.html + // Get config + var config = ctx.AvatarRootObject.GetComponentInChildren(); + if (config == null) { + ErrorReport.ReportError(localizer, ErrorSeverity.Error, "yots.error.no_config", + "No YOTS config component found on the avatar."); + return; + } + if (config.jsonConfig == null) { + ErrorReport.ReportError(localizer, ErrorSeverity.Error, "yots.error.no_json", + "YOTS config component is missing JSON config file."); + return; + } + // Get descriptor + var descriptor = ctx.AvatarDescriptor; + if (descriptor == null) { + ErrorReport.ReportError(localizer, ErrorSeverity.Error, "yots.error.no_descriptor", + "Avatar descriptor is missing."); + return; + } + RuntimeAnimatorController animator = descriptor.baseAnimationLayers[4].animatorController; + if (animator == null) { + ErrorReport.ReportError(localizer, ErrorSeverity.Error, "yots.error.no_animator", + "FX layer is missing."); + return; + } + var menu = descriptor.expressionsMenu; + var parameters = descriptor.expressionParameters; + if (parameters == null || menu == null) + { + ErrorReport.ReportError(localizer, ErrorSeverity.Error, "yots.error.missing_assets", + "Avatar parameters or menu is missing."); + return; + } + // Create a clone of the menu and parameters and save them + menu = UnityEngine.Object.Instantiate(menu); + parameters = UnityEngine.Object.Instantiate(parameters); + ctx.AssetSaver.SaveAsset(menu); + ctx.AssetSaver.SaveAsset(parameters); + descriptor.expressionsMenu = menu; + descriptor.expressionParameters = parameters; + // Generate the animator asset using the BuildContext's AssetSaver + RuntimeAnimatorController generatedAnimator = YOTSCore.GenerateAnimator( + config.jsonConfig.text, + parameters, + menu, + ctx.AssetSaver.SaveAsset + ); + if (generatedAnimator == null) { + ErrorReport.ReportError(localizer, ErrorSeverity.Error, "yots.error.generation_failed", + "Failed to generate animator controller."); + return; + } + // TODO merge animators + descriptor.baseAnimationLayers[4].animatorController = generatedAnimator; + + // During play mode, apply additional temporary processing to the avatar. + //AvatarProcessor.ProcessAvatar(ctx.AvatarRootObject); + } + ); + } + } +} -- cgit v1.2.3