Skip to content

Commit 6373f5a

Browse files
committed
update metadata to include new systems, swap to in house libretro cores for many emulators
1 parent 81da158 commit 6373f5a

16 files changed

+3779
-460
lines changed

frontend/css/index.css

+20
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,11 @@ html {
33
overflow: hidden;
44
}
55

6+
canvas {
7+
border: none;
8+
outline: none;
9+
}
10+
611
#menu {
712
visibility: visible;
813
position: fixed;
@@ -59,6 +64,21 @@ html {
5964
height: 50vh;
6065
}
6166

67+
#game {
68+
text-align: center;
69+
color: white;
70+
}
71+
72+
.full-button {
73+
position: absolute;
74+
bottom: 0;
75+
right: 0;
76+
color: white;
77+
background: transparent;
78+
cursor: pointer;
79+
border: none;
80+
font-size: 3vw;
81+
}
6282

6383
@keyframes growonce {
6484
0% {

frontend/index.html

+2
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
<head>
44
<link rel="stylesheet" href="css/index.css">
55
<script src="js/vendor/jquery.min.js"></script>
6+
<script src="js/vendor/jquery.hotkeys.js"></script>
7+
<script src="js/vendor/browserfs.min.js"></script>
68
<script src="js/vendor/hammer.min.js"></script>
79
<script src="js/index.js"></script>
810
</head>

frontend/js/index.js

+26-16
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,19 @@ function launch(active_item) {
135135
$(document).off('keydown');
136136
// Default variables for emulator
137137
var emulator = $('#i' + active_item.toString()).data('emulator');
138+
if (emulator.startsWith('libretro-')) {
139+
var emulator = emulator.replace('libretro-','');
140+
var script = 'js/libretro.js'
141+
EJS_onGameStart = function() {
142+
Module.requestFullscreen(false);
143+
}
144+
} else {
145+
var script = 'data/loader.js'
146+
var EJSemu = true;
147+
EJS_onGameStart = function() {
148+
document.querySelectorAll('[data-btn="fullscreen"]')[0].click();
149+
}
150+
};
138151
var path = $('#i' + active_item.toString()).data('path');
139152
var rom_path = 'user/' + path + '/roms/';
140153
var rom_extension = $('#i' + active_item.toString()).data('rom_extension');
@@ -152,30 +165,27 @@ function launch(active_item) {
152165
EJS_gameUrl = rom_path + name + rom_extension;
153166
EJS_core = emulator;
154167
EJS_pathtodata = 'data/';
155-
EJS_onGameStart = function() {
156-
document.querySelectorAll('[data-btn="fullscreen"]')[0].click();
157-
}
158168
// Load in EJS loader
159169
var loaderscript = document.createElement('script');
160-
loaderscript.src = 'data/loader.js';
170+
loaderscript.src = script;
161171
document.head.append(loaderscript);
162172
// Click play button as soon as it appears
163-
var clickplay = setInterval(() => {
164-
if (typeof document.getElementsByClassName('ejs--73f9b4e94a7a1fe74e11107d5ab2ef')[0] !== 'undefined') {
165-
clearInterval(clickplay);
166-
document.getElementsByClassName('ejs--73f9b4e94a7a1fe74e11107d5ab2ef')[0].click();
167-
}
168-
}, 100);
169-
// Call to save every minute the game is active
170-
var saveEveryMinute = setInterval(() => {
171-
if (window.exit == false ) {
172-
window.dispatchEvent(new Event('beforeunload'));
173-
};
174-
}, 60000);
173+
if (EJSemu) {
174+
var clickplay = setInterval(() => {
175+
if (typeof document.getElementsByClassName('ejs--73f9b4e94a7a1fe74e11107d5ab2ef')[0] !== 'undefined') {
176+
clearInterval(clickplay);
177+
document.getElementsByClassName('ejs--73f9b4e94a7a1fe74e11107d5ab2ef')[0].click();
178+
}
179+
}, 100);
180+
};
175181
// Reload window if user clicks back
176182
$(window).on('hashchange', async function() {
177183
if (window.location.hash !== '#game') {
184+
// Make sure games are saved by sleeping for a second before reloading
178185
window.exit = true;
186+
if (Module) {
187+
Module._cmd_savefiles();
188+
};
179189
window.dispatchEvent(new Event('beforeunload'));
180190
setTimeout(function(){
181191
window.location.href = '#' + root + '---' + active_item;

frontend/js/libretro.js

+155
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
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();

frontend/js/vendor/browserfs.min.js

+10
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)