|
| 1 | +// Game vars |
| 2 | +var Module; |
| 3 | +var EJS_biosUrl; |
| 4 | +var EJS_onGameStart; |
| 5 | +var rom = EJS_gameUrl.substr(EJS_gameUrl.lastIndexOf("/")+1); |
| 6 | +// Function vars |
| 7 | +var dlProgress = 0; |
| 8 | +var afs; |
| 9 | +BrowserFS.install(window); |
| 10 | +var fs = require('fs'); |
| 11 | +var retroArchCfg = ` |
| 12 | +input_menu_toggle_gamepad_combo = 3 |
| 13 | +system_directory = /home/web_user/retroarch/system/` |
| 14 | +var retroArchDir = '/home/web_user/retroarch/' |
| 15 | + |
| 16 | +// Update loading div |
| 17 | +function setLoader(name) { |
| 18 | + $('#loading').empty(); |
| 19 | + var message = $('<p>').text('Loading ' + name + ': '); |
| 20 | + var progress = $('<span>').attr('id','progress'); |
| 21 | + message.append(progress); |
| 22 | + $('#loading').append(message); |
| 23 | +}; |
| 24 | + |
| 25 | +// File downloads with progress |
| 26 | +async function downloadFile(url) { |
| 27 | + var response = await fetch(url); |
| 28 | + var length = response.headers.get('Content-Length'); |
| 29 | + if (!length) { |
| 30 | + return await response.arrayBuffer(); |
| 31 | + }; |
| 32 | + var array = new Uint8Array(length); |
| 33 | + let at = 0; |
| 34 | + var reader = response.body.getReader(); |
| 35 | + for (;;) { |
| 36 | + var {done, value} = await reader.read(); |
| 37 | + if (done) { |
| 38 | + break; |
| 39 | + } |
| 40 | + array.set(value, at); |
| 41 | + at += value.length; |
| 42 | + dlProgress = ((at / length).toFixed(2) * 100).toFixed(0); |
| 43 | + $('#progress').text(dlProgress.toString() + '%'); |
| 44 | + } |
| 45 | + return array; |
| 46 | +}; |
| 47 | + |
| 48 | +// Create IndexDB filestore |
| 49 | +async function setupFileSystem() { |
| 50 | + var imfs = new BrowserFS.FileSystem.InMemory(); |
| 51 | + afs = new BrowserFS.FileSystem.AsyncMirror(imfs, |
| 52 | + new BrowserFS.FileSystem.IndexedDB(async function(e, fs) { |
| 53 | + afs.initialize(async function(e) { |
| 54 | + console.log('WEBPLAYER: idbfs setup successful'); |
| 55 | + setupMounts(); |
| 56 | + }); |
| 57 | + }, |
| 58 | + 'RetroArch')); |
| 59 | +}; |
| 60 | + |
| 61 | +// Download all needed files and setup base filesystem |
| 62 | +async function setupMounts() { |
| 63 | + setLoader('Frontend'); |
| 64 | + var frontendData = await downloadFile('data/frontend.zip'); |
| 65 | + var mfs = new BrowserFS.FileSystem.MountableFileSystem(); |
| 66 | + var memfs = new BrowserFS.FileSystem.InMemory(); |
| 67 | + var memfs = new BrowserFS.FileSystem.InMemory(); |
| 68 | + var frontend = new BrowserFS.FileSystem.ZipFS(new Buffer(frontendData)); |
| 69 | + console.log('WEBPLAYER: initializing filesystem'); |
| 70 | + mfs.mount(retroArchDir + 'userdata', afs); |
| 71 | + mfs.mount(retroArchDir + 'roms', memfs); |
| 72 | + mfs.mount(retroArchDir + 'bundle', frontend); |
| 73 | + if (EJS_biosUrl) { |
| 74 | + setLoader('Bios'); |
| 75 | + var biosFile = await downloadFile(EJS_biosUrl); |
| 76 | + if (EJS_biosUrl.endsWith(".zip")) { |
| 77 | + var biosPackage = new BrowserFS.FileSystem.ZipFS(new Buffer(biosFile)); |
| 78 | + mfs.mount(retroArchDir + 'system/', biosPackage); |
| 79 | + BrowserFS.initialize(mfs); |
| 80 | + } else { |
| 81 | + var bios = EJS_biosUrl.substr(EJS_biosUrl.lastIndexOf("/")+1); |
| 82 | + BrowserFS.initialize(mfs); |
| 83 | + fs.mkdirSync(retroArchDir + 'system'); |
| 84 | + fs.appendFileSync(retroArchDir + 'system/' + bios, new Buffer(biosFile)); |
| 85 | + } |
| 86 | + } else { |
| 87 | + BrowserFS.initialize(mfs); |
| 88 | + }; |
| 89 | + var BFS = new BrowserFS.EmscriptenFS(); |
| 90 | + FS.mount(BFS, { |
| 91 | + root: '/home' |
| 92 | + }, '/home'); |
| 93 | + if (! fs.existsSync(retroArchDir + 'userdata/retroarch.cfg')) { |
| 94 | + fs.writeFileSync(retroArchDir + 'userdata/retroarch.cfg', retroArchCfg); |
| 95 | + }; |
| 96 | + console.log('WEBPLAYER: filesystem initialization successful'); |
| 97 | + downloadGame(); |
| 98 | +} |
| 99 | + |
| 100 | +// Download assets needed for this game |
| 101 | +async function downloadGame() { |
| 102 | + setLoader('Game'); |
| 103 | + var romFile = await downloadFile(EJS_gameUrl); |
| 104 | + fs.appendFileSync(retroArchDir + 'roms/' + rom, new Buffer(romFile)); |
| 105 | + $('#loading').empty(); |
| 106 | + Module['callMain'](Module['arguments']); |
| 107 | + document.getElementById('canvas').focus(); |
| 108 | + if (EJS_onGameStart) { |
| 109 | + EJS_onGameStart(); |
| 110 | + }; |
| 111 | +}; |
| 112 | + |
| 113 | +// When the browser has loaded everything. |
| 114 | +async function run() { |
| 115 | + $(EJS_player).empty().append('<div id="loading"></div><canvas id="canvas" tabindex="1"></canvas><button alt="FullScreen" title="FullScreen" class="full-button" onclick="Module.requestFullscreen(false)">\u26F6</button>'); |
| 116 | + // Retroarch run logic |
| 117 | + Module = { |
| 118 | + noInitialRun: true, |
| 119 | + arguments: ['-v', retroArchDir + 'roms/' + rom], |
| 120 | + preRun: [], |
| 121 | + postRun: [], |
| 122 | + print: function(text) { |
| 123 | + console.log(text); |
| 124 | + }, |
| 125 | + printErr: function(text) { |
| 126 | + console.log(text); |
| 127 | + }, |
| 128 | + canvas: document.getElementById('canvas'), |
| 129 | + totalDependencies: 0, |
| 130 | + monitorRunDependencies: function(left) { |
| 131 | + this.totalDependencies = Math.max(this.totalDependencies, left); |
| 132 | + } |
| 133 | + }; |
| 134 | + // Load core script |
| 135 | + $.getScript('data/' + EJS_core + '_libretro.js', async function() { |
| 136 | + setupFileSystem(); |
| 137 | + }); |
| 138 | +}; |
| 139 | + |
| 140 | +// Keypress event capture |
| 141 | +function keyPress(k) { |
| 142 | + kp(k, 'keydown'); |
| 143 | + setTimeout(function() { |
| 144 | + kp(k, 'keyup') |
| 145 | + }, 50); |
| 146 | +}; |
| 147 | +kp = function(k, event) { |
| 148 | + var oEvent = new KeyboardEvent(event, { |
| 149 | + code: k |
| 150 | + }); |
| 151 | + document.dispatchEvent(oEvent); |
| 152 | + document.getElementById('canvas').focus(); |
| 153 | +}; |
| 154 | + |
| 155 | +run(); |
0 commit comments