Skip to content

Parameter Setters

TL;DR: All write paths converge on AvatarAnimatorManager.SetParameter, which respects the read-only flag (core parameters can’t be written from outside the engine), the curve-controlled flag, and bumps AASParameterChangedSinceLastSync = true when a synced parameter is modified. PlayerSetup.ChangeAnimatorParam is the central dispatcher used by OSC, the AAS menu UI, and most scripting paths.

MechanismSource fileEffect
OSC /avatar/parameters/<name>ABI_RC.Systems.OSC.Modules/OSCAvatarModule.cs (HandleIncoming)Writes int / float / bool / null. Null is treated as 1.0. Floats also dual-write to face tracking — see OSC Face Tracking.
AAS menu UIABI_RC.Core.InteractionSystem/CVR_MenuManager.cs (SendAdvancedAvatarUpdate)Sliders, colour pickers, dropdowns in the Big Menu’s Avatar tab. Pushes values into AdvAvatarUpdateQueue for the player loop to drain.
ProfilesABI_RC.Core.Util.AnimatorManager/AvatarAnimatorManager.cs (ApplyAdvancedSettingsFileProfile)Loads a list of CVRAdvancedSettingsFileProfileValue and writes each. Also notifies the menu via SendAdvancedAvatarUpdate(name, value, markChange: false).
CVRParameterStreamABI.CCK.Components/CVRParameterStreamEntry.csPipes a data source into an animator/variable-buffer/custom-float/avatar-animator parameter.
CVRAnimatorDriverABI.CCK.Components/CVRAnimatorDriver.csWorld-authored component that writes a list of animator parameters when an AnimatorDriverTask fires.
CVRSpawnable (syncValues)ABI.CCK.Components/CVRSpawnable.csSpawnables sync their own syncValues to remote clients. This is a separate pipeline from avatar AAS — name/value pairs propagate per-spawnable, not via the avatar’s 3200-bit budget.
NAK.Contacts.ContactAnimatorNAK.Contacts/ContactAnimator.csA ContactReceiver companion that writes info.targetValue into a named animator parameter on every enter / update / exit. Routes through Animator.SetFloat/SetInteger/SetBool based on parameter type.
Koneko.Sensors.SensorKoneko.Sensors/Sensor.csWrites parameters when its volume detects something. Drives Distance, BoxDistance, SignedDistance.x/y/z, Rotation.x/y/z, and named per-target int/float/bool values.
Lua scriptsABI.Scripting.CVRSTL.Common.Modules/CVR_CCKLuaModule.csLua can read/write animator parameters via the bound API surface (subject to the access manager).
WASM scriptsCVR.CCK.Wasm/Scripting/Links/WasmBinder/UnityEngine/AnimatorLinks.csSandboxed scripts can call Animator.SetBool/SetFloat/SetInteger/SetTrigger and the matching Get* methods on any animator they have access to.
PlayerSetup.ChangeAnimatorParamABI_RC.Core.Player/PlayerSetup.cs (line 1259)Central dispatcher used by OSC, the AAS UI, scripting, and modders. Tracks a ParameterChangeSource (Default, MainMenu, OSC, QuickMenu).
public void ChangeAnimatorParam(string parameterName, float value,
ParameterChangeSource source = ParameterChangeSource.Default)
{
base.AnimatorManager.SetParameter(parameterName, value);
if (source == ParameterChangeSource.Default
|| source == ParameterChangeSource.MainMenu
|| source == ParameterChangeSource.OSC)
{
CVR_MenuManager.Instance.SendAdvancedAvatarUpdate(parameterName, value);
}
if (source == ParameterChangeSource.QuickMenu
|| source == ParameterChangeSource.OSC)
{
ViewManager.Instance.OnAdvancedAvatarUpdate();
}
}

ParameterChangeSource controls which secondary listener is notified — the AAS dropdown menu, the Quick Menu, or both. The actual write goes through AvatarAnimatorManager.SetParameter, which means core parameters are silently dropped by this entry point.

AvatarAnimatorManager.SetParameter(name, …) (inherited from CVRAnimatorManager) checks:

if (Parameters.TryGetValue(name, out var p) && p.isValid && !p.IsReadOnly)
{
ParameterChanged = true;
SetParameter_Internal(p, value);
}

AvatarParam.IsReadOnly returns true when:

  • the parameter is curve-controlled (isControlledByCurve)
  • the parameter is in AvatarDefinitions.CoreParameters

That covers the 22 core names. To write MovementX, Grounded, etc., the engine uses the typed properties on AvatarAnimatorManager (MovementX = 1f;) — those call SetParameter_Internal directly and bypass the read-only check.

Swimming and AFK are [Obsolete] and not in CoreParameters, so they go through SetParameter like any other custom parameter — that’s why the engine can write to them and so can a mod, but they’re never sent on the wire.

When SetParameter_Internal writes through SetFloat/Int/Bool_Animator (the AvatarAnimatorManager overrides):

int hash = param.nameHash;
if (_aasOutboundIndicesFloat.ContainsKey(hash) && idx < _aasOutboundCacheFloat.Count)
{
_aasOutboundCacheFloat[idx] = value;
AASParameterChangedSinceLastSync = true;
}

So writes to AAS-tracked parameters bump the cache and the dirty flag, and the next sync tick will broadcast them. Local-only parameters (including triggers and #-prefixed names) skip this step.

Triggers are special: when isTrigger is true, the AAS bool cache update is skipped entirely. The trigger’s effect is purely local and never serialized.

OSCAvatarModule.RegisterQueues registers four delegates on the OSC payload queues. Each one looks the parameter up by nameHash in AvatarAnimatorManager.ParametersHash and routes through ChangeAnimatorParam:

_avatarFloatParamQueue = OSCJobSystem.RegisterQueue(8192, payload =>
{
if (AvatarAnimatorManager.ParametersHash.TryGetValue(payload.NameHash, out var p))
{
PlayerSetup.Instance.ChangeAnimatorParam(p.name, payload.FloatValue,
PlayerSetup.ParameterChangeSource.OSC);
OnIncomingAvatarFloatOSCParameter?.Invoke(p.name, payload.FloatValue);
}
});

Bool and int values follow the same shape; null values dispatch as 1.0 (so OSC null becomes a “trigger pulse” of value 1). The OnIncomingAvatar*OSCParameter events are public hooks for mods that need to observe OSC writes.