diff options
Diffstat (limited to 'deploy_template/.dragonruby')
| -rw-r--r-- | deploy_template/.dragonruby/stubs/html5/dragonruby-html5-loader.js | 313 | ||||
| -rw-r--r-- | deploy_template/.dragonruby/stubs/html5/stub/index.html | 4 |
2 files changed, 172 insertions, 145 deletions
diff --git a/deploy_template/.dragonruby/stubs/html5/dragonruby-html5-loader.js b/deploy_template/.dragonruby/stubs/html5/dragonruby-html5-loader.js index c321422..bb4ef56 100644 --- a/deploy_template/.dragonruby/stubs/html5/dragonruby-html5-loader.js +++ b/deploy_template/.dragonruby/stubs/html5/dragonruby-html5-loader.js @@ -25,7 +25,7 @@ function syncDataFiles(dbname, baseurl) total_to_download: 0, total_downloaded: 0, total_files: 0, - pending_files: 0 + pending_files: [] }; var log = function(str) { console.log("CACHEAPPDATA: " + str); } @@ -98,15 +98,16 @@ function syncDataFiles(dbname, baseurl) failed("Couldn't open local database: " + event.target.error.message); }; + // !!! FIXME: there _has_ to be a better way to do this, right? + var hash_count = function(h) { + var k = Object.keys(h); + return (k === undefined) ? 0 : k.length; + } + var finished_file = function(fname) { debug("Finished writing '" + fname + "' to the database!"); - state.pending_files--; - if (state.pending_files < 0) { - state.pending_files = 0; - debug("Uhoh, pending_files went negative?!"); - } - if (state.pending_files == 0) { - succeeded(); + if ((hash_count(state.xhrs) == 0) && (state.pending_files.length == 0)) { + succeeded(); // nothing downloading, nothing new to download, and everything is written to disk. Success! } }; @@ -138,10 +139,63 @@ function syncDataFiles(dbname, baseurl) }; }; + var download_another_file = function() { + if (state.pending_files.length == 0) { + return false; // nothing to do. + } + + var remotefname = state.pending_files.pop(); + var remoteitem = state.remote_manifest[remotefname]; + var xhr = new XMLHttpRequest(); + state.xhrs[remotefname] = xhr; + xhr.previously_loaded = 0; + xhr.filename = remotefname; + xhr.filesize = remoteitem.filesize; + xhr.filetime = remoteitem.filetime; + xhr.expected_filesize = remoteitem.filesize; + xhr.responseType = "arraybuffer"; + xhr.addEventListener("error", function(e) { failed("Download error on '" + e.target.filename + "'!"); }); + xhr.addEventListener("timeout", function(e) { failed("Download timeout on '" + e.target.filename + "'!"); }); + xhr.addEventListener("abort", function(e) { failed("Download abort on '" + e.target.filename + "'!"); }); + + xhr.addEventListener('progress', function(e) { + if (state.reported_result) { return; } + var xhr = e.target; + var additional = e.loaded - xhr.previously_loaded; + state.total_downloaded += additional; + xhr.previously_loaded = e.loaded; + debug("Downloaded " + additional + " more bytes for file '" + xhr.filename + "'"); + var percent = state.total_to_download ? Math.floor((state.total_downloaded / state.total_to_download) * 100.0) : 0; + progress("Downloaded " + percent + "% (" + Math.ceil(state.total_downloaded / 1048576) + "/" + Math.ceil(state.total_to_download / 1048576) + " megabytes)"); + }); + + xhr.addEventListener("load", function(e) { + if (state.reported_result) { return; } + var xhr = e.target; + if (xhr.status != 200) { + failed("Server reported failure downloading '" + xhr.filename + "'!"); + } else { + debug("Finished download of '" + xhr.filename + "'!"); + state.total_downloaded -= xhr.previously_loaded; + state.total_downloaded += xhr.expected_filesize; + xhr.previously_loaded = xhr.expected_filesize; + delete state.xhrs[xhr.filename]; + var percent = state.total_to_download ? Math.floor((state.total_downloaded / state.total_to_download) * 100.0) : 0; + progress("Downloaded " + percent + "% (" + Math.ceil(state.total_downloaded / 1048576) + "/" + Math.ceil(state.total_to_download / 1048576) + " megabytes)"); + download_another_file(); // kick off another download now that this one is done. + store_file(xhr); + } + }); + + debug("Starting download of '" + xhr.filename + "'..."); + xhr.open("get", baseurl + remotefname + urlrandomizerarg, true); + xhr.send(); + return true; + } + var download_new_files = function() { if (state.reported_result) { return; } progress("Downloading new files..."); - var downloadme = []; for (var i in state.remote_manifest) { var remoteitem = state.remote_manifest[i]; var remotefname = i; @@ -149,65 +203,25 @@ function syncDataFiles(dbname, baseurl) debug("remote filename '" + remotefname + "' already downloaded."); } else { debug("remote filename '" + remotefname + "' needs downloading."); - // the browser will let a handful of these go in parallel, and - // then will queue the rest, firing events as appropriate - // when it gets around to them, so just fire them all off - // here. - // !!! FIXME: use the Fetch API, plus streaming, as an option. // !!! FIXME: It can use less memory, since it doesn't need // !!! FIXME: to keep the whole file in memory. state.total_to_download += remoteitem.filesize; state.total_files++; - state.pending_files++; - - var xhr = new XMLHttpRequest(); - state.xhrs[remotefname] = xhr; - xhr.previously_loaded = 0; - xhr.filename = remotefname; - xhr.filesize = state.remote_manifest[i].filesize; - xhr.filetime = state.remote_manifest[i].filetime; - xhr.expected_filesize = remoteitem.filesize; - xhr.responseType = "arraybuffer"; - xhr.addEventListener("error", function(e) { failed("Download error on '" + e.target.filename + "'!"); }); - xhr.addEventListener("timeout", function(e) { failed("Download timeout on '" + e.target.filename + "'!"); }); - xhr.addEventListener("abort", function(e) { failed("Download abort on '" + e.target.filename + "'!"); }); - - xhr.addEventListener('progress', function(e) { - if (state.reported_result) { return; } - var xhr = e.target; - var additional = e.loaded - xhr.previously_loaded; - state.total_downloaded += additional; - xhr.previously_loaded = e.loaded; - debug("Downloaded " + additional + " more bytes for file '" + xhr.filename + "'"); - var percent = state.total_to_download ? Math.floor((state.total_downloaded / state.total_to_download) * 100.0) : 0; - progress("Downloaded " + percent + "% (" + Math.ceil(state.total_downloaded / 1048576) + "/" + Math.ceil(state.total_to_download / 1048576) + " megabytes)"); - }); - - xhr.addEventListener("load", function(e) { - if (state.reported_result) { return; } - var xhr = e.target; - if (xhr.status != 200) { - failed("Server reported failure downloading '" + xhr.filename + "'!"); - } else { - debug("Finished download of '" + xhr.filename + "'!"); - state.total_downloaded -= xhr.previously_loaded; - state.total_downloaded += xhr.expected_filesize; - xhr.previously_loaded = xhr.expected_filesize; - delete state.xhrs[xhr.filename]; - var percent = state.total_to_download ? Math.floor((state.total_downloaded / state.total_to_download) * 100.0) : 0; - progress("Downloaded " + percent + "% (" + Math.ceil(state.total_downloaded / 1048576) + "/" + Math.ceil(state.total_to_download / 1048576) + " megabytes)"); - store_file(xhr); - } - }); - - xhr.open("get", baseurl + remotefname + urlrandomizerarg, true); - xhr.send(); + state.pending_files.push(remotefname) } } - if (state.pending_files == 0) { + if (state.pending_files.length == 0) { succeeded(); // we're already done. :) + return; + } + + var max_concurrent_downloads = 4; + while (download_another_file()) { + if (hash_count(state.xhrs) >= max_concurrent_downloads) { + break; // we'll start another as each download completes. + } } }; @@ -340,30 +354,52 @@ function syncDataFiles(dbname, baseurl) return retval; } +var prepareFilesystem = function() +{ + // Download the game data and set up the filesystem! + // set up a persistent store for save games, etc. + FS.mkdir('/persistent'); + FS.mount(IDBFS, {}, '/persistent'); + FS.syncfs(true, function(err) { + if (err) { + console.log("WARNING: Failed to populate persistent store. Save games likely lost?"); + } else { + console.log("Read in from persistent store."); + } + + loadDataFiles(GDragonRubyGameId, 'gamedata/', function() { + console.log("Game data is sync'd to MEMFS. Starting click-to-play()..."); + //Module.setStatus("Ready!"); + //setTimeout(function() { Module.setStatus(""); statusElement.style.display='none'; }, 1000); + Module.setStatus(""); + statusElement.style.display='none'; + Module.startClickToPlay(); + }); + }); +} + + var statusElement = document.getElementById('status'); var progressElement = document.getElementById('progress'); var canvasElement = document.getElementById('canvas'); -canvasElement.style.width = '1280px'; -canvasElement.style.height = '720px'; -canvasElement.style.display = 'block'; -canvasElement.style['margin-left'] = 'auto'; -canvasElement.style['margin-right'] = 'auto'; +canvasElement.style.width = '100%'; +canvasElement.style.height = '100%'; +document.getElementById('borderdiv').style.border = '0px'; -statusElement.style.display = 'none'; -progressElement.style.display = 'none'; -document.getElementById('progressdiv').style.display = 'none'; +//statusElement.style.display = 'none'; +//progressElement.style.display = 'none'; +//document.getElementById('progressdiv').style.display = 'none'; document.getElementById('output').style.display = 'none'; -document.getElementById('game-input').style.display = "none" -if (!window.parent.window.gtk) { - window.parent.window.gtk = {}; -} +// if (!window.parent.window.gtk) { +// window.parent.window.gtk = {}; +// } -window.parent.window.gtk.saveMain = function(text) { - FS.writeFile('app/main.rb', text); - window.gtk.play(); -} +// window.parent.window.gtk.saveMain = function(text) { +// FS.writeFile('app/main.rb', text); +// window.gtk.play(); +// } var loadDataFiles = function(dbname, baseurl, onsuccess) { @@ -481,8 +517,14 @@ var base64Encode = function(ui8array) { return out; } +function startGame() +{ + Module["removeRunDependency"]("dragonruby_init"); +} + + var Module = { - noInitialRun: true, + noInitialRun: false, preInit: [], clickedToPlay: false, clickToPlayListener: function() { @@ -493,10 +535,11 @@ var Module = { div.removeEventListener('click', Module.clickToPlayListener); document.body.removeChild(div); } - if (window.parent.window.gtk.starting) { - window.parent.window.gtk.starting(); - } - Module["callMain"](); // go go go! + // if (window.parent.window.gtk.starting) { + // window.parent.window.gtk.starting(); + // } + + startGame(); // go go go! }, startClickToPlay: function() { var base64 = base64Encode(FS.readFile(GDragonRubyIcon, {})); @@ -504,27 +547,38 @@ var Module = { var leftPx = ((window.innerWidth - 640) / 2); var leftPerc = Math.floor((leftPx / window.innerWidth) * 100); div.id = 'clicktoplaydiv'; + div.style.width = '50%'; + div.style.height = '50%'; div.style.backgroundColor = 'rgb(40, 44, 52)'; - div.style.left = leftPerc.toString() + "%"; - div.style.top = '10%'; - div.style.display = 'block'; div.style.position = 'absolute'; - div.style.width = "640px" - div.style.height = "360px" - - + div.style.top = '50%'; + div.style.left = '50%'; + div.style.transform = 'translate(-50%, -50%)'; var img = new Image(); img.onload = function() { // once we know its size, scale it, keeping aspect ratio. - var zoomRatio = 100.0 / this.width; - img.style.width = (zoomRatio * this.width.toString()) + "px"; - img.style.height = (zoomRatio * this.height.toString()) + "px"; - img.style.display = "block"; - img.style['margin-left'] = 'auto'; - img.style['margin-right'] = 'auto'; + var pct = 30; + var w = img.naturalWidth; + var h = img.naturalHeight; + if (!w || !h || (w == h)) { + img.style.width = '' + pct + '%'; + img.style.height = '' + pct + '%'; + } else if (w > h) { + img.style.width = '' + pct + '%'; + } else { + img.style.height = '' + pct + '%'; + } + img.style.display = 'block'; } img.style.display = 'none'; + img.style.width = 'auto'; + img.style.height = 'auto'; + img.style.margin = 0; + img.style.position = 'absolute'; + img.style.top = '50%'; + img.style.left = '50%'; + img.style.transform = 'translate(-50%, -50%)'; img.src = 'data:image/png;base64,' + base64; div.appendChild(img); @@ -536,17 +590,21 @@ var Module = { p.style.textAlign = 'center'; p.style.color = '#FFFFFF'; p.style.width = '100%'; + p.style.position = 'absolute'; + p.style.top = '10%'; p.style['font-family'] = "monospace"; div.appendChild(p); - + p = document.createElement('p'); - p.innerHTML = 'Click here to begin.'; + p.innerHTML = 'Click or tap here to begin.'; p.style['font-family'] = "monospace"; p.style['font-size'] = "20px"; p.style.textAlign = 'center'; p.style.backgroundColor = 'rgb(40, 44, 52)'; p.style.color = '#FFFFFF'; p.style.width = '100%'; + p.style.position = 'absolute'; + p.style.top = '75%'; div.appendChild(p); document.body.appendChild(div); @@ -554,25 +612,10 @@ var Module = { window.gtk.play = Module.clickToPlayListener; }, preRun: function() { - // set up a persistent store for save games, etc. - FS.mkdir('/persistent'); - FS.mount(IDBFS, {}, '/persistent'); - FS.syncfs(true, function(err) { - if (err) { - console.log("WARNING: Failed to populate persistent store. Save games likely lost?"); - } else { - console.log("Read in from persistent store."); - } - - loadDataFiles(GDragonRubyGameId, 'gamedata/', function() { - console.log("Game data is sync'd to MEMFS. Starting click-to-play()..."); - //Module.setStatus("Ready!"); - //setTimeout(function() { Module.setStatus(""); statusElement.style.display='none'; }, 1000); - Module.setStatus(""); - statusElement.style.display='none'; - Module.startClickToPlay(); - }); - }); + // this prevents the game from running. We'll remove the dependency when + // we have downloaded everything and the user has clicked-through to play. + Module["addRunDependency"]("dragonruby_init"); + prepareFilesystem(); // will get data, async. }, postRun: [], print: (function() { @@ -610,10 +653,6 @@ var Module = { canvas.addEventListener("click", function() { document.getElementById('toplevel').click(); document.getElementById('toplevel').focus(); - document.getElementById('game-input').style.display = "inline" - document.getElementById('game-input').focus(); - document.getElementById('game-input').blur(); - document.getElementById('game-input').style.display = "none" canvas.focus(); }); @@ -653,36 +692,26 @@ window.onerror = function(event) { }; }; +// sanity check this before downloading anything heavy. var hasWebAssembly = false; if (typeof WebAssembly==="object" && typeof WebAssembly.Memory==="function") { hasWebAssembly = true; } //console.log("Do we have WebAssembly? " + ((hasWebAssembly) ? "YES" : "NO")); +if (!hasWebAssembly) { + Module.setStatus("Your browser doesn't have WebAssembly support. Please upgrade."); +} else { + var buildtype = "wasm"; + var module = "dragonruby-" + buildtype + ".js"; + window.gtk = {}; + window.gtk.module = Module; -var buildtype = hasWebAssembly ? "wasm" : "asmjs"; -var module = "dragonruby-" + buildtype + ".js"; -window.gtk = {}; -window.gtk.module = Module; - -//console.log("Our main module is: " + module); + //console.log("Our main module is: " + module); -var script = document.createElement('script'); -script.src = module; -if (hasWebAssembly) { + var script = document.createElement('script'); + script.src = module; script.async = true; -} else { - script.async = false; // !!! FIXME: can this be async? - (function() { - var memoryInitializer = module + '.mem'; - if (typeof Module['locateFile'] === 'function') { - memoryInitializer = Module['locateFile'](memoryInitializer); - } else if (Module['memoryInitializerPrefixURL']) { - memoryInitializer = Module['memoryInitializerPrefixURL'] + memoryInitializer; - } - var meminitXHR = Module['memoryInitializerRequest'] = new XMLHttpRequest(); - meminitXHR.open('GET', memoryInitializer, true); - meminitXHR.responseType = 'arraybuffer'; - meminitXHR.send(null); - })(); + document.body.appendChild(script); } -document.body.appendChild(script); + +// end of dragonruby-html5-loader.js ... diff --git a/deploy_template/.dragonruby/stubs/html5/stub/index.html b/deploy_template/.dragonruby/stubs/html5/stub/index.html index b2bcf9f..b9d48b7 100644 --- a/deploy_template/.dragonruby/stubs/html5/stub/index.html +++ b/deploy_template/.dragonruby/stubs/html5/stub/index.html @@ -77,10 +77,8 @@ </head> <body id='toplevel'> <div class="emscripten_border" id='borderdiv'> - <input id="game-input" autocomplete="off" /> - <canvas class="game emscripten" id="canvas" oncontextmenu="event.preventDefault()"></canvas> + <canvas class="emscripten" id="canvas" oncontextmenu="event.preventDefault()" tabindex=-1></canvas> </div> - <br/> <textarea style="display: none;" id="output" rows="8"></textarea> <div class="emscripten" id="status"></div> |
