Skip to main content
The PolyglotScript class represents a single loaded script instance in LiquidBounce. It manages the script’s lifecycle, context, registered features, and event handling.

Class Declaration

class PolyglotScript(
    val language: String,
    val file: File,
    val debugOptions: ScriptDebugOptions = ScriptDebugOptions()
) : AutoCloseable
language
String
required
The programming language of the script (e.g., “js”, “python”, “ruby”)
file
File
required
The script file on disk
debugOptions
ScriptDebugOptions
Debug configuration for the script

Properties

Script Metadata

These properties are set when registerScript() is called from within the script.
scriptName
String
required
Display name of the script
scriptVersion
String
required
Script version string
scriptAuthors
Array<String>
required
Array of script authors
Example from script:
registerScript({
    name: "MyAwesomeScript",
    version: "2.1.0",
    authors: ["Author1", "Author2"]
});

Context

The GraalVM polyglot context for executing script code.
private val context: Context
The context is configured with:
  • Host Access: Full access to Java classes
  • IO Access: File system and network operations
  • Working Directory: Script’s parent directory
  • Thread Creation: Enabled
  • Native Access: Disabled for security
  • Language Options: Language-specific features

Script State

scriptEnabled
Boolean
Whether the script is currently enabled

Registered Features

Scripts can register various features that are tracked by the instance:
registeredModules
MutableList<ClientModule>
Modules created by the script
registeredCommands
MutableList<Command>
Commands created by the script
registeredModes
MutableList<Mode>
Modes created by the script

Methods

initScript()

Initializes the script by evaluating its source code.
fun initScript()
Initialization process:
  1. Evaluates the script source code
  2. Calls the global load event
  3. Validates required metadata (name, version, authors)
  4. Logs loading time
Throws: Exception if script evaluation fails or metadata is missing Logged output:
[ScriptAPI] Successfully loaded script 'my-script.js' in 42ms.

registerModule()

Registers a new module from the script.
fun registerModule(
    moduleObject: Map<String, Any>,
    callback: Consumer<ClientModule>
)
moduleObject
Map<String, Any>
required
JavaScript object containing module configuration
callback
Consumer<ClientModule>
required
Function called with the created module instance
Module object structure:
{
    name: "ModuleName",
    category: "Combat",
    description: "Optional description",
    tag: "Optional tag",
    settings: {
        settingName: Setting.type(...)
    }
}
Example:
script.registerModule({
    name: "AutoClicker",
    category: "Combat"
}, module => {
    module.on("enable", () => {
        // Enable logic
    });
});

registerCommand()

Registers a new command from the script.
fun registerCommand(commandObject: Value)
commandObject
Value
required
GraalVM Value containing command configuration
Example:
script.registerCommand({
    name: "test",
    aliases: ["t"],
    parameters: [
        {
            name: "arg",
            required: true,
            validate: (value) => ({
                accept: value.length > 0,
                value: value,
                error: "Argument cannot be empty"
            })
        }
    ],
    onExecute: (arg) => {
        Client.displayChatMessage("Received: " + arg);
    }
});

registerMode()

Registers a new mode for an existing mode value group.
fun registerMode(
    modeValueGroup: ModeValueGroup<Mode>,
    modeObject: Map<String, Any>,
    callback: Consumer<Mode>
)
modeValueGroup
ModeValueGroup<Mode>
required
The mode group to add the mode to
modeObject
Map<String, Any>
required
Mode configuration object
callback
Consumer<Mode>
required
Function called with the created mode instance
Example:
const killAura = Client.moduleManager.getModule("KillAura");
const rotationMode = killAura.settings.rotationMode;

script.registerMode(rotationMode, {
    name: "CustomRotation"
}, mode => {
    // Configure mode
});

on()

Registers a global event handler.
fun on(eventName: String, handler: Runnable)
eventName
String
required
Name of the event to listen to
handler
Runnable
required
Function to call when the event fires
Global events:
  • load - Called when script is loaded
  • enable - Called when script is enabled
  • disable - Called when script is disabled
Example:
script.on("load", () => {
    console.log("Script loaded!");
});

script.on("enable", () => {
    console.log("Script enabled!");
});

enable()

Enables the script and all its registered features.
fun enable()
Behavior:
  1. Calls global enable event
  2. Registers all modules with ModuleManager
  3. Registers all commands with CommandManager
  4. Adds all modes to their respective mode groups
  5. Sets scriptEnabled to true
Idempotent - calling when already enabled has no effect.

disable()

Disables the script and all its registered features.
fun disable()
Behavior:
  1. Calls global disable event
  2. Unregisters all modules from ModuleManager
  3. Unregisters all commands from CommandManager
  4. Removes all modes from their mode groups
  5. Triggers RefreshArrayListEvent
  6. Sets scriptEnabled to false
Idempotent - calling when already disabled has no effect.

close()

Closes the script context and releases resources.
override fun close()
Behavior:
  • Closes the GraalVM context
  • Releases all script resources
  • Should be called before removing script from memory
Implements AutoCloseable for use with try-with-resources.

Context Configuration

The script context is configured differently based on language:

JavaScript Features

if (language == "js") {
    option("js.nashorn-compat", "true")
    option("js.ecmascript-version", "2023")
    option("js.commonjs-require", "true")
    option("js.commonjs-require-cwd", file.parentFile.absolutePath)
}
Features:
  • Nashorn compatibility mode
  • ECMAScript 2023 support
  • CommonJS require() support
  • Module resolution from script directory
Example:
// Import other JavaScript files
const utils = require('./utils.js');
const config = require('./config.json');

Debug Options

data class ScriptDebugOptions(
    val enabled: Boolean = false,
    val protocol: DebugProtocol = DebugProtocol.INSPECT,
    val port: Int = 9229,
    val suspendOnStart: Boolean = false,
    val inspectInternals: Boolean = true
)
enabled
Boolean
default:"false"
Enable debugging for the script
protocol
DebugProtocol
default:"INSPECT"
Debug protocol to use (INSPECT or DAP)
port
Int
default:"9229"
Port for debug connection
suspendOnStart
Boolean
default:"false"
Pause execution at script start
inspectInternals
Boolean
default:"true"
Allow inspecting internal variables

INSPECT Protocol

Chrome DevTools Protocol support:
devtools://devtools/bundled/js_app.html?ws=127.0.0.1:9229/script-name.js
Use Chrome/Edge DevTools to debug JavaScript scripts.

DAP Protocol

Debug Adapter Protocol for VS Code and other editors:
{
  "type": "node",
  "request": "attach",
  "name": "Attach to LiquidBounce Script",
  "port": 9229
}

Lifecycle Example

// Load script
val script = ScriptManager.loadScript(
    file = File("my-script.js"),
    language = "js",
    debugOptions = ScriptDebugOptions(enabled = true)
)

// Script is now loaded and initialized
// Metadata is available
println("${script.scriptName} v${script.scriptVersion}")

// Enable script
script.enable()

// Script features are now active
val modules = script.registeredModules
val commands = script.registeredCommands

// Disable script
script.disable()

// Features are deactivated but script remains in memory

// Unload script
script.close()
ScriptManager.scripts.remove(script)

// Script is fully unloaded

Error Handling

Errors during event handling are caught and logged:
private fun callGlobalEvent(eventName: String) {
    try {
        globalEvents[eventName]?.run()
    } catch (throwable: Throwable) {
        logger.error(
            "${file.name}::$scriptName -> Event Function $eventName threw an error",
            throwable
        )
    }
}
This prevents a single faulty event handler from crashing the entire script.

See Also

Build docs developers (and LLMs) love