using System; using System.Collections.Generic; using System.Linq; using AnimatorAsCode.V1; using UnityEngine; using VRC.SDK3.Dynamics.Constraint.Components; namespace gay.lilyy.SoldAvatarBootstrap { public static class AvatarUtils { public static GameObject FindChildRecursive(GameObject parent, string name) { return FindChildRecursive(parent.transform, name)?.gameObject; } public static Transform FindChildRecursive(Transform parent, string name) { return parent.GetComponentsInChildren(true).FirstOrDefault(t => t.gameObject.name == name); } public static Transform[] FindChildrenRecursive(Transform parent, string name) { return parent.GetComponentsInChildren(true).Where(t => t.gameObject.name == name).ToArray(); } public static AacFlClip CreateConstraintWeightClip(AvatarAssets assets, VRCParentConstraint constraint, int index, int indexCount) { return assets.aac.NewClip() .Animating(action => { action.Animates(constraint, $"Sources.source{index}.Weight").WithOneFrame(1f); for (int i = 0; i < indexCount; i++) { if (i == index) continue; action.Animates(constraint, $"Sources.source{i}.Weight").WithOneFrame(0f); } }); } public static AacFlClip CreateEmptyClipWithFrames(AvatarAssets assets, int frames) { if (frames == 0) return assets.emptyClip; var emptyGo = new GameObject(); emptyGo.name = "_EmptyClipInstant"; emptyGo.transform.SetParent(assets.root.transform); var clip = assets.aac.NewClip().Animating(action => { action.Animates(emptyGo.transform, "m_LocalScale.z").WithFrameCountUnit(unit => { unit.Constant(0, 0); unit.Constant(frames, 1); }); }); UnityEngine.Object.DestroyImmediate(emptyGo); return clip; } public static AacFlClip CreateEmptyClipWithSeconds(AvatarAssets assets, float seconds) { if (seconds == 0) return assets.emptyClip; var emptyGo = new GameObject(); emptyGo.name = "_EmptyClipInstant"; emptyGo.transform.SetParent(assets.root.transform); var clip = assets.aac.NewClip().Animating(action => { action.Animates(emptyGo.transform, "m_LocalScale.z").WithFrameCountUnit(unit => { unit.Constant(0, 0); unit.Constant(seconds, 1); }); }); UnityEngine.Object.DestroyImmediate(emptyGo); return clip; } public static List FindWithBlendshape(AvatarAssets assets, string shapeName) { var list = new List(); foreach (var smr in assets.root.GetComponentsInChildren(true)) { var mesh = smr.sharedMesh; if (!mesh) continue; int count = mesh.blendShapeCount; for (int i = 0; i < count; i++) { if (mesh.GetBlendShapeName(i) == shapeName) { list.Add(smr); break; } } } return list; } public static List FindNamedComponents(Transform parent, string name) where T : Component { var list = new List(); foreach (var component in parent.GetComponentsInChildren(true)) { if (component.gameObject.name == name) { list.Add(component); } } UnityEngine.Debug.Log($"Found {list.Count} {name} components"); foreach (var component in list) { UnityEngine.Debug.Log($"Component: {component.gameObject.name}"); } return list; } public static List FindNamedComponents(AvatarAssets assets, string name) where T : Component { return FindNamedComponents(assets.root.transform, name); } public static class Dissolve { public class DissolveHooks { #nullable enable public Action? TransitionAnim { get; set; } public Action? TransitionClip { get; set; } public Action? OffAnim { get; set; } public Action? OffClip { get; set; } public Action? OnAnim { get; set; } public Action? OnClip { get; set; } #nullable disable } public static void CreateDissolveLayer(Transform item, string paramStr, AvatarAssets assets, bool isDefault = true, float dissolveSeconds = 1f, DissolveHooks hooks = null) { var layer = assets.aac.CreateSupportingArbitraryControllerLayer(assets.fx, paramStr); var param = layer.BoolParameter(paramStr); var mesh = item.GetComponent(); var itemGo = item.gameObject; var offClip = assets.aac.NewClip().Toggling(itemGo, false); if (hooks != null && hooks.OffAnim != null) offClip.Animating(hooks.OffAnim); if (hooks != null && hooks.OffClip != null) hooks.OffClip(offClip); var onClip = assets.aac.NewClip().Toggling(itemGo, true); if (hooks != null && hooks.OnAnim != null) onClip.Animating(hooks.OnAnim); if (hooks != null && hooks.OnClip != null) hooks.OnClip(onClip); var off = layer.NewState("Off").WithAnimation(offClip); var on = layer.NewState("On").WithAnimation(onClip); // if (assets.isPC) // { var transitionClip = assets.aac.NewClip().Animating(anim => { if (hooks != null && hooks.TransitionAnim != null) hooks.TransitionAnim(anim); anim.Animates(itemGo).WithOneFrame(1f); anim.Animates(mesh, "material._DissolveAlpha").WithSecondsUnit(dissolve => { dissolve.Easing(0f, 0f); dissolve.Easing(dissolveSeconds, 1f); }); }); if (hooks != null && hooks.TransitionClip != null) hooks.TransitionClip(transitionClip); var onToOff = layer.NewState("On To Off").WithAnimation(transitionClip).WithSpeedSetTo(1); var offToOn = layer.NewState("Off To On").WithAnimation(transitionClip).WithSpeedSetTo(-1); on.TransitionsTo(onToOff).When(param.IsFalse()); onToOff.TransitionsTo(off).AfterAnimationFinishes(); off.TransitionsTo(offToOn).When(param.IsTrue()); offToOn.TransitionsTo(on).AfterAnimationFinishes(); } // else // { // on.TransitionsTo(off).When(param.IsFalse()); // off.TransitionsTo(on).When(param.IsTrue()); // } // layer.WithDefaultState(isDefault ? on : off); // } } } }