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;
}