diff --git a/os/emscripten/pre.js b/os/emscripten/pre.js index 68e76678aa..8e46ae3460 100644 --- a/os/emscripten/pre.js +++ b/os/emscripten/pre.js @@ -30,24 +30,6 @@ Module.preRun.push(function() { Module.addRunDependency('syncfs'); FS.syncfs(true, function (err) { - /* FS.mkdir() tends to fail if parent folders do not exist. */ - if (!FS.analyzePath(content_download_dir).exists) { - FS.mkdir(content_download_dir); - } - if (!FS.analyzePath(content_download_dir + '/baseset').exists) { - FS.mkdir(content_download_dir + '/baseset'); - } - - /* Check if the OpenGFX baseset is already downloaded. */ - if (!FS.analyzePath(content_download_dir + '/baseset/opengfx-0.6.0.tar').exists) { - window.openttd_downloaded_opengfx = true; - FS.createPreloadedFile(content_download_dir + '/baseset', 'opengfx-0.6.0.tar', 'https://binaries.openttd.org/installer/emscripten/opengfx-0.6.0.tar', true, true); - } else { - /* Fake dependency increase, so the counter is stable. */ - Module.addRunDependency('opengfx'); - Module.removeRunDependency('opengfx'); - } - Module.removeRunDependency('syncfs'); }); @@ -74,6 +56,23 @@ Module.preRun.push(function() { window.openttd_syncfs(Module.onAbort); } + window.openttd_bootstrap = function(current, total) { + Module.onBootstrap(current, total); + } + + window.openttd_bootstrap_failed = function() { + Module.onBootstrapFailed(); + } + + window.openttd_bootstrap_reload = function() { + window.openttd_syncfs(function() { + Module.onBootstrapReload(); + setTimeout(function() { + location.reload(); + }, 1000); + }); + } + window.openttd_server_list = function() { add_server = Module.cwrap("em_openttd_add_server", null, ["string"]); @@ -125,11 +124,3 @@ Module.preRun.push(function() { return ret; } }); - -Module.postRun.push(function() { - /* Check if we downloaded OpenGFX; if so, sync the virtual FS back to the - * IDBFS so OpenGFX is stored persistent. */ - if (window['openttd_downloaded_opengfx']) { - FS.syncfs(false, function (err) { }); - } -}); diff --git a/os/emscripten/shell.html b/os/emscripten/shell.html index af031c6df8..21f720e7e4 100644 --- a/os/emscripten/shell.html +++ b/os/emscripten/shell.html @@ -75,7 +75,6 @@ } #message { color: #101010; - height: 54px; padding: 4px 4px; } @@ -144,6 +143,8 @@ })(), setStatus: function(text) { + if (document.getElementById("canvas").style.display == "none") return; + var m = text.match(/^([^(]+)\((\d+(\.\d+)?)\/(\d+)\)$/); if (m) { @@ -171,6 +172,27 @@ document.getElementById("message").innerHTML = "Preparing game ..."; }, + onBootstrap: function(current, total) { + document.getElementById("canvas").style.display = "none"; + + document.getElementById("title").innerHTML = "Missing base graphics"; + document.getElementById("message").innerHTML = "OpenTTD is downloading base graphics.

" + current + " / " + total + " bytes downloaded."; + }, + + onBootstrapFailed: function(current, total) { + document.getElementById("canvas").style.display = "none"; + + document.getElementById("title").innerHTML = "Missing base graphics"; + document.getElementById("message").innerHTML = "Failed to download base graphics.
The game cannot start without base graphics.

Please check your Internet connection and/or the console log.
Reload your browser to try again."; + }, + + onBootstrapReload: function() { + document.getElementById("canvas").style.display = "none"; + + document.getElementById("title").innerHTML = "Missing base graphics"; + document.getElementById("message").innerHTML = "Downloading base graphics done.

Your browser will reload to start the game."; + }, + onExit: function() { document.getElementById("canvas").style.display = "none"; diff --git a/src/bootstrap_gui.cpp b/src/bootstrap_gui.cpp index 57d7e96fd2..063e908a32 100644 --- a/src/bootstrap_gui.cpp +++ b/src/bootstrap_gui.cpp @@ -286,6 +286,76 @@ public: #endif /* defined(WITH_FREETYPE) */ +#if defined(__EMSCRIPTEN__) +# include +# include "network/network.h" +# include "network/network_content.h" +# include "openttd.h" +# include "video/video_driver.hpp" + +class BootstrapEmscripten : public ContentCallback { + bool downloading{false}; + uint total_files{0}; + uint total_bytes{0}; + uint downloaded_bytes{0}; + +public: + BootstrapEmscripten() + { + _network_content_client.AddCallback(this); + _network_content_client.Connect(); + } + + ~BootstrapEmscripten() + { + _network_content_client.RemoveCallback(this); + } + + void OnConnect(bool success) override + { + if (!success) { + EM_ASM({ if (window["openttd_bootstrap_failed"]) openttd_bootstrap_failed(); }); + return; + } + + /* Once connected, request the metadata. */ + _network_content_client.RequestContentList(CONTENT_TYPE_BASE_GRAPHICS); + } + + void OnReceiveContentInfo(const ContentInfo *ci) override + { + if (this->downloading) return; + + /* And once the metadata is received, start downloading it. */ + _network_content_client.Select(ci->id); + _network_content_client.DownloadSelectedContent(this->total_files, this->total_bytes); + this->downloading = true; + + EM_ASM({ if (window["openttd_bootstrap"]) openttd_bootstrap($0, $1); }, this->downloaded_bytes, this->total_bytes); + } + + void OnDownloadProgress(const ContentInfo *ci, int bytes) override + { + /* A negative value means we are resetting; for example, when retrying or using a fallback. */ + if (bytes < 0) { + this->downloaded_bytes = 0; + } else { + this->downloaded_bytes += bytes; + } + + EM_ASM({ if (window["openttd_bootstrap"]) openttd_bootstrap($0, $1); }, this->downloaded_bytes, this->total_bytes); + } + + void OnDownloadComplete(ContentID cid) override + { + /* _exit_game is used to break out of the outer video driver's MainLoop. */ + _exit_game = true; + + delete this; + } +}; +#endif /* __EMSCRIPTEN__ */ + /** * Handle all procedures for bootstrapping OpenTTD without a base graphics set. * This requires all kinds of trickery that is needed to avoid the use of @@ -300,12 +370,15 @@ bool HandleBootstrap() if (BlitterFactory::GetCurrentBlitter()->GetScreenDepth() == 0) goto failure; /* If there is no network or no non-sprite font, then there is nothing we can do. Go straight to failure. */ -#if (defined(_WIN32) && defined(WITH_UNISCRIBE)) || (defined(WITH_FREETYPE) && (defined(WITH_FONTCONFIG) || defined(__APPLE__))) || defined(WITH_COCOA) +#if defined(__EMSCRIPTEN__) || (defined(_WIN32) && defined(WITH_UNISCRIBE)) || (defined(WITH_FREETYPE) && (defined(WITH_FONTCONFIG) || defined(__APPLE__))) || defined(WITH_COCOA) if (!_network_available) goto failure; /* First tell the game we're bootstrapping. */ _game_mode = GM_BOOTSTRAP; +#if defined(__EMSCRIPTEN__) + new BootstrapEmscripten(); +#else /* Initialise the font cache. */ InitializeUnicodeGlyphMap(); /* Next "force" finding a suitable non-sprite font as the local font is missing. */ @@ -324,6 +397,7 @@ bool HandleBootstrap() /* Finally ask the question. */ new BootstrapBackground(); new BootstrapAskForDownloadWindow(); +#endif /* __EMSCRIPTEN__ */ /* Process the user events. */ VideoDriver::GetInstance()->MainLoop(); diff --git a/src/video/sdl2_v.cpp b/src/video/sdl2_v.cpp index 1f18d143fd..183b8354c1 100644 --- a/src/video/sdl2_v.cpp +++ b/src/video/sdl2_v.cpp @@ -615,7 +615,11 @@ void VideoDriver_SDL_Base::LoopOnce() /* In effect, the game ends here. As emscripten_set_main_loop() caused * the stack to be unwound, the code after MainLoop() in * openttd_main() is never executed. */ - EM_ASM(if (window["openttd_exit"]) openttd_exit()); + if (_game_mode == GM_BOOTSTRAP) { + EM_ASM(if (window["openttd_bootstrap_reload"]) openttd_bootstrap_reload()); + } else { + EM_ASM(if (window["openttd_exit"]) openttd_exit()); + } #endif return; }