Skip to content

API Conventions

TL;DR: CVR-provided APIs use explicit Get*() / Set*() methods (signalling the interop marshalling cost); UnityEngine and library APIs keep idiomatic property access. The surface is still shifting — expect periodic breaking changes during closed testing, and read this page when an API that used to be a property is now a method.

Author-facing surface as of CCK 4.0.0-Preview.27-WASM.27

Section titled “Author-facing surface as of CCK 4.0.0-Preview.27-WASM.27”

Anything that returns a wrapped host object or crosses the VM boundary is a method:

// Player
string userId = player.GetUserId();
string name = player.GetUsername();
short netId = player.GetNetworkId();
GameObject rootGO = player.GetGameObject();
AvatarPoint view = player.GetViewPoint();
AvatarPoint voice = player.GetVoicePoint();
Avatar avatar = player.GetWornAvatar();
Prop[] spawned = player.GetSpawnedProps();
// Avatar
Player wearer = avatar.GetWearer();
string aName = avatar.GetName();
string aId = avatar.GetContentId();
GameObject aRoot = avatar.GetRootObject();
Transform aT = avatar.GetRootTransform();
avatar.SetCollisionExcludeLayers(someLayerMask);
LayerMask exclude = avatar.GetCollisionExcludeLayers();
avatar.ResetCollisionExcludeLayers();
// Prop
Player spawner = prop.GetSpawner();
string pName = prop.GetName();
string pId = prop.GetContentId();
GameObject pRoot = prop.GetRootObject();
Transform pT = prop.GetRootTransform();
prop.Destroy();
// World
World world = World.GetCurrentWorld();
string wName = world.Name; // one of the few remaining property accessors
string wId = world.ContentId;

Why methods? Each call marshals across the host-guest boundary. Using methods rather than properties signals that work is being done — and prevents the common pitfall of reading player.Username in a tight loop without realising it’s a host round-trip.

Not every CVR type has been migrated yet. CVR.Portal still exposes a few properties:

Player pSpawner = portal.Spawner; // still a property
GameObject pRoot = portal.RootObject; // still a property
Transform pT = portal.RootTransform; // still a property
Vector3 pos = portal.GetPosition(); // method
portal.SetPosition(newPos); // method
bool anchored = portal.IsAnchored(); // method

CVR.World also still exposes Name and ContentId as properties. These may move to Get*() methods in a future preview.

Properties are idiomatic Unity. These stay:

transform.position // property
transform.localPosition // property
rigidbody.velocity // property
display.text // property on TextMeshProUGUI

Setters on scope-sensitive Unity properties are scope-gated by the binder (writes typically require CVRScriptScopeContext.Self). See Permissions → Rules of thumb.

Helper subsystems are static classes in the WasmScripting namespace (source: CVR.CCK.Wasm/Scripting/Links/APIs/CCKStubs/):

  • WasmScripting.NetworkingSendMessage(Span<byte>, short[], SendType, bool), SendMessage(BufferReaderWriter, ...), WillMessageBeDropped(int), NetworkCloggedPercentage(), GetInstanceOwner(), Ping (property), GetServerStartTime(), GetServerUptime(), OnReceiveMessage delegate.
  • WasmScripting.FileStorageReadFile, WriteFile, DeleteFile, RenameFile, FileExists, GetFiles, GetFileSize, GetTotalSize, GetTotalCapacity. No CanUseFileStorage / RequestUseFileStorage helpers — call WorldPermissions.Request directly.
  • WasmScripting.WorldPermissionsRequest(WorldPermissions), CurrentPermissions static property.
  • WasmScripting.WasmUtilsGetObjectContext() (returns the VM’s CVRScriptObjectContext, resolved guest-side), GetScopeContext(UnityEngine.Object) and GetOwnerContext() (both cross to the host).

CVR.Avatar collides semantically with UnityEngine.Avatar (animation rig type). The team has discussed renaming the CVR-side types to carry an Api suffix:

CVR.Player -> CVR.PlayerApi
CVR.Avatar -> CVR.AvatarApi
CVR.Prop -> CVR.PropApi
CVR.Portal -> CVR.PortalApi
CVR.World -> CVR.WorldApi
CVR.Clone -> CVR.CloneApi (not yet shipped)

Not implemented yet. Write scripts against the current names; if the refactor lands, expect a rename-only breaking change.

  • Username is no longer gated by AccessUserIdentity. Only GetUserId() requires that world permission. GetUsername() works without it. (Changelog: Preview.27-WASM.27.)

If a call that used to compile now fails with error CS1061: 'Player' does not contain a definition for 'Username':

  1. Check this page for the migrated name (GetUsername()).
  2. Check the CCK stubs at CVR.CCK.Wasm/Scripting/Links/APIs/CCKStubs/ — they are the source of truth for what the guest sees.
  3. If still unclear, grep the decompile at CVR-GameFiles/WasmScripting/*Bindings.cs for the host function name; the shim mirror is usually adjacent in naming.