diff --git a/platforms/emscripten/cmake/autorevision_externpostjs.cmake b/platforms/emscripten/cmake/autorevision_externpostjs.cmake index 0dbe350c31f..b0bce7d4706 100644 --- a/platforms/emscripten/cmake/autorevision_externpostjs.cmake +++ b/platforms/emscripten/cmake/autorevision_externpostjs.cmake @@ -67,15 +67,19 @@ if(NOT DEFINED EMSCRIPTEN_WZ_VERSIONSTRING) endif() ################################## -# EMSCRIPTEN_WZ_GITCOMMIT +# Other variables set(EMSCRIPTEN_WZ_GITCOMMIT "${VCS_FULL_HASH}") +set(EMSCRIPTEN_WZ_GITBRANCH "${VCS_BRANCH}") +set(EMSCRIPTEN_WZ_GITTAG "${VCS_TAG}") ################################## # Debug output execute_process(COMMAND ${CMAKE_COMMAND} -E echo "++EMSCRIPTEN_WZ_VERSIONSTRING: ${EMSCRIPTEN_WZ_VERSIONSTRING}") execute_process(COMMAND ${CMAKE_COMMAND} -E echo "++EMSCRIPTEN_WZ_GITCOMMIT: ${EMSCRIPTEN_WZ_GITCOMMIT}") +execute_process(COMMAND ${CMAKE_COMMAND} -E echo "++EMSCRIPTEN_WZ_GITBRANCH: ${EMSCRIPTEN_WZ_GITBRANCH}") +execute_process(COMMAND ${CMAKE_COMMAND} -E echo "++EMSCRIPTEN_WZ_GITTAG: ${EMSCRIPTEN_WZ_GITTAG}") ################################## # Output configured file based on the template diff --git a/platforms/emscripten/extern-postjs.js.in b/platforms/emscripten/extern-postjs.js.in index b87d294de51..d64a35bd75d 100644 --- a/platforms/emscripten/extern-postjs.js.in +++ b/platforms/emscripten/extern-postjs.js.in @@ -1,4 +1,6 @@ let WZ2100_WASM_CURRENT_BUILD_INFO = { versionString: "@EMSCRIPTEN_WZ_VERSIONSTRING@", - gitCommit: "@EMSCRIPTEN_WZ_GITCOMMIT@" + gitCommit: "@EMSCRIPTEN_WZ_GITCOMMIT@", + gitBranch: "@EMSCRIPTEN_WZ_GITBRANCH@", + gitTag: "@EMSCRIPTEN_WZ_GITTAG@" }; diff --git a/platforms/emscripten/shell.html b/platforms/emscripten/shell.html index 27c6430cb85..1cd219cfb95 100644 --- a/platforms/emscripten/shell.html +++ b/platforms/emscripten/shell.html @@ -359,7 +359,7 @@ Get the Full Version Donate - + @@ -704,6 +704,8 @@

Update Required

'debug_3d': 'launchOption_Debug3D' } + var Module; // populated once setting up to start game - must be a global for the additional data package scripts to find it (music, etc) + var LaunchedModule; // set once createWZModule succeeds var statusElement = document.getElementById('status'); var progressElement = document.getElementById('progress'); const originalStartButtonContents = document.getElementById('start-button').innerHTML; @@ -803,59 +805,7 @@

