Avatar Context Examples
TL;DR: An avatar script runs on every client that sees the avatar, not just the wearer’s. Reads are generous (hierarchy, components, player identity), writes are gated to the avatar’s own content root. Global APIs like LocalPlayer.*, FileStorage.*, WorldPermissions.*, WorldSettings.* are world-only and will throw WasmAccessDeniedException at runtime if called from an avatar script.
What avatar scripts can do
Section titled “What avatar scripts can do”- Read and write their own hierarchy:
transform, childGameObjects, components on them. - Respond to Unity lifecycle events (
Awake,Start,Update,LateUpdate,FixedUpdate,OnEnable,OnDisable). - Respond to trigger and collision events via Unity’s standard events (
OnTriggerEnter,OnCollisionEnter, …). - Listen to CVR game events:
OnPlayerJoined,OnPlayerLeft,OnPlayerRespawned,OnInstanceOwnerChange,OnWorldPermissionsChanged,OnInputReady. - Differentiate “me” vs “everyone else” via
CVRScriptOwnerContext— a script inSelfowner context runs on the wearer’s client; same script inOthercontext runs on remote viewers. - Send/receive network messages via
WasmScripting.Networking(no context restriction). - Sample input via
CVR.CVRInput.*(reads only — writes only materialize whenOwnerContext == Self).
What avatar scripts cannot do
Section titled “What avatar scripts cannot do”- Call
LocalPlayer.*— world-only. - Touch
FileStorage/WorldPermissions/WorldSettings— world-only. - Mutate transforms outside the avatar’s own root (scope check fails).
- Create new portals, spawn props, or destroy other players’ content.
- Observe
OnPropSpawned/OnPortalCreatedmeaningfully — those dispatch in world VMs.
- Cache the owner check.
CVR.WasmUtils.GetOwnerContext()returnsSelfon the wearer’s client; capture it once inStart. - Use the owner check to gate write-heavy code. Cosmetic/visual code runs on every client; expensive logic should short-circuit unless you’re the wearer.
- Subscribe to
OnInputReadybefore readingCVRInput.*— input is only guaranteed populated after this event. - Wire UI via persistent UnityEvents (
Button.onClick→ apublic voidhandler on your behaviour). Build-time rewiring sends the click into your WASM script automatically. - Use
[WasmSerialized]on any private field that represents “preserved-across-reload” avatar state (toggle status, accessory index, etc.).
Don’ts
Section titled “Don’ts”- Don’t try to rewire world state from an avatar script — scope checks will fail.
- Don’t assume your script only runs on the wearer. Avatar scripts run on every client that sees the avatar. Compute one set of values for visuals; gate authoritative writes behind
OwnerContext == Self. - Don’t call
FileStorage.*from an avatar script — every binding callsCheckAccess(World, Any)and throwsWasmAccessDeniedExceptionoutside a world VM. - Don’t hold references to external-content transforms (world props, other avatars). Scope checks will reject mutations; even reads depend on the specific binder’s scope mask.
- Don’t use
OnApplicationQuit/OnGUI/OnApplicationFocus— these are stubbed and never dispatch (see Events).
Included in this book
Section titled “Included in this book”Author-facing patterns in the avatar/ subtree demonstrate the typical shapes. See the pages below or open them directly in the validator.
- Accessory Toggle — toggle a cosmetic child, preserve state across play sessions, broadcast the choice so remote viewers match.
More patterns will be added as the API surface stabilizes.
Related
Section titled “Related”- Permissions — why certain calls throw.
- Events — what you can hook from an avatar.
- Networking — reaching other clients without touching world state.
- CVR Input — input read/write rules by context.