Skip to content

Latest commit

 

History

History
146 lines (107 loc) · 5.5 KB

running_code_in_editor.md

File metadata and controls

146 lines (107 loc) · 5.5 KB

Running code in the editor

Note

Read Godot Docs for more details about @tool.

If a GodotJS class is annotated with tool(), it'll be instantiated in the editor. Check Engine.is_editor_hint() in the script to check if it's running in the editor.
It's also possible to show warnings on a Node on Scene panel with _get_configuration_warnings defined. Here is a simple example:

import { Engine, PackedStringArray, Sprite2D, Variant } from "godot";
import { export_, tool } from "jsb.core";

@tool()
export default class MyEditorSprite extends Sprite2D {

    /**
     * get/set property for `export` (both must be defined)
     */
    @export_(Variant.Type.TYPE_FLOAT)
    get speed(): number { return this._speed; }
    set speed(value: number) {
        if (this._speed != value) {
            this._speed = value;
            this.update_configuration_warnings();
        }
    }

    /**
     * plain field for `export`
     */
    @export_(Variant.Type.TYPE_INT)
    unused_int = 0;

    private _clockwise = false;
    private _speed = 0;

    _ready() {
        this._clockwise = Engine.is_editor_hint();
    }

    _process(delta: number) {
        const step = Math.PI * delta * (this._clockwise ? this._speed : -this._speed);
        this.rotation = this.rotation + step;

        // this version is available only if `JSB_EXCLUDE_GETSET_METHODS` is disabled on your side
        // this.set_rotation(this.get_rotation() + step);
    }

    _get_configuration_warnings() {
        let warnings = new PackedStringArray();
        if (this._speed >= -0.01 && this._speed < 0.01) {
            warnings.append("speed is too low");
        }
        return warnings;

        // it's OK to directly use javascript Array as the return value (except the complains from ts compiler):
        // return this._speed >= -0.01 && this._speed < 0.01 ? ["speed is too low"] : [];
        
        // So, you need to write it like this one which would be slightly ugly:
        // return <any> (this._speed >= -0.01 && this._speed < 0.01 ? ["speed is too low"] : []);
    }
}

By attaching this script on a Sprite2D node and setting _speed as 0, a warning message will be listed on Scene panel if _speed is too small.

show warnings on node

Running one-off scripts using EditorScript

Sometimes, you need to run code just one time to automate a certain task that is not available in the editor out of the box. Some examples might be:

  • Use as a playground for GodotJS scripting without having to run a project. print() output is displayed in the editor Output panel.

  • Scale all light nodes in the currently edited scene, as you noticed your level ends up looking too dark or too bright after placing lights where desired.

  • Replace nodes that were copy-pasted with scene instances to make them easier to modify later.

This is available in Godot by extending EditorScript in a script. This provides a way to run individual scripts in the editor without having to create an editor plugin.

import { EditorScript } from "godot";
import { tool } from "jsb.core";

@tool()
export default class MyEditorScript1 extends EditorScript {
    _run() {
        console.log("my editor script run");
    }
}

This _run() method is executed when you use File > Run or the keyboard shortcut Ctrl + Shift + X while the EditorScript is the currently open script in the script editor. This keyboard shortcut is only effective when currently focused on the script editor.

run_editor_script.png

Running batch scripts using editor parameters

Scripts can also be executed from command line arguments, making them very suitable for batch processing tasks, such as generating config files, converting formats, and so on.

./bin/your_godot_binary_file --path "path\to\your_project" --script res://tests/read_xlsx.ts

It's an example script which leverages xlsx.js for directly reading data from Excel xlsx files, re-saving it as csv or anything you want.

import * as jsb from "godot-jsb";
import { FileAccess } from "godot";

console.log("please run 'npm install' in the directory './' at first if 'xlsx' module can not be resolved");

//NOTE xlsx requires 'stream' module if 'require' exists
//     but, actually, this module is not utilized by xlsx in practice, 
//     pretending it exists helps avoid errors as a workaround.
jsb.internal.add_module("stream", {});
import * as xlsx from "xlsx";

let filename = "res://test.xlsx";
let wb = xlsx.read(FileAccess.get_file_as_bytes(filename).to_array_buffer(), { type: "buffer" });

console.log("read excel:", filename);
for (let sheetIndex in wb.SheetNames) {
    let sheetName = wb.SheetNames[sheetIndex]

    console.log(`read sheet: ${sheetName}`);
    let sheet = wb.Sheets[sheetName];
    let csv = xlsx.utils.sheet_to_csv(sheet);
    console.log("to_csv:", csv);
    let range = xlsx.utils.decode_range(sheet["!ref"]!);
    for (let row = range.s.r; row <= range.e.r; row++) {
        for (let col = range.s.c; col <= range.e.c; col++) {
            let cell = sheet[xlsx.utils.encode_cell({ c: col, r: row })];
            if (cell) {
                console.log(cell.v);
            }
        }
    }
}

Go Back