Skip to content

ScriptingGetting started

The folder

~/.bitchos/scripts/            *.js     one file, one module. _name.js is ignored.
~/.bitchos/scripts/lib/        *.js     never auto-loaded; for require()
~/.bitchos/scripts/data/       *.json   per-script storage
~/.bitchos/extensions/         *.jar    compiled extensions (NOT sandboxed)

Flat, deliberately. No per-script folder, no manifest.

%USERPROFILE%\.bitchos\scripts

~/.bitchos/scripts — press Shift+Cmd+G in Finder and paste the path to reach the hidden folder.

~/.bitchos/scripts

/bitchos script folder prints the path and opens it.

The example scripts

Four working example scripts are written to the folder the first time bitchos runs:

file what it shows
example.js a commented tour of everything
lobby-threat.js a HUD readout built from the lobby threat model
enemy-highlight.js events + 3D world rendering + a 2D counter
uuid-lookup.js an HTTP request with a callback, and per-script storage

Edit one, then /bitchos script reload <name>. /bitchos script new mything writes a fresh starter file and loads it.

Switching a script off

A file whose name begins with _ is ignored. That is how you switch a script off without deleting it, and it works from a file manager with the game closed, which is what you want when a script is the reason the game will not start.

The shape of a script

A script is a plain JavaScript file. Its top-level code runs once at load; the interesting parts are the functions it defines.

script.meta({
    name:        'Bed Alert',
    author:      'you',
    version:     '1.0.0',
    description: 'Shouts when an enemy bed is close to breaking.'
});

function onLoad() {
    settings.bool('Alert', true, 'Shout when a bed is close.');
}

function onChat(e) {
    if (e.message.indexOf('gg') === 0) chat.print('gg');
}

Everything in meta is optional. Without it, the script is named after its file. The name is also available as the bare global scriptName and as script.name.

Every script appears in the menu under Scripts as a module with its own on/off switch, keybind and settings. That is fixed: a script cannot file itself under Render or Bed Wars, because the sidebar is the one place you can answer "what is this and where did it come from".

The file name is the module name, so it has to be free

A script becomes a module named after its file, and module names are unique across the whole mod. So hud.js, stats.js, scripts.js and anything else already taken by a built-in module are refused: the script is listed as broken by /bitchos script, the reason names the clash, and nothing is registered. Rename the file and reload.

Why this is checked

Before it was, saving hud.js replaced the HUD module in the registry and the entire HUD stopped drawing, permanently, with nothing said anywhere. /bitchos list is the authoritative list of names in use.

What happens when a script goes away

Delete a script, or rename it to _name.js, and after the next reload its module leaves the menu entirely rather than sitting there as a dead switch. Its section of config.json is left alone, so renaming it back gives you the script with every setting exactly as you left it.

The one case that does lose settings is deleting a file and reloading and quitting, all in the same session. After that there is nothing on disk to associate the settings with.

Language

Rhino 1.7.14 in ES6 mode. let, const, arrow functions, template literals, for…of, destructuring, Map/Set, JSON, Math, RegExp and Date all work.

There is no import, no async/await and no Promise. Asynchronous work is callbacks (see HTTP and scheduling).

Scripts are interpreted by default. The Scripts module has a Compiled switch that turns on Rhino's compiling mode for scripts doing heavy per-frame arithmetic. If compiling ever fails it falls back to the interpreter for the rest of the session and says so in chat.

Threading

All script code runs on the client thread. Events, HUD suppliers, scheduled callbacks, HTTP callbacks, command handlers, providers: all of them. You never have to think about threads, and you must not try to make one; java.lang.Thread is not reachable.

The one visible consequence: schedule(fn, 10) will not fire in 10 ms. Callbacks run on the client tick, so the resolution is 50 ms.

Do not touch the world from top-level code

The initial load of every script happens during start-up on the licence-check thread, before the world exists. Do world work in onLoad or later. That is also the one moment when two threads are inside the script system at once: the render thread can be calling an already-loaded script's HUD supplier while the next file is still being evaluated. Nothing about that is visible from a script, but it is why top-level code must stay to itself.