Skip to main content

2026-08-06 Creating content using Cilbox in Basis

Cilbox is a scripting system that is available by default in Basis. User-generated content such as worlds, props, and avatars may contain scripts, and they will execute in separate sandboxes that have different lists of permitted types and accesses to functions.

Setup

The class should be marked as [Cilboxable], such as:

[Cilboxable]
public class Pencil : MonoBehaviour {
// ...
  • To use a scene that uses Cilbox scripts, a single Cilbox Scene Basis component needs to exist somewhere in the scene.
    • Scene scripts written using Cilbox can be placed outside of that component.
  • To use a prop that uses Cilbox scripts, a single Cilbox Prop Basis component should be put at the root of the prop.
  • To use an avatar that uses Cilbox scripts, a single Cilbox Avatar Basis component should be put at the root of the avatar.

Those components do not need to be configured.

OnEnable is not called the first time

Cilbox seems to have a quirk, where OnEnable will not be called the first time the prop is enabled.

You may have to resort to workarounds similar to the following:

private bool _isEnabled;
public void Start()
{
// Do one-time initialization stuff here.

WhenEnable();
}
public void OnEnable() { WhenEnable(); }
private void OnDisable() { _isEnabled = false; }
private void WhenEnable()
{
if (_isEnabled) return; // Cilbox quirk
_isEnabled = true;

// Do OnEnable stuff here.
}

Networking

To make an object networkable, either:

  • Call _networkShim = Basis.SafeUtil.MakeNetworkable(this),
  • or add a BasisNetworkShim component and reference it as a field.

Check ownership using _networkShim.IsLocalOwner()

To send and receive data:

  • Send packets using _networkShim.SendCustomNetworkEvent(bytes, ...)
  • receive packets by registering an event listener using _networkShim.NetworkMessageReceived += OnNetworkMessageReceived

Props load at different times for different players, so you may have to detect when network is ready using _networkShim.NetworkReady += OnNetworkReady to start sending packets.

According to the creator of the Basis Framework, it is impossible for other players to load the prop faster than the person who spawns and owns the prop, therefore when OnNetworkReady is triggered on a non-owner, it should be safe to assume that the network owner is ready to receive the packets. EDIT: It is unclear if that's the case.

UI Buttons

Follow the official Canvas UI documentation, then.

To make a UI button trigger events when clicked:

  • Reference the Unity UI button as a field, and then
  • register an event listener, such as _eraseAllButton.onClick.AddListener(OnEraseAllClicked);

Pickups

Follow the official Interactable documentation on how to set up a network synced pickup.

To detect pickup and drop events:

  • Reference the BasisPickupInteractable component as a field, and then
  • register an event listener, such as pickup.OnInteractStartEvent.AddListener(OnPickup); and pickup.OnInteractEndEvent.AddListener(OnDrop);
  • for the trigger events, use pickup.OnPickupUse.AddListener(OnPickupUse). The callback method has an enum value that tells you when the trigger press starts, continues being held, or ends.

Pickups do not affect component ownership.

  • If a user grabs a synced pickup, they only own the synced pickup component.
  • The other networked components that are on the same GameObject do not change ownership.

Teleportation

Scene props can teleport the player using by calling the BasisLocalPlayer.Instance.Teleport(spawn.position, spawn.rotation) function.

Troubleshooting builds

If a non-uploaded prop works in editor but doesn't work when the built BEE file is loaded in the real application, then consider loading the BEE file inside the Unity Editor while in Play Mode and debug it directly inside the editor.

This way, I found out that the non-uploaded prop worked in editor because it was executing using the Cilbox Scene box component instead of the Cilbox Prop box component, as the prop didn't have a Cilbox Prop box component attached.

Not supported

Do not use Array.Empty<HVRNPSCilBeacon>()

Privilege failed for System.Array.Empty generic argument 0 type HVR.NPS.ForCilbox.HVRNPSCilBeacon

CilboxException: Error: Could not find reference to: [mscorlib][System.Array][HVR.NPS.ForCilbox.HVRNPSCilBeacon[] Empty[HVRNPSCilBeacon]()] Type from:System.Array

Do not use lambdas

ArgumentException: Object of type 'Cilbox.CilboxHeapInstance' cannot be converted to type 'Cilbox.CilboxProxy'.

Do not implicit cast from Vector4 to Vector3

  • Error raised on method op_Implicit of type UnityEngine.Vector4 with 0 args.
  • AmbiguousMatchException: Ambiguous match found.

Bugs

Negating a value is not working properly

The value of x in var x = -someValue; will be incorrect.

  • Discovered when Random.Range(-x, x) was returning values way out of expected range.
  • This can be worked around by multiplying with -1

This bug has been fixed in the Cilbox repository, but it may be reflected in the Basis Framework project and client at a later point.

Server XML configuration ignores scale

The scale of props is ignored in the XML configuration.