Bring in AAC!
project ive been working on for a while, just felt confident enough to move it here
This commit is contained in:
parent
e608e2a56b
commit
1d7052a258
209 changed files with 1561 additions and 74738 deletions
8
AAC/AACShared/Layers.meta
Normal file
8
AAC/AACShared/Layers.meta
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: fbd24b1ba03c78f4bbb7279612566919
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
27
AAC/AACShared/Layers/AACSharedLayers.asmdef
Normal file
27
AAC/AACShared/Layers/AACSharedLayers.asmdef
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
{
|
||||
"name": "AACSharedLayers",
|
||||
"rootNamespace": "",
|
||||
"references": [
|
||||
"GUID:8d0a4403a05276c4087dd785a3c7818d",
|
||||
"GUID:95124d49b8c897e4286f0bf6c6e57f4d",
|
||||
"GUID:5718fb738711cd34ea54e9553040911d",
|
||||
"GUID:b906909fcc54f634db50f2cad0f988d9",
|
||||
"GUID:d689052aa981bf8459346a530f6e6678",
|
||||
"GUID:71d9dcc7d30ab1c45866d01afa59b6cf",
|
||||
"GUID:04a7e5cf006503242b1db329a84d694d",
|
||||
"GUID:62ced99b048af7f4d8dfe4bed8373d76",
|
||||
"GUID:e73da13578f7b4d4fa785d6f8fe72ba3",
|
||||
"GUID:fc900867c0f47cd49b6e2ae4ef907300"
|
||||
],
|
||||
"includePlatforms": [
|
||||
"Editor"
|
||||
],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": false,
|
||||
"overrideReferences": false,
|
||||
"precompiledReferences": [],
|
||||
"autoReferenced": true,
|
||||
"defineConstraints": [],
|
||||
"versionDefines": [],
|
||||
"noEngineReferences": false
|
||||
}
|
||||
7
AAC/AACShared/Layers/AACSharedLayers.asmdef.meta
Normal file
7
AAC/AACShared/Layers/AACSharedLayers.asmdef.meta
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 82ac5caf0663be04faa61ac94362fd55
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
217
AAC/AACShared/Layers/ChildToggle.cs
Normal file
217
AAC/AACShared/Layers/ChildToggle.cs
Normal file
|
|
@ -0,0 +1,217 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using AnimatorAsCode.V1;
|
||||
using gay.lilyy.aaccore;
|
||||
using gay.lilyy.aacshared.runtimecomponents;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using VRC.SDK3.Avatars.ScriptableObjects;
|
||||
using AnimatorAsCode.V1.ModularAvatar;
|
||||
using nadena.dev.modular_avatar.core;
|
||||
|
||||
namespace gay.lilyy.aacshared.layers {
|
||||
[InitializeOnLoad]
|
||||
public class ChildToggle : LayerGroup
|
||||
{
|
||||
// remove when ready for uploaded
|
||||
public override bool experimental => false;
|
||||
public override bool shouldWarnIfNotApplicable => false;
|
||||
private static readonly ChildToggle _instance = new();
|
||||
|
||||
static ChildToggle() {}
|
||||
|
||||
public override string DisplayName => "Child Toggle";
|
||||
public override string SystemName => "childtoggle";
|
||||
|
||||
private static ChildToggleDefinition[] getDefinitions(AACAssets assets)
|
||||
{
|
||||
return assets.ctx.AvatarRootObject.GetComponentsInChildren<ChildToggleDefinition>();
|
||||
}
|
||||
|
||||
public override bool IsApplicable(AACAssets assets)
|
||||
{
|
||||
return getDefinitions(assets).Length > 0;
|
||||
}
|
||||
|
||||
private AacFlBoolParameter createLayer(AACAssets assets, ChildToggleDefinition definition, Transform transform)
|
||||
{
|
||||
var layer = assets.fx.NewLayer($"Child toggle {definition.name} {transform.name}");
|
||||
var toggle = layer.BoolParameter($"child_{definition.name}_{transform.name}");
|
||||
|
||||
var idle = layer.NewState("Idle").WithAnimation(assets.emptyClip);
|
||||
var flipped = layer.NewState("Flipped").WithAnimation(assets.aac.NewClip().Toggling(transform.gameObject, !transform.gameObject.activeSelf));
|
||||
|
||||
idle.TransitionsTo(flipped).When(toggle.IsEqualTo(true));
|
||||
flipped.TransitionsTo(idle).When(toggle.IsEqualTo(false));
|
||||
|
||||
return toggle;
|
||||
}
|
||||
|
||||
/**
|
||||
<summary>
|
||||
im gonna be so honest i got cursor to hack together my MusicPlayer's menu creator into this monstrosity. im so sorry.
|
||||
</summary>
|
||||
<param name="assets">The AACAssets instance.</param>
|
||||
<param name="definition">The ChildToggleDefinition instance.</param>
|
||||
<param name="childParameters">A dictionary of child transforms and their corresponding toggle parameters.</param>
|
||||
<param name="sharedFolderHierarchy">A shared dictionary of folder paths to GameObjects across all definitions.</param>
|
||||
*/
|
||||
private GameObject FindOrCreateFolder(GameObject parent, string folderName, Dictionary<string, GameObject> sharedFolderHierarchy, string fullPath, Transform definitionTransform, HashSet<GameObject> allRootMenus)
|
||||
{
|
||||
// Check if folder already exists in shared hierarchy
|
||||
if (sharedFolderHierarchy.ContainsKey(fullPath))
|
||||
{
|
||||
var existingFolder = sharedFolderHierarchy[fullPath];
|
||||
// Verify it still exists and is accessible
|
||||
if (existingFolder != null)
|
||||
{
|
||||
return existingFolder;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Remove stale entry
|
||||
sharedFolderHierarchy.Remove(fullPath);
|
||||
}
|
||||
}
|
||||
|
||||
// Check if a folder with the same name already exists as a sibling in current parent
|
||||
foreach (Transform child in parent.transform)
|
||||
{
|
||||
var existingMenuItem = child.GetComponent<ModularAvatarMenuItem>();
|
||||
if (existingMenuItem != null && existingMenuItem.label == folderName)
|
||||
{
|
||||
// Found existing folder, add it to shared hierarchy and return it
|
||||
sharedFolderHierarchy[fullPath] = child.gameObject;
|
||||
return child.gameObject;
|
||||
}
|
||||
}
|
||||
|
||||
// Check all other root menus for a folder with the same name at the same level
|
||||
// This prevents duplicate folders when multiple definitions share the same MenuPath prefix
|
||||
foreach (var rootMenu in allRootMenus)
|
||||
{
|
||||
if (rootMenu == parent) continue; // Skip current menu
|
||||
|
||||
// If we're at root level (parent is a Menu_*), check root level of other menus
|
||||
// If we're in a nested folder, check the same nesting level
|
||||
if (parent.name.StartsWith("Menu_") && rootMenu.name.StartsWith("Menu_"))
|
||||
{
|
||||
// Check root level folders
|
||||
foreach (Transform child in rootMenu.transform)
|
||||
{
|
||||
var existingMenuItem = child.GetComponent<ModularAvatarMenuItem>();
|
||||
if (existingMenuItem != null && existingMenuItem.label == folderName)
|
||||
{
|
||||
// Found existing folder in another root menu, reuse it
|
||||
sharedFolderHierarchy[fullPath] = child.gameObject;
|
||||
return child.gameObject;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create new folder
|
||||
var folderGo = new GameObject($"Folder_{folderName}");
|
||||
folderGo.transform.SetParent(parent.transform);
|
||||
var folderMenuItem = folderGo.AddComponent<ModularAvatarMenuItem>();
|
||||
folderMenuItem.label = folderName;
|
||||
folderMenuItem.Control.type = VRCExpressionsMenu.Control.ControlType.SubMenu;
|
||||
folderMenuItem.MenuSource = SubmenuSource.Children;
|
||||
|
||||
sharedFolderHierarchy[fullPath] = folderGo;
|
||||
return folderGo;
|
||||
}
|
||||
|
||||
private void CreateMenu(AACAssets assets, ChildToggleDefinition definition, Dictionary<Transform, AacFlBoolParameter> childParameters, Dictionary<string, GameObject> sharedFolderHierarchy, HashSet<GameObject> allRootMenus)
|
||||
{
|
||||
if (childParameters.Count == 0) return;
|
||||
|
||||
var menuGo = new GameObject($"Menu_{definition.name}");
|
||||
menuGo.transform.SetParent(definition.transform);
|
||||
var menuItem = menuGo.AddComponent<ModularAvatarMenuItem>();
|
||||
menuItem.label = "Child Toggle";
|
||||
menuItem.Control.type = VRCExpressionsMenu.Control.ControlType.SubMenu;
|
||||
menuItem.MenuSource = SubmenuSource.Children;
|
||||
|
||||
allRootMenus.Add(menuGo);
|
||||
|
||||
GameObject firstFolder = null;
|
||||
|
||||
foreach (var kvp in childParameters)
|
||||
{
|
||||
var childTransform = kvp.Key;
|
||||
var toggleParam = kvp.Value;
|
||||
GameObject currentParent = menuGo;
|
||||
|
||||
// Create folder hierarchy if MenuPath is specified
|
||||
if (!string.IsNullOrEmpty(definition.MenuPath))
|
||||
{
|
||||
string[] folderPath = definition.MenuPath.Split('/');
|
||||
|
||||
// Create nested folder structure
|
||||
for (int i = 0; i < folderPath.Length; i++)
|
||||
{
|
||||
string folderName = folderPath[i];
|
||||
string fullPath = string.Join("/", folderPath, 0, i + 1);
|
||||
|
||||
currentParent = FindOrCreateFolder(currentParent, folderName, sharedFolderHierarchy, fullPath, definition.transform, allRootMenus);
|
||||
|
||||
// Store the first folder for MenuInstaller
|
||||
if (firstFolder == null && i == 0)
|
||||
{
|
||||
firstFolder = currentParent;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create the toggle menu item
|
||||
var go = new GameObject($"Toggle_{childTransform.name}");
|
||||
go.transform.SetParent(currentParent.transform);
|
||||
assets.modularAvatar.EditMenuItem(go).Toggle(toggleParam).Name(childTransform.name);
|
||||
}
|
||||
|
||||
// Place MenuInstaller on the first folder if it exists, otherwise on root menu
|
||||
if (firstFolder != null)
|
||||
{
|
||||
// Only add MenuInstaller if it doesn't already exist
|
||||
if (firstFolder.GetComponent<ModularAvatarMenuInstaller>() == null)
|
||||
{
|
||||
firstFolder.AddComponent<ModularAvatarMenuInstaller>();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
menuGo.AddComponent<ModularAvatarMenuInstaller>();
|
||||
}
|
||||
}
|
||||
|
||||
private void runDefinition(AACAssets assets, ChildToggleDefinition definition, Dictionary<string, GameObject> sharedFolderHierarchy, HashSet<GameObject> allRootMenus)
|
||||
{
|
||||
var childParameters = new Dictionary<Transform, AacFlBoolParameter>();
|
||||
|
||||
foreach (Transform child in definition.transform)
|
||||
{
|
||||
var toggleParam = createLayer(assets, definition, child);
|
||||
childParameters[child] = toggleParam;
|
||||
}
|
||||
|
||||
CreateMenu(assets, definition, childParameters, sharedFolderHierarchy, allRootMenus);
|
||||
}
|
||||
|
||||
public override void Run(AACAssets assets)
|
||||
{
|
||||
var definitions = getDefinitions(assets);
|
||||
Logger.LogDebug($"Child Toggle system: Found {definitions.Length} child toggle definitions");
|
||||
|
||||
// Shared folder hierarchy across all definitions to prevent duplicates
|
||||
var sharedFolderHierarchy = new Dictionary<string, GameObject>();
|
||||
// Track all root menus to check for duplicate folders
|
||||
var allRootMenus = new HashSet<GameObject>();
|
||||
|
||||
foreach (var definition in definitions)
|
||||
{
|
||||
runDefinition(assets, definition, sharedFolderHierarchy, allRootMenus);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
11
AAC/AACShared/Layers/ChildToggle.cs.meta
Normal file
11
AAC/AACShared/Layers/ChildToggle.cs.meta
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 2c428d7f31c05e0479683c9b1f17a05d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
156
AAC/AACShared/Layers/Floater.cs
Normal file
156
AAC/AACShared/Layers/Floater.cs
Normal file
|
|
@ -0,0 +1,156 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using gay.lilyy.aaccore;
|
||||
using gay.lilyy.aacshared.runtimecomponents;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace gay.lilyy.aacshared.layers {
|
||||
[InitializeOnLoad]
|
||||
public class Floater : LayerGroup
|
||||
{
|
||||
// remove when ready for uploaded
|
||||
public override bool experimental => false;
|
||||
public override bool shouldWarnIfNotApplicable => false;
|
||||
private static readonly Floater _instance = new();
|
||||
|
||||
static Floater() {}
|
||||
|
||||
public override string DisplayName => "Floater";
|
||||
public override string SystemName => "floater";
|
||||
|
||||
private static FloaterDefinition[] getDefinitions(AACAssets assets)
|
||||
{
|
||||
return assets.ctx.AvatarRootObject.GetComponentsInChildren<FloaterDefinition>();
|
||||
}
|
||||
|
||||
public override bool IsApplicable(AACAssets assets)
|
||||
{
|
||||
return getDefinitions(assets).Length > 0;
|
||||
}
|
||||
|
||||
private void createLayer(AACAssets assets, MultiTransformDefinition multiDef)
|
||||
{
|
||||
var layer = assets.fx.NewLayer($"Floater {multiDef.Definition.name} and {multiDef.Transforms.Count - 1} more");
|
||||
if (!new[] { "x", "y", "z" }.Contains(multiDef.Definition.spinAxis.ToLower()))
|
||||
{
|
||||
Logger.LogWarning($"Floater system: Invalid spin axis '{multiDef.Definition.spinAxis}' in definition '{multiDef.Definition.name}'. Must be one of 'x', 'y', or 'z'. Skipping.");
|
||||
return;
|
||||
}
|
||||
|
||||
var state = layer.NewState("Floater").WithAnimation(assets.aac.NewClip().Animating(action =>
|
||||
{
|
||||
Logger.LogInfo($"Floater system: Creating animation for definition '{multiDef.Definition.name}' with {multiDef.Transforms.Count} transforms");
|
||||
foreach (var t in multiDef.Transforms)
|
||||
{
|
||||
if (multiDef.Definition.floatHeight != 0f)
|
||||
{
|
||||
action.Animates(t, "m_LocalPosition.y").WithSecondsUnit(unit =>
|
||||
{
|
||||
unit
|
||||
.Easing(0, t.transform.localPosition.y);
|
||||
unit
|
||||
.Easing(multiDef.Definition.loopInSeconds / 2f, t.transform.localPosition.y + multiDef.Definition.floatHeight)
|
||||
.Easing(multiDef.Definition.loopInSeconds, t.transform.localPosition.y);
|
||||
});
|
||||
}
|
||||
if (multiDef.Definition.spinCycles > 0)
|
||||
{
|
||||
string axis = multiDef.Definition.spinAxis.ToLower();
|
||||
string prop = $"m_LocalEulerAngles.{axis}";
|
||||
float segment = multiDef.Definition.loopInSeconds / multiDef.Definition.spinCycles;
|
||||
|
||||
for (int cycle = 0; cycle < multiDef.Definition.spinCycles; cycle++)
|
||||
{
|
||||
action.Animates(t, prop).WithSecondsUnit(unit =>
|
||||
{
|
||||
float baseAngle = 0f; // ignore quaternion components entirely
|
||||
float startTime = cycle * segment;
|
||||
float endTime = (cycle + 1) * segment;
|
||||
|
||||
float startAngle = baseAngle + 360f * cycle;
|
||||
float endAngle = baseAngle + 360f * (cycle + 1);
|
||||
|
||||
Logger.LogDebug($"Floater system: Animating {t.name} {prop} on cycle {cycle} from {startAngle} to {endAngle} between {startTime}s and {endTime}s");
|
||||
unit
|
||||
.Linear(startTime, startAngle)
|
||||
.Linear(endTime, endAngle);
|
||||
|
||||
Logger.LogDebug($"unit.Linear({startTime}, {startAngle}).Linear({endTime}, {endAngle})");
|
||||
});
|
||||
}
|
||||
|
||||
// Fill OTHER Euler axes with constant values
|
||||
foreach (var other in new[] { "x", "y", "z" })
|
||||
{
|
||||
if (other == axis) continue;
|
||||
float current =
|
||||
other == "x" ? t.transform.localEulerAngles.x :
|
||||
other == "y" ? t.transform.localEulerAngles.y :
|
||||
t.transform.localEulerAngles.z;
|
||||
|
||||
Logger.LogDebug($"Floater system: Setting constant {t.name} {other} to {current}");
|
||||
|
||||
action.Animates(t, $"m_LocalEulerAngles.{other}")
|
||||
.WithSecondsUnit(unit =>
|
||||
{
|
||||
unit
|
||||
.Linear(0f, current)
|
||||
.Linear(multiDef.Definition.loopInSeconds, current);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}).Looping());
|
||||
|
||||
if (multiDef.Definition.toggleParamName != "")
|
||||
{
|
||||
var param = layer.BoolParameter(multiDef.Definition.toggleParamName);
|
||||
var offState = layer.NewState("Floater Off").WithAnimation(assets.emptyClip);
|
||||
layer.WithDefaultState(offState);
|
||||
|
||||
offState.TransitionsTo(state).When(param.IsTrue());
|
||||
state.TransitionsTo(offState).When(param.IsFalse());
|
||||
}
|
||||
}
|
||||
private struct MultiTransformDefinition
|
||||
{
|
||||
public List<Transform> Transforms { get; set; }
|
||||
public FloaterDefinition Definition { get; set; }
|
||||
}
|
||||
|
||||
public override void Run(AACAssets assets)
|
||||
{
|
||||
var definitions = getDefinitions(assets);
|
||||
Logger.LogDebug($"Floater system: Found {definitions.Length} floater definitions");
|
||||
|
||||
var matchedDefinitions = new Dictionary<int, MultiTransformDefinition>();
|
||||
foreach (var def in definitions)
|
||||
{
|
||||
if (!def.enabled) continue;
|
||||
if (!def.enableOnPC && assets.isPC) continue;
|
||||
if (!def.enableOnMobile && !assets.isPC) continue;
|
||||
Logger.LogInfo($"Floater system: Found definition '{def.name}'");
|
||||
var hash = def.GetHashCode();
|
||||
if (!matchedDefinitions.ContainsKey(hash))
|
||||
{
|
||||
matchedDefinitions[hash] = new MultiTransformDefinition
|
||||
{
|
||||
Definition = def,
|
||||
Transforms = new List<Transform>()
|
||||
};
|
||||
} else
|
||||
{
|
||||
Logger.LogInfo($"Floater system: Adding additional transform to definition '{def.name}'");
|
||||
}
|
||||
matchedDefinitions[hash].Transforms.Add(def.transform);
|
||||
}
|
||||
|
||||
foreach (var multiDef in matchedDefinitions.Values)
|
||||
{
|
||||
createLayer(assets, multiDef);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
11
AAC/AACShared/Layers/Floater.cs.meta
Normal file
11
AAC/AACShared/Layers/Floater.cs.meta
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 8c1340bf8df44f24cabe4db762796c21
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
187
AAC/AACShared/Layers/LanternFlicker.cs
Normal file
187
AAC/AACShared/Layers/LanternFlicker.cs
Normal file
|
|
@ -0,0 +1,187 @@
|
|||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using AnimatorAsCode.V1;
|
||||
using System.Collections.Generic;
|
||||
using gay.lilyy.aaccore;
|
||||
|
||||
namespace gay.lilyy.aacshared.layers
|
||||
{
|
||||
/**
|
||||
<summary>
|
||||
ported from v5
|
||||
</summary>
|
||||
*/
|
||||
[InitializeOnLoad]
|
||||
public class LanternFlicker : LayerGroup
|
||||
{
|
||||
private static readonly LanternFlicker _instance = new();
|
||||
|
||||
static LanternFlicker() { }
|
||||
|
||||
public override string DisplayName => "Lantern Flicker";
|
||||
public override string SystemName => "lantern_flicker";
|
||||
public override bool shouldWarnIfNotApplicable => false;
|
||||
|
||||
private Transform GetLantern(AACAssets assets)
|
||||
{
|
||||
return AACUtils.FindChildRecursive(assets.ctx.AvatarRootTransform, "Lantern Floater");
|
||||
}
|
||||
|
||||
public override bool IsApplicable(AACAssets assets)
|
||||
{
|
||||
var lamp = GetLantern(assets);
|
||||
if (lamp == null)
|
||||
{
|
||||
Logger.LogWarning("Lamp Light could not be found!");
|
||||
return false;
|
||||
}
|
||||
var light = lamp.GetComponentInChildren<Light>();
|
||||
return light != null;
|
||||
}
|
||||
|
||||
private void CreateFlickerLayer(AACAssets assets)
|
||||
{
|
||||
var lamp = GetLantern(assets);
|
||||
var light = lamp.GetComponentInChildren<Light>();
|
||||
|
||||
var layer = assets.fx.NewLayer("Lantern Flicker");
|
||||
var flickerParam = layer.BoolParameter("LanternFlicker");
|
||||
|
||||
var off = layer.NewState("Off").WithAnimation(
|
||||
assets.aac.NewClip().Animating(anim =>
|
||||
{
|
||||
if (light != null) {
|
||||
anim.Animates(light, "m_Enabled").WithFrameCountUnit(sec =>
|
||||
{
|
||||
sec.Constant(0, 0);
|
||||
});
|
||||
anim.Animates(light, "m_Intensity").WithFrameCountUnit(sec =>
|
||||
{
|
||||
sec.Constant(0, light.intensity);
|
||||
});
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
layer.WithDefaultState(off);
|
||||
|
||||
var on = layer.NewState("Flicker").WithAnimation(
|
||||
assets.aac.NewClip().Animating(anim =>
|
||||
{
|
||||
AnimateLantern(assets, anim, lamp);
|
||||
}).Looping()
|
||||
);
|
||||
|
||||
off.TransitionsTo(on).When(flickerParam.IsEqualTo(true));
|
||||
on.TransitionsTo(off).When(flickerParam.IsEqualTo(false));
|
||||
}
|
||||
|
||||
private void CreateBrightnessLayer(AACAssets assets)
|
||||
{
|
||||
var lamp = GetLantern(assets);
|
||||
var light = lamp.GetComponentInChildren<Light>();
|
||||
if (light == null) return;
|
||||
|
||||
var layer = assets.fx.NewLayer("Lantern Brightness");
|
||||
var brightnessParam = layer.FloatParameter("LanternBrightness");
|
||||
|
||||
var state = layer.NewState("Brightness").WithAnimation(
|
||||
assets.aac.NewClip().Animating(anim =>
|
||||
{
|
||||
anim.Animates(light, "m_Enabled").WithUnit(AacFlUnit.Frames, sec =>
|
||||
{
|
||||
sec.Linear(0, 0);
|
||||
sec.Linear(1, 1);
|
||||
});
|
||||
anim.AnimatesColor(light, "m_Color").WithUnit(AacFlUnit.Frames, sec =>
|
||||
{
|
||||
sec.Linear(0, light.color * 0);
|
||||
sec.Linear(100, light.color);
|
||||
});
|
||||
})
|
||||
).WithMotionTime(brightnessParam);
|
||||
}
|
||||
|
||||
private void AnimateLantern(AACAssets assets, AacFlEditClip anim, Transform lantern)
|
||||
{
|
||||
var renderer = lantern.GetComponent<MeshRenderer>();
|
||||
var light = lantern.GetComponentInChildren<Light>();
|
||||
if (renderer == null)
|
||||
{
|
||||
Logger.LogWarning("AnimateLantern: Missing renderer on lantern");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
var rng = new System.Random("lillithlanternrandomseed".GetHashCode());
|
||||
|
||||
var keyframes = new List<(float time, double value)>();
|
||||
float time = 0;
|
||||
while (time < 60)
|
||||
{
|
||||
double value = rng.NextDouble();
|
||||
keyframes.Add((time, value));
|
||||
|
||||
time += (float)(rng.NextDouble() * (0.3 - 0.05) + 0.05);
|
||||
}
|
||||
|
||||
if (keyframes.Count == 0)
|
||||
{
|
||||
Logger.LogWarning("AnimateLantern: No keyframes generated");
|
||||
}
|
||||
|
||||
if (light != null)
|
||||
{
|
||||
anim.Animates(light, "m_Intensity").WithSecondsUnit(sec =>
|
||||
{
|
||||
foreach (var (t, v) in keyframes)
|
||||
{
|
||||
sec.Easing(t, (float)v * light.intensity);
|
||||
}
|
||||
});
|
||||
}
|
||||
if (assets.isPC) {
|
||||
Logger.LogInfo("Using PC material for lantern flicker");
|
||||
Color initialColor = renderer.sharedMaterial.GetColor("_Emission_Color");
|
||||
// ValueFactory Orbits
|
||||
var prop = "material._Emission_Color";
|
||||
void animateChannel(string suffix, float initial)
|
||||
{
|
||||
anim.Animates(renderer, $"{prop}.{suffix}").WithSecondsUnit(sec =>
|
||||
{
|
||||
foreach (var (t, v) in keyframes)
|
||||
{
|
||||
sec.Easing(t, initial * (float)v);
|
||||
}
|
||||
});
|
||||
}
|
||||
animateChannel("x", initialColor.r);
|
||||
animateChannel("y", initialColor.g);
|
||||
animateChannel("z", initialColor.b);
|
||||
animateChannel("w", initialColor.a);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Toon Standard
|
||||
Logger.LogInfo("Using Non-PC material for lantern flicker");
|
||||
|
||||
// float initialStrength = renderer.sharedMaterial.GetFloat("_EmissionStrength");
|
||||
// this still isnt running before vqt for some cursed reason so im just gonna hardcode this
|
||||
var initialStrength = 2;
|
||||
anim.Animates(renderer, "material._EmissionStrength").WithSecondsUnit(sec =>
|
||||
{
|
||||
foreach (var (t, v) in keyframes)
|
||||
{
|
||||
sec.Easing(t, initialStrength * (float)v);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public override void Run(AACAssets assets)
|
||||
{
|
||||
CreateFlickerLayer(assets);
|
||||
CreateBrightnessLayer(assets);
|
||||
}
|
||||
}
|
||||
}
|
||||
11
AAC/AACShared/Layers/LanternFlicker.cs.meta
Normal file
11
AAC/AACShared/Layers/LanternFlicker.cs.meta
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: b23933d2d4383264e8a63812c8580be2
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
114
AAC/AACShared/Layers/ParameterPreset.cs
Normal file
114
AAC/AACShared/Layers/ParameterPreset.cs
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
using System.Collections.Generic;
|
||||
using AnimatorAsCode.V1;
|
||||
using AnimatorAsCode.V1.VRC;
|
||||
using gay.lilyy.aaccore;
|
||||
using gay.lilyy.aacshared.runtimecomponents;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using VRC.SDK3.Avatars.ScriptableObjects;
|
||||
|
||||
namespace gay.lilyy.aacshared.layers
|
||||
{
|
||||
[InitializeOnLoad]
|
||||
public class ParameterPreset : LayerGroup
|
||||
{
|
||||
private static readonly ParameterPreset _instance = new();
|
||||
|
||||
static ParameterPreset() { }
|
||||
|
||||
public override string DisplayName => "Parameter Preset";
|
||||
public override string SystemName => "parameter_preset";
|
||||
public override bool shouldWarnIfNotApplicable => false;
|
||||
|
||||
private static ParameterPresetDefinition[] getDefinitions(AACAssets assets)
|
||||
{
|
||||
return assets.ctx.AvatarRootObject.GetComponents<ParameterPresetDefinition>();
|
||||
}
|
||||
|
||||
public override bool IsApplicable(AACAssets assets)
|
||||
{
|
||||
return getDefinitions(assets).Length > 0;
|
||||
}
|
||||
|
||||
private void RunGroup(AACAssets assets, List<ParameterPresetDefinition> presets)
|
||||
{
|
||||
if (presets.Count == 0) return; // If there are none in the avatar, skip this entirely.
|
||||
|
||||
var layer = assets.fx.NewLayer("Presets " + presets[0].Group);
|
||||
var presetParam = layer.IntParameter("Preset " + presets[0].Group);
|
||||
Dictionary<string, AacFlParameter<int>> intParams = new();
|
||||
Dictionary<string, AacFlParameter<float>> floatParams = new();
|
||||
Dictionary<string, AacFlParameter<bool>> boolParams = new();
|
||||
var idle = layer.NewState("Idle").WithAnimation(assets.emptyClip);
|
||||
layer.WithDefaultState(idle);
|
||||
|
||||
var presetIndex = 0;
|
||||
foreach (var preset in presets)
|
||||
{
|
||||
presetIndex++;
|
||||
var state = layer.NewState("Preset " + preset.Name)
|
||||
.WithAnimation(assets.emptyClip);
|
||||
|
||||
foreach (var param in preset.Parameters)
|
||||
{
|
||||
if (!param.shouldChange) continue;
|
||||
switch (param.valueType)
|
||||
{
|
||||
case VRCExpressionParameters.ValueType.Int:
|
||||
{
|
||||
if (!intParams.ContainsKey(param.name))
|
||||
{
|
||||
intParams[param.name] = layer.IntParameter(param.name);
|
||||
}
|
||||
var layerParam = intParams[param.name];
|
||||
state.Drives(layerParam, (int)param.setTo);
|
||||
break;
|
||||
}
|
||||
case VRCExpressionParameters.ValueType.Float:
|
||||
{
|
||||
if (!floatParams.ContainsKey(param.name))
|
||||
{
|
||||
floatParams[param.name] = layer.FloatParameter(param.name);
|
||||
}
|
||||
var layerParam = floatParams[param.name];
|
||||
state.Drives(layerParam, param.setTo);
|
||||
break;
|
||||
}
|
||||
case VRCExpressionParameters.ValueType.Bool:
|
||||
{
|
||||
if (!boolParams.ContainsKey(param.name))
|
||||
{
|
||||
boolParams[param.name] = layer.BoolParameter(param.name);
|
||||
}
|
||||
var layerParam = boolParams[param.name];
|
||||
state.Drives(layerParam, param.setTo > 0.5f);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
idle.TransitionsTo(state).When(presetParam.IsEqualTo(presetIndex));
|
||||
state.TransitionsTo(idle).When(presetParam.IsEqualTo(0));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public override void Run(AACAssets assets)
|
||||
{
|
||||
var presets = getDefinitions(assets);
|
||||
Dictionary<string, List<ParameterPresetDefinition>> groupedPresets = new();
|
||||
foreach (var preset in presets)
|
||||
{
|
||||
if (!groupedPresets.ContainsKey(preset.Group))
|
||||
{
|
||||
groupedPresets[preset.Group] = new List<ParameterPresetDefinition>();
|
||||
}
|
||||
groupedPresets[preset.Group].Add(preset);
|
||||
}
|
||||
foreach (var group in groupedPresets)
|
||||
{
|
||||
RunGroup(assets, group.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
11
AAC/AACShared/Layers/ParameterPreset.cs.meta
Normal file
11
AAC/AACShared/Layers/ParameterPreset.cs.meta
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 35b03c4eb985a2a489054b0738690d57
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
9
AAC/AACShared/README.md
Normal file
9
AAC/AACShared/README.md
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
# AACShared
|
||||
|
||||
A group of AACCore layers that arent avatar specific
|
||||
|
||||
lillith if u dont make all of these togglable / configurable im going to commit
|
||||
|
||||
im so fr
|
||||
|
||||
also MAKE SURE ALL LAYERS HAVE `public override bool shouldWarnIfNotApplicable => false;`
|
||||
7
AAC/AACShared/README.md.meta
Normal file
7
AAC/AACShared/README.md.meta
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 6b5e9937d32bd674fb0909528112acc2
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
AAC/AACShared/Runtime.meta
Normal file
8
AAC/AACShared/Runtime.meta
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 71318e6f58f43d24b911579de721d22b
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
16
AAC/AACShared/Runtime/AACSharedRuntime.asmdef
Normal file
16
AAC/AACShared/Runtime/AACSharedRuntime.asmdef
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
{
|
||||
"name": "AACSharedRuntime",
|
||||
"rootNamespace": "",
|
||||
"references": [
|
||||
"GUID:3456780c4fb2d324ab9c633d6f1b0ddb"
|
||||
],
|
||||
"includePlatforms": [],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": false,
|
||||
"overrideReferences": false,
|
||||
"precompiledReferences": [],
|
||||
"autoReferenced": true,
|
||||
"defineConstraints": [],
|
||||
"versionDefines": [],
|
||||
"noEngineReferences": false
|
||||
}
|
||||
7
AAC/AACShared/Runtime/AACSharedRuntime.asmdef.meta
Normal file
7
AAC/AACShared/Runtime/AACSharedRuntime.asmdef.meta
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
fileFormatVersion: 2
|
||||
guid: e73da13578f7b4d4fa785d6f8fe72ba3
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
36
AAC/AACShared/Runtime/ChildToggleDefinition.cs
Normal file
36
AAC/AACShared/Runtime/ChildToggleDefinition.cs
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
using System;
|
||||
using UnityEngine;
|
||||
using VRC.SDKBase;
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
#endif
|
||||
|
||||
namespace gay.lilyy.aacshared.runtimecomponents
|
||||
{
|
||||
public class ChildToggleDefinition : MonoBehaviour, IEditorOnly {
|
||||
|
||||
// unity needs this to show the enable/disable box
|
||||
void Start(){}
|
||||
|
||||
public string MenuPath = "";
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
[CustomEditor(typeof(ChildToggleDefinition))]
|
||||
public class ChildToggleDefinitionInspector : Editor
|
||||
{
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
EditorGUILayout.HelpBox(
|
||||
"Any direct children of this object will have a toggle in the menu",
|
||||
MessageType.Info
|
||||
);
|
||||
|
||||
EditorGUILayout.Space();
|
||||
|
||||
// Draw the default inspector to show the 'enable' field
|
||||
DrawDefaultInspector();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
11
AAC/AACShared/Runtime/ChildToggleDefinition.cs.meta
Normal file
11
AAC/AACShared/Runtime/ChildToggleDefinition.cs.meta
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: be675dd25b2a8854687c05c2ab33af0c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
35
AAC/AACShared/Runtime/FloaterDefinition.cs
Normal file
35
AAC/AACShared/Runtime/FloaterDefinition.cs
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
using System;
|
||||
using UnityEngine;
|
||||
using VRC.SDKBase;
|
||||
|
||||
namespace gay.lilyy.aacshared.runtimecomponents
|
||||
{
|
||||
public class FloaterDefinition: MonoBehaviour, IEditorOnly {
|
||||
|
||||
// unity needs this to show the enable/disable box
|
||||
void Start(){}
|
||||
public float floatHeight = 0;
|
||||
[Tooltip("Time in seconds for one full spin cycle")]
|
||||
public float loopInSeconds = 10f;
|
||||
[Tooltip("Number of times object spins in one loop")]
|
||||
public int spinCycles = 2;
|
||||
[Tooltip("Axis to spin around (x, y, or z)")]
|
||||
public string spinAxis = "z";
|
||||
public bool enableOnPC = true;
|
||||
[Tooltip("Quest, Pico, Android/iOS Mobile, etc.")]
|
||||
public bool enableOnMobile = true;
|
||||
|
||||
[Tooltip("If set, this parameter will toggle the floater on/off")]
|
||||
public string toggleParamName = "";
|
||||
|
||||
|
||||
/** <summary>
|
||||
Compares two FloaterDefinitions for equality based on their properties.
|
||||
Used for chunking similar floaters into one animation layer
|
||||
</summary> */
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return HashCode.Combine(floatHeight, loopInSeconds, spinCycles, enableOnPC, enableOnMobile, toggleParamName);
|
||||
}
|
||||
}
|
||||
}
|
||||
11
AAC/AACShared/Runtime/FloaterDefinition.cs.meta
Normal file
11
AAC/AACShared/Runtime/FloaterDefinition.cs.meta
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 3b3b5f65ee33db24bbb5f0042bec1f87
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
224
AAC/AACShared/Runtime/ParameterPresetDefinition.cs
Normal file
224
AAC/AACShared/Runtime/ParameterPresetDefinition.cs
Normal file
|
|
@ -0,0 +1,224 @@
|
|||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using VRC.SDK3.Avatars.ScriptableObjects;
|
||||
using VRC.SDKBase;
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
using System.Linq;
|
||||
using VRC.SDK3.Avatars.Components;
|
||||
#endif
|
||||
|
||||
namespace gay.lilyy.aacshared.runtimecomponents
|
||||
{
|
||||
[System.Serializable]
|
||||
public class PresetParameter
|
||||
{
|
||||
public string name;
|
||||
public VRCExpressionParameters.ValueType valueType;
|
||||
public float setTo;
|
||||
public bool shouldChange = false;
|
||||
}
|
||||
|
||||
[AddComponentMenu("LillithRosePup/Parameter Preset")]
|
||||
public class ParameterPresetDefinition : MonoBehaviour, IEditorOnly
|
||||
{
|
||||
public string Name = "New Preset";
|
||||
public string Group = "Default";
|
||||
[HideInInspector] // custom inspector
|
||||
public List<PresetParameter> Parameters;
|
||||
|
||||
// unity needs this to show the enable/disable box
|
||||
void Start() { }
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
[CustomEditor(typeof(ParameterPresetDefinition))]
|
||||
public class ParameterPresetDefinitionInspector : Editor
|
||||
{
|
||||
private ParameterPresetDefinition preset;
|
||||
private bool parametersLoaded = false;
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
preset = (ParameterPresetDefinition)target;
|
||||
LoadMissingParameters();
|
||||
}
|
||||
|
||||
private void LoadMissingParameters()
|
||||
{
|
||||
VRCAvatarDescriptor aviDesc = preset.gameObject.GetComponent<VRCAvatarDescriptor>();
|
||||
if (aviDesc == null || aviDesc.expressionParameters == null || parametersLoaded)
|
||||
return;
|
||||
|
||||
// Initialize Parameters list if it's null
|
||||
if (preset.Parameters == null)
|
||||
preset.Parameters = new List<PresetParameter>();
|
||||
|
||||
// Get parameters from the Group's ParametersFile
|
||||
var sourceParameters = aviDesc.expressionParameters.parameters;
|
||||
if (sourceParameters == null)
|
||||
return;
|
||||
|
||||
// Create a dictionary of source parameters for quick lookup
|
||||
var sourceParamDict = sourceParameters.ToDictionary(p => p.name, p => p);
|
||||
|
||||
// Create a set of source parameter names
|
||||
var sourceParameterNames = new HashSet<string>(sourceParamDict.Keys);
|
||||
|
||||
// Remove parameters that exist in preset but not in source
|
||||
bool hasChanges = false;
|
||||
preset.Parameters.RemoveAll(presetParam =>
|
||||
{
|
||||
if (!sourceParameterNames.Contains(presetParam.name))
|
||||
{
|
||||
hasChanges = true;
|
||||
return true; // Remove this parameter
|
||||
}
|
||||
return false; // Keep this parameter
|
||||
});
|
||||
|
||||
// Add missing parameters and update existing ones
|
||||
foreach (var sourceParam in sourceParameters)
|
||||
{
|
||||
var existingParam = preset.Parameters.FirstOrDefault(p => p.name == sourceParam.name);
|
||||
|
||||
if (existingParam == null)
|
||||
{
|
||||
// Add new parameter
|
||||
var clonedParam = new PresetParameter
|
||||
{
|
||||
name = sourceParam.name,
|
||||
valueType = sourceParam.valueType,
|
||||
setTo = sourceParam.defaultValue,
|
||||
shouldChange = false,
|
||||
};
|
||||
|
||||
preset.Parameters.Add(clonedParam);
|
||||
hasChanges = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Update existing parameter to match source type
|
||||
if (existingParam.valueType != sourceParam.valueType)
|
||||
{
|
||||
existingParam.valueType = sourceParam.valueType;
|
||||
hasChanges = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (hasChanges)
|
||||
{
|
||||
EditorUtility.SetDirty(preset);
|
||||
Debug.Log($"Updated parameters in preset '{preset.Name}' to match source parameters file");
|
||||
}
|
||||
|
||||
parametersLoaded = true;
|
||||
}
|
||||
|
||||
private int GetPresetIndex()
|
||||
{
|
||||
VRCAvatarDescriptor aviDesc = preset.gameObject.GetComponent<VRCAvatarDescriptor>();
|
||||
if (aviDesc == null)
|
||||
return -1;
|
||||
|
||||
var presets = aviDesc.GetComponentsInChildren<ParameterPresetDefinition>().ToList().Where(p => p.Group == preset.Group).ToList();
|
||||
for (int i = 0; i < presets.Count; i++)
|
||||
{
|
||||
if (presets[i] == preset)
|
||||
{
|
||||
return i + 1; // 1-based index matching ParameterPreset.cs
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
// Ensure parameters are loaded when inspector is drawn
|
||||
LoadMissingParameters();
|
||||
|
||||
// Draw the default inspector
|
||||
DrawDefaultInspector();
|
||||
|
||||
// Display preset index
|
||||
int presetIndex = GetPresetIndex();
|
||||
if (presetIndex > 0)
|
||||
{
|
||||
EditorGUILayout.Space();
|
||||
EditorGUILayout.HelpBox($"Preset Index: {presetIndex}\n(This preset will be activated when the 'Preset {preset.Group}' parameter equals {presetIndex})", MessageType.Info);
|
||||
}
|
||||
|
||||
if (GUILayout.Button("Copy Parameter Name")) {
|
||||
GUIUtility.systemCopyBuffer = "Preset " + preset.Group;
|
||||
EditorGUILayout.LabelField("Parameter Name Copied to Clipboard", EditorStyles.boldLabel);
|
||||
}
|
||||
|
||||
// Custom parameter list rendering
|
||||
if (preset.Parameters != null && preset.Parameters.Count > 0)
|
||||
{
|
||||
EditorGUILayout.Space();
|
||||
EditorGUILayout.LabelField("Parameters", EditorStyles.boldLabel);
|
||||
|
||||
for (int i = 0; i < preset.Parameters.Count; i++)
|
||||
{
|
||||
var param = preset.Parameters[i];
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
|
||||
// Parameter name
|
||||
EditorGUILayout.LabelField(param.name, GUILayout.Width(150));
|
||||
|
||||
// Parameter type (read-only)
|
||||
EditorGUILayout.LabelField($"Type: {param.valueType}", GUILayout.Width(100));
|
||||
|
||||
// Should change toggle
|
||||
param.shouldChange = EditorGUILayout.Toggle(param.shouldChange, GUILayout.Width(60));
|
||||
|
||||
// Set to value (only show if shouldChange is true)
|
||||
if (param.shouldChange)
|
||||
{
|
||||
switch (param.valueType)
|
||||
{
|
||||
case VRCExpressionParameters.ValueType.Bool:
|
||||
param.setTo = EditorGUILayout.Toggle(param.setTo > 0.5f) ? 1f : 0f;
|
||||
break;
|
||||
case VRCExpressionParameters.ValueType.Int:
|
||||
param.setTo = EditorGUILayout.IntField((int)param.setTo);
|
||||
break;
|
||||
case VRCExpressionParameters.ValueType.Float:
|
||||
param.setTo = EditorGUILayout.FloatField(param.setTo);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
EditorGUILayout.LabelField("(unchanged)", GUILayout.Width(80));
|
||||
}
|
||||
|
||||
EditorGUILayout.EndHorizontal();
|
||||
}
|
||||
}
|
||||
|
||||
// Add a button to manually reload parameters
|
||||
EditorGUILayout.Space();
|
||||
if (GUILayout.Button("Reload Parameters from Group"))
|
||||
{
|
||||
parametersLoaded = false;
|
||||
LoadMissingParameters();
|
||||
}
|
||||
|
||||
// Add a button to clear all parameters
|
||||
if (GUILayout.Button("Clear All Parameters"))
|
||||
{
|
||||
if (EditorUtility.DisplayDialog("Clear Parameters",
|
||||
"Are you sure you want to clear all parameters from this preset?",
|
||||
"Yes", "No"))
|
||||
{
|
||||
preset.Parameters.Clear();
|
||||
EditorUtility.SetDirty(preset);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
11
AAC/AACShared/Runtime/ParameterPresetDefinition.cs.meta
Normal file
11
AAC/AACShared/Runtime/ParameterPresetDefinition.cs.meta
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: d6a5ecef749799144819cc07612056ef
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Loading…
Add table
Add a link
Reference in a new issue