Update Required

})(); let WZ_MUSIC_PKG_SUBDIR = 'pkg/music/'; let WZ_TERRAIN_PKG_SUBDIR = 'pkg/terrain_overrides/'; - - // Initialize config dir suffix and the title badge (based on location pathname) - var WZ_CONFIG_DIR_SUFFIX = ""; - (function() { - - WZ_CONFIG_DIR_SUFFIX = (() => { - // Determine default config dir suffix based on window.location, to ensure that separate branches get separate config directories - var pathArray = window.location.pathname.split('/').filter(n => n); - if (!window.location.pathname.endsWith('/') && pathArray.length > 0) { - pathArray.pop(); - } - let dirSuffix = pathArray.join('-'); - if (dirSuffix.length > 0) { - return "-" + dirSuffix; - } - else { - return ""; - } - })(); - - var el = document.getElementById('wz-title-badge'); - if (/\/(latest|previous)[\/]?$/.test(WZ_DATA_FILES_URL_SUBDIR) || WZ_DATA_FILES_URL_SUBDIR === '/' || WZ_DATA_FILES_URL_SUBDIR.length === 0) { - WZ_CONFIG_DIR_SUFFIX = ""; - el.innerText = 'Web Edition'; - } - else if (/^\/release\/([^\/]+)/.test(WZ_DATA_FILES_URL_SUBDIR)) { - // Release build (but possibly an older one, or a pre-release) - WZ_CONFIG_DIR_SUFFIX = ""; - let tagname = WZ_DATA_FILES_URL_SUBDIR.match(/^\/release\/([^\/]+)/)[1]; - el.innerText = tagname; - if (/[\-\_](beta|rc)[\d]*[\/]?$/.test(WZ_DATA_FILES_URL_SUBDIR)) { - document.body.classList.add('prerelease'); - } - } - else if (/(preview|prerelease)[\/]?$/.test(WZ_DATA_FILES_URL_SUBDIR)) { - WZ_CONFIG_DIR_SUFFIX = ""; - document.body.classList.add('prerelease'); - el.innerText = 'Pre-release'; - } - else if (/\/(dev|development|master|main)[\/]?$/.test(WZ_DATA_FILES_URL_SUBDIR)) { - if (/\/(dev|development)[\/]?$/.test(WZ_DATA_FILES_URL_SUBDIR)) { - WZ_CONFIG_DIR_SUFFIX = "-dev"; - } - document.body.classList.add('dev-preview'); - el.innerText = 'Dev Preview'; - } - else { - document.body.classList.add('branch-build'); - let displayValue = WZ_DATA_FILES_URL_SUBDIR.replace(/^\/+|\/+$/g, ''); - el.innerText = displayValue; - el.title = displayValue; - } - })(); + var WZ_CONFIG_DIR_SUFFIX = null; // initialized after async script load // Localstorage persistence of launch (and other) options function storageAvailable(type) { @@ -995,6 +945,9 @@

Update Required

function wz_js_get_config_dir_path() { + if (WZ_CONFIG_DIR_SUFFIX === null) { + console.error('Config dir not initialized yet'); + } return '/warzone2100' + WZ_CONFIG_DIR_SUFFIX; } @@ -1076,8 +1029,8 @@

Update Required

