Path: blob/master/platform/web/js/libs/library_godot_javascript_singleton.js
10279 views
/**************************************************************************/1/* library_godot_javascript_singleton.js */2/**************************************************************************/3/* This file is part of: */4/* GODOT ENGINE */5/* https://godotengine.org */6/**************************************************************************/7/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */8/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */9/* */10/* Permission is hereby granted, free of charge, to any person obtaining */11/* a copy of this software and associated documentation files (the */12/* "Software"), to deal in the Software without restriction, including */13/* without limitation the rights to use, copy, modify, merge, publish, */14/* distribute, sublicense, and/or sell copies of the Software, and to */15/* permit persons to whom the Software is furnished to do so, subject to */16/* the following conditions: */17/* */18/* The above copyright notice and this permission notice shall be */19/* included in all copies or substantial portions of the Software. */20/* */21/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */22/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */23/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */24/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */25/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */26/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */27/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */28/**************************************************************************/2930const GodotJSWrapper = {3132$GodotJSWrapper__deps: ['$GodotRuntime', '$IDHandler'],33$GodotJSWrapper__postset: 'GodotJSWrapper.proxies = new Map();',34$GodotJSWrapper: {35proxies: null,36cb_ret: null,3738MyProxy: function (val) {39const id = IDHandler.add(this);40GodotJSWrapper.proxies.set(val, id);41let refs = 1;42this.ref = function () {43refs++;44};45this.unref = function () {46refs--;47if (refs === 0) {48IDHandler.remove(id);49GodotJSWrapper.proxies.delete(val);50}51};52this.get_val = function () {53return val;54};55this.get_id = function () {56return id;57};58},5960get_proxied: function (val) {61const id = GodotJSWrapper.proxies.get(val);62if (id === undefined) {63const proxy = new GodotJSWrapper.MyProxy(val);64return proxy.get_id();65}66IDHandler.get(id).ref();67return id;68},6970get_proxied_value: function (id) {71const proxy = IDHandler.get(id);72if (proxy === undefined) {73return undefined;74}75return proxy.get_val();76},7778variant2js: function (type, val) {79switch (type) {80case 0:81return null;82case 1:83return Boolean(GodotRuntime.getHeapValue(val, 'i64'));84case 2: {85// `heap_value` may be a bigint.86const heap_value = GodotRuntime.getHeapValue(val, 'i64');87return heap_value >= Number.MIN_SAFE_INTEGER && heap_value <= Number.MAX_SAFE_INTEGER88? Number(heap_value)89: heap_value;90}91case 3:92return Number(GodotRuntime.getHeapValue(val, 'double'));93case 4:94return GodotRuntime.parseString(GodotRuntime.getHeapValue(val, '*'));95case 24: // OBJECT96return GodotJSWrapper.get_proxied_value(GodotRuntime.getHeapValue(val, 'i64'));97default:98return undefined;99}100},101102js2variant: function (p_val, p_exchange) {103if (p_val === undefined || p_val === null) {104return 0; // NIL105}106const type = typeof (p_val);107if (type === 'boolean') {108GodotRuntime.setHeapValue(p_exchange, p_val, 'i64');109return 1; // BOOL110} else if (type === 'number') {111if (Number.isInteger(p_val)) {112GodotRuntime.setHeapValue(p_exchange, p_val, 'i64');113return 2; // INT114}115GodotRuntime.setHeapValue(p_exchange, p_val, 'double');116return 3; // FLOAT117} else if (type === 'bigint') {118GodotRuntime.setHeapValue(p_exchange, p_val, 'i64');119return 2; // INT120} else if (type === 'string') {121const c_str = GodotRuntime.allocString(p_val);122GodotRuntime.setHeapValue(p_exchange, c_str, '*');123return 4; // STRING124}125const id = GodotJSWrapper.get_proxied(p_val);126GodotRuntime.setHeapValue(p_exchange, id, 'i64');127return 24; // OBJECT128},129130isBuffer: function (obj) {131return obj instanceof ArrayBuffer || ArrayBuffer.isView(obj);132},133},134135godot_js_wrapper_interface_get__proxy: 'sync',136godot_js_wrapper_interface_get__sig: 'ii',137godot_js_wrapper_interface_get: function (p_name) {138const name = GodotRuntime.parseString(p_name);139if (typeof (window[name]) !== 'undefined') {140return GodotJSWrapper.get_proxied(window[name]);141}142return 0;143},144145godot_js_wrapper_object_get__proxy: 'sync',146godot_js_wrapper_object_get__sig: 'iiii',147godot_js_wrapper_object_get: function (p_id, p_exchange, p_prop) {148const obj = GodotJSWrapper.get_proxied_value(p_id);149if (obj === undefined) {150return 0;151}152if (p_prop) {153const prop = GodotRuntime.parseString(p_prop);154try {155return GodotJSWrapper.js2variant(obj[prop], p_exchange);156} catch (e) {157GodotRuntime.error(`Error getting variable ${prop} on object`, obj);158return 0; // NIL159}160}161return GodotJSWrapper.js2variant(obj, p_exchange);162},163164godot_js_wrapper_object_set__proxy: 'sync',165godot_js_wrapper_object_set__sig: 'viiii',166godot_js_wrapper_object_set: function (p_id, p_name, p_type, p_exchange) {167const obj = GodotJSWrapper.get_proxied_value(p_id);168if (obj === undefined) {169return;170}171const name = GodotRuntime.parseString(p_name);172try {173obj[name] = GodotJSWrapper.variant2js(p_type, p_exchange);174} catch (e) {175GodotRuntime.error(`Error setting variable ${name} on object`, obj);176}177},178179godot_js_wrapper_object_call__proxy: 'sync',180godot_js_wrapper_object_call__sig: 'iiiiiiiii',181godot_js_wrapper_object_call: function (p_id, p_method, p_args, p_argc, p_convert_callback, p_exchange, p_lock, p_free_lock_callback) {182const obj = GodotJSWrapper.get_proxied_value(p_id);183if (obj === undefined) {184return -1;185}186const method = GodotRuntime.parseString(p_method);187const convert = GodotRuntime.get_func(p_convert_callback);188const freeLock = GodotRuntime.get_func(p_free_lock_callback);189const args = new Array(p_argc);190for (let i = 0; i < p_argc; i++) {191const type = convert(p_args, i, p_exchange, p_lock);192const lock = GodotRuntime.getHeapValue(p_lock, '*');193args[i] = GodotJSWrapper.variant2js(type, p_exchange);194if (lock) {195freeLock(p_lock, type);196}197}198try {199const res = obj[method](...args);200return GodotJSWrapper.js2variant(res, p_exchange);201} catch (e) {202GodotRuntime.error(`Error calling method ${method} on:`, obj, 'error:', e);203return -1;204}205},206207godot_js_wrapper_object_unref__proxy: 'sync',208godot_js_wrapper_object_unref__sig: 'vi',209godot_js_wrapper_object_unref: function (p_id) {210const proxy = IDHandler.get(p_id);211if (proxy !== undefined) {212proxy.unref();213}214},215216godot_js_wrapper_create_cb__proxy: 'sync',217godot_js_wrapper_create_cb__sig: 'iii',218godot_js_wrapper_create_cb: function (p_ref, p_func) {219const func = GodotRuntime.get_func(p_func);220let id = 0;221const cb = function () {222if (!GodotJSWrapper.get_proxied_value(id)) {223return undefined;224}225// The callback will store the returned value in this variable via226// "godot_js_wrapper_object_set_cb_ret" upon calling the user function.227// This is safe! JavaScript is single threaded (and using it in threads is not a good idea anyway).228GodotJSWrapper.cb_ret = null;229const args = Array.from(arguments);230const argsProxy = new GodotJSWrapper.MyProxy(args);231func(p_ref, argsProxy.get_id(), args.length);232argsProxy.unref();233const ret = GodotJSWrapper.cb_ret;234GodotJSWrapper.cb_ret = null;235return ret;236};237id = GodotJSWrapper.get_proxied(cb);238return id;239},240241godot_js_wrapper_object_set_cb_ret__proxy: 'sync',242godot_js_wrapper_object_set_cb_ret__sig: 'vii',243godot_js_wrapper_object_set_cb_ret: function (p_val_type, p_val_ex) {244GodotJSWrapper.cb_ret = GodotJSWrapper.variant2js(p_val_type, p_val_ex);245},246247godot_js_wrapper_object_getvar__proxy: 'sync',248godot_js_wrapper_object_getvar__sig: 'iiii',249godot_js_wrapper_object_getvar: function (p_id, p_type, p_exchange) {250const obj = GodotJSWrapper.get_proxied_value(p_id);251if (obj === undefined) {252return -1;253}254const prop = GodotJSWrapper.variant2js(p_type, p_exchange);255if (prop === undefined || prop === null) {256return -1;257}258try {259return GodotJSWrapper.js2variant(obj[prop], p_exchange);260} catch (e) {261GodotRuntime.error(`Error getting variable ${prop} on object`, obj, e);262return -1;263}264},265266godot_js_wrapper_object_setvar__proxy: 'sync',267godot_js_wrapper_object_setvar__sig: 'iiiiii',268godot_js_wrapper_object_setvar: function (p_id, p_key_type, p_key_ex, p_val_type, p_val_ex) {269const obj = GodotJSWrapper.get_proxied_value(p_id);270if (obj === undefined) {271return -1;272}273const key = GodotJSWrapper.variant2js(p_key_type, p_key_ex);274try {275obj[key] = GodotJSWrapper.variant2js(p_val_type, p_val_ex);276return 0;277} catch (e) {278GodotRuntime.error(`Error setting variable ${key} on object`, obj);279return -1;280}281},282283godot_js_wrapper_create_object__proxy: 'sync',284godot_js_wrapper_create_object__sig: 'iiiiiiii',285godot_js_wrapper_create_object: function (p_object, p_args, p_argc, p_convert_callback, p_exchange, p_lock, p_free_lock_callback) {286const name = GodotRuntime.parseString(p_object);287if (typeof (window[name]) === 'undefined') {288return -1;289}290const convert = GodotRuntime.get_func(p_convert_callback);291const freeLock = GodotRuntime.get_func(p_free_lock_callback);292const args = new Array(p_argc);293for (let i = 0; i < p_argc; i++) {294const type = convert(p_args, i, p_exchange, p_lock);295const lock = GodotRuntime.getHeapValue(p_lock, '*');296args[i] = GodotJSWrapper.variant2js(type, p_exchange);297if (lock) {298freeLock(p_lock, type);299}300}301try {302const res = new window[name](...args);303return GodotJSWrapper.js2variant(res, p_exchange);304} catch (e) {305GodotRuntime.error(`Error calling constructor ${name} with args:`, args, 'error:', e);306return -1;307}308},309310godot_js_wrapper_object_is_buffer__proxy: 'sync',311godot_js_wrapper_object_is_buffer__sig: 'ii',312godot_js_wrapper_object_is_buffer: function (p_id) {313const obj = GodotJSWrapper.get_proxied_value(p_id);314return GodotJSWrapper.isBuffer(obj)315? 1316: 0;317},318319godot_js_wrapper_object_transfer_buffer__proxy: 'sync',320godot_js_wrapper_object_transfer_buffer__sig: 'viiii',321godot_js_wrapper_object_transfer_buffer: function (p_id, p_byte_arr, p_byte_arr_write, p_callback) {322let obj = GodotJSWrapper.get_proxied_value(p_id);323if (!GodotJSWrapper.isBuffer(obj)) {324return;325}326327if (ArrayBuffer.isView(obj) && !(obj instanceof Uint8Array)) {328obj = new Uint8Array(obj.buffer);329} else if (obj instanceof ArrayBuffer) {330obj = new Uint8Array(obj);331}332333const resizePackedByteArrayAndOpenWrite = GodotRuntime.get_func(p_callback);334const bytesPtr = resizePackedByteArrayAndOpenWrite(p_byte_arr, p_byte_arr_write, obj.length);335HEAPU8.set(obj, bytesPtr);336},337};338339autoAddDeps(GodotJSWrapper, '$GodotJSWrapper');340mergeInto(LibraryManager.library, GodotJSWrapper);341342const GodotEval = {343godot_js_eval__deps: ['$GodotRuntime'],344godot_js_eval__sig: 'iiiiiii',345godot_js_eval: function (p_js, p_use_global_ctx, p_union_ptr, p_byte_arr, p_byte_arr_write, p_callback) {346const js_code = GodotRuntime.parseString(p_js);347let eval_ret = null;348try {349if (p_use_global_ctx) {350// indirect eval call grants global execution context351const global_eval = eval; // eslint-disable-line no-eval352eval_ret = global_eval(js_code);353} else {354eval_ret = eval(js_code); // eslint-disable-line no-eval355}356} catch (e) {357GodotRuntime.error(e);358}359360switch (typeof eval_ret) {361case 'boolean':362GodotRuntime.setHeapValue(p_union_ptr, eval_ret, 'i32');363return 1; // BOOL364365case 'number':366GodotRuntime.setHeapValue(p_union_ptr, eval_ret, 'double');367return 3; // FLOAT368369case 'string':370GodotRuntime.setHeapValue(p_union_ptr, GodotRuntime.allocString(eval_ret), '*');371return 4; // STRING372373case 'object':374if (eval_ret === null) {375break;376}377378if (ArrayBuffer.isView(eval_ret) && !(eval_ret instanceof Uint8Array)) {379eval_ret = new Uint8Array(eval_ret.buffer);380} else if (eval_ret instanceof ArrayBuffer) {381eval_ret = new Uint8Array(eval_ret);382}383if (eval_ret instanceof Uint8Array) {384const func = GodotRuntime.get_func(p_callback);385const bytes_ptr = func(p_byte_arr, p_byte_arr_write, eval_ret.length);386HEAPU8.set(eval_ret, bytes_ptr);387return 29; // PACKED_BYTE_ARRAY388}389break;390391// no default392}393return 0; // NIL394},395};396397mergeInto(LibraryManager.library, GodotEval);398399400