Knight docs
EN ID
GitHub

Modules & Imports

Split a gamemode into modules and share exported functions.

A module is a normal .sa file with a module header that other files can import. Modules keep large gamemodes organised and let you drop in community-written systems without touching the main file.

1. Write a module

Create Gamemodes/modules/economy.sa, next to your gamemode (a modules folder inside the gamemode folder also works).

knight
module "economy" {
    version: "1.0.0";
    author: "Knight";
};

let balances = {};

function economyAdd(int id, int amount) {
    balances[id] = at(balances, id) + amount;
    return at(balances, id);
}

export function economyBalance(int id) {
    return at(balances, id);
}

export function economySpend(int id, int amount) {
    if (at(balances, id) < amount) { return false; }
    balances[id] = at(balances, id) - amount;
    return true;
}
Note
module metadata is optional. export is documentation for humans: every top-level function in the program can be called from any file.

2. Import it

knight
import "economy";

system::start() {
    AddPlayerClass(0, 1958.4, 1343.2, 15.4, 270.0, 24, 50);
    economyAdd(0, 100);
};

player::command("/bal") {
    SendClientMessage(playerid, "Saldo: {economyBalance(playerid)}");
};

player::command("/spend", int amount) {
    if (economySpend(playerid, amount)) {
        SendClientMessage(playerid, "Berhasil.");
    } else {
        SendClientMessage(playerid, "Saldo kurang.");
    }
};

3. Hooks and vetoes

Modules can register event hooks with on. Returning false vetoes the event: no later handler runs and the default action is skipped. This is how a chat filter blocks a line without the main gamemode knowing about it.

knight
module "anticheat" { version: "1.0.0"; };

const MAX_WARNINGS = 3;
const BANNED = ["cheat", "hack", "aimbot"];
let warnings = {};

on player::chat(string message) {
    let low = lower(message);
    for (let word in BANNED) {
        if (contains(low, word)) {
            let n = at(warnings, playerid) + 1;
            warnings[playerid] = n;
            SendClientMessage(playerid, "Peringatan {n}/{MAX_WARNINGS}");
            if (n >= MAX_WARNINGS) { Kick(playerid); }
            return false;
        }
    }
    return true;
};

4. Where modules are found

Search orderExample
Gamemode folderGamemodes/economy.sa
modules/ next to the gamemodeGamemodes/modules/economy.sa
modules/ one level upmodules/economy.sa
working directorymodules/economy.sa

Each module is loaded once. Circular imports are reported as an error at startup, before any player can connect.

5. Errors you may see

MessageMeaning
module not found: xNo x.sa in any search location.
circular import: a -> b -> aTwo modules import each other.
expected ';' after event blockAn on hook block must end with ;.