// Init EJS stuff class HomeplayEmulator { scriptElement = null; initInterval = null; oldGetRetroArchCfg = null; constructor() { // Set up the EJS stuff window.EJS_player = "#game"; window.EJS_pathtodata = "https://cdn.emulatorjs.org/stable/data/"; window.EJS_language = "en-US"; window.EJS_volume = 0; window.EJS_startOnLoaded = true; window.EJS_backgroundColor = '#000'; window.EJS_Buttons = { playPause: false, restart: false, mute: false, settings: false, fullscreen: false, saveState: false, loadState: false, screenRecord: false, gamepad: false, cheat: false, volume: false, saveSavFiles: false, loadSavFiles: false, quickSave: false, quickLoad: false, screenshot: false, cacheManager: false, exitEmulation: false } window.EJS_defaultOptions = { }; // Bind events window.EJS_ready = this.onEJSReady; window.EJS_onGameStart = this.onEJSGameStart; window.EJS_onGameEnd = this.onEJSGameEnd; window.EJS_onSaveState = this.onEJSSaveState; window.EJS_onLoadState = this.onEJSLoadState; window.onmessage = this.onMessage; // Begin the init interval this.initInterval = setInterval(() => { this.send({ message: 'iframe_loaded' }); }, 1000); } send = data => { window.parent.postMessage(data, '*'); } init = data => { window.EJS_gameUrl = `/api/v1/rom?id=${data.gameId}`; window.EJS_core = data.core; window.EJS_gameName = data.gameName; window.EJS_externalFiles = { '/homeplay/saves/': `/api/v1/save?id=${data.gameId}` } this.scriptElement = document.createElement('script'); this.scriptElement.src = 'https://cdn.emulatorjs.org/stable/data/loader.js'; document.body.appendChild(this.scriptElement); clearInterval(this.initInterval); } onEJSReady = () => { // Modify the EJS stuff this.oldGetRetroArchCfg = window.EJS_GameManager.prototype.getRetroArchCfg; const raConfig = (...a) => this.getRetroArchCfg(...a); window.EJS_GameManager.prototype.getRetroArchCfg = function() { return raConfig(this); } this.send({ message: 'ready' }); console.log('EJS Ready'); } onEJSGameStart = () => { console.log('EJS Game Start'); } onEJSGameEnd = () => { console.log('EJS Game End'); } onEJSSaveState = () => { console.log('EJS Save State'); } onEJSLoadState = () => { console.log('EJS Load State');; } onMessage = e => { const { data } = e; if(!data) { console.error('No data'); return; } const { message } = data; switch(message) { case 'init': this.init(data); break; case 'volume': window.EJS_volume = data.volume; break; case 'save': window.EJS_emulator.saveSaveFiles(); break; default: console.error('Unknown message', message); } } md5File = async path => { const buffer = window.EJS_emulator.gameManager.FS.readFile(path); const hash = await crypto.subtle.digest('SHA-256', buffer); const hashArray = Array.from(new Uint8Array(hash)); const hashHex = hashArray.map(b => b.toString(16).padStart(2, '0')).join(''); return hashHex; } getRetroArchCfg = (gameManager) => { const ejsConfig = this.oldGetRetroArchCfg.call(gameManager); // Parse back into key value pair const raConfig = ejsConfig.split('\n').reduce((acc, line) => { if(!line.length) return acc; const [key, value] = line.split('='); acc[key.trim()] = value.trim(); return acc; }, {}); // Add new options raConfig['savefiles_in_content_dir'] = false; raConfig['sort_savefiles_by_content_enable'] = false; raConfig['sort_savefiles_enable'] = false; raConfig['savefile_directory'] = '/homeplay/saves'; // Return back as RA config string return Object.entries(raConfig).map(([k, v]) => `${k} = ${v}`).join('\n'); } } // const emulatorSave = async () => { // // First, we get the currently saved MD5 hash of all files in the save // // directory // const contents = EJS_emulator.gameManager.FS.readdir('/homeplay/saves').filter(f => !f.startsWith('.')); // const hashes = await Promise.all(contents.map(f => md5File(`/homeplay/saves/${f}`))); // EJS_emulator.gameManager.saveSaveFiles(); // const newHashes = await Promise.all(contents.map(f => md5File(`/homeplay/saves/${f}`))); // const changedFiles = contents.filter((f, i) => hashes[i] !== newHashes[i]); // console.log('Changed files', changedFiles); // send({ // message: '' // }) // } window.homeplay = new HomeplayEmulator();