codeGetting Started with CSL

CSL is All Out's custom programming language built to make writing multiplayer games as easy as creating single player games.

CSL is All Out’s custom scripting language. It’s statically typed and feels most similar to Go/Odin — except gameplay state is automatically synced from the server to clients.

circle-info

You don’t need to write RPCs, SyncVars, or custom replication. Focus on gameplay logic; the platform handles networking for you.

Your first script (main.csl)

When you create a new project, All Out generates a main.csl in your project’s scripts/ folder.

import "core:ao"

// ============================================================================
// Global lifecycle
// ============================================================================

ao_before_scene_load :: proc() {
    // Register item definitions, currencies, etc.
    // Runs before the scene is created.
}

ao_start :: proc() {
    // Called once when the scene starts.
}

ao_update :: proc(dt: float) {
    // Called every frame.
}

ao_late_update :: proc(dt: float) {
    // Called every frame after ao_update.
}

// ============================================================================
// Player lifecycle
// ============================================================================

Player :: class : Player_Base {
    ao_start :: method() {
    }

    ao_update :: method(dt: float) {
    }

    ao_late_update :: method(dt: float) {
    }

    ao_end :: method() {
    }
}

For example, log a message when each player joins:

If you want a deeper explanation of when these functions run, see Game/Frame Lifecycle.

Imports

Your main.csl should import core:ao and any folders you create (like ui/, abilities/, etc).

circle-exclamation

Declarations (variables and constants)

Declarations bind a name to a value.

Variables

Either <type> or <expression> can be omitted:

Constants

Constants use :: and must be compile-time constants:

This is invalid (because a is not compile-time constant):

Types

Primitive types

  • Signed integers: s8, s16, s32, s64

  • Unsigned integers: u8, u16, u32, u64

  • Booleans: b8, b16, b32, b64

  • Floats: f32, f64

  • Aliases:

    • int == s64

    • uint == u64

    • bool == b8

    • float == f32

  • Vectors: v2, v3, v4

  • string

  • typeid

  • any

Vector types

v2, v3, and v4 have .x, .y, .z, .w float fields:

Structs and classes

Structs are value types (copies on assignment). Classes are reference types (you allocate them with new).

Structs (value types)

Classes (reference types)

Inheritance

Structs/classes can inherit from other structs/classes:

Procedures and methods

Procedures (proc)

Procedures are normal values and can be assigned/stored like any other value:

Methods (method)

Use method() inside a struct/class. Methods have an implicit this reference parameter.

Field access vs method calls

Use . for fields, -> for methods:

circle-info

Any procedure can be called as a “method” if its first parameter matches the receiver type. This is a common CSL pattern.

Arrays

CSL has a few “array-like” types you’ll use constantly:

  • Fixed arrays: [4]int

  • Slices / managed arrays: []T (often used as “read-only view” into an array)

  • Dynamic arrays: [..]T (resizable list)

Dynamic arrays expose .data, .count, and .capacity, and use method-call syntax for operations:

For a full guide (including removal patterns), see Arrays and Collections.

Control flow

If / else

Switch

While / for / foreach

Casting

Use expr.(T) to cast:

Passing by reference: ref (preferred)

When you need to modify a parameter, prefer ref over raw pointers.

Callbacks: function pointers + userdata (no closures)

CSL does not have closures. Inline proc(...) { ... } cannot capture surrounding variables.

To carry context, pair callbacks with a userdata: Object field:

Type info (types as values)

typeid values can be passed to polymorphic procs:

Best practices (CSL in All Out)

  • Avoid global gameplay state. Multiple players connect — store per-player state on Player instead.

  • Separate cosmetic vs gameplay logic. Use is_local() for local-only UI/particles, and is_local_or_server() for gameplay inputs that must run on server + local client.

  • Mobile-first defaults. Don’t rely on keyboard/mouse input unless your game is explicitly PC-focused.

  • If you’re unsure about syntax or APIs, check the api_reference/ folder generated in your project (it contains the latest core.csl surface).

Last updated