Move utils out, add dissolve mgr

This commit is contained in:
Lillith Rose 2026-05-19 13:56:11 -04:00
parent 65f7206b46
commit 3a51c82762
3 changed files with 210 additions and 113 deletions

View file

@ -7,6 +7,7 @@ using VRC.SDK3.Avatars.Components;
using VRC.SDK3.Dynamics.Constraint.Components;
using System.Collections.Generic;
using UnityEditor.Animations;
using System;
namespace gay.lilyy.SoldAvatarBootstrap
@ -21,117 +22,7 @@ namespace gay.lilyy.SoldAvatarBootstrap
public AnimatorController fx;
public AacFlClip emptyClip;
public bool experimentalEnabled;
public bool isPC;
}
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<Transform>(true).FirstOrDefault(t => t.gameObject.name == name);
}
public static Transform[] FindChildrenRecursive(Transform parent, string name)
{
return parent.GetComponentsInChildren<Transform>(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);
});
});
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);
});
});
Object.DestroyImmediate(emptyGo);
return clip;
}
public static List<SkinnedMeshRenderer> FindWithBlendshape(AvatarAssets assets, string shapeName)
{
var list = new List<SkinnedMeshRenderer>();
foreach (var smr in assets.root.GetComponentsInChildren<SkinnedMeshRenderer>(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<T> FindNamedComponents<T>(Transform parent, string name) where T : Component
{
var list = new List<T>();
foreach (var component in parent.GetComponentsInChildren<T>(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<T> FindNamedComponents<T>(AvatarAssets assets, string name) where T : Component
{
return FindNamedComponents<T>(assets.root.transform, name);
}
// public bool isPC;
}
@ -214,8 +105,8 @@ namespace gay.lilyy.SoldAvatarBootstrap
{
root = root,
isPC = EditorUserBuildSettings.activeBuildTarget == BuildTarget.StandaloneWindows
|| EditorUserBuildSettings.activeBuildTarget == BuildTarget.StandaloneWindows64,
// isPC = EditorUserBuildSettings.activeBuildTarget == BuildTarget.StandaloneWindows
// || EditorUserBuildSettings.activeBuildTarget == BuildTarget.StandaloneWindows64,
fx = GetController(definition)
};
@ -284,6 +175,17 @@ namespace gay.lilyy.SoldAvatarBootstrap
AvatarLogger.LogInfo($"AAC initialization: {initStopwatch.ElapsedMilliseconds}ms");
AvatarLogger.LogInfo($"Layer groups: {totalLayerGroupTime}ms (processed: {processedCount}, skipped: {skippedCount})");
AvatarLogger.LogInfo($"Average per layer group: {(processedCount > 0 ? totalLayerGroupTime / processedCount : 0)}ms");
// replace the animator controller
var animatorControllers = root.GetComponent<VRCAvatarDescriptor>().baseAnimationLayers
.ToList();
animatorControllers.RemoveAll(layer => layer.type == VRCAvatarDescriptor.AnimLayerType.FX);
animatorControllers.Add(new VRCAvatarDescriptor.CustomAnimLayer
{
type = VRCAvatarDescriptor.AnimLayerType.FX,
animatorController = assets.fx
});
root.GetComponent<VRCAvatarDescriptor>().baseAnimationLayers = animatorControllers.ToArray();
}
}
}