-
-
Notifications
You must be signed in to change notification settings - Fork 1.9k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Workerized (non-async) web player, using OPFS
This patch eliminates the need for asyncify and uses modern filesystem APIs instead of the deprecated, unmaintained BrowserFS. This is a WIP patch because it won't fully work until these two Emscripten PRs land and are released: emscripten-core/emscripten#23518 emscripten-core/emscripten#23021 The former fixes an offscreen canvas context recreation bug, and the latter adds an equivalent to BrowserFS's XHR filesystem (but without the hazardous running-XHR-on-the-main-thread problem). The biggest issue is that local storage of users who were using the old version of the webplayer will be gone when they switch to the new webplayer. I don't have a good story for converting the old BrowserFS IDBFS contents into the new OPFS filesystem (the move is worth doing because OPFS supports seeking and reading only bits of a file, and because BrowserFS is dead). I've kept around the old libretro webplayer under pkg/emscripten/libretro-classic, and with these make flags you can build a non-workerized RA that uses asyncify to sleep as before: make -f Makefile.emscripten libretro=$CORE HAVE_WORKER=0 HAVE_WASMFS=0 PTHREAD=0 HAVE_AL=1 I also moved the default directory for core content on emscripten to not be a subdirectory of the local filesystem mount, because it's confusing to have a subdirectory that's lazily fetched and not mirrored to the local storage. I think it won't impact existing users of the classic web player because they already have a retroarch.cfg in place.
- Loading branch information
Showing
10 changed files
with
868 additions
and
144 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,210 @@ | ||
<!doctype html> | ||
<html lang="en"> | ||
<head> | ||
<meta charset="utf-8"> | ||
<title>RetroArch Web Player</title> | ||
<meta name="viewport" content="width=device-width, initial-scale=1"> | ||
<!-- Bootstrap core CSS --> | ||
<link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0-alpha.3/css/bootstrap.min.css" rel="stylesheet" type="text/css"> | ||
<!-- Font Awesome --> | ||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.6.0/css/font-awesome.min.css"> | ||
<!-- Material Design Bootstrap --> | ||
<link href="//cdnjs.cloudflare.com/ajax/libs/mdbootstrap/4.1.1/css/mdb.min.css" rel="stylesheet"> | ||
|
||
<link href="libretro.css" rel="stylesheet" type="text/css"> | ||
<link rel="shortcut icon" href="media/retroarch.ico" /> | ||
|
||
</head> | ||
<body> | ||
<!--Navbar--> | ||
<nav class="navbar navbar-dark bg-primary"> | ||
<div class="container"> | ||
<!--navbar content--> | ||
<div class="navbar-toggleable-xs"> | ||
<!--Links--> | ||
<ul class="nav navbar-nav"> | ||
<div class="dropdown"> | ||
<li class="nav-item dropdown"> | ||
<button class="btn btn-primary dropdown-toggle" type="button" id="dropdownMenu1" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">Core Selection</button> | ||
<div class="dropdown-menu dropdown-primary" aria-labelledby="dropdownMenu1" data-dropdown-in="fadeIn" data-dropdown-out="fadeOut" id="core-selector"> | ||
<a class="dropdown-item" href="." data-core="2048">2048</a> | ||
<a class="dropdown-item" href="." data-core="arduous">Arduous</a> | ||
<a class="dropdown-item" href="." data-core="bk">BK</a> | ||
<a class="dropdown-item" href="." data-core="bluemsx">BlueMSX</a> | ||
<a class="dropdown-item" href="." data-core="chailove">ChaiLove</a> | ||
<a class="dropdown-item" href="." data-core="craft">Craft</a> | ||
<a class="dropdown-item" href="." data-core="desmume">DeSmuME</a> | ||
<a class="dropdown-item" href="." data-core="dosbox">DOSBox</a> | ||
<a class="dropdown-item" href="." data-core="easyrpg">EasyRPG</a> | ||
<a class="dropdown-item" href="." data-core="ecwolf">ECWolf</a> | ||
<a class="dropdown-item" href="." data-core="fbalpha2012">FB Alpha 2012</a> | ||
<a class="dropdown-item" href="." data-core="fbalpha2012_cps1">FB Alpha 2012 CPS1</a> | ||
<a class="dropdown-item" href="." data-core="fbalpha2012_cps2">FB Alpha 2012 CPS2</a> | ||
<a class="dropdown-item" href="." data-core="fbalpha2012_neo">FB Alpha 2012 NeoGeo</a> | ||
<a class="dropdown-item" href="." data-core="fceumm">FCEUmm</a> | ||
<a class="dropdown-item" href="." data-core="ffmpeg">FFmpeg</a> | ||
<a class="dropdown-item" href="." data-core="freechaf">FreeChaF</a> | ||
<a class="dropdown-item" href="." data-core="gambatte">Gambatte</a> | ||
<a class="dropdown-item" href="." data-core="gme">Game Music Emu</a> | ||
<a class="dropdown-item" href="." data-core="gearboy">GearBoy</a> | ||
<a class="dropdown-item" href="." data-core="gearcoleco">GearColeco</a> | ||
<a class="dropdown-item" href="." data-core="gearsystem">GearSystem</a> | ||
<a class="dropdown-item" href="." data-core="genesis_plus_gx">Genesis Plus GX</a> | ||
<a class="dropdown-item" href="." data-core="genesis_plus_gx_wide">Genesis Plus GX Wide</a> | ||
<a class="dropdown-item" href="." data-core="glupen64">GLupeN64</a> | ||
<!--<a class="dropdown-item" href="." data-core="gpsp">gPSP</a>--> | ||
<a class="dropdown-item" href="." data-core="handy">Handy</a> | ||
<a class="dropdown-item" href="." data-core="jaxe">JAXE</a> | ||
<a class="dropdown-item" href="." data-core="jumpnbump">Jump 'n Bump</a> | ||
<a class="dropdown-item" href="." data-core="lowresnx">LowResNX</a> | ||
<a class="dropdown-item" href="." data-core="lutro">Lutro</a> | ||
<a class="dropdown-item" href="." data-core="m2000">M2000</a> | ||
<a class="dropdown-item" href="." data-core="mame2000">MAME 2000</a> | ||
<a class="dropdown-item" href="." data-core="mame2003">MAME 2003</a> | ||
<a class="dropdown-item" href="." data-core="mame2003_plus">MAME 2003-Plus</a> | ||
<a class="dropdown-item" href="." data-core="mednafen_lynx">Mednafen Lynx</a> | ||
<a class="dropdown-item" href="." data-core="mednafen_ngp">Mednafen Neo Geo Pocket</a> | ||
<a class="dropdown-item" href="." data-core="mednafen_pce_fast">Mednafen PC Engine Fast</a> | ||
<!--<a class="dropdown-item" href="." data-core="mednafen_pcfx">Mednafen/Beetle PCFX</a>--> | ||
<a class="dropdown-item" href="." data-core="mednafen_psx">Mednafen/Beetle PSX</a> | ||
<!--<a class="dropdown-item" href="." data-core="mednafen_saturn">Mednafen/Beetle Saturn</a>--> | ||
<a class="dropdown-item" href="." data-core="mednafen_snes">Mednafen/Beetle SNES</a> | ||
<a class="dropdown-item" href="." data-core="mednafen_vb">Mednafen/Beetle Virtual Boy</a> | ||
<a class="dropdown-item" href="." data-core="mednafen_wswan">Mednafen/Beetle WonderSwan</a> | ||
<a class="dropdown-item" href="." data-core="mgba">Mgba</a> | ||
<a class="dropdown-item" href="." data-core="minivmac">MiniVmac</a> | ||
<a class="dropdown-item" href="." data-core="mu">Mu</a> | ||
<a class="dropdown-item" href="." data-core="mupen64plus">Mupen64 Plus</a> | ||
<a class="dropdown-item" href="." data-core="mrboom">MrBoom</a> | ||
<a class="dropdown-item" href="." data-core="nestopia">Nestopia</a> | ||
<a class="dropdown-item" href="." data-core="nxengine">NX Engine</a> | ||
<a class="dropdown-item" href="." data-core="o2em">O2em</a> | ||
<a class="dropdown-item" href="." data-core="opera">Opera</a> | ||
<a class="dropdown-item" href="." data-core="picodrive">PicoDrive</a> | ||
<a class="dropdown-item" href="." data-core="prboom">PrBoom</a> | ||
<a class="dropdown-item" href="." data-core="quasi88">Quasi88</a> | ||
<a class="dropdown-item" href="." data-core="quicknes">QuickNES</a> | ||
<a class="dropdown-item" href="." data-core="retro8">Retro8</a> | ||
<a class="dropdown-item" href="." data-core="flycast">Flycast</a> | ||
<a class="dropdown-item" href="." data-core="snes9x2002">Snes9x 2002</a> | ||
<a class="dropdown-item" href="." data-core="snes9x2005">Snes9x 2005</a> | ||
<a class="dropdown-item" href="." data-core="snes9x2010">Snes9x 2010</a> | ||
<a class="dropdown-item" href="." data-core="snes9x">Snes9x</a> | ||
<a class="dropdown-item" href="." data-core="squirreljme">SquirrelJME</a> | ||
<a class="dropdown-item" href="." data-core="stella">Stella</a> | ||
<a class="dropdown-item" href="." data-core="tgbdual">TGB Dual</a> | ||
<a class="dropdown-item" href="." data-core="theodore">Theodore (Thomson TO8/TO9)</a> | ||
<a class="dropdown-item" href="." data-core="tic80">TIC-80</a> | ||
<a class="dropdown-item" href="." data-core="tyrquake">TyrQuake</a> | ||
<a class="dropdown-item" href="." data-core="uzem">UZEM</a> | ||
<a class="dropdown-item" href="." data-core="vaporspec">Vaporspec</a> | ||
<a class="dropdown-item" href="." data-core="vba_next">VBA Next</a> | ||
<a class="dropdown-item" href="." data-core="vecx">Vecx</a> | ||
<a class="dropdown-item" href="." data-core="vice_x64">VICE x64</a> | ||
<a class="dropdown-item" href="." data-core="vice_x64sc">VICE x64sc</a> | ||
<a class="dropdown-item" href="." data-core="vice_x128">VICE x128</a> | ||
<a class="dropdown-item" href="." data-core="vice_xcbm2">VICE xcbm2</a> | ||
<a class="dropdown-item" href="." data-core="vice_xcbm5x0">VICE xcbm5x0</a> | ||
<a class="dropdown-item" href="." data-core="vice_xpet">VICE xPET</a> | ||
<a class="dropdown-item" href="." data-core="vice_xplus4">VICE xPlus4</a> | ||
<a class="dropdown-item" href="." data-core="vice_xscpu64">VICE xscpu4</a> | ||
<a class="dropdown-item" href="." data-core="vice_xvic">VICE xVIC</a> | ||
<a class="dropdown-item" href="." data-core="vitaquake2">Vita Quake2</a> | ||
<a class="dropdown-item" href="." data-core="vitaquake2-rogue">Vita Quake2 (rogue)</a> | ||
<a class="dropdown-item" href="." data-core="vitaquake2-xatrix">Vita Quake2 (xatrix)</a> | ||
<a class="dropdown-item" href="." data-core="vitaquake2-zaero">Vita Quake2 (zaero)</a> | ||
<a class="dropdown-item" href="." data-core="virtualjaguar">Virtual Jaguar</a> | ||
<a class="dropdown-item" href="." data-core="wasm4">WASM4</a> | ||
<a class="dropdown-item" href="." data-core="x1">XMillenium</a> | ||
<a class="dropdown-item" href="." data-core="xrick">XRick</a> | ||
<a class="dropdown-item" href="." data-core="yabause">Yabause</a> | ||
</div> | ||
<button class="btn btn-primary disabled" id="btnRun" onclick="startRetroArch()" disabled> | ||
<span class="fa fa-spinner fa-spin" id="icnRun"></span> Run | ||
</button> | ||
<button class="btn btn-primary disabled" id="btnAdd" onclick="document.getElementById('btnRom').click()" disabled> | ||
<span class="fa fa-plus" id="icnAdd"></span> Add Content | ||
</button> | ||
<button class="btn btn-primary tooltip-enable" id="btnClean" onclick="cleanupStorage();" title="Cleanup storage"> | ||
<span class="fa fa-trash-o" id="icnClean"></span> <span class="sr-only">Cleanup</span> | ||
</button> | ||
<input class="btn btn-primary disabled" style="display: none" type="file" id="btnRom" name="upload" onclick="document.getElementById('btnAdd').click();" onchange="selectFiles(event.target.files)" multiple /> | ||
<button class="btn btn-primary disabled tooltip-enable" id="btnMenu" onclick="keyPress('F1');" title="Menu toggle" disabled> | ||
<span class="fa fa-bars" id="btnMenu"></span> <span class="sr-only">Menu</span> | ||
</button> | ||
<button class="btn btn-primary disabled tooltip-enable" id="btnFullscreen" onclick="Module.requestFullscreen(false)" title="Fullscreen" disabled> | ||
<span class="fa fa-desktop" id="icnAdd"></span> <span class="sr-only">Fullscreen</span> | ||
</button> | ||
</button> | ||
<button type="button" class="btn btn-primary tooltip-enable" data-toggle="modal" data-target="#helpModal">Help</button> | ||
</li> | ||
</div> | ||
</ul> | ||
<div class="toggleMenu"> | ||
<button class="btn btn-primary" id="btnHideMenu" title="Toggle Menu"> | ||
<span class="fa fa-chevron-up" id="icnHideMenu"></span> <span class="sr-only">Hide Top Navigation</span> | ||
</button> | ||
</div> | ||
</div> | ||
<!-- Basics steps modal for Web Libretro --> | ||
<div class="modal fade" id="helpModal" role="dialog" style="color:black;"> | ||
<div class="modal-dialog modal-lg"> | ||
<div class="modal-content"> | ||
<div class="modal-header"> | ||
<button type="button" class="close" data-dismiss="modal">×</button> | ||
<h1 class="modal-title">Basics</h1> | ||
</div> | ||
<div class="modal-body"> | ||
<h3><b>Load Core</b></h3> | ||
<p>Load your core by clicking on the first tab. Scroll down until you reach the desired Core. We will use Nestopia for now. Don't forget - Content must be compatible with the matched Core.</p> | ||
<li>Nes: <i>NESTOPIA</i></li> | ||
<li>Game Boy / Color: <i>Gambatte</i></li> | ||
</ul> | ||
<p>etc.</p> | ||
<p></p> | ||
<h3><b>Load Content</b></h3> | ||
<p>After selecting Core, click Run. After RetroArch opens, click Add Content and select your compatible ROM.</p> | ||
<li>Nestopia > <i>YourGame.nes</i></li> | ||
<li>Gambatte > <i>YourGame.gbc</i></li> | ||
</ul> | ||
<p>etc.</p> | ||
<p></p> | ||
<h3><b><span class="fa fa-trash-o"></span> Cleanup Storage</b></h3> | ||
<p>The trashcan erases your existing configuration and presets. If the Web Player doesn't start, you should click the trashcan and refresh the cache in your browser (usually F5 or Shift+F5).</p> | ||
<p></p> | ||
<h3><b><span class="fa fa-bars"></span> Quick Menu</b></h3> | ||
<p>If you click on the three line icons, the Quick Menu will open here as in RetroArch.</p> | ||
|
||
</div> | ||
<div class="modal-footer"> | ||
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button> | ||
</div> | ||
</div> | ||
</div> | ||
</div> | ||
</div> | ||
<!--/.navbar content--> | ||
</div> | ||
</nav> | ||
<div class="bg-inverse webplayer-container"> | ||
<div class="webplayer_border text-xs-center" id="canvas_div"> | ||
<div class="showMenu"> | ||
<button type="button" class="btn btn-link"> | ||
<span class="fa fa-chevron-down" id="icnShowMenu"></span> <span class="sr-only">Show Top Navigation</span> | ||
</button> | ||
</div> | ||
<canvas class="webplayer" id="canvas" tabindex="1" oncontextmenu="event.preventDefault()" style="display: none"></canvas> | ||
<img class="webplayer-preview img-fluid" src="media/canvas.png" width="960px" height="720px" alt="RetroArch Logo"> | ||
</div> | ||
</div> | ||
|
||
<script crossorigin="anonymous" src="//code.jquery.com/jquery-3.1.0.min.js"></script> | ||
<script crossorigin="anonymous" src="//rawgit.com/jeresig/jquery.hotkeys/master/jquery.hotkeys.js"></script> | ||
<script crossorigin="anonymous" src="//cdnjs.cloudflare.com/ajax/libs/tether/1.3.4/js/tether.min.js"></script> | ||
<script crossorigin="anonymous" src="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0-alpha.3/js/bootstrap.min.js"></script> | ||
<script src="analytics.js"></script> | ||
<!--script src="//wzrd.in/standalone/[email protected]"></script--> | ||
<script src="browserfs.min.js"></script> | ||
<script src="libretro.js"></script> | ||
</body> | ||
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
#! /usr/bin/env coffee | ||
|
||
fs = require 'fs' | ||
path = require 'path' | ||
|
||
symLinks = {} | ||
|
||
rdSync = (dpath, tree, name) -> | ||
files = fs.readdirSync(dpath) | ||
for file in files | ||
# ignore non-essential directories / files | ||
continue if file in ['.git', 'node_modules', 'bower_components', 'build'] or file[0] is '.' | ||
fpath = dpath + '/' + file | ||
try | ||
# Avoid infinite loops. | ||
lstat = fs.lstatSync(fpath) | ||
if lstat.isSymbolicLink() | ||
symLinks[lstat.dev] ?= {} | ||
# Ignore if we've seen it before | ||
continue if symLinks[lstat.dev][lstat.ino]? | ||
symLinks[lstat.dev][lstat.ino] = 0 | ||
|
||
fstat = fs.statSync(fpath) | ||
if fstat.isDirectory() | ||
tree[file] = child = {} | ||
rdSync(fpath, child, file) | ||
else | ||
tree[file] = null | ||
catch e | ||
# Ignore and move on. | ||
return tree | ||
|
||
fs_listing = rdSync(process.cwd(), {}, '/') | ||
console.log(JSON.stringify(fs_listing)) |
Oops, something went wrong.