Skip to content

Commit 7bad78a

Browse files
fix: GArray.create/GDictionary.create recursive JS -> Godot collection conversion (#96)
* fix: GArray.create/GDictionary.create recursive value wrapping Added godot_wrap to the runtime which ensures GArray.create and GDictionary.create are able to recursively convert JS objects to Godot types. Actually thought I'd already implemented this, hence the recent type changes I made. Whoops! Fixed now. Other changes are just clean-up (mostly DRY). * chore: Build latest runtime
1 parent b1ceac4 commit 7bad78a

File tree

5 files changed

+120
-69
lines changed

5 files changed

+120
-69
lines changed

scripts/jsb.runtime/src/jsb.inject.ts

Lines changed: 61 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -9,31 +9,66 @@ type GDictionaryProxy<T> = Godot.GDictionaryProxy<T> & {
99
[Godot.ProxyTarget]: Godot.GDictionary<T>;
1010
};
1111

12+
interface ProxyHelpers {
13+
get_member: typeof GodotJsb.internal.names.get_member;
14+
godot_wrap: (value: any) => any;
15+
proxy_unwrap: (value: any) => any;
16+
proxy_wrap: (value: any) => any;
17+
ProxyTarget: typeof Godot.ProxyTarget;
18+
}
19+
1220
const proxyable_prototypes: any[] = [];
1321

14-
const proxy_wrap = function(value: any) {
15-
if (typeof value !== "object" || value === null) {
16-
return value;
17-
}
22+
let helpers: null | ProxyHelpers = null;
1823

19-
const proto = Object.getPrototypeOf(value);
20-
return proto && proxyable_prototypes.includes(proto)
21-
? value.proxy()
22-
: value;
23-
};
24+
function get_helpers(): ProxyHelpers {
25+
if (!helpers) {
26+
const { GArray, GDictionary, ProxyTarget } = require("godot") as typeof Godot;
27+
const get_member = (require("godot-jsb") as typeof GodotJsb).internal.names.get_member;
2428

25-
require("godot.typeloader").on_type_loaded("GArray", function (type: any) {
26-
const ProxyTarget = require("godot").ProxyTarget;
29+
helpers = {
30+
get_member,
31+
proxy_wrap: function(value: any) {
32+
if (typeof value !== "object" || value === null) {
33+
return value;
34+
}
35+
36+
const proto = Object.getPrototypeOf(value);
37+
return proto && proxyable_prototypes.includes(proto)
38+
? value.proxy()
39+
: value;
40+
},
41+
proxy_unwrap: function(value: any) {
42+
if (typeof value !== "object" || value === null) {
43+
return value;
44+
}
45+
46+
return value[ProxyTarget] ?? value;
47+
},
48+
godot_wrap: function (value: any) {
49+
if (Array.isArray(value)) {
50+
return GArray.create(value);
51+
}
52+
53+
const proto = Object.getPrototypeOf(value);
54+
55+
if (proto === Object.prototype || proto === null) {
56+
return GDictionary.create(value);
57+
}
2758

28-
const proxy_unwrap = function(value: any) {
29-
if (typeof value !== "object" || value === null) {
30-
return value;
59+
return value;
60+
},
61+
ProxyTarget: ProxyTarget as ProxyHelpers['ProxyTarget'],
3162
}
63+
}
3264

33-
return value[ProxyTarget] ?? value;
34-
};
65+
return helpers;
66+
}
3567

36-
const get_member = (require("godot-jsb") as typeof GodotJsb).internal.names.get_member;
68+
require("godot.typeloader").on_type_loaded("GArray", function (type: any) {
69+
const helpers = get_helpers();
70+
const { get_member, godot_wrap, proxy_unwrap, proxy_wrap } = helpers;
71+
const ProxyTarget: ProxyHelpers['ProxyTarget'] = helpers.ProxyTarget;
3772

3873
proxyable_prototypes.push(type.prototype);
3974

@@ -186,24 +221,16 @@ require("godot.typeloader").on_type_loaded("GArray", function (type: any) {
186221

187222
type.create = function(values: any[]) {
188223
const arr = new type();
189-
const proxy = arr.proxy();
190-
proxy.push.apply(proxy, values);
224+
const proxy = arr.proxy();
225+
proxy.push.apply(proxy, values.map(godot_wrap));
191226
return arr;
192227
};
193228
});
194229

195230
require("godot.typeloader").on_type_loaded("GDictionary", function (type: any) {
196-
const ProxyTarget = require("godot").ProxyTarget;
197-
198-
const proxy_unwrap = function(value: any) {
199-
if (typeof value !== "object" || value === null) {
200-
return value;
201-
}
202-
203-
return value[ProxyTarget] ?? value;
204-
};
205-
206-
const get_member = (require("godot-jsb") as typeof GodotJsb).internal.names.get_member;
231+
const helpers = get_helpers();
232+
const { get_member, godot_wrap, proxy_unwrap, proxy_wrap } = helpers;
233+
const ProxyTarget: ProxyHelpers['ProxyTarget'] = helpers.ProxyTarget;
207234

208235
proxyable_prototypes.push(type.prototype);
209236

@@ -292,12 +319,12 @@ require("godot.typeloader").on_type_loaded("GDictionary", function (type: any) {
292319
};
293320

294321
type.create = function(entries: Record<string, any>) {
295-
const arr = new type();
296-
const proxy = arr.proxy();
322+
const dict = new type();
323+
const proxy = dict.proxy();
297324
for (const [key, value] of Object.entries(entries)) {
298-
proxy[key] = value;
325+
proxy[key] = godot_wrap(value);
299326
}
300-
return arr;
327+
return dict;
301328
};
302329
});
303330

scripts/out/jsb.editor.bundle.js

Lines changed: 9 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

scripts/out/jsb.editor.bundle.js.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

scripts/out/jsb.runtime.bundle.js

Lines changed: 48 additions & 31 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

scripts/out/jsb.runtime.bundle.js.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)