using System.Collections.Generic; using System.Linq; using gay.lilyy.Common; using gay.lilyy.BetterParamMerger; using nadena.dev.ndmf; using nadena.dev.ndmf.vrchat; using UnityEngine; using VRC.SDK3.Avatars.ScriptableObjects; [assembly: ExportsPlugin(typeof(BetterParamMergerPlugin))] namespace gay.lilyy.BetterParamMerger { public class BetterParamMergerPlugin : Plugin { public override string DisplayName => "Better Param Merger"; public override string QualifiedName => "gay.lilyy.BetterParamMerger"; protected override void Configure() { InPhase(BuildPhase.Optimizing).Run("MergeParameters", ctx => { var configs = ctx.AvatarRootObject.GetComponentsInChildren(true); if (configs == null || configs.Length == 0) return; var descriptor = ctx.VRChatAvatarDescriptor(); if (descriptor.expressionParameters == null) { Debug.LogWarning($"[Better Param Merger] No expression parameters found on avatar {ctx.AvatarRootObject.name}"); return; } // Duplicate the parameters asset to avoid modifying the original var originalParams = descriptor.expressionParameters; var newParams = ScriptableObject.CreateInstance(); var paramList = new List(); if (originalParams.parameters != null) { paramList.AddRange(originalParams.parameters); } newParams.parameters = paramList.ToArray(); // Create a dictionary for quick lookup of existing parameters by name var paramDict = paramList.ToDictionary(p => p.name, p => p); // Iterate over all config components foreach (var config in configs) { if (config == null || config.parameterAssets == null) continue; // Iterate over all VRCExpressionParameters assets in this config foreach (var paramAsset in config.parameterAssets) { if (paramAsset == null || paramAsset.parameters == null) continue; // Iterate over all parameters in this asset foreach (var param in paramAsset.parameters) { if (string.IsNullOrEmpty(param.name)) continue; if (paramDict.ContainsKey(param.name)) { // Parameter exists - update its settings var existingParam = paramDict[param.name]; existingParam.valueType = param.valueType; existingParam.defaultValue = param.defaultValue; existingParam.saved = param.saved; existingParam.networkSynced = param.networkSynced; } else { // Parameter doesn't exist - add it var newParam = new VRCExpressionParameters.Parameter { name = param.name, valueType = param.valueType, defaultValue = param.defaultValue, saved = param.saved, networkSynced = param.networkSynced }; paramList.Add(newParam); paramDict[param.name] = newParam; } } } // Destroy the config component after processing Object.DestroyImmediate(config); } // Update the parameters array from the list newParams.parameters = paramList.ToArray(); // Assign the new parameters asset to the descriptor descriptor.expressionParameters = newParams; }); } } }