What is as-badlads?
as-badlads is the BadLads WebAssembly host API implementation in AssemblyScript, used for building server plugins. The as prefix stands for AssemblyScript. This is not JavaScript — it compiles to WebAssembly and runs natively in the game engine.
Prerequisites
Node.js is required for the npm package manager.
Creating a Plugin from Scratch
-
Find your BadLads plugins folder (
BadLadsPlugins):- Windows client:
C:\Users\{you}\AppData\Local\BadLads\Saved\ - Server:
{ServerDirectory}\BadLads\Saved\
- Windows client:
- Create a new directory inside
BadLadsPluginsfor your plugin and navigate into it. -
Initialize the project and install dependencies:
npm init npm install --save-dev assemblyscript npm install @chemicalheads/as-badlads npx asinit . -
Create a
plugin.jsonfile (must be all lowercase) in your plugin root. This describes your plugin to the game. -
Add
exportRuntime: trueto both thereleaseanddebugtargets inasconfig.json:{ "targets": { "debug": { "outFile": "build/debug.wasm", "textFile": "build/debug.wat", "sourceMap": true, "debug": true, "exportRuntime": true }, "release": { "outFile": "build/release.wasm", "textFile": "build/release.wat", "sourceMap": true, "optimizeLevel": 3, "shrinkLevel": 0, "converge": false, "noAssert": false, "exportRuntime": true } } } -
Open
assembly/index.tsand start writing your plugin. Compile with:npm run asbuild -
Open BadLads in Sandbox mode. Hot reload is enabled by default. To reload plugins at runtime:
/reloadplugins
Event Hooks
Export these functions from your assembly/index.ts to listen for game events:
import { BadLadsObject } from "@chemicalheads/as-badlads";
// Called when the plugin starts
export function onPluginStart(pluginId: i32): void {}
// Called when the plugin stops
export function onPluginStop(pluginId: i32): void {}
// Called every server tick
export function onPluginTick(deltaTime: f64): void {}
// Called when a player joins
export function onPlayerLogin(playerState: BadLadsObject): void {}
// Called when a player leaves
export function onPlayerLogout(playerState: BadLadsObject): void {}
// Called on chat message — return false to block it
export function onPlayerChatMessage(
playerState: BadLadsObject,
messageBuffer: ArrayBuffer,
channel_index: i32
): bool {
return true;
}
// Called when something dies
export function onLivingDeath(
victim: BadLadsObject,
killerPlayerState: BadLadsObject
): void {}
// Called when a player changes job
export function onBecomeJob(
playerState: BadLadsObject,
jobName: ArrayBuffer
): void {} Core Types
BadLadsObject
A 64-bit object ID (u64) used for all host API lookups. The first 32 bits are object search flags, the next 32 bits are the actual object ID.
Vector
3D vector with x, y, z as f32. Up is +Z.
Rotation
Roll, yaw, pitch as f32.
Transform
Combines position (Vector), rotation (Rotation), and scale (Vector).
Color
RGB color with values 0–255 per channel.
Object Flags
Bitmask enum for filtering objects:
BadLadsObjectFlags.None
BadLadsObjectFlags.PlayerStates
BadLadsObjectFlags.PlayerCharacters
BadLadsObjectFlags.Vehicles
BadLadsObjectFlags.EstateVolumes
BadLadsObjectFlags.EstateObjects
BadLadsObjectFlags.Buildables
BadLadsObjectFlags.All API Reference
| Function | Description |
|---|---|
getPlayerCharacter(playerState) | Get the PlayerCharacter from a PlayerState. |
isObjectValid(object) | Check if an object ID is valid. |
postGlobalChatMessage(msg, color?, isEventful?) | Send a message to all players. |
postPlayerMessage(playerState, msg, color?, isEventful?) | Send a message to a specific player. |
decodeString(buffer) | Decode a UTF-8 ArrayBuffer to a string. |
getBadLadsVersion() | Get the host game version string. |
getObjectsIdsByType(flags) | Get all object IDs matching the given flags. |
setObjectTransform(object, transform) | Set an object's position, rotation, and scale. |
getObjectTransform(objectId) | Get an object's current transform. |
spawnObject(flag, index, transform, async?) | Spawn a new object in the world. |
getPlayerAccountId(playerState) | Get a player's account ID (e.g. SteamId). |
getPlayerName(playerState) | Get a player's display name. |
kickPlayer(playerState) | Kick a player from the server. |
banPlayer(playerState) | Ban a player from the server. |
setLivingHealth(playerState, newHealth) | Set a living entity's health (0 = death). |
setDoorState(doorObject, state) | Set door state: 0 closed, 1 open forward, -1 open backward. |
getEstateVolumeBuildables(estateVolume) | Get all buildables within an estate volume. |
giveItem(playerState, itemId, stackSize?, autoStack?) | Give an item to a player. |
getPlayerJob(playerState) | Get a player's current job. |
setPlayerJob(playerState, job, ...) | Set a player's job. |
getObjectBounds(object) | Get an object's bounding box (center + extents). |
rayTrace(start, end, channel?, ignored?) | Line trace through the collision world. |
getGameTime() | Get the server game time in seconds. |
getEconomyCurrencyValue() | Get the current economy currency value. |
Tips
- To explore the full API, middle-click on an import in your IDE to jump to the type definitions in
badlads.ts. - Functions prefixed with
__hostare low-level host bindings. Use the wrapper functions instead unless you know what you're doing. - String parameters from events arrive as
ArrayBuffer. UsedecodeString(buffer)to convert them. - The game has hot reload enabled by default in Sandbox mode. Use
/reloadpluginsto pick up new plugins without restarting.
Example: Chat Filter Plugin
A minimal plugin that filters a word from chat messages:
import {
BadLadsObject,
decodeString,
postPlayerMessage,
Color
} from "@chemicalheads/as-badlads";
export function onPluginStart(pluginId: i32): void {
// Plugin loaded
}
export function onPlayerChatMessage(
playerState: BadLadsObject,
messageBuffer: ArrayBuffer,
channel_index: i32
): bool {
const message = decodeString(messageBuffer);
if (message.toLowerCase().includes("bad")) {
postPlayerMessage(
playerState,
"Watch your language!",
new Color(255, 100, 100),
false
);
return false; // Block the message
}
return true; // Allow the message
}