Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/platform/web/js/engine/config.js
10279 views
1
/**
2
* An object used to configure the Engine instance based on godot export options, and to override those in custom HTML
3
* templates if needed.
4
*
5
* @header Engine configuration
6
* @summary The Engine configuration object. This is just a typedef, create it like a regular object, e.g.:
7
*
8
* ``const MyConfig = { executable: 'godot', unloadAfterInit: false }``
9
*
10
* @typedef {Object} EngineConfig
11
*/
12
const EngineConfig = {}; // eslint-disable-line no-unused-vars
13
14
/**
15
* @struct
16
* @constructor
17
* @ignore
18
*/
19
const InternalConfig = function (initConfig) { // eslint-disable-line no-unused-vars
20
const cfg = /** @lends {InternalConfig.prototype} */ {
21
/**
22
* Whether to unload the engine automatically after the instance is initialized.
23
*
24
* @memberof EngineConfig
25
* @default
26
* @type {boolean}
27
*/
28
unloadAfterInit: true,
29
/**
30
* The HTML DOM Canvas object to use.
31
*
32
* By default, the first canvas element in the document will be used is none is specified.
33
*
34
* @memberof EngineConfig
35
* @default
36
* @type {?HTMLCanvasElement}
37
*/
38
canvas: null,
39
/**
40
* The name of the WASM file without the extension. (Set by Godot Editor export process).
41
*
42
* @memberof EngineConfig
43
* @default
44
* @type {string}
45
*/
46
executable: '',
47
/**
48
* An alternative name for the game pck to load. The executable name is used otherwise.
49
*
50
* @memberof EngineConfig
51
* @default
52
* @type {?string}
53
*/
54
mainPack: null,
55
/**
56
* Specify a language code to select the proper localization for the game.
57
*
58
* The browser locale will be used if none is specified. See complete list of
59
* :ref:`supported locales <doc_locales>`.
60
*
61
* @memberof EngineConfig
62
* @type {?string}
63
* @default
64
*/
65
locale: null,
66
/**
67
* The canvas resize policy determines how the canvas should be resized by Godot.
68
*
69
* ``0`` means Godot won't do any resizing. This is useful if you want to control the canvas size from
70
* javascript code in your template.
71
*
72
* ``1`` means Godot will resize the canvas on start, and when changing window size via engine functions.
73
*
74
* ``2`` means Godot will adapt the canvas size to match the whole browser window.
75
*
76
* @memberof EngineConfig
77
* @type {number}
78
* @default
79
*/
80
canvasResizePolicy: 2,
81
/**
82
* The arguments to be passed as command line arguments on startup.
83
*
84
* See :ref:`command line tutorial <doc_command_line_tutorial>`.
85
*
86
* **Note**: :js:meth:`startGame <Engine.prototype.startGame>` will always add the ``--main-pack`` argument.
87
*
88
* @memberof EngineConfig
89
* @type {Array<string>}
90
* @default
91
*/
92
args: [],
93
/**
94
* When enabled, the game canvas will automatically grab the focus when the engine starts.
95
*
96
* @memberof EngineConfig
97
* @type {boolean}
98
* @default
99
*/
100
focusCanvas: true,
101
/**
102
* When enabled, this will turn on experimental virtual keyboard support on mobile.
103
*
104
* @memberof EngineConfig
105
* @type {boolean}
106
* @default
107
*/
108
experimentalVK: false,
109
/**
110
* The progressive web app service worker to install.
111
* @memberof EngineConfig
112
* @default
113
* @type {string}
114
*/
115
serviceWorker: '',
116
/**
117
* @ignore
118
* @type {Array.<string>}
119
*/
120
persistentPaths: ['/userfs'],
121
/**
122
* @ignore
123
* @type {boolean}
124
*/
125
persistentDrops: false,
126
/**
127
* @ignore
128
* @type {Array.<string>}
129
*/
130
gdextensionLibs: [],
131
/**
132
* @ignore
133
* @type {Array.<string>}
134
*/
135
fileSizes: [],
136
/**
137
* @ignore
138
* @type {number}
139
*/
140
emscriptenPoolSize: 8,
141
/**
142
* @ignore
143
* @type {number}
144
*/
145
godotPoolSize: 4,
146
/**
147
* A callback function for handling Godot's ``OS.execute`` calls.
148
*
149
* This is for example used in the Web Editor template to switch between project manager and editor, and for running the game.
150
*
151
* @callback EngineConfig.onExecute
152
* @param {string} path The path that Godot's wants executed.
153
* @param {Array.<string>} args The arguments of the "command" to execute.
154
*/
155
/**
156
* @ignore
157
* @type {?function(string, Array.<string>)}
158
*/
159
onExecute: null,
160
/**
161
* A callback function for being notified when the Godot instance quits.
162
*
163
* **Note**: This function will not be called if the engine crashes or become unresponsive.
164
*
165
* @callback EngineConfig.onExit
166
* @param {number} status_code The status code returned by Godot on exit.
167
*/
168
/**
169
* @ignore
170
* @type {?function(number)}
171
*/
172
onExit: null,
173
/**
174
* A callback function for displaying download progress.
175
*
176
* The function is called once per frame while downloading files, so the usage of ``requestAnimationFrame()``
177
* is not necessary.
178
*
179
* If the callback function receives a total amount of bytes as 0, this means that it is impossible to calculate.
180
* Possible reasons include:
181
*
182
* - Files are delivered with server-side chunked compression
183
* - Files are delivered with server-side compression on Chromium
184
* - Not all file downloads have started yet (usually on servers without multi-threading)
185
*
186
* @callback EngineConfig.onProgress
187
* @param {number} current The current amount of downloaded bytes so far.
188
* @param {number} total The total amount of bytes to be downloaded.
189
*/
190
/**
191
* @ignore
192
* @type {?function(number, number)}
193
*/
194
onProgress: null,
195
/**
196
* A callback function for handling the standard output stream. This method should usually only be used in debug pages.
197
*
198
* By default, ``console.log()`` is used.
199
*
200
* @callback EngineConfig.onPrint
201
* @param {...*} [var_args] A variadic number of arguments to be printed.
202
*/
203
/**
204
* @ignore
205
* @type {?function(...*)}
206
*/
207
onPrint: function () {
208
console.log.apply(console, Array.from(arguments)); // eslint-disable-line no-console
209
},
210
/**
211
* A callback function for handling the standard error stream. This method should usually only be used in debug pages.
212
*
213
* By default, ``console.error()`` is used.
214
*
215
* @callback EngineConfig.onPrintError
216
* @param {...*} [var_args] A variadic number of arguments to be printed as errors.
217
*/
218
/**
219
* @ignore
220
* @type {?function(...*)}
221
*/
222
onPrintError: function (var_args) {
223
console.error.apply(console, Array.from(arguments)); // eslint-disable-line no-console
224
},
225
};
226
227
/**
228
* @ignore
229
* @struct
230
* @constructor
231
* @param {EngineConfig} opts
232
*/
233
function Config(opts) {
234
this.update(opts);
235
}
236
237
Config.prototype = cfg;
238
239
/**
240
* @ignore
241
* @param {EngineConfig} opts
242
*/
243
Config.prototype.update = function (opts) {
244
const config = opts || {};
245
// NOTE: We must explicitly pass the default, accessing it via
246
// the key will fail due to closure compiler renames.
247
function parse(key, def) {
248
if (typeof (config[key]) === 'undefined') {
249
return def;
250
}
251
return config[key];
252
}
253
// Module config
254
this.unloadAfterInit = parse('unloadAfterInit', this.unloadAfterInit);
255
this.onPrintError = parse('onPrintError', this.onPrintError);
256
this.onPrint = parse('onPrint', this.onPrint);
257
this.onProgress = parse('onProgress', this.onProgress);
258
259
// Godot config
260
this.canvas = parse('canvas', this.canvas);
261
this.executable = parse('executable', this.executable);
262
this.mainPack = parse('mainPack', this.mainPack);
263
this.locale = parse('locale', this.locale);
264
this.canvasResizePolicy = parse('canvasResizePolicy', this.canvasResizePolicy);
265
this.persistentPaths = parse('persistentPaths', this.persistentPaths);
266
this.persistentDrops = parse('persistentDrops', this.persistentDrops);
267
this.experimentalVK = parse('experimentalVK', this.experimentalVK);
268
this.focusCanvas = parse('focusCanvas', this.focusCanvas);
269
this.serviceWorker = parse('serviceWorker', this.serviceWorker);
270
this.gdextensionLibs = parse('gdextensionLibs', this.gdextensionLibs);
271
this.fileSizes = parse('fileSizes', this.fileSizes);
272
this.emscriptenPoolSize = parse('emscriptenPoolSize', this.emscriptenPoolSize);
273
this.godotPoolSize = parse('godotPoolSize', this.godotPoolSize);
274
this.args = parse('args', this.args);
275
this.onExecute = parse('onExecute', this.onExecute);
276
this.onExit = parse('onExit', this.onExit);
277
};
278
279
/**
280
* @ignore
281
* @param {string} loadPath
282
* @param {Response} response
283
*/
284
Config.prototype.getModuleConfig = function (loadPath, response) {
285
let r = response;
286
const gdext = this.gdextensionLibs;
287
return {
288
'print': this.onPrint,
289
'printErr': this.onPrintError,
290
'thisProgram': this.executable,
291
'noExitRuntime': false,
292
'dynamicLibraries': [`${loadPath}.side.wasm`].concat(this.gdextensionLibs),
293
'emscriptenPoolSize': this.emscriptenPoolSize,
294
'instantiateWasm': function (imports, onSuccess) {
295
function done(result) {
296
onSuccess(result['instance'], result['module']);
297
}
298
if (typeof (WebAssembly.instantiateStreaming) !== 'undefined') {
299
WebAssembly.instantiateStreaming(Promise.resolve(r), imports).then(done);
300
} else {
301
r.arrayBuffer().then(function (buffer) {
302
WebAssembly.instantiate(buffer, imports).then(done);
303
});
304
}
305
r = null;
306
return {};
307
},
308
'locateFile': function (path) {
309
if (!path.startsWith('godot.')) {
310
return path;
311
} else if (path.endsWith('.audio.worklet.js')) {
312
return `${loadPath}.audio.worklet.js`;
313
} else if (path.endsWith('.audio.position.worklet.js')) {
314
return `${loadPath}.audio.position.worklet.js`;
315
} else if (path.endsWith('.js')) {
316
return `${loadPath}.js`;
317
} else if (path in gdext) {
318
return path;
319
} else if (path.endsWith('.side.wasm')) {
320
return `${loadPath}.side.wasm`;
321
} else if (path.endsWith('.wasm')) {
322
return `${loadPath}.wasm`;
323
}
324
return path;
325
},
326
};
327
};
328
329
/**
330
* @ignore
331
* @param {function()} cleanup
332
*/
333
Config.prototype.getGodotConfig = function (cleanup) {
334
// Try to find a canvas
335
if (!(this.canvas instanceof HTMLCanvasElement)) {
336
const nodes = document.getElementsByTagName('canvas');
337
if (nodes.length && nodes[0] instanceof HTMLCanvasElement) {
338
const first = nodes[0];
339
this.canvas = /** @type {!HTMLCanvasElement} */ (first);
340
}
341
if (!this.canvas) {
342
throw new Error('No canvas found in page');
343
}
344
}
345
// Canvas can grab focus on click, or key events won't work.
346
if (this.canvas.tabIndex < 0) {
347
this.canvas.tabIndex = 0;
348
}
349
350
// Browser locale, or custom one if defined.
351
let locale = this.locale;
352
if (!locale) {
353
locale = navigator.languages ? navigator.languages[0] : navigator.language;
354
locale = locale.split('.')[0];
355
}
356
locale = locale.replace('-', '_');
357
const onExit = this.onExit;
358
359
// Godot configuration.
360
return {
361
'canvas': this.canvas,
362
'canvasResizePolicy': this.canvasResizePolicy,
363
'locale': locale,
364
'persistentDrops': this.persistentDrops,
365
'virtualKeyboard': this.experimentalVK,
366
'godotPoolSize': this.godotPoolSize,
367
'focusCanvas': this.focusCanvas,
368
'onExecute': this.onExecute,
369
'onExit': function (p_code) {
370
cleanup(); // We always need to call the cleanup callback to free memory.
371
if (typeof (onExit) === 'function') {
372
onExit(p_code);
373
}
374
},
375
};
376
};
377
return new Config(initConfig);
378
};
379
380