godotjs / javascript

Javascript binding for godotengine
https://godotjs.github.io/
MIT License
982 stars 82 forks source link

OS.execute cannot capture shell output #79

Open fidasx opened 3 years ago

fidasx commented 3 years ago

executing applications works fine like xterm for example or firefox but i cannot get the shell output from command line apps like ls

   _ready() {
        let args = new godot.PoolStringArray(["-c", "ls"])
        let arr = []
        godot.OS.execute("sh", args, true, arr)

        godot.print(arr) // prints empty []
    }
Geequlim commented 3 years ago

We don't support return values by out arguments. You have to make a gdscript wrap then call from JavaScript to achieve this

fidasx commented 3 years ago

hmm ok any example how i can achieve this

Geequlim commented 3 years ago

OSExecuter.gd

var code: int = 0
var output: Array = []
func execute(path: String, arguments: PoolStringArray = [],  blocking: bool = true, read_stderr: bool = false):
    code = OS.execute(path, arguments, blocking, self.output, read_stderr)
    return self

main.jsx

import OSExecuter from 'res://OSExecuter.gd'

export default class Main extends godot.Control {
    _ready() {
        const executer = OSExecuter.new();
        executer.call("execute", "node", ["-v"])
        console.log(executer.get("code"), executer.get("output"))
    }
}

If you are using TypeScript you can wrap call and get by decorators to avoid mannually passing member names as string.

fidasx commented 3 years ago

ty but that will make things so verbose and complicated thx again anyways i hope in the future you can sort this out

Geequlim commented 3 years ago

This is because the Array and Dictionary is diffrent thing in JavaScript and Godot. For most maybe >99% use case they looks like same so I convert JavaScript Array/Object to Godot Array/Dictionary internally in the binding implementation. I'm not going to fix this as it will make most use case become more complicated like this

let arr = new godot.Array();
arr.push_back(0);
arr.push_back(1);
this.connect('signal_name', this.callback_method, arr);

In current implemention it is much clear

this.connect('signal_name', this.callback_method, [0, 1]);