bootstrap.Toast.getOrCreateInstance(document.getElementById('runtimeErrToast')).show(); } function wz_display_update_available_refresh_needed() { - if (Module && Module.hasOwnProperty('pauseMainLoop')) { - Module.pauseMainLoop(); // a bit of a hack... + if (LaunchedModule && LaunchedModule.hasOwnProperty('pauseMainLoop')) { + LaunchedModule.pauseMainLoop(); // a bit of a hack... } console.log('An update is available - please refresh'); const myModal = bootstrap.Modal.getOrCreateInstance(document.getElementById('refreshForUpdate'), {keyboard: false, backdrop: 'static'}); @@ -1186,6 +1139,100 @@

Update Required

return { wasmMemory: wasmMemory, maximumMemory: maximumMemory }; } + function constructWZModuleConfig(additional_command_line_args) { + // Initial Module configuration + let Module = { + preRun: [], + postRun: [], + print: (function() { + return function(text) { + if (arguments.length > 1) text = Array.prototype.slice.call(arguments).join(' '); + console.log(text); + }; + })(), + canvas: (function() { + var canvas = document.getElementById('canvas'); + // As a default initial behavior, pop up an alert when webgl context is lost. To make your + // application robust, you may want to override this behavior before shipping! + // See http://www.khronos.org/registry/webgl/specs/latest/1.0/#5.15.2 + canvas.addEventListener("webglcontextlost", function(e) { alert('WebGL context lost. You will need to reload the page.'); e.preventDefault(); }, false); + return canvas; + })(), + setStatus: function(text) { + if (!this.setStatus.last) this.setStatus.last = { time: Date.now(), text: '' }; + if (text === this.setStatus.last.text) return; + var m = text.match(/([^(]+)\((\d+(\.\d+)?)\/(\d+)\)/); + var now = Date.now(); + if (m && now - this.setStatus.last.time < 30) return; // if this is a progress update, skip it if too soon + this.setStatus.last.time = now; + this.setStatus.last.text = text; + if (m) { + progressElement.value = parseInt(m[2])*100; + progressElement.max = parseInt(m[4])*100; + progressElement.hidden = false; + } else { + progressElement.value = null; + progressElement.max = null; + progressElement.hidden = true; + } + statusElement.innerHTML = text; + }, + totalDependencies: 0, + monitorRunDependencies: function(left) { + this.totalDependencies = Math.max(this.totalDependencies, left); + this.setStatus(left ? 'Preparing... (' + (this.totalDependencies-left) + '/' + this.totalDependencies + ')' : 'All downloads complete.'); + } + }; + + function wz_pre_run_fixup_canvas(Module) { + Module.canvas.style.backgroundColor = "black"; + } + + function wz_handle_post_run(Module) { + Module.wzEncounteredPostRun = true; + } + + Module['preRun'].push(wz_pre_run_fixup_canvas); + Module['postRun'].push(wz_handle_post_run); + Module.arguments = ['--configdir='+wz_js_get_config_dir_path()]; + if (WZ_VIDEO_SEQUENCES_BASE_URL !== null) { + Module.arguments.push('--videourl='+WZ_VIDEO_SEQUENCES_BASE_URL); + } + if (additional_command_line_args) { + Module.arguments = Module.arguments.concat(additional_command_line_args); + } + + Module['locateFile'] = function(path, prefix) { + // Custom handling for .data files + if (path.endsWith(".data")) { + // NOTE: Prefix is not guaranteed to be set for these by the preloader, so construct the paths manually + + // Shared data files + // - music + if (path === 'warzone2100-music.data') { + let musicDataURL = WZ_DATA_FILES_URL_HOST + WZ_DATA_FILES_URL_SUBDIR + WZ_MUSIC_PKG_SUBDIR + path; + console.debug('Loading: ' + musicDataURL); + return musicDataURL; + } + // - terrain_overrides + if (path.startsWith('warzone2100-terrain-')) { + let terrainDataURL = WZ_DATA_FILES_URL_HOST + WZ_DATA_FILES_URL_SUBDIR + WZ_TERRAIN_PKG_SUBDIR + path; + console.debug('Loading: ' + terrainDataURL); + return terrainDataURL; + } + + // Regular build-specific data files + var dataURL = WZ_DATA_FILES_URL_HOST + WZ_DATA_FILES_URL_SUBDIR + path; + console.debug('Loading: ' + dataURL); + return dataURL; + } + // otherwise, use the default, the prefix (JS file's dir) + the path + return prefix + path; + } + + return Module; + } + function startGame() { // Make canvas visible document.getElementById('loading-game').style.display = 'block'; @@ -1203,7 +1250,7 @@

Update Required

wz_js_display_loading_indicator(1); window.wz_starting_game = true; - function actuallyStartGame() { + function actuallyStartGame(Module) { setTimeout( function() { // try to create WebAssembly.Memory @@ -1216,8 +1263,12 @@

Update Required

localStorage.setItem('lastRun_Details', JSON.stringify({ maxMem: maximumMemory, success: 0, time: (new Date()).getTime() })); } - createWZModule(Module).then(function(Module) { - // this is reached when everything is ready, and you can call methods on Module + createWZModule(Module).then(function(ResultModule) { + // this is reached when everything is ready, and you can call methods on ResultModule + + // Store the launched module in a global + LaunchedModule = ResultModule; + // Hide the loading-game panel document.getElementById('loading-game').style.display = 'none'; // Since some browsers (i.e. Safari) won't show the spinner animation when WZ's main thread is blocked @@ -1245,12 +1296,15 @@

Update Required

}, 10); } - var WZ_LAUNCH_OPTIONS = {}; + // customize initial Module config + Module = constructWZModuleConfig(); + + let WZ_LAUNCH_OPTIONS = {}; Object.entries(WZ_LAUNCH_OPTIONS_MAPPING).forEach(([k,v]) => { WZ_LAUNCH_OPTIONS[k] = document.getElementById(v)?.checked; }) wz_save_launch_options(); - var data_load_promises = []; + let data_load_promises = []; // additional debug flags Object.entries(WZ_LAUNCH_OPTIONS).forEach(([k,v]) => { @@ -1285,7 +1339,7 @@

Update Required

console.error('Failed to load at least one required data file'); return; } - actuallyStartGame(); + actuallyStartGame(Module); }); } @@ -1513,6 +1567,49 @@

