[HTML5] Export process writes sizes in template.
This allow the loading bar to be much more reliable, even in cases where realible stream loading status is not detectable (server-side compression, chunked encoding).
This commit is contained in:
parent
f64ec5f1ad
commit
41c64533b0
|
@ -242,7 +242,7 @@ class EditorExportPlatformJavaScript : public EditorExportPlatform {
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
void _fix_html(Vector<uint8_t> &p_html, const Ref<EditorExportPreset> &p_preset, const String &p_name, bool p_debug, int p_flags, const Vector<SharedObject> p_shared_objects);
|
void _fix_html(Vector<uint8_t> &p_html, const Ref<EditorExportPreset> &p_preset, const String &p_name, bool p_debug, int p_flags, const Vector<SharedObject> p_shared_objects, const Dictionary &p_file_sizes);
|
||||||
|
|
||||||
static void _server_thread_poll(void *data);
|
static void _server_thread_poll(void *data);
|
||||||
|
|
||||||
|
@ -280,7 +280,7 @@ public:
|
||||||
~EditorExportPlatformJavaScript();
|
~EditorExportPlatformJavaScript();
|
||||||
};
|
};
|
||||||
|
|
||||||
void EditorExportPlatformJavaScript::_fix_html(Vector<uint8_t> &p_html, const Ref<EditorExportPreset> &p_preset, const String &p_name, bool p_debug, int p_flags, const Vector<SharedObject> p_shared_objects) {
|
void EditorExportPlatformJavaScript::_fix_html(Vector<uint8_t> &p_html, const Ref<EditorExportPreset> &p_preset, const String &p_name, bool p_debug, int p_flags, const Vector<SharedObject> p_shared_objects, const Dictionary &p_file_sizes) {
|
||||||
|
|
||||||
String str_template = String::utf8(reinterpret_cast<const char *>(p_html.ptr()), p_html.size());
|
String str_template = String::utf8(reinterpret_cast<const char *>(p_html.ptr()), p_html.size());
|
||||||
String str_export;
|
String str_export;
|
||||||
|
@ -300,6 +300,7 @@ void EditorExportPlatformJavaScript::_fix_html(Vector<uint8_t> &p_html, const Re
|
||||||
config["gdnativeLibs"] = libs;
|
config["gdnativeLibs"] = libs;
|
||||||
config["executable"] = p_name;
|
config["executable"] = p_name;
|
||||||
config["args"] = args;
|
config["args"] = args;
|
||||||
|
config["fileSizes"] = p_file_sizes;
|
||||||
const String str_config = JSON::print(config);
|
const String str_config = JSON::print(config);
|
||||||
|
|
||||||
for (int i = 0; i < lines.size(); i++) {
|
for (int i = 0; i < lines.size(); i++) {
|
||||||
|
@ -481,6 +482,8 @@ Error EditorExportPlatformJavaScript::export_project(const Ref<EditorExportPrese
|
||||||
return ERR_FILE_CORRUPT;
|
return ERR_FILE_CORRUPT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Vector<uint8_t> html;
|
||||||
|
Dictionary file_sizes;
|
||||||
do {
|
do {
|
||||||
//get filename
|
//get filename
|
||||||
unz_file_info info;
|
unz_file_info info;
|
||||||
|
@ -489,6 +492,16 @@ Error EditorExportPlatformJavaScript::export_project(const Ref<EditorExportPrese
|
||||||
|
|
||||||
String file = fname;
|
String file = fname;
|
||||||
|
|
||||||
|
// HTML is handled later
|
||||||
|
if (file == "godot.html") {
|
||||||
|
if (custom_html.empty()) {
|
||||||
|
html.resize(info.uncompressed_size);
|
||||||
|
unzOpenCurrentFile(pkg);
|
||||||
|
unzReadCurrentFile(pkg, html.ptrw(), html.size());
|
||||||
|
unzCloseCurrentFile(pkg);
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
Vector<uint8_t> data;
|
Vector<uint8_t> data;
|
||||||
data.resize(info.uncompressed_size);
|
data.resize(info.uncompressed_size);
|
||||||
|
|
||||||
|
@ -499,15 +512,7 @@ Error EditorExportPlatformJavaScript::export_project(const Ref<EditorExportPrese
|
||||||
|
|
||||||
//write
|
//write
|
||||||
|
|
||||||
if (file == "godot.html") {
|
if (file == "godot.js") {
|
||||||
|
|
||||||
if (!custom_html.empty()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
_fix_html(data, p_preset, p_path.get_file().get_basename(), p_debug, p_flags, shared_objects);
|
|
||||||
file = p_path.get_file();
|
|
||||||
|
|
||||||
} else if (file == "godot.js") {
|
|
||||||
|
|
||||||
file = p_path.get_file().get_basename() + ".js";
|
file = p_path.get_file().get_basename() + ".js";
|
||||||
} else if (file == "godot.worker.js") {
|
} else if (file == "godot.worker.js") {
|
||||||
|
@ -525,6 +530,7 @@ Error EditorExportPlatformJavaScript::export_project(const Ref<EditorExportPrese
|
||||||
} else if (file == "godot.wasm") {
|
} else if (file == "godot.wasm") {
|
||||||
|
|
||||||
file = p_path.get_file().get_basename() + ".wasm";
|
file = p_path.get_file().get_basename() + ".wasm";
|
||||||
|
file_sizes[file.get_file()] = (uint64_t)info.uncompressed_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
String dst = p_path.get_base_dir().plus_file(file);
|
String dst = p_path.get_base_dir().plus_file(file);
|
||||||
|
@ -547,19 +553,26 @@ Error EditorExportPlatformJavaScript::export_project(const Ref<EditorExportPrese
|
||||||
EditorNode::get_singleton()->show_warning(TTR("Could not read custom HTML shell:") + "\n" + custom_html);
|
EditorNode::get_singleton()->show_warning(TTR("Could not read custom HTML shell:") + "\n" + custom_html);
|
||||||
return ERR_FILE_CANT_READ;
|
return ERR_FILE_CANT_READ;
|
||||||
}
|
}
|
||||||
Vector<uint8_t> buf;
|
html.resize(f->get_len());
|
||||||
buf.resize(f->get_len());
|
f->get_buffer(html.ptrw(), html.size());
|
||||||
f->get_buffer(buf.ptrw(), buf.size());
|
|
||||||
memdelete(f);
|
memdelete(f);
|
||||||
_fix_html(buf, p_preset, p_path.get_file().get_basename(), p_debug, p_flags, shared_objects);
|
}
|
||||||
|
{
|
||||||
|
FileAccess *f = FileAccess::open(pck_path, FileAccess::READ);
|
||||||
|
if (f) {
|
||||||
|
file_sizes[pck_path.get_file()] = (uint64_t)f->get_len();
|
||||||
|
memdelete(f);
|
||||||
|
f = NULL;
|
||||||
|
}
|
||||||
|
_fix_html(html, p_preset, p_path.get_file().get_basename(), p_debug, p_flags, shared_objects, file_sizes);
|
||||||
f = FileAccess::open(p_path, FileAccess::WRITE);
|
f = FileAccess::open(p_path, FileAccess::WRITE);
|
||||||
if (!f) {
|
if (!f) {
|
||||||
EditorNode::get_singleton()->show_warning(TTR("Could not write file:") + "\n" + p_path);
|
EditorNode::get_singleton()->show_warning(TTR("Could not write file:") + "\n" + p_path);
|
||||||
return ERR_FILE_CANT_WRITE;
|
return ERR_FILE_CANT_WRITE;
|
||||||
}
|
}
|
||||||
f->store_buffer(buf.ptr(), buf.size());
|
f->store_buffer(html.ptr(), html.size());
|
||||||
memdelete(f);
|
memdelete(f);
|
||||||
|
html.resize(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ref<Image> splash;
|
Ref<Image> splash;
|
||||||
|
|
|
@ -100,6 +100,11 @@ const InternalConfig = function (initConfig) { // eslint-disable-line no-unused-
|
||||||
* @type {Array.<string>}
|
* @type {Array.<string>}
|
||||||
*/
|
*/
|
||||||
gdnativeLibs: [],
|
gdnativeLibs: [],
|
||||||
|
/**
|
||||||
|
* @ignore
|
||||||
|
* @type {Array.<string>}
|
||||||
|
*/
|
||||||
|
fileSizes: [],
|
||||||
/**
|
/**
|
||||||
* A callback function for handling Godot's ``OS.execute`` calls.
|
* A callback function for handling Godot's ``OS.execute`` calls.
|
||||||
*
|
*
|
||||||
|
@ -219,6 +224,7 @@ const InternalConfig = function (initConfig) { // eslint-disable-line no-unused-
|
||||||
this.canvasResizePolicy = parse('canvasResizePolicy', this.canvasResizePolicy);
|
this.canvasResizePolicy = parse('canvasResizePolicy', this.canvasResizePolicy);
|
||||||
this.persistentPaths = parse('persistentPaths', this.persistentPaths);
|
this.persistentPaths = parse('persistentPaths', this.persistentPaths);
|
||||||
this.gdnativeLibs = parse('gdnativeLibs', this.gdnativeLibs);
|
this.gdnativeLibs = parse('gdnativeLibs', this.gdnativeLibs);
|
||||||
|
this.fileSizes = parse('fileSizes', this.fileSizes);
|
||||||
this.args = parse('args', this.args);
|
this.args = parse('args', this.args);
|
||||||
this.onExecute = parse('onExecute', this.onExecute);
|
this.onExecute = parse('onExecute', this.onExecute);
|
||||||
this.onExit = parse('onExit', this.onExit);
|
this.onExit = parse('onExit', this.onExit);
|
||||||
|
|
|
@ -35,14 +35,15 @@ const Engine = (function () {
|
||||||
* Load the engine from the specified base path.
|
* Load the engine from the specified base path.
|
||||||
*
|
*
|
||||||
* @param {string} basePath Base path of the engine to load.
|
* @param {string} basePath Base path of the engine to load.
|
||||||
|
* @param {number=} [size=0] The file size if known.
|
||||||
* @returns {Promise} A Promise that resolves once the engine is loaded.
|
* @returns {Promise} A Promise that resolves once the engine is loaded.
|
||||||
*
|
*
|
||||||
* @function Engine.load
|
* @function Engine.load
|
||||||
*/
|
*/
|
||||||
Engine.load = function (basePath) {
|
Engine.load = function (basePath, size) {
|
||||||
if (loadPromise == null) {
|
if (loadPromise == null) {
|
||||||
loadPath = basePath;
|
loadPath = basePath;
|
||||||
loadPromise = preloader.loadPromise(`${loadPath}.wasm`, true);
|
loadPromise = preloader.loadPromise(`${loadPath}.wasm`, size, true);
|
||||||
requestAnimationFrame(preloader.animateProgress);
|
requestAnimationFrame(preloader.animateProgress);
|
||||||
}
|
}
|
||||||
return loadPromise;
|
return loadPromise;
|
||||||
|
@ -96,7 +97,7 @@ const Engine = (function () {
|
||||||
initPromise = Promise.reject(new Error('A base path must be provided when calling `init` and the engine is not loaded.'));
|
initPromise = Promise.reject(new Error('A base path must be provided when calling `init` and the engine is not loaded.'));
|
||||||
return initPromise;
|
return initPromise;
|
||||||
}
|
}
|
||||||
Engine.load(basePath);
|
Engine.load(basePath, this.config.fileSizes[`${basePath}.wasm`]);
|
||||||
}
|
}
|
||||||
const me = this;
|
const me = this;
|
||||||
function doInit(promise) {
|
function doInit(promise) {
|
||||||
|
@ -137,7 +138,7 @@ const Engine = (function () {
|
||||||
* @returns {Promise} A Promise that resolves once the file is loaded.
|
* @returns {Promise} A Promise that resolves once the file is loaded.
|
||||||
*/
|
*/
|
||||||
preloadFile: function (file, path) {
|
preloadFile: function (file, path) {
|
||||||
return preloader.preload(file, path);
|
return preloader.preload(file, path, this.config.fileSizes[file]);
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -43,9 +43,9 @@ const Preloader = /** @constructor */ function () { // eslint-disable-line no-un
|
||||||
}), { headers: response.headers });
|
}), { headers: response.headers });
|
||||||
}
|
}
|
||||||
|
|
||||||
function loadFetch(file, tracker, raw) {
|
function loadFetch(file, tracker, fileSize, raw) {
|
||||||
tracker[file] = {
|
tracker[file] = {
|
||||||
total: 0,
|
total: fileSize || 0,
|
||||||
loaded: 0,
|
loaded: 0,
|
||||||
done: false,
|
done: false,
|
||||||
};
|
};
|
||||||
|
@ -117,16 +117,16 @@ const Preloader = /** @constructor */ function () { // eslint-disable-line no-un
|
||||||
progressFunc = callback;
|
progressFunc = callback;
|
||||||
};
|
};
|
||||||
|
|
||||||
this.loadPromise = function (file, raw = false) {
|
this.loadPromise = function (file, fileSize, raw = false) {
|
||||||
return retry(loadFetch.bind(null, file, loadingFiles, raw), DOWNLOAD_ATTEMPTS_MAX);
|
return retry(loadFetch.bind(null, file, loadingFiles, fileSize, raw), DOWNLOAD_ATTEMPTS_MAX);
|
||||||
};
|
};
|
||||||
|
|
||||||
this.preloadedFiles = [];
|
this.preloadedFiles = [];
|
||||||
this.preload = function (pathOrBuffer, destPath) {
|
this.preload = function (pathOrBuffer, destPath, fileSize) {
|
||||||
let buffer = null;
|
let buffer = null;
|
||||||
if (typeof pathOrBuffer === 'string') {
|
if (typeof pathOrBuffer === 'string') {
|
||||||
const me = this;
|
const me = this;
|
||||||
return this.loadPromise(pathOrBuffer).then(function (buf) {
|
return this.loadPromise(pathOrBuffer, fileSize).then(function (buf) {
|
||||||
me.preloadedFiles.push({
|
me.preloadedFiles.push({
|
||||||
path: destPath || pathOrBuffer,
|
path: destPath || pathOrBuffer,
|
||||||
buffer: buf,
|
buffer: buf,
|
||||||
|
|
Loading…
Reference in New Issue