Skip to content

NexusScript basics & lifecycle

A NexusScript is a C#‑style class that extends NexusBehaviour. You write it as a .cs file in your project; the SDK compiles it with NexusVM and you assign the result to a NexusComponent on a GameObject.

using UnityEngine;
using NexusVM.Unity;      // NexusBehaviour + the script APIs

class DoorController : NexusBehaviour
{
    public float openAngle = 90f;     // public fields show up in the inspector
    public Transform door;

    protected override void Start()
    {
        Debug.Log("Door ready.");
    }

    void OnTriggerEnter(Collider other)
    {
        if (Player.IdOf(other.gameObject) != "")   // a player walked in
            door.localRotation = Quaternion.Euler(0, openAngle, 0);
    }
}

Adding [Synced] or an RPC later? You need a second using

The attributes live in a different namespace from NexusBehaviour — add using SocialScape.SDK; as well, or you get CS0246: The type or namespace name 'SyncedAttribute' could not be found. See Networking.

Lifecycle methods

The runtime calls these for you (define only the ones you need):

Method When
protected override void Awake() once, as the script loads
protected override void Start() once, before the first frame it's active
protected override void OnEnable() / OnDisable() when enabled / disabled
protected override void Update() every frame
protected override void FixedUpdate() every physics step
protected override void LateUpdate() every frame, after Update
protected override void OnDestroy() when removed
void OnTriggerEnter/Stay/Exit(Collider other) physics trigger overlap
void OnCollisionEnter/Stay/Exit(Collision c) physics collision

Two call styles

Engine lifecycle (Start, Update, …) is declared on NexusBehaviour, so you override it. Physics callbacks (OnTriggerEnter, …) are matched by name, so they're plain methods. Your own custom methods (action handlers, event callbacks like OnPlayerJoined) are also plain public methods.

Public fields → inspector

Any public field becomes an inspector slot on the NexusComponent — drag in scene references (a Transform, a Light, an array of NPCs) or set values. This is how you wire a script to your scene without hard‑coding names.

public Light lamp;
public GameObject[] targetNpcs;
public int maxScore = 10;

What you can use

  • Core C# — variables (incl. multiple in one statement: int a, b, c; / float x = 0f, y = 1f;), if/for/while/do/foreach/switch, methods, class/struct/enum/interface, generics, arrays (incl. 2‑D and jagged), List/Dictionary/HashSet/Queue/Stack + LINQ, properties (incl. { get; set; }), try/catch/finally, lambdas + closures, delegate/event, yield iterators.
  • Modern C# conveniences — interpolated strings $"…", ?? / ?., is Type x patterns, switch expressions (x switch { 1 => "a", _ => "b" }), expression‑bodied members (int Area => w*h;, void Hi() => …;), nameof(x), digit separators (1_000), base.Method() / base.Field, tuples ((a, b), var (x, y) = pair;, (int, int) F(), and tuple switch patterns (0, 0) => …), string.Format/Join, int.Parse/.ToString().
  • MathMathf.* (Mathf.Abs, Mathf.Clamp, Mathf.Lerp, Mathf.PI, …). Math.* works too — it's aliased to Mathf, so Math.Abs/Math.Max/Math.PI compile (results are float). Plus full Vector2/3/4, Quaternion, Matrix4x4, Color, Rect, Bounds, and Random.
  • Numbers — all the C# numeric types and conversions: every width (byteulong, with real unsigned math), casts, literals (5u, 1.5f, 0xFF), constants (int.MaxValue, float.NaN), and parsing (int.Parse, int.TryParse(s, out n), Convert.ToInt32). See Numbers, casts & parsing.
  • Unity value typesVector3, Quaternion, Color, Transform, GameObject, Light, Collider, …
  • Debug.Log(...) for console output.
  • The platform APIsPlayer.*, NPC.*/Self.*, Storage.*, HTTP.*, Json.*.

struct is a reference type here

NexusScript has no value types, so a struct behaves exactly like a classreference semantics: assigning one struct to another shares the same object (no value‑copy). Use struct freely for little data bundles; just don't rely on struct copy‑on‑assignment.

Not everything from modern C#

A few conveniences aren't in the subset yet: when guards / type‑pattern case, params + optional/named arguments, typeof/default(T). Use overloads instead of optional args. async/await is replaced by coroutines. (Tuples are supported — see Tuples.)

Behaviour & gotchas

The catalog tells you what to call; these are the behaviours that decide whether it's correct.

  • == on objects tests identity. if (hit.transform == myTransform) correctly asks "is it the same object?" — the same object always compares equal however you got the reference. Don't compare .name (duplicates share names). Value types (Vector3, Color, Quaternion) compare by value, as usual. Avoid == null on an object you've already Destroyd — track that yourself.
  • Objects are truthy. if (go) / if (!go) / go ? a : b work on a GameObject, component, or script reference — they mean "is it not null?", exactly like Unity. (Numbers, strings and Vector3/Color still need an explicit comparison — if (count > 0), not if (count).)
  • renderer.material is the SHARED material. Setting renderer.material.color recolours every object using that material. To tint one object, use renderer.SetColor(color) (a MaterialPropertyBlock — sets _Color/_BaseColor). Emission has no per‑instance path, so an emissive glow always changes every copy of the material.
  • No tween libraries. External tween libraries aren't available — animate by moving a little each Update with Time.deltaTime + Vector3.Lerp (or a coroutine with WaitForSeconds). Mathf.PingPong/Mathf.MoveTowards aren't included; use Mathf.Sin and clamp yourself.
  • out parameters work, including Physics.Raycast(origin, dir, out RaycastHit hit, dist) — then read hit.point / hit.transform / hit.collider. (The API reference shows one Raycast form; the out hit, maxDistance, and layerMask variants all work.)
  • GetComponent<T> is an allowlist. Call it bare (GetComponent<Renderer>(), implicit this) or on an object (gameObject.GetComponent<T>()) — both work. The whole family is available: GetComponentInChildren<T>/GetComponentInParent<T> (search the hierarchy) and the plural GetComponents<T>/GetComponentsInChildren<T>/GetComponentsInParent<T> (return a T[] you can foreach/index). Works for Transform, Rigidbody, Collider(s), Renderer(s), AudioSource, Animator, Light, CharacterController, NavMeshAgent, ParticleSystem, and the uGUI/TMP UI types. Blocked (returns null): Camera, Canvas, AudioListener, EventSystem. Use Camera.main for camera rays.
  • Silent limits: audio is capped at ~120 plays/second; Instantiate is rate‑limited and you can only Destroy objects your script created; Physics.gravity and Time.timeScale are read‑only. Over‑budget calls no‑op rather than error.

What you can't (the sandbox)

NexusScript is deliberately limited so worlds are safe to run:

  • ❌ No file system, no direct OS / process access.
  • ❌ No reflection, no arbitrary .NET libraries.
  • ❌ No raw sockets — use HTTP.* instead.

If something you need isn't reachable, that's usually on purpose — there's typically a safe API for it.

Helpers you'll use a lot

  • Json.FromJsonToDict(jsonString) — parse a JSON string into a dictionary (action params, event data).
  • GameObject.Find(name) — find a scene object by name.

→ Next: the Player API, or see real scripts in Examples.