Update Required

}); } + function wz_initialize_config_build_info() { + WZ_CONFIG_DIR_SUFFIX = ""; + + if (!WZ2100_WASM_CURRENT_BUILD_INFO || WZ2100_WASM_CURRENT_BUILD_INFO.constructor != Object) { + console.error('Failed to load build info'); + window.alert('Failed to load build info'); + return; + } + + var el = document.getElementById('wz-title-badge'); + try { + if (WZ2100_WASM_CURRENT_BUILD_INFO['gitTag'].length > 0) { + // On a tag - release build (but possibly an older one, or a pre-release) + WZ_CONFIG_DIR_SUFFIX = ""; + if (/[\-\_](beta|rc)[\d]*[\/]?$/.test(WZ2100_WASM_CURRENT_BUILD_INFO['gitTag'])) { + // Is a pre-release + el.innerText = WZ2100_WASM_CURRENT_BUILD_INFO['gitTag']; + document.body.classList.add('prerelease'); + } else { + // Full release + if (/\/(latest|previous)[\/]?$/.test(WZ_DATA_FILES_URL_SUBDIR) || WZ_DATA_FILES_URL_SUBDIR === '/' || WZ_DATA_FILES_URL_SUBDIR.length === 0) { + el.innerText = 'Web Edition'; + } else { + el.innerText = WZ2100_WASM_CURRENT_BUILD_INFO['gitTag']; + } + } + } else if (/^(master|main)$/.test(WZ2100_WASM_CURRENT_BUILD_INFO['gitBranch'])) { + // Development preview + if (/\/(dev|development)[\/]?$/.test(WZ_DATA_FILES_URL_SUBDIR)) { + WZ_CONFIG_DIR_SUFFIX = "-dev"; + } + document.body.classList.add('dev-preview'); + el.innerText = 'Dev Preview'; + } else if (WZ2100_WASM_CURRENT_BUILD_INFO['gitBranch'].length > 0) { + document.body.classList.add('branch-build'); + el.innerText = WZ2100_WASM_CURRENT_BUILD_INFO['gitBranch']; + el.title = WZ2100_WASM_CURRENT_BUILD_INFO['gitBranch']; + } + } catch (err) { + console.error('Processing build info failed:', err); + } + } + function wz_set_options_build_info() { if (typeof WZ2100_WASM_CURRENT_BUILD_INFO !== 'undefined') { try { @@ -1531,8 +1628,10 @@

Update Required

// Initial page startup (once everything is loaded) function wz_everything_is_loaded() { + wz_initialize_config_build_info(); wz_restore_launch_options(); wz_set_options_build_info(); + document.getElementById('nav-options-button').disabled = false; checkWZBrowserSupport().then((r) => { // All required features are available wz_display_launch_game_msg(); @@ -1630,93 +1729,6 @@

Update Required

} progressElement.hidden = false; }); - - // Initial Module configuration - var Module = { - preRun: [], - postRun: [], - print: (function() { - return function(text) { - if (arguments.length > 1) text = Array.prototype.slice.call(arguments).join(' '); - console.log(text); - }; - })(), - canvas: (function() { - var canvas = document.getElementById('canvas'); - // As a default initial behavior, pop up an alert when webgl context is lost. To make your - // application robust, you may want to override this behavior before shipping! - // See http://www.khronos.org/registry/webgl/specs/latest/1.0/#5.15.2 - canvas.addEventListener("webglcontextlost", function(e) { alert('WebGL context lost. You will need to reload the page.'); e.preventDefault(); }, false); - return canvas; - })(), - setStatus: function(text) { - if (!Module.setStatus.last) Module.setStatus.last = { time: Date.now(), text: '' }; - if (text === Module.setStatus.last.text) return; - var m = text.match(/([^(]+)\((\d+(\.\d+)?)\/(\d+)\)/); - var now = Date.now(); - if (m && now - Module.setStatus.last.time < 30) return; // if this is a progress update, skip it if too soon - Module.setStatus.last.time = now; - Module.setStatus.last.text = text; - if (m) { - progressElement.value = parseInt(m[2])*100; - progressElement.max = parseInt(m[4])*100; - progressElement.hidden = false; - } else { - progressElement.value = null; - progressElement.max = null; - progressElement.hidden = true; - } - statusElement.innerHTML = text; - }, - totalDependencies: 0, - monitorRunDependencies: function(left) { - this.totalDependencies = Math.max(this.totalDependencies, left); - Module.setStatus(left ? 'Preparing... (' + (this.totalDependencies-left) + '/' + this.totalDependencies + ')' : 'All downloads complete.'); - } - }; - - function wz_pre_run_fixup_canvas() { - Module.canvas.style.backgroundColor = "black"; - } - - function wz_handle_post_run() { - Module.wzEncounteredPostRun = true; - } - - Module['preRun'].push(wz_pre_run_fixup_canvas); - Module['postRun'].push(wz_handle_post_run); - Module.arguments = ['--configdir='+wz_js_get_config_dir_path()]; - if (WZ_VIDEO_SEQUENCES_BASE_URL !== null) { - Module.arguments.push('--videourl='+WZ_VIDEO_SEQUENCES_BASE_URL); - } - - Module['locateFile'] = function(path, prefix) { - // Custom handling for .data files - if (path.endsWith(".data")) { - // NOTE: Prefix is not guaranteed to be set for these by the preloader, so construct the paths manually - - // Shared data files - // - music - if (path === 'warzone2100-music.data') { - let musicDataURL = WZ_DATA_FILES_URL_HOST + WZ_DATA_FILES_URL_SUBDIR + WZ_MUSIC_PKG_SUBDIR + path; - console.debug('Loading: ' + musicDataURL); - return musicDataURL; - } - // - terrain_overrides - if (path.startsWith('warzone2100-terrain-')) { - let terrainDataURL = WZ_DATA_FILES_URL_HOST + WZ_DATA_FILES_URL_SUBDIR + WZ_TERRAIN_PKG_SUBDIR + path; - console.debug('Loading: ' + terrainDataURL); - return terrainDataURL; - } - - // Regular build-specific data files - var dataURL = WZ_DATA_FILES_URL_HOST + WZ_DATA_FILES_URL_SUBDIR + path; - console.debug('Loading: ' + dataURL); - return dataURL; - } - // otherwise, use the default, the prefix (JS file's dir) + the path - return prefix + path; - } function wz_js_handle_app_exit() { document.getElementById('emscripten_container').style.display = 'none'; @@ -1726,12 +1738,15 @@

