geequlim / ecmascript Goto Github PK
View Code? Open in Web Editor NEWJavascript binding for godotengine
License: MIT License
Javascript binding for godotengine
License: MIT License
Hello there, there seems to be an issue according to Typescript's compiler, tsc, with the following lines in the automatically-generated godot.d.ts:
This yields the following errors:
../godot.d.ts:2177:15 - error TS1005: ',' expected.
2177 const INF: 1.#INF;
~~~~
../godot.d.ts:2182:15 - error TS1005: ',' expected.
2182 const NAN: 1.#QNAN;
Thankfully, the typescript file for my compiles just fine regardless.
Steps to reproduce:
Project > Tools > ECMAScript > Generate Typescript Declaration File
which generates godot.d.ts
in res://
res://src/ts/new_script.ts
res://src/ts/
, create a subdirectory called godot
and place godot.d.ts
in it.new_script.ts
, import the declarations by writing import "godot";
tsc
in the src/ts/
directory. It will then print the errors.Error log:
modules/ECMAScript/quickjs/quickjs/quickjs.c:16065:11: error: use of undeclared identifier 'debugger_dispatch_table'; did you mean 'active_dispatch_table'?
? debugger_dispatch_table : dispatch_table;
^~~~~~~~~~~~~~~~~~~~~~~
active_dispatch_table
modules/ECMAScript/quickjs/quickjs/quickjs.c:16064:26: note: 'active_dispatch_table' declared here
const void * const * active_dispatch_table = caller_ctx->rt->debugger_info.transport_close
^
modules/ECMAScript/quickjs/quickjs/quickjs.c:16065:37: error: use of undeclared identifier 'dispatch_table'
? debugger_dispatch_table : dispatch_table;
I tried to import typescript / javascript modules but it doesn't seem to like the module format I'm using.
godot generates an error:
E 0:00:00.514 reload: JavaScript Error at <anonymous> (res://node_modules/of-range/range.js:2)
exports is not defined
<C++ Source> modules/ECMAScript/ecmascript.cpp:90 @ reload()
I have tried both node_modules and and files within my project directory. I think a way around this problem would be to use a bundler such-as webpack but I am hoping there is a simpler way to make this work.
Try to import an ogg file or to open a project with an ogg file. This crahes the editor on my system (Window 10 professional) with the following error in the console:
Assertion failed: f->temp_offset == f->alloc.alloc_buffer_length_in_bytes, file thirdparty/misc/stb_vorbis.c, line 4160
im getting this error:
ERROR: _load: No loader found for resource: res://Main.js.
At: core/io/resource_loader.cpp:280.
ERROR: poll: res://Main.tscn:3 - Parse Error: [ext_resource] referenced nonexistent resource at: res://Main.js
At: scene/resources/resource_format_text.cpp:440.
ERROR: load: Failed to load resource 'res://Main.tscn'.
At: core/io/resource_loader.cpp:208.
ERROR: _load: Failed loading resource: res://Main.tscn.
At: core/io/resource_loader.cpp:278.
ERROR: start: Failed loading scene: res://Main.tscn
At: main/main.cpp:1846.
WARNING: cleanup: ObjectDB Instances still exist!
At: core/object.cpp:2074.
ERROR: clear: Resources Still in use at Exit!
At: core/resource.cpp:473.
it works fine running from the editor
btw what export templates do i have to use with your builds
thx for your time developing this
I am trying to use this in godot (tagged commit 3.1.2-stable) with ECMAScript (tagged commit godot3.1-duktape) and the Godot UI will not allow me to attach an ECMAScript to a Node2D. It seems like a form validation issue but maybe I'm doing something wrong?
I've tried using the alpha3 branch as well but that one won't build w/ godot 3.1.2-stable. I'm going to try more branches, but do you know what the issue might be?
_physics_process(delta)
{
if (Input.is_action_pressed("ui_right"))
{
console.log("Right Pressed !");
}
}
Example:
a.js
export default class A extends godot.Node {
}
b.js
export { default } from './a';
And this will also crash:
c.js
export class C extends godot.Node {
}
d.js
export { C as default } from './c';
Suppose you have two source files, A and B, with A attached as a script to some node.
A:
import B from "./B.jsx"
export default class A extends godot.Node {
@signal static readonly mysignal: string;
_ready() {
this.add_child(new B());
}
}
B:
export default class B extends godot.Node {
@signal static readonly mysignal: string;
}
A is loaded as a script so register_ecma_class
is called and the signals property is used to register signals. B however only gets the signals property, but they don't get registered. I can look into a fix.
are there plans to generate puppet/master/remote/remotesync etc decorators?
Is there any reason they haven't been done yet? Couldn't it be done with a call to rpc_config at least in the short term?
https://i.imgur.com/MJ5uiQS.png
Thank you for working towards giving Godot the ease of use of JavaScript.
I noticed you said in the read me:
It is also possible to replace the ECMAScript engine like V8 or SpiderMonkey but not in the near plan.
I'm guessing that you're already aware of the performance difference, but just in case, a few people mention benchmark results in this thread: https://news.ycombinator.com/item?id=20418602
[QuickJS] shows only 2~3% of V8 performance
[QuickJS is] still 2-3x slower than [the V8 interpreter], and 20-100x slower than [the V8 compiler].
Scores on V8 benchmark suite:
QuickJS: 445 424 633 271 771 180 923 1979 549
V8: 31083 51056 36692 63343 50309 7910 22964 35214 32307
Deno seems like it might be helpful, and will hit v1.0 in about 8 days. I've not mixed Rust and C++ before (I haven't done any C++ coding at all) but apparently Rust plays well with other languages: https://doc.rust-lang.org/1.5.0/book/rust-inside-other-languages.html
Anyway, I'll close this right away because I don't have anything extra to add here - just thought I'd add this note in case you weren't aware of how vast the performance difference is.
Great project and works fine as is just leaving this issue as the jsx
/tsx
file extensions used are pretty much exclusive to React/hyperscript.
It's a little weird to adopt these in this project and causes some extensions in editors such as VSCode to believe that the file you are editing is of a react type. While it doesn't break anything it'd be nice not to have to disable/configure extensions in my editor to avoid react exclusive code suggestions/linting.
I would like to suggest changing this requirement to js
/ts
as in theory they are normal JS files without any additional syntax added.
console.log(godot.Performance.get_monitor(Performance.TIME_FPS));
Error "Performance not defined".
I also tried: console.log(Performance.get_monitor(Performance.TIME_FPS));
Both doesn't work.
export default class Ball extends godot.KinematicBody
{
// Declare member variables here. Examples:
a = 2;
b = "text";
velocity = godot.Vector3(0,0,0); //This crash the scene, please help thanks.
constructor()
{
super();
}
_ready()
{
}
_process(delta)
{
}
_physics_process(delta)
{
}
}
the following code yields an error:
const a = new godot.Vector2(1, 1);
const b = new godot.Vector2(1, 1);
const c = a + b;
The error is:
Argument of type 'number' is not assignable to parameter of type 'Vector2'.ts(2345)
it can be avoided like so:
const c = ((a as any) + (b as any) as any as godot.Vector2);
is there anyway to avoid this in typescript?
I did not succeed.
I generated the apk and installed it on my smartphone, but the game didn't work
given the following code:
export default class A extends godot.Node2D {
_ready() {
console.log(godot.Input.MOUSE_MODE_CONFINED) // logs undefined
console.log(godot.Input.MouseMode) // logs undefined
godot.Input.set_mouse_mode(godot.Input.MOUSE_MODE_CONFINED)
}
}
you can see that both the enum which typescript expects, as wells as the enum constants on the godot.Input
class itself are undefined. The equivalent gdscript works:
extends Node
class_name A
func _ready():
print(Input.MOUSE_MODE_CONFINED) // prints 3
Input.set_mouse_mode(Input.MOUSE_MODE_CONFINED)
Here is a project containing the scripts:
ecmascript-mouse-mode-confined.zip
If the enum is not intended to be supported by the JS runtime, just typescript types, I would recommend making it a typescript const enum which would be replaced by 3
at typescript compile time so the JS runtime only needs to be aware of godot.Input.MOUSE_MODE_*
not both that and godot.Input.MouseMode.MOUSE_MODE_*
is there any interest in generating strong types for connections such as:
(this is probably a poor example, I'd need to dig in and make a PR to do it correctly)
declare module godot {
interface SceneTree implements MainLoop {
//overload 1 for network_peer_connected signal
function connect<T extends Object>(
signal: "network_peer_connected",
target: T,
method: Extract<T, Function> | (...args: Parameters<onNetworkPeerConnected>) => void, //could use e.g. MethodOf<T>,
binds: Tail<Parameters<onNetworkPeerConnected>>,
flags: number = 0,
): number;
// more overloads, one per signal for discriminating union
}
}
Provided is a minimal reproduction of a bug (I'm not sure whether in QuickJS or these bindings) where cyclic imports cause a segmentation fault.
Cyclic imports don't really work in ECMAScript modules (they're often undefined) so I should probably work around them, and maybe it's not even a bug then, but perhaps having a warning in the documentation or even detecting it would be helpful. I'll try to reproduce in quickjs by itself to confirm if it's a bug here or in quickjs.
Here are the root 50 frames in gdb:
(gdb) bt -50
#37664 0x00000000004fc7bf in js_resolve_module (ctx=0x417b48f0, m=0x5405db30) at modules/ECMAScript/quickjs/quickjs/quickjs.c:27441
#37665 0x000000000050af7e in __JS_EvalInternal (ctx=0x417b48f0, this_obj=...,
input=0x5405d150 "import TestA from \"./TestA\"\n\nclass TestB extends godot.Node2D {\n _ready() {\n testA.connect(TestA.my_signal, () => { godot.print(\"my_signal!\") })\n }\n}\n\nexport default TestB\n",
input_len=185, filename=0x5405ba70 "res://TestB.jsx", flags=33, scope_idx=-1) at modules/ECMAScript/quickjs/quickjs/quickjs.c:33094
#37666 0x000000000050b15b in JS_EvalInternal (ctx=0x417b48f0, this_obj=...,
input=0x5405d150 "import TestA from \"./TestA\"\n\nclass TestB extends godot.Node2D {\n _ready() {\n testA.connect(TestA.my_signal, () => { godot.print(\"my_signal!\") })\n }\n}\n\nexport default TestB\n",
input_len=185, filename=0x5405ba70 "res://TestB.jsx", flags=33, scope_idx=-1) at modules/ECMAScript/quickjs/quickjs/quickjs.c:33119
#37667 0x000000000050b360 in JS_Eval (ctx=0x417b48f0,
input=0x5405d150 "import TestA from \"./TestA\"\n\nclass TestB extends godot.Node2D {\n _ready() {\n testA.connect(TestA.my_signal, () => { godot.print(\"my_signal!\") })\n }\n}\n\nexport default TestB\n",
input_len=185, filename=0x5405ba70 "res://TestB.jsx", eval_flags=33) at modules/ECMAScript/quickjs/quickjs/quickjs.c:33149
#37668 0x0000000000463725 in QuickJSBinder::js_compile_module (this=0x415acc20, ctx=0x417b48f0, p_code=..., p_filename=..., r_error=0x254f8e00) at modules/ECMAScript/quickjs/quickjs_binder.cpp:639
#37669 0x00000000004630d3 in QuickJSBinder::js_module_loader (ctx=0x417b48f0, module_name=0x5405c0a0 "res://TestB", opaque=0x415acc20) at modules/ECMAScript/quickjs/quickjs_binder.cpp:574
#37670 0x00000000004fb66b in js_host_resolve_imported_module (ctx=0x417b48f0, base_module_name=13844, module_name1=13850) at modules/ECMAScript/quickjs/quickjs/quickjs.c:26993
#37671 0x00000000004fc7bf in js_resolve_module (ctx=0x417b48f0, m=0x5405b760) at modules/ECMAScript/quickjs/quickjs/quickjs.c:27441
#37672 0x000000000050af7e in __JS_EvalInternal (ctx=0x417b48f0, this_obj=...,
input=0x5405b420 "import TestB from \"./TestB\";\n\nexport default class TestA extends godot.Area2D {\n static my_signal = \"my_signal\"\n\n _ready() {\n this.add_child(new TestB())\n }\n}\n\ngodot.register_signal(Te"..., input_len=221, filename=0x540098d0 "res://TestA.jsx", flags=33, scope_idx=-1) at modules/ECMAScript/quickjs/quickjs/quickjs.c:33094
#37673 0x000000000050b15b in JS_EvalInternal (ctx=0x417b48f0, this_obj=...,
input=0x5405b420 "import TestB from \"./TestB\";\n\nexport default class TestA extends godot.Area2D {\n static my_signal = \"my_signal\"\n\n _ready() {\n this.add_child(new TestB())\n }\n}\n\ngodot.register_signal(Te"..., input_len=221, filename=0x540098d0 "res://TestA.jsx", flags=33, scope_idx=-1) at modules/ECMAScript/quickjs/quickjs/quickjs.c:33119
#37674 0x000000000050b360 in JS_Eval (ctx=0x417b48f0,
input=0x5405b420 "import TestB from \"./TestB\";\n\nexport default class TestA extends godot.Area2D {\n static my_signal = \"my_signal\"\n\n _ready() {\n this.add_child(new TestB())\n }\n}\n\ngodot.register_signal(Te"..., input_len=221, filename=0x540098d0 "res://TestA.jsx", eval_flags=33) at modules/ECMAScript/quickjs/quickjs/quickjs.c:33149
#37675 0x0000000000463725 in QuickJSBinder::js_compile_module (this=0x415acc20, ctx=0x417b48f0, p_code=..., p_filename=..., r_error=0x254f94a0) at modules/ECMAScript/quickjs/quickjs_binder.cpp:639
#37676 0x000000000046e4e5 in QuickJSBinder::parse_ecma_class (this=0x415acc20, p_code=..., p_path=..., r_error=0x254f94a0) at modules/ECMAScript/quickjs/quickjs_binder.cpp:2003
#37677 0x0000000000459e7a in ECMAScript::reload (this=0x5405aea0, p_keep_state=true) at modules/ECMAScript/ecmascript.cpp:92
#37678 0x000000000045aaf7 in ResourceFormatLoaderECMAScript::load (this=0x415ab810, p_path=..., p_original_path=..., r_error=0x0) at modules/ECMAScript/ecmascript.cpp:256
#37679 0x0000000001a181e6 in ResourceLoader::_load (p_path=..., p_original_path=..., p_type_hint=..., p_no_cache=false, r_error=0x0) at core/io/resource_loader.cpp:270
#37680 0x0000000001a18ca3 in ResourceLoader::load (p_path=..., p_type_hint=..., p_no_cache=false, r_error=0x0) at core/io/resource_loader.cpp:401
#37681 0x0000000001616d8f in ResourceInteractiveLoaderText::poll (this=0x540692e0) at scene/resources/resource_format_text.cpp:433
#37682 0x0000000001a168ff in ResourceFormatLoader::load (this=0x34c6bcb0, p_path=..., p_original_path=..., r_error=0x254fa25c) at core/io/resource_loader.cpp:197
#37683 0x0000000001a181e6 in ResourceLoader::_load (p_path=..., p_original_path=..., p_type_hint=..., p_no_cache=true, r_error=0x254fa25c) at core/io/resource_loader.cpp:270
#37684 0x0000000001a18ca3 in ResourceLoader::load (p_path=..., p_type_hint=..., p_no_cache=true, r_error=0x254fa25c) at core/io/resource_loader.cpp:401
#37685 0x0000000000b52fd6 in EditorNode::load_scene (this=0x43fc5060, p_scene=..., p_ignore_broken_deps=false, p_set_inherited=false, p_clear_errors=true, p_force_open_imported=false) at editor/editor_node.cpp:3371
#37686 0x0000000000b53e20 in EditorNode::open_request (this=0x43fc5060, p_path=...) at editor/editor_node.cpp:3488
#37687 0x0000000000c10687 in FileSystemDock::_select_file (this=0x5cb42880, p_path=..., p_select_in_favorites=false) at editor/filesystem_dock.cpp:832
#37688 0x0000000000c1091a in FileSystemDock::_tree_activate_file (this=0x5cb42880) at editor/filesystem_dock.cpp:851
#37689 0x00000000022be420 in MethodBind0::call (this=0x415a3890, p_object=0x5cb42880, p_args=0x254fa9b0, p_arg_count=0, r_error=...) at ./core/method_bind.gen.inc:59
#37690 0x00000000018c5549 in Object::call (this=0x5cb42880, p_method=..., p_args=0x254fa9b0, p_argcount=0, r_error=...) at core/object.cpp:922
#37691 0x00000000018c7184 in Object::emit_signal (this=0x5cb57a60, p_name=..., p_args=0x254fa9b0, p_argcount=0) at core/object.cpp:1249
#37692 0x00000000018c780d in Object::emit_signal (this=0x5cb57a60, p_name=..., p_arg1=..., p_arg2=..., p_arg3=..., p_arg4=..., p_arg5=...) at core/object.cpp:1306
#37693 0x0000000001317cb3 in Tree::_gui_input (this=0x5cb57a60, p_event=...) at scene/gui/tree.cpp:2727
#37694 0x00000000022c031b in MethodBind1<Ref<InputEvent> >::call (this=0x34d7a610, p_object=0x5cb57a60, p_args=0x254fb590, p_arg_count=1, r_error=...) at ./core/method_bind.gen.inc:775
#37695 0x00000000018c4b0b in Object::call_multilevel (this=0x5cb57a60, p_method=..., p_args=0x254fb590, p_argcount=1) at core/object.cpp:764
#37696 0x00000000018c524d in Object::call_multilevel (this=0x5cb57a60, p_name=..., p_arg1=..., p_arg2=..., p_arg3=..., p_arg4=..., p_arg5=...) at core/object.cpp:864
#37697 0x00000000011bde80 in Viewport::_gui_call_input (this=0x43f67520, p_control=0x5cb57a60, p_input=...) at scene/main/viewport.cpp:1669
#37698 0x00000000011bf128 in Viewport::_gui_input_event (this=0x43f67520, p_event=...) at scene/main/viewport.cpp:1979
#37699 0x00000000011c3ae0 in Viewport::input (this=0x43f67520, p_event=...) at scene/main/viewport.cpp:2825
#37700 0x00000000011bcc98 in Viewport::_vp_input (this=0x43f67520, p_ev=...) at scene/main/viewport.cpp:1446
#37701 0x00000000022fc3db in MethodBind1<Ref<InputEvent> const&>::call (this=0x34c86540, p_object=0x43f67520, p_args=0x254fc2c0, p_arg_count=1, r_error=...) at ./core/method_bind.gen.inc:775
#37702 0x00000000018c5549 in Object::call (this=0x43f67520, p_method=..., p_args=0x254fc2c0, p_argcount=1, r_error=...) at core/object.cpp:922
#37703 0x00000000018c519e in Object::call (this=0x43f67520, p_name=..., p_arg1=..., p_arg2=..., p_arg3=..., p_arg4=..., p_arg5=...) at core/object.cpp:848
#37704 0x00000000011a2f95 in SceneTree::call_group_flags (this=0x43f671d0, p_call_flags=2, p_group=..., p_function=..., p_arg1=..., p_arg2=..., p_arg3=..., p_arg4=..., p_arg5=...) at scene/main/scene_tree.cpp:275
#37705 0x00000000011a3bfd in SceneTree::input_event (this=0x43f671d0, p_event=...) at scene/main/scene_tree.cpp:431
#37706 0x0000000000416fed in InputDefault::_parse_input_event_impl (this=0x2a350d00, p_event=..., p_is_emulated=false) at main/input_default.cpp:442
#37707 0x0000000000416060 in InputDefault::parse_input_event (this=0x2a350d00, p_event=...) at main/input_default.cpp:259
#37708 0x0000000000418081 in InputDefault::flush_accumulated_events (this=0x2a350d00) at main/input_default.cpp:678
#37709 0x000000000040bc2e in OS_Windows::process_events (this=0x254fc910) at platform/windows/os_windows.cpp:2598
#37710 0x00000000004100a4 in OS_Windows::run (this=0x254fc910) at platform/windows/os_windows.cpp:3396
#37711 0x00000000004019da in widechar_main (argc=2, argv=0x256cc710) at platform/windows/godot_windows.cpp:161
#37712 0x0000000000401af3 in _main () at platform/windows/godot_windows.cpp:184
#37713 0x0000000000401b28 in main (_argc=2, _argv=0x1e8f80) at platform/windows/godot_windows.cpp:201
Hello the GodotExplorer ECMAScript Team !
First: Thank you, this is awesome !
Second: the question in the title, so "Are Singleton / Autoload supported ? How ?"
Thank you !
Hi, thanks for the great module getting JS support in Godot! I was wondering if you were looking at supporting Godot 4.0 in a separate branch.
Godot 4.0 (currently pre-alpha / in development on master branch of godot repository) has a number of breaking API changes, I was experimenting with some of these changes in https://github.com/Flux159/ECMAScript/tree/godot_4.0, but ran into some issues with how PackedArrays were being used differently from PooledArrays along with a number of other C++ errors during compilation.
Hi, do you have thoughts on providing prebuilt binaries of Godot with the ECMAScript module already installed?
Specifically, making the builds as mentioned in the README
Compilation
Clone the source code of godot
Clone this module and put it into godot/modules/ and make sure the folder name of this module is ECMAScript
Recompile the godot engine (Only MinGW is supported on Windows for now!)
is a significant burden to getting started with the project (not to mention making binaries w/out tools for exporting published games). I was wondering if it makes sense to provide prebuilt binaries (or setup a CI/CD pipeline with Github Actions to build & publish them as part of the repo).
Hello, first of thanks for this great implementation of ES for Godot. It helps me alot getting started.
i ran into an issue when trying to get the world space state, in order to cast an ray between two Spatials. (i want to copy the Y position of the element below the player)
export default class Example extends godot.KinematicBody {
_physics_process(delta) {
var world = this.get_world()
var spaceState = world.get_direct_space_state() // this line throws the error
}
}
E 0:00:01.516 variant_to_var: Parameter ' data->ecma_object ' is null.
<C++-Quellcode>modules/ECMAScript/quickjs/quickjs_binder.cpp:132 @ variant_to_var()
This method of ray casting is recommendet in http://docs.godotengine.org/en/3.2/tutorials/physics/ray-casting.html
My Godot Built is based on
e707b712e8
(3.2 branch)ec69d88
(maybe a bit outdated)I'm trying to redo https://docs.godotengine.org/en/latest/getting_started/step_by_step/your_first_game.html#main-scene with ECMAScript and did not manage to translate export (PackedScene) var Mob
.
I tried
import Mob from 'res://mob.js';
godot.register_property(Main, 'Mob', Mob);
and
godot.register_property(Main, 'Mob', godot.PackedScene);
but both crashed the editor. What's the correct way to do this?
fib.js
default export is fib
function and not a godot class, so every time the file is loaded i get an error message "modules/ECMAScript/ecmascript.cpp:92 - JavaScript Error". Is this how it is supposed to be right now (work in progress)? So for now to avoid this message on every save one should export some empty class inheriting godot.Object
?
This one is less straightforward. When i press "Calculate in Worker" the playing scene just exits without any error ("Calculate in Main Thread" works fine). I tested different things and it seems like there is a stack overflow in worker thread on my machine when N
is higher than 26. Even when fib
is a simple function as (n) => n < 2 ? n : fib( n - 1 )
. With 26 or lower worker is fine. Any clues what this might be caused by? What is the maximum N on your machine if you use the provided simple function?
Spawns next error log:
UnicodeEncodeError: 'charmap' codec can't encode character '\xd7' in position 24610: character maps to <undefined>:
File "C:\Users\Teashrock\Documents\Development\Not-Mine\godot-3.2-stable\SConstruct", line 518:
SConscript("modules/SCsub")
File "c:\users\teashrock\envs\py3.7.4\lib\site-packages\scons\SCons\Script\SConscript.py", line 668:
return method(*args, **kw)
File "c:\users\teashrock\envs\py3.7.4\lib\site-packages\scons\SCons\Script\SConscript.py", line 605:
return _SConscript(self.fs, *files, **subst_kw)
File "c:\users\teashrock\envs\py3.7.4\lib\site-packages\scons\SCons\Script\SConscript.py", line 286:
exec(compile(scriptdata, scriptname, 'exec'), call_stack[-1].globals)
File "C:\Users\Teashrock\Documents\Development\Not-Mine\godot-3.2-stable\modules\SCsub", line 17:
SConscript(x + "/SCsub")
File "c:\users\teashrock\envs\py3.7.4\lib\site-packages\scons\SCons\Script\SConscript.py", line 668:
return method(*args, **kw)
File "c:\users\teashrock\envs\py3.7.4\lib\site-packages\scons\SCons\Script\SConscript.py", line 605:
return _SConscript(self.fs, *files, **subst_kw)
File "c:\users\teashrock\envs\py3.7.4\lib\site-packages\scons\SCons\Script\SConscript.py", line 286:
exec(compile(scriptdata, scriptname, 'exec'), call_stack[-1].globals)
File "C:\Users\Teashrock\Documents\Development\Not-Mine\godot-3.2-stable\modules\ECMAScript\SCsub", line 63:
f.write(text.replace('${source}', dump_text_file_to_cpp("misc/godot.d.ts")))
File "C:\Users\Teashrock\Envs\Py3.7.4\lib\encodings\cp1251.py", line 19:
return codecs.charmap_encode(input,self.errors,encoding_table)[0]
Similar to C#'s GetNode<Label>()
, add a generic argument to the $
and get_node
types.
Something like:
interface Node {
$<T extends godot.Node>(path: string): T;
}
If there's no reason against it, I could submit a PR once I read up on the repository.
Hello!
I'm facing a weird issue, every time I try to create a script and attach it to a node I get an error. Here is the error when I tried to attach a script to a sprite. Obviously, the script exists and the code is correct (didn't change the template).
E 0:00:00.531 parse_ecma_class_from_module: Condition "p_module == __null || p_module->module == __null" is true. Returned: __null <Source C++> modules/ECMAScript/quickjs/quickjs_binder.cpp:1630 @ parse_ecma_class_from_module()
E 0:00:00.531 reload: JavaScript Error at res://SpriteTest.js:1
stack overflow
<Source C++> modules/ECMAScript/ecmascript.cpp:92 @ reload()
E 0:00:00.531 load: Cannot parse source code from file 'res://SpriteTest.js'.
<Source C++> modules/ECMAScript/ecmascript.cpp:267 @ load()
I notice we're missing some print functions that are in gdscript. Namely prints, printt, print_debug, and print-stack.
When writing gdscript I use prints
in every situation (as it inserts spaces between arguments, just like console.log
in JavaScript), so I noticed it quickly when trying this project.
Also I'm not sure that print
is working as expected. It is supposed to accept and print any number of arguments, but in my testing it only prints the first:
// this prints: "a"
godot.print("a", "b", "c")
The typings for print
seem correct though:
function godot.print(...args: any[]): void
With Javascript being very async heavy, and ECMAScript not having to completely match how GDScript implements its features, there's potentially to provide slight usability improvements to the workflow with regards to Godot coroutines and signals workflow. These do not need to be implemented at a low level and may just be shims that wrap existing behavior
#gdscript Player
func jump():
var anim = $AnimationPlayer
anim.play("jump")
yield($AnimationPlayer, "animation_finished")
// javascript
async function() {
const player = get_node("Player");
const result = await player.jump();
}
node.connect("my_signal", (param) => { console.log(param) });
node.connect("my_signal", this.mySignalHandler);
// with async/await
const async_result = await godot.OnSignal(node, "my_signal")
do_stuff(async_result);
// or with promises
godot.OnSignal(node, "my_signal")
.then((result) => { do_stuff(result) })
If developers want to have a more advance version of the signalling, they could write a custom wrapper using RxJS where results get piped into an Observable.
Has anyone had any luck with getting socket.io-client npm functional with this? It seems that it does not read npm module entry properly for me.
E 0:03:17.602 resolve_module_file: Module entry does not exists: node_modules/socket.io-client/./lib/index.js
<C++ Error> Condition "!FileAccess::exists(entry)" is true. Returned: ""
<C++ Source> modules/ECMAScript/quickjs/quickjs_binder.cpp:631 @ resolve_module_file()
In resolve_module_file
requested CommonJS module with require('$name')
is expected to have a package at node_modules/$name/package.json
at root of a godot project.
What if one want to move all js files (with node_modules) into a subfolder, like /js
?
What if packages installed like this - nodule_modules/a/node_modules/b
? Package a
requires package b
and they might be positioned in such way if some other package requires package b
with a different version.
What if one want to require node_modules/a/b.js
by require('a/b')
? If b
is not exported in index of package a
.
Imo, more idiomatic typescript development (this might change with deno) practices call for the godot.d.ts
and decorators.ts
files to be a dependency, rather than generated by the editor. A combination of both could work, but I think the current workflow:
Run the menu command Project > Tools > ECMAScript > Generate TypeScript Project from the godot editor to generate a TypeScript project
would be better done by generating a package.json
that depends on some godot-ecmascript
package on npm that would be maintained by this group.
I wouldn't mind contributing this, but I think it warrants discussion.
Other benefits I can think of:
Currently godot scans and exports all files in node_modules folder, which is no good as it is notorious for becoming big in size. (Typescript folder is more than 50MB.)
There is .gdignore
for that. Can be added automatically with some script in package.json:
"postinstall": "touch ./node_modules/.gdignore"
(Should be something else on windows - there is no touch
there.)
Problem is - it will prevent needed files from being included in export too...
But previous two issues (#50 and #51) make me think that it might be easier to delegate work with node_modules to some other tool.
For example - you create a file index.js
through which you export all cjs used by godot scripts and then build it with webpack. And you get a single script that contains only requested packages, which then is required by godot scripts with a relative path.
It removes all the problems associated with node_modules.
Thoughts?
According to the documentation, randi()
should return a random integer between 0 and 2^32-1 which should make it trivial to get a random number in an interval via modulo.
godot.randi()
can return negative values (I would assume between -2^16 and 2^16-1?) which forces you to wrap calls with godot.floor()
.
What is the URL to download the compiled release ?
Thanks.
I haven't set up a minimal viable reproduction yet, but I have a script class (A) with a signal, and then two nodes (both of class B) connect to the node of class A. When A emits its signal, the first node of class B gets the emitted arguments with the call:
emit_signal('signal_of_a', {ARGUMENT: "something"})
But the second node of class B gets an undefined argument instead, and because the bad argument is never set in QuickJSBinder::call, an uninitialized value is used to index the array of arguments which often leads to segfaults.
I also noticed that it happens while the code is in the JS_Call in QuickJSBinder::call_method, but I'm going to sleep for tonight. I will investigate more later. I have a suspicion since it occurs in the JS runtime that the variant_to_var is missing a reference count or something, but I don't know.
I'm not sure this is possible, but for now I have to do:
const bytes: PoolByteArray = godot.var2bytes({"hello": "world"});
for(let i = 0; i < bytes.size(); i++) {
const byte = bytes.get(i);
I may be able to do this myself by attaching a Symbol.iterator property to the prototype which I will try, and can submit a PR for when done. Which might still take some time considering the codebase I'm converting.
Right now it's very difficult to figure out how to actually 'export' (in the Godot meaning of that) NodePaths
and other types. I saw the latest release notes and figured out that support has been added for something like as the 'default value':
{
type: godot.VariantType.TYPE_NODE_PATH,
name: 'Tile Map',
}
But only after crashing the editor a few times by trying to set default value to something like new godot.TileMap()
.
Would be great to have this documented along with all the valid usages. I can pick this one up and improve the documentation but I'd like to learn more first about everything before I do so to make sure I document it correctly.
I will wait until quickjs is more stable at least the debugger is implemented.
ECMAScriptGCHandler
to improve the binding processgodot.Object
godot.Reference
godot.sin
godot.randi
godot.Vector2
godot.Color
Rect2.end
, Color.r8
godot.register_class
to register classes form JSexport default ClassFunction
syntaxObject.connect
, Object.disconnect
and Object.is_connected
await
support for signalsWorker
APIECMAScriptGCHandler
Array
Dictionary
On my machine playing scene crashes if i have a js class with _input
or _unhandled_input
.
Reproduction: create empty project, create some root node, attach new ecma script to it and add _input(event) {}
or _unhandled_input(even) {}
. Play the scene and move a mouse few seconds.
Without those methods everything is working, as soon as i add them, crashes appear. On crashes i can see messages about malloc
in terminal with godot editor process.
Is this reproducible on your machine?
Please excuse my ignorance in complexity of these things but I was wonder the following.
Since V8 is in orders of magnitude faster than quickjs, why not use V8 as the js engine?
Create something with a Position
, like Area2D
. Now try to manipulate only x
or only y
of the position:
export default class Player extends godot.Area2D {
constructor() {
this.velocity = new godot.Vector2();
}
_process() {
this.velocity.x++; //this works!
this.position.x++; //this should work but doesn't!
this.position = new godot.Vector2(this.position.x + 1, this.position.y); //this works!
}
}
I tried with position
and scale
, I assume all built-in vecors might behave the same.
@GDScript
into ECMAScriptObject
) into ECMAScriptOS
, ResourceLoader
... ) into ECMAScript
As mentioned in #41 windows (mingw) builds are broken on master due to quickjs_debugger using sys/socket.h
I merged the upstream changes, and all of my auto load scripts now cause the following:
Godot Engine v3.2.3.beta.custom_build.63cd61ce4 - https://godotengine.org
OpenGL ES 3.0 Renderer: Quadro P2000/PCIe/SSE2
"mike-HP-ZBook-15-G5" 14:21 15-Aug-20
ERROR: get_parent_class: Cannot get class 'JSEnvBootstrapper'.
At: core/class_db.cpp:343.
ERROR: start: Script does not inherit a Node: res://js-extensions/JSEnvBootstrapper.jsx
At: main/main.cpp:1758.
ERROR: get_parent_class: Cannot get class 'SteamManager'.
At: core/class_db.cpp:343.
ERROR: start: Script does not inherit a Node: res://core/network/SteamManager.jsx
At: main/main.cpp:1758.
ERROR: object_method: Parameter "bind" is null.
At: modules/ECMAScript/quickjs/quickjs_binder.cpp:117.
ERROR: godot_load: Condition "argc < 1 || !JS_IsString(argv[0])" is true. Returned: JS_ThrowTypeError(ctx, "string expected for %s.%s", "godot", "load")
At: modules/ECMAScript/quickjs/quickjs_binder.cpp:451.
ERROR: object_method: Parameter "bind" is null.
At: modules/ECMAScript/quickjs/quickjs_binder.cpp:117.
ERROR: get_parent_class: Cannot get class 'GameState'.
At: core/class_db.cpp:343.
ERROR: start: Script does not inherit a Node: res://core/GameState.jsx
At: main/main.cpp:1758.
I'm sorry for the vague issue, but I used git bisect
to find that the multi threaded classes commit broke it:
commit 35505d14417c3a5ef37eaf5d76977b1cd9d3c302 (refs/bisect/bad)
Author: Geequlim <[email protected]>
Date: Sat Aug 8 12:38:37 2020 +0800
ECMAScript class with multi-thread support
And I thought you might know what happened, faster than I can dig in.
Here's a reproduction:
ecmascript-pressed.zip
Here's the running script:
export default class A extends godot.Node2D {
_input(evt) {
if (evt.button_index === godot.ButtonList.BUTTON_RIGHT && evt.is_pressed())
godot.print('right click!')
if (evt.button_index === godot.ButtonList.BUTTON_LEFT && evt.pressed)
godot.print('left click!')
}
}
Notice that the right click triggers the print, but not the left.
It works in editor, but once exported does not.
It works in export only with a relative path in require
call and with "Script Export Mode" as "Text".
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.