Skip to content

Limits

TL;DR: Each WASM call must complete within a ~20 ms epoch deadline (worlds); overrun traps the Store. WASM threads are disabled. File storage defaults to a 4 MB per-world quota. There is no explicit memory cap in the decompile — memory growth is bounded by the host process’s available memory and Wasmtime’s own guarded heap.

File: CVR-GameFiles/WasmScripting/WasmManager.cs.

// Timer thread target cadence = 100 kHz (every ~10 µs):
long targetTicks = Stopwatch.Frequency / 100_000;
// Per-call deadline for every script:
private const ulong EpochDeadlineTicks = 2000uL; // 2000 ticks
  • The shared Engine has WithEpochInterruption(true).
  • A background TimerThread busy-spins (Thread.SpinWait(1000) inside the loop) and calls Engine.IncrementEpoch() roughly every 10 µs whenever any Store has an active call.
  • WasmManager.StartEpochTimer(store) sets store.SetEpochDeadline(2000uL) and wakes the timer thread through an AutoResetEvent. StopEpochTimer() clears the flag so the thread parks again.
  • When the counter hits the deadline mid-call the guest traps. The host catches TrapException, logs it, and sets IsCrashed = true on the WasmVM — no further events dispatched on that VM.
  • Startup path gets a temporary wider budget: _store.SetEpochDeadline(100000uL) inside WasmVM.Setup (roughly 1 s) covers scripting_initialize + the per-behaviour scripting_create_instance + scripting_deserialize_instance calls, then StopEpochTimer parks the thread until the first runtime event.

There is no separate deadline for avatars vs props vs worlds in the current decompile. The EpochDeadlineTicks = 2000 constant applies uniformly.

Only guest-side wall-clock time between entering and leaving WASM. If the guest calls a host binding that itself takes time (e.g. a networking call), that time is host-side and does not tick the epoch — but the total call still has to complete within the deadline because the epoch keeps incrementing.

  • Separate deadlines for Update, FixedUpdate, OnCollisionEnter, etc. — each is a separate call, each gets its own fresh 20 ms budget.
  • Cumulative cost. A script can spend 19 ms every frame indefinitely.

In CVR, Time.fixedDeltaTime scales with the user’s display refresh rate (30 Hz → 144 Hz). The timestep remains consistent within a client, but does not match Unity’s default 0.02 across users. Don’t hard-code the expected rate; read Time.fixedDeltaTime or use Time.time deltas.

From WasmManager.Awake():

FeatureSettingComment
Epoch interruptionEnabledWithEpochInterruption(true)
Reference typesEnabledexternref allowed
Multi-valueEnabledmulti-return functions
Bulk memoryEnabledmemory.copy, memory.fill
Debug infoEnableduseful stack traces in Debug builds
SIMDEnabledv128
WASM exceptionsEnabledvia P/Invoke wasmtime_config_wasm_exceptions_set(handle, true) because the .NET wrapper doesn’t expose this flag
WASM threadsNot setWithWasmThreads(true) is never called — the shared atomics / thread proposal is off
  • Wasmtime defaults apply. No explicit WithMaxMemorySize / WithStoreLimits in the decompile.
  • In practice the host process’s physical memory is the only upper bound; an OOM from a runaway memory.grow will tear down the Store.
  • No per-call allocation accounting.

See File Storage for the API.

  • Default quota: 4_194_304 bytes (4 MB) per world, defined in CVR-GameFiles/WasmScripting/WorldPermissions.cs.
  • User-adjustable: 1 KB to ~17 TB via the WasmPermissionsPage palette.
  • Requires world permission: FileStorageApiAllowed. Without it every FileStorage_* call errors.

See Networking. The constants below are from CVR-GameFiles/WasmScripting/WasmNetworkManager.cs.

ConstantValueApplies to
MaxBytesPerSecond4096Sustained send budget per VM. Drained at 4 KB/s of wall clock.
MaxBytesSendSpike16384Instantaneous cap on in-flight bytes. CVR_Networking_NetworkCloggedPercentage returns bytesSent / 16384.
MaxBytesQueued65536Upper bound on the per-VM queue. CVR_Networking_WillMessageBeDropped(size) returns true if queuedBytes + size > 65536.

Message header overhead: "CVR.TN:1.0.0".Length * 2 + playerIds.Length * 4 + message.Length + 22 bytes. Any outbound message that would push the header+payload above MaxBytesSendSpike (16 KB) is dropped silently at WasmNetworkManager.SendMessage.

SendType values (CVR-GameFiles/WasmScripting/SendType.cs): Unreliable = 0, UnreliableSequenced = 1, Reliable = 2. Values 0 / 1 route through DarkRift’s unreliable channel; 2 through the reliable channel.

See Not Exposed for the full list. Brief:

  • Filesystem — use the sandboxed FileStorage_* API instead.
  • Network sockets — use CVR_Networking_* or world-permissioned HTTP.
  • Process spawning, reflection emit, application-lifetime calls.
  • First CCK build in a fresh Unity project downloads ~300 MB of toolchain (.NET SDK + WASI SDK). Subsequent builds are fast.
  • Per VM startup: one module compile if the cache misses (roughly linear in .wasm size, seconds for small modules); then a cheap Module.DeserializeFile for subsequent loads (~tens of ms).
  • Per VM instantiation + scripting_initialize + per-behaviour _createInstance: typically low-single-digit ms for a small module.
  • Tight loops without natural return points in Update — risk epoch trap.
  • Allocating large arrays each frame — GC churn plus risk of memory growth that never shrinks.
  • Calling many host bindings per frame per behaviour — each is a WASM-host transition with locks; batch where possible.
  • Long for loops over players in worlds with large instance caps — prefer OnPlayerJoined / OnPlayerLeft events and maintain your own list.

From CVR-GameFiles/WasmScripting/FileStorageManager.cs:

ConstantValueMeaning
MaxFileNameCharacterLimit100Characters accepted per filename. Extra characters are silently truncated after disallowed-character sanitization.
MaxFileLimit1000Upper bound on the number of .wasmdata files per world. New writes fail once this is reached.

Filename sanitization strips every Path.GetInvalidFileNameChars() character before checking the length cap.

  • CVR-GameFiles/WasmScripting/WasmManager.csEpochDeadlineTicks = 2000, timer thread, feature-flag config.
  • CVR-GameFiles/WasmScripting/WasmVM.cs — one-time 100000uL startup deadline inside Setup.
  • CVR-GameFiles/WasmScripting/WasmNetworkManager.cs — networking budget constants.
  • CVR-GameFiles/WasmScripting/FileStorageManager.cs — file count + filename-length limits.
  • CVR-GameFiles/WasmScripting/WorldPermissions.cs — default storage quota.