Update Required

} window.onerror = function(event) { - Module.setStatus('Exception thrown, see JavaScript console'); - Module.setStatus = function(text) { - if (text) console.log('[post-exception status] ' + text); - }; - if (!Module.hasOwnProperty('calledRun') || !Module.calledRun - || !Module.hasOwnProperty('wzEncounteredPostRun') || !Module.wzEncounteredPostRun) { + progressElement.hidden = true; + statusElement.innerHTML = 'Exception thrown, see JavaScript console'; + if (LaunchedModule) { + LaunchedModule.setStatus = function(text) { + if (text) console.log('[post-exception status] ' + text); + }; + } + if (!LaunchedModule || !LaunchedModule.hasOwnProperty('calledRun') || !LaunchedModule.calledRun + || !LaunchedModule.hasOwnProperty('wzEncounteredPostRun') || !LaunchedModule.wzEncounteredPostRun) { wz_display_loading_error(event); } else { diff --git a/platforms/emscripten/wz-workbox-config.js b/platforms/emscripten/wz-workbox-config.js index 61bbc69cead..4a07e1fa1d5 100644 --- a/platforms/emscripten/wz-workbox-config.js +++ b/platforms/emscripten/wz-workbox-config.js @@ -20,6 +20,7 @@ module.exports = { globIgnores: [ '**\/node_modules\/**\/*', '**/service-worker.js', // do not precache the service-worker file (which shouldn't exist when this is run, but just in case) + '**/extern-postjs.js', // do not precache generated extern-postjs.js file (ends up included in build) '**/*.data', // do not precache .data files, which are often huge '**/*.debug.wasm', // do not precache wasm debug symbols '**\/music\/**\/*', // do not precache music (which is optional)