fixes to prefabs

This commit is contained in:
Lillith Rose 2026-05-21 16:32:03 -04:00
parent 1e82822d3e
commit 03aca7fcd4
2 changed files with 44 additions and 3 deletions

View file

@ -49,6 +49,12 @@ namespace gay.lilyy.SoldAvatarBootstrap
AssetDatabase.DeleteAsset(definition.FXLayerPath);
AssetDatabase.Refresh();
}
var directory = System.IO.Path.GetDirectoryName(definition.FXLayerPath);
if (!AssetDatabase.IsValidFolder(directory))
{
System.IO.Directory.CreateDirectory(directory);
AssetDatabase.Refresh();
}
var newController = AnimatorController.CreateAnimatorControllerAtPath(definition.FXLayerPath);
if (originalGuid != null && System.IO.File.Exists(metaPath))
{
@ -70,8 +76,23 @@ namespace gay.lilyy.SoldAvatarBootstrap
{
var allLayerGroups = LayerGroup.Instances.ToList();
var definitionsToProcess = new HashSet<AvatarDefinition> { definition };
var definitionsToExpand = new Queue<AvatarDefinition>(definitionsToProcess);
while (definitionsToExpand.Count > 0)
{
var current = definitionsToExpand.Dequeue();
foreach (var extended in current.Extends)
{
if (definitionsToProcess.Add(extended))
{
definitionsToExpand.Enqueue(extended);
}
}
}
var layerGroups = allLayerGroups
.Where(lg => lg.TargetDefinitions.Contains(definition))
.Where(lg => lg.TargetDefinitions.Any(definitionsToProcess.Contains))
.ToList();
// Start overall timer
@ -81,6 +102,11 @@ namespace gay.lilyy.SoldAvatarBootstrap
GameObject root = null;
foreach (var candidate in GameObject.FindObjectsOfType<VRCAvatarDescriptor>(true))
{
if (PrefabUtility.IsPartOfPrefabAsset(candidate.gameObject))
{
continue;
}
if (definition.IsApplicable(candidate.gameObject))
{
AvatarLogger.LogInfo($"Found suitable avatar: {candidate.gameObject.name}");
@ -94,6 +120,12 @@ namespace gay.lilyy.SoldAvatarBootstrap
return;
}
// If the avatar is part of a prefab instance, use the instance root so we create overrides.
if (PrefabUtility.IsPartOfPrefabInstance(root))
{
root = PrefabUtility.GetNearestPrefabInstanceRoot(root);
}
// Skip if the root GameObject or the component itself is disabled
if (!root.activeSelf || !root.gameObject.activeInHierarchy)
{
@ -177,7 +209,8 @@ namespace gay.lilyy.SoldAvatarBootstrap
AvatarLogger.LogInfo($"Average per layer group: {(processedCount > 0 ? totalLayerGroupTime / processedCount : 0)}ms");
// replace the animator controller
var animatorControllers = root.GetComponent<VRCAvatarDescriptor>().baseAnimationLayers
var descriptor = root.GetComponent<VRCAvatarDescriptor>();
var animatorControllers = descriptor.baseAnimationLayers
.ToList();
animatorControllers.RemoveAll(layer => layer.type == VRCAvatarDescriptor.AnimLayerType.FX);
animatorControllers.Add(new VRCAvatarDescriptor.CustomAnimLayer
@ -185,7 +218,12 @@ namespace gay.lilyy.SoldAvatarBootstrap
type = VRCAvatarDescriptor.AnimLayerType.FX,
animatorController = assets.fx
});
root.GetComponent<VRCAvatarDescriptor>().baseAnimationLayers = animatorControllers.ToArray();
descriptor.baseAnimationLayers = animatorControllers.ToArray();
if (PrefabUtility.IsPartOfPrefabInstance(root))
{
PrefabUtility.RecordPrefabInstancePropertyModifications(descriptor);
}
}
}
}

View file

@ -11,9 +11,12 @@ namespace gay.lilyy.SoldAvatarBootstrap
public static IEnumerable<AvatarDefinition> Instances => instances;
public abstract string DisplayName { get; }
public abstract string SystemName { get; }
public abstract string FXLayerPath { get; }
public virtual AvatarDefinition[] Extends => new AvatarDefinition[0];
public abstract bool IsApplicable(GameObject avatarRoot);
}