Changeset - r27845:2ecc8f63d57a
[Not reviewed]
master
0 4 0
glx22 - 17 months ago 2023-07-06 16:20:33
glx@openttd.org
Add: [Emscripten] Support for bootstrapping
4 files changed with 120 insertions and 29 deletions:
0 comments (0 inline, 0 general)
os/emscripten/pre.js
Show inline comments
 
@@ -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) { });
 
    }
 
});
os/emscripten/shell.html
Show inline comments
 
@@ -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.<br/><br/>" + 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.<br/>The game cannot start without base graphics.<br/><br/>Please check your Internet connection and/or the console log.<br/>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.<br/><br/>Your browser will reload to start the game.";
 
        },
 

	
 
        onExit: function() {
 
          document.getElementById("canvas").style.display = "none";
 

	
src/bootstrap_gui.cpp
Show inline comments
 
@@ -286,6 +286,76 @@ public:
 

	
 
#endif /* defined(WITH_FREETYPE) */
 

	
 
#if defined(__EMSCRIPTEN__)
 
#	include <emscripten.h>
 
#	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();
src/video/sdl2_v.cpp
Show inline comments
 
@@ -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;
 
	}
0 comments (0 inline, 0 general)