using System.Collections.Generic; using System.Linq; using UnityEditor.Animations; using UnityEngine; using VF.Builder; using VF.Feature.Base; using VRC.SDK3.Avatars.Components; using VRC.SDKBase; namespace VF.Feature { /** * This builder is responsible for correcting any AnimatorLayerControl behaviours in * the animators which may have been broken by VRCFury adding / deleting layers * while doing other things. */ public class AnimatorLayerControlOffsetBuilder : FeatureBuilder { private Dictionary mapping = new Dictionary(); [FeatureBuilderAction(FeatureOrder.AnimatorLayerControlRecordBase)] public void RecordBase() { RegisterControllerSet(manager.GetAllUsedControllers().Select(c => (c.GetType(), c.GetRaw()))); } [FeatureBuilderAction(FeatureOrder.AnimatorLayerControlFix)] public void Fix() { var smToTypeAndNumber = new Dictionary(); foreach (var c in manager.GetAllUsedControllers()) { foreach (var (i,l) in c.GetLayers().Select((l,i) => (i,l))) { smToTypeAndNumber[l] = (c.GetType(), i); } } foreach (var c in manager.GetAllUsedControllers()) { foreach (var l in c.GetLayers()) { AnimatorIterator.ForEachBehaviour(l, (b, add) => { if (!(b is VRCAnimatorLayerControl control)) return true; if (!mapping.TryGetValue(control, out var targetSm)) { Debug.LogError("Removing invalid AnimatorLayerControl (not found in mapping??) " + b); return false; } if (!smToTypeAndNumber.TryGetValue(targetSm, out var pair)) { Debug.LogError("Removing invalid AnimatorLayerControl (target sm has disappeared) " + b); return false; } var (newType, newI) = pair; var newCastedType = VRCFEnumUtils.Parse( VRCFEnumUtils.GetName(newType)); Debug.LogWarning($"Rewriting {b} from {control.playable}:{control.layer} to {newCastedType}:{newI}"); control.playable = newCastedType; control.layer = newI; return true; }); } } } public void RegisterControllerSet(IEnumerable<(VRCAvatarDescriptor.AnimLayerType, AnimatorController)> set) { foreach (var (type, controller) in set) { foreach (var layer in controller.layers) { AnimatorIterator.ForEachBehaviour(layer.stateMachine, (b, add) => { if (b is VRCAnimatorLayerControl control) { var targetController = set .Where(tuple => VRCFEnumUtils.GetName(tuple.Item1) == VRCFEnumUtils.GetName(control.playable)) .Select(tuple => tuple.Item2) .FirstOrDefault(); if (targetController == null) return false; if (control.layer < 0 || control.layer >= targetController.layers.Length) return false; var targetSm = targetController.layers[control.layer].stateMachine; mapping[control] = targetSm; } return true; }); } } } } }