Path: blob/main/public/games/files/webretro/assets/base.js
1034 views
// Source Code: https://github.com/BinBashBanana/webretro1// please dont use IE2var indexedDB = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;3if (!window.fetch || !indexedDB) {4alert("Update your browser!");5throw "Update your browser!";6}78var fsBundleDirs, fsBundleFiles, loadStatus, romName, stateReadersReady, stateReaders2Ready, saveReadersReady, isPaused, wasmReady, bundleReady, romMode, core, wIdb, romUploadCallback, latestVersion;9var bundleCdn = "https://cdn.jsdelivr.net/gh/BinBashBanana/webretro/";10var keybinds = 'input_player1_start = "enter"\ninput_player1_select = "space"\ninput_player1_l = "e"\ninput_player1_l2 = "r"\ninput_player1_r = "p"\ninput_player1_r2 = "o"\ninput_player1_a = "h"\ninput_player1_b = "g"\ninput_player1_x = "y"\ninput_player1_y = "t"\ninput_player1_up = "up"\ninput_player1_left = "left"\ninput_player1_down = "down"\ninput_player1_right = "right"\ninput_player1_l_x_minus = "a"\ninput_player1_l_x_plus = "d"\ninput_player1_l_y_minus = "w"\ninput_player1_l_y_plus = "s"\ninput_player1_l3_btn = "x"\ninput_player1_r_x_minus = "j"\ninput_player1_r_x_plus = "l"\ninput_player1_r_y_minus = "i"\ninput_player1_r_y_plus = "k"\ninput_player1_r3_btn = "comma"\ninput_menu_toggle = "f1"\ninput_save_state = "f2"\ninput_load_state = "f3"\n';11var nulKeys = 'input_ai_service = "nul"\ninput_ai_service_axis = "nul"\ninput_ai_service_btn = "nul"\ninput_ai_service_mbtn = "nul"\ninput_audio_mute = "nul"\ninput_audio_mute_axis = "nul"\ninput_audio_mute_btn = "nul"\ninput_audio_mute_mbtn = "nul"\ninput_cheat_index_minus = "nul"\ninput_cheat_index_minus_axis = "nul"\ninput_cheat_index_minus_btn = "nul"\ninput_cheat_index_minus_mbtn = "nul"\ninput_cheat_index_plus = "nul"\ninput_cheat_index_plus_axis = "nul"\ninput_cheat_index_plus_btn = "nul"\ninput_cheat_index_plus_mbtn = "nul"\ninput_cheat_toggle = "nul"\ninput_cheat_toggle_axis = "nul"\ninput_cheat_toggle_btn = "nul"\ninput_cheat_toggle_mbtn = "nul"\ninput_desktop_menu_toggle = "nul"\ninput_desktop_menu_toggle_axis = "nul"\ninput_desktop_menu_toggle_btn = "nul"\ninput_desktop_menu_toggle_mbtn = "nul"\ninput_disk_eject_toggle = "nul"\ninput_disk_eject_toggle_axis = "nul"\ninput_disk_eject_toggle_btn = "nul"\ninput_disk_eject_toggle_mbtn = "nul"\ninput_disk_next = "nul"\ninput_disk_next_axis = "nul"\ninput_disk_next_btn = "nul"\ninput_disk_next_mbtn = "nul"\ninput_disk_prev = "nul"\ninput_disk_prev_axis = "nul"\ninput_disk_prev_btn = "nul"\ninput_disk_prev_mbtn = "nul"\ninput_duty_cycle = "nul"\ninput_enable_hotkey = "nul"\ninput_enable_hotkey_axis = "nul"\ninput_enable_hotkey_btn = "nul"\ninput_enable_hotkey_mbtn = "nul"\ninput_exit_emulator = "nul"\ninput_exit_emulator_axis = "nul"\ninput_exit_emulator_btn = "nul"\ninput_exit_emulator_mbtn = "nul"\ninput_fps_toggle = "nul"\ninput_fps_toggle_axis = "nul"\ninput_fps_toggle_btn = "nul"\ninput_fps_toggle_mbtn = "nul"\ninput_frame_advance = "nul"\ninput_frame_advance_axis = "nul"\ninput_frame_advance_btn = "nul"\ninput_frame_advance_mbtn = "nul"\ninput_game_focus_toggle = "nul"\ninput_game_focus_toggle_axis = "nul"\ninput_game_focus_toggle_btn = "nul"\ninput_game_focus_toggle_mbtn = "nul"\ninput_grab_mouse_toggle = "nul"\ninput_grab_mouse_toggle_axis = "nul"\ninput_grab_mouse_toggle_btn = "nul"\ninput_grab_mouse_toggle_mbtn = "nul"\ninput_hold_fast_forward = "nul"\ninput_hold_fast_forward_axis = "nul"\ninput_hold_fast_forward_btn = "nul"\ninput_hold_fast_forward_mbtn = "nul"\ninput_hold_slowmotion = "nul"\ninput_slowmotion = "nul"\ninput_hold_slowmotion_axis = "nul"\ninput_hold_slowmotion_btn = "nul"\ninput_hold_slowmotion_mbtn = "nul"\ninput_hotkey_block_delay = "nul"\ninput_load_state_axis = "nul"\ninput_load_state_btn = "nul"\ninput_load_state_mbtn = "nul"\ninput_menu_toggle_axis = "nul"\ninput_menu_toggle_btn = "nul"\ninput_menu_toggle_mbtn = "nul"\ninput_movie_record_toggle = "nul"\ninput_movie_record_toggle_axis = "nul"\ninput_movie_record_toggle_btn = "nul"\ninput_movie_record_toggle_mbtn = "nul"\ninput_netplay_game_watch = "nul"\ninput_netplay_game_watch_axis = "nul"\ninput_netplay_game_watch_btn = "nul"\ninput_netplay_game_watch_mbtn = "nul"\ninput_netplay_host_toggle = "nul"\ninput_netplay_host_toggle_axis = "nul"\ninput_netplay_host_toggle_btn = "nul"\ninput_netplay_host_toggle_mbtn = "nul"\ninput_osk_toggle = "nul"\ninput_osk_toggle_axis = "nul"\ninput_osk_toggle_btn = "nul"\ninput_osk_toggle_mbtn = "nul"\ninput_overlay_next = "nul"\ninput_overlay_next_axis = "nul"\ninput_overlay_next_btn = "nul"\ninput_overlay_next_mbtn = "nul"\ninput_pause_toggle = "nul"\ninput_pause_toggle_axis = "nul"\ninput_pause_toggle_btn = "nul"\ninput_pause_toggle_mbtn = "nul"\ninput_player1_a_axis = "nul"\ninput_player1_a_btn = "nul"\ninput_player1_a_mbtn = "nul"\ninput_player1_b_axis = "nul"\ninput_player1_b_btn = "nul"\ninput_player1_b_mbtn = "nul"\ninput_player1_down_axis = "nul"\ninput_player1_down_btn = "nul"\ninput_player1_down_mbtn = "nul"\ninput_player1_gun_aux_a = "nul"\ninput_player1_gun_aux_a_axis = "nul"\ninput_player1_gun_aux_a_btn = "nul"\ninput_player1_gun_aux_a_mbtn = "nul"\ninput_player1_gun_aux_b = "nul"\ninput_player1_gun_aux_b_axis = "nul"\ninput_player1_gun_aux_b_btn = "nul"\ninput_player1_gun_aux_b_mbtn = "nul"\ninput_player1_gun_aux_c = "nul"\ninput_player1_gun_aux_c_axis = "nul"\ninput_player1_gun_aux_c_btn = "nul"\ninput_player1_gun_aux_c_mbtn = "nul"\ninput_player1_gun_dpad_down = "nul"\ninput_player1_gun_dpad_down_axis = "nul"\ninput_player1_gun_dpad_down_btn = "nul"\ninput_player1_gun_dpad_down_mbtn = "nul"\ninput_player1_gun_dpad_left = "nul"\ninput_player1_gun_dpad_left_axis = "nul"\ninput_player1_gun_dpad_left_btn = "nul"\ninput_player1_gun_dpad_left_mbtn = "nul"\ninput_player1_gun_dpad_right = "nul"\ninput_player1_gun_dpad_right_axis = "nul"\ninput_player1_gun_dpad_right_btn = "nul"\ninput_player1_gun_dpad_right_mbtn = "nul"\ninput_player1_gun_dpad_up = "nul"\ninput_player1_gun_dpad_up_axis = "nul"\ninput_player1_gun_dpad_up_btn = "nul"\ninput_player1_gun_dpad_up_mbtn = "nul"\ninput_player1_gun_offscreen_shot = "nul"\ninput_player1_gun_offscreen_shot_axis = "nul"\ninput_player1_gun_offscreen_shot_btn = "nul"\ninput_player1_gun_offscreen_shot_mbtn = "nul"\ninput_player1_gun_select = "nul"\ninput_player1_gun_select_axis = "nul"\ninput_player1_gun_select_btn = "nul"\ninput_player1_gun_select_mbtn = "nul"\ninput_player1_gun_start = "nul"\ninput_player1_gun_start_axis = "nul"\ninput_player1_gun_start_btn = "nul"\ninput_player1_gun_start_mbtn = "nul"\ninput_player1_gun_trigger = "nul"\ninput_player1_gun_trigger_axis = "nul"\ninput_player1_gun_trigger_btn = "nul"\ninput_player1_gun_trigger_mbtn = "nul"\ninput_player1_l2_axis = "nul"\ninput_player1_l2_btn = "nul"\ninput_player1_l2_mbtn = "nul"\ninput_player1_l3 = "nul"\ninput_player1_l3_axis = "nul"\ninput_player1_l3_mbtn = "nul"\ninput_player1_l_axis = "nul"\ninput_player1_l_btn = "nul"\ninput_player1_l_mbtn = "nul"\ninput_player1_l_x_minus_axis = "nul"\ninput_player1_l_x_minus_btn = "nul"\ninput_player1_l_x_minus_mbtn = "nul"\ninput_player1_l_x_plus_axis = "nul"\ninput_player1_l_x_plus_btn = "nul"\ninput_player1_l_x_plus_mbtn = "nul"\ninput_player1_l_y_minus_axis = "nul"\ninput_player1_l_y_minus_btn = "nul"\ninput_player1_l_y_minus_mbtn = "nul"\ninput_player1_l_y_plus_axis = "nul"\ninput_player1_l_y_plus_btn = "nul"\ninput_player1_l_y_plus_mbtn = "nul"\ninput_player1_left_axis = "nul"\ninput_player1_left_mbtn = "nul"\ninput_player1_r2_axis = "nul"\ninput_player1_r2_btn = "nul"\ninput_player1_r2_mbtn = "nul"\ninput_player1_r3 = "nul"\ninput_player1_r3_axis = "nul"\ninput_player1_r3_mbtn = "nul"\ninput_player1_r_axis = "nul"\ninput_player1_r_btn = "nul"\ninput_player1_r_mbtn = "nul"\ninput_player1_r_x_minus_axis = "nul"\ninput_player1_r_x_minus_btn = "nul"\ninput_player1_r_x_minus_mbtn = "nul"\ninput_player1_r_x_plus_axis = "nul"\ninput_player1_r_x_plus_btn = "nul"\ninput_player1_r_x_plus_mbtn = "nul"\ninput_player1_r_y_minus_axis = "nul"\ninput_player1_r_y_minus_btn = "nul"\ninput_player1_r_y_minus_mbtn = "nul"\ninput_player1_r_y_plus_axis = "nul"\ninput_player1_r_y_plus_btn = "nul"\ninput_player1_r_y_plus_mbtn = "nul"\ninput_player1_right_axis = "nul"\ninput_player1_right_mbtn = "nul"\ninput_player1_select_axis = "nul"\ninput_player1_select_btn = "nul"\ninput_player1_select_mbtn = "nul"\ninput_player1_start_axis = "nul"\ninput_player1_start_btn = "nul"\ninput_player1_start_mbtn = "nul"\ninput_player1_turbo = "nul"\ninput_player1_turbo_axis = "nul"\ninput_player1_turbo_btn = "nul"\ninput_player1_turbo_mbtn = "nul"\ninput_player1_up_axis = "nul"\ninput_player1_up_btn = "nul"\ninput_player1_up_mbtn = "nul"\ninput_player1_x_axis = "nul"\ninput_player1_x_btn = "nul"\ninput_player1_x_mbtn = "nul"\ninput_player1_y_axis = "nul"\ninput_player1_y_btn = "nul"\ninput_player1_y_mbtn = "nul"\ninput_poll_type_behavior = "nul"\ninput_recording_toggle = "nul"\ninput_recording_toggle_axis = "nul"\ninput_recording_toggle_btn = "nul"\ninput_recording_toggle_mbtn = "nul"\ninput_reset = "nul"\ninput_reset_axis = "nul"\ninput_reset_btn = "nul"\ninput_reset_mbtn = "nul"\ninput_rewind = "nul"\ninput_rewind_axis = "nul"\ninput_rewind_btn = "nul"\ninput_rewind_mbtn = "nul"\ninput_save_state_axis = "nul"\ninput_save_state_btn = "nul"\ninput_save_state_mbtn = "nul"\ninput_screenshot = "nul"\ninput_screenshot_axis = "nul"\ninput_screenshot_btn = "nul"\ninput_screenshot_mbtn = "nul"\ninput_send_debug_info = "nul"\ninput_send_debug_info_axis = "nul"\ninput_send_debug_info_btn = "nul"\ninput_send_debug_info_mbtn = "nul"\ninput_shader_next = "nul"\ninput_shader_next_axis = "nul"\ninput_shader_next_btn = "nul"\ninput_shader_next_mbtn = "nul"\ninput_shader_prev = "nul"\ninput_shader_prev_axis = "nul"\ninput_shader_prev_btn = "nul"\ninput_shader_prev_mbtn = "nul"\ninput_state_slot_decrease = "nul"\ninput_state_slot_decrease_axis = "nul"\ninput_state_slot_decrease_btn = "nul"\ninput_state_slot_decrease_mbtn = "nul"\ninput_state_slot_increase = "nul"\ninput_state_slot_increase_axis = "nul"\ninput_state_slot_increase_btn = "nul"\ninput_state_slot_increase_mbtn = "nul"\ninput_streaming_toggle = "nul"\ninput_streaming_toggle_axis = "nul"\ninput_streaming_toggle_btn = "nul"\ninput_streaming_toggle_mbtn = "nul"\ninput_toggle_fast_forward = "nul"\ninput_toggle_fast_forward_axis = "nul"\ninput_toggle_fast_forward_btn = "nul"\ninput_toggle_fast_forward_mbtn = "nul"\ninput_toggle_fullscreen = "nul"\ninput_toggle_fullscreen_axis = "nul"\ninput_toggle_fullscreen_btn = "nul"\ninput_toggle_fullscreen_mbtn = "nul"\ninput_toggle_slowmotion = "nul"\ninput_toggle_slowmotion_axis = "nul"\ninput_toggle_slowmotion_btn = "nul"\ninput_toggle_slowmotion_mbtn = "nul"\ninput_turbo_default_button = "nul"\ninput_turbo_mode = "nul"\ninput_turbo_period = "nul"\ninput_volume_down = "nul"\ninput_volume_down_axis = "nul"\ninput_volume_down_btn = "nul"\ninput_volume_down_mbtn = "nul"\ninput_volume_up = "nul"\ninput_volume_up_axis = "nul"\ninput_volume_up_btn = "nul"\ninput_volume_up_mbtn = "nul"\n';12var extraConfig = 'rgui_show_start_screen = "false"\n';13var pdKeys = [8, 9, 13, 19, 27, 32, 33, 34, 35, 36, 42, 44, 45, 91, 92, 93, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135];14var webretroVersion = 6.3;15var updateNotice = document.getElementById("updatenotice");16var versionIndicator = document.getElementById("versionindicator");17var upload = document.getElementById("upload");18var googleDriveUpload = document.getElementById("googledriveupload");19var dropboxUpload = document.getElementById("dropboxupload");20var oneDriveUpload = document.getElementById("onedriveupload");21var startButton = document.getElementById("startbutton");22var smooth = document.getElementById("smooth");23var doubleRes = document.getElementById("doubleres");24var resModifier = 1;25var canvas = document.getElementById("canvas");26var canvasMask = document.getElementById("canvasmask");27var dateTime = new Date();28var saveState = document.getElementById("savestate");29var loadState = document.getElementById("loadstate");30var undoSaveState = document.getElementById("undosavestate");31var undoLoadState = document.getElementById("undoloadstate");32var exportState = document.getElementById("exportstate");33var importState = document.getElementById("importstate");34var ffd = document.getElementById("ffd");35var ffdContent = document.getElementById("ffdcontent");36var systemName = document.getElementById("systemname");37var consoleButton = document.getElementById("consolebutton");38var menuButton = document.getElementById("menubutton");39var pauseButton = document.getElementById("pause");40var resumeOverlay = document.getElementById("resume");41var sideAlertHolder = document.getElementById("sidealertholder");42var saveGame = document.getElementById("savegame");43var exportSave = document.getElementById("exportsave");44var importSave = document.getElementById("importsave");45var autosave = document.getElementById("autosave");46var mainArea = document.getElementById("mainarea");47var hoverMenu = document.getElementById("menu");48var hoverMenuIndicator = document.getElementById("menuindicator");49var search = decodeURIComponent(window.location.search).substring(1).split("&");50var systems = {"beetle_psx": "PS1", "citra": "Nintendo 3DS", "desmume": "Nintendo DS", "dolphin": "GC/Wii", "genesis_plus_gx": "Genesis", "mgba": "GBA", "mupen64plus_next": "Nintendo 64", "nestopia": "NES", "parallel_n64": "Nintendo 64", "ppsspp": "PSP", "snes9x": "SNES"};51var installedCores = ["genesis_plus_gx", "mgba", "mupen64plus_next", "nestopia", "snes9x"];52var fileExts = {"GBA": ".gb, .gbc, .gba", "GC/Wii": ".iso, .gcm, .dol, .tgc, .wbfs, .ciso, .gcz, .wad", "Genesis": ".mdx, .md, .smd, .gen, .sms, .gg, .sg, .68k, .chd", "NES": ".nes, .fds, .unf, .unif", "Nintendo 64": ".n64, .v64, .z64, .u1, .ndd", "Nintendo 3DS": ".3ds, .3dsx, .cci, .cxi", "Nintendo DS": ".nds, .srl", "PS1": ".ccd, .iso", "PSP": ".cso, .pbp", "SNES": ".smc, .sfc, .swc, .fig, .bs, .st"};53var allFileExts = Object.values(fileExts).join(", ");54var allValidFileExts = [];55for (var i = 0; i < installedCores.length; i++) {56allValidFileExts.push(fileExts[systems[installedCores[i]]]);57}58allValidFileExts = allValidFileExts.join(", ");59var baseFsBundleDir = "/home/web_user/retroarch/bundle";60var awaitLogQueue = {};61var bundleErrors = 0;62var sramExt = ".srm";63var smasBrickFix = {"16a160ddd431a3db6fcd7453ffae9c4c": [80,65,84,67,72,0,127,160,0,8,169,1,133,160,141,0,22,107,1,191,182,0,4,34,160,255,0,6,189,164,0,4,34,160,255,0,69,79,70], "e87d43969bdf563d1148e3b35e8b5360": [80,65,84,67,72,0,129,160,0,8,169,1,133,160,141,0,22,107,1,193,182,0,4,34,160,255,0,6,191,164,0,4,34,160,255,0,69,79,70], "2071b049a463cefd7a0b7aeab8037ca0": [80,65,84,67,72,0,127,160,0,8,169,1,133,160,141,0,22,107,1,191,190,0,4,34,160,255,0,6,189,164,0,4,34,160,255,0,69,79,70]}; // Couldn't find SMAS+W SMC ROM [80,65,84,67,72,0,129,160,0,8,169,1,133,160,141,0,22,107,1,193,190,0,4,34,160,255,0,6,191,164,0,4,34,160,255,0,69,79,70]6465// make core lists66var aCoreList = '<li><b>Select a Core</b></li><li><a href="?core=autodetect" class="greyer">AutoDetect (Slower to load)</a></li>';67for (var i = 0; i < installedCores.length; i++) {68aCoreList += '<li><a href="?core=' + installedCores[i] + '">' + installedCores[i] + ' (' + systems[installedCores[i]] + ')</a></li>';69}7071// query string into object72var queries = {};73for (var i = 0; i < search.length; i++) {74var p = search[i].split("=");75queries[p[0]] = p[1];76}7778// Binary to UTF-879function u8atoutf8(data) {80return new TextDecoder().decode(data);81}8283function avShift(array, shift) {84for (var i = 0; i < array.length; i++) {85array[i] += shift;86}87return array;88}8990// key press stuff91function fakeKey(type, info) {92var e = new KeyboardEvent(type, {code: info.code || undefined, key: info.key || undefined, shiftKey: info.shiftKey || undefined});93document.dispatchEvent(e);94}9596function fakeKeyPress(info) {97fakeKey("keydown", info);98window.setTimeout(function() {99fakeKey("keyup", info);100}, 50);101}102103function fakeCharPress(key) {104if (charToCodeMap.hasOwnProperty(key)) fakeKeyPress({code: charToCodeMap[key].code, key: charToKeyMap.hasOwnProperty(key) ? charToKeyMap[key].key : key, shiftKey: charToCodeMap[key].hasOwnProperty("shift") ? true : false});105}106107function sendText(text) {108for (var i = 0; i < text.length; i++) {109fakeCharPress(text.charAt(i));110}111}112113// indexedDB114function openIdb() {115var request = indexedDB.open("webretro", 1);116request.onsuccess = function(e) {117wIdb = e.target.result;118}119request.onupgradeneeded = function(e) {120var store = e.target.result.createObjectStore("main", {keyPath: "key"});121store.transaction.oncomplete = function(e2) {122wIdb = e.target.db;123}124}125}126127openIdb();128129function setIdbItem(key, value) {130wIdb.transaction("main", "readwrite").objectStore("main").put({key: key, value: value});131}132133function getIdbItem(key) {134return new Promise(function(resolve) {135wIdb.transaction("main", "readwrite").objectStore("main").get(key).onsuccess = function(e) {136resolve(e.target.result ? e.target.result.value : null);137}138});139}140141// localStorage to indexedDB142async function tryLsToIdb() {143var ls = Object.keys(window.localStorage);144for (var i = 0; i < ls.length; i++) {145if (ls[i].startsWith("RetroArch_")) {146setIdbItem(ls[i], new Uint8Array(JSON.parse(window.localStorage.getItem(ls[i]))));147window.localStorage.removeItem(ls[i]);148}149if (i == ls.length - 1) return;150}151}152153// side alerts154function sideAlert(initialText, time) {155var p = document.createElement("p");156p.className = "sidealert";157p.appendChild(document.createTextNode(initialText));158sideAlertHolder.appendChild(p);159window.setTimeout(function() {160p.classList.add("on");161}, 10);162this.dismiss = function() {163p.classList.remove("on");164window.setTimeout(function() {165p.remove();166}, 100);167}168this.setText = function(text) {169p.textContent = text;170}171if (time) window.setTimeout(this.dismiss, time);172}173174// change background for status messages175function setStatus(message) {176loadStatus = message;177canvas.style.backgroundImage = 'url("data:image/svg+xml;base64,' + btoa('<svg xmlns="http://www.w3.org/2000/svg" width="150" height="150"><text style="font: 30px sans-serif;" fill="white" x="50%" y="40%" dominant-baseline="middle" text-anchor="middle">Loading</text><text style="font: 15px sans-serif;" fill="white" x="50%" y="60%" dominant-baseline="middle" text-anchor="middle">' + message + '</text></svg>') + '")';178}179180// remove status messages181function removeStatus(message) {182if (loadStatus === message) setStatus("");183}184185// adjust canvas size to window186function adjustCanvasSize() {187if (window.innerHeight >= window.innerWidth * (3/4)) {188var s = window.innerWidth;189var t = Math.floor(s * (3/4));190Module.setCanvasSize(s * resModifier, t * resModifier);191canvasMask.style.width = s + "px";192canvasMask.style.height = t + "px";193} else {194var s = window.innerHeight;195var t = Math.floor(s * (4/3));196Module.setCanvasSize(t * resModifier, s * resModifier);197canvasMask.style.width = t + "px";198canvasMask.style.height = s + "px";199}200}201202// logging203function log(log, userInput) {204console.log(log);205wconsole.textContent += (userInput ? "> " + userInput + "\n\t" + JSON.stringify(log) : log) + "\n";206wconsole.scrollTo({top: wconsole.scrollHeight});207208if (typeof log == "string") {209// export state210if (log.includes("New state file is ready to be read")) saveStateFunc();211212// await log queue213if (Object.keys(awaitLogQueue).length) {214var lq = Object.keys(awaitLogQueue);215for (var i = 0; i < lq.length; i++) {216if (log.toLowerCase().includes(lq[i].toLowerCase())) {217awaitLogQueue[lq[i]](log);218delete awaitLogQueue[lq[i]];219}220}221}222}223}224225function awaitLog(contains, callback, timeout, expire) {226awaitLogQueue[contains] = callback;227if (timeout && !isNaN(timeout)) {228window.setTimeout(function() {229if (awaitLogQueue[contains]) {230expire();231delete awaitLogQueue[contains];232}233}, timeout);234}235}236237// xhr238function grab(url, type, success, fail) {239var req = new XMLHttpRequest();240req.open("GET", url, true);241req.overrideMimeType("text/plain; charset=x-user-defined");242req.responseType = type;243req.onload = function() {244if (req.status >= "400") {245if (fail) fail(req.status);246} else {247if (success) success(this.response);248}249}250req.send();251}252253// file readers254function readFile(file, callback) {255var reader = new FileReader();256reader.onload = function() {257callback(this.result);258}259reader.readAsArrayBuffer(file);260}261262function downloadFile(data, name) {263var a = document.createElement("a");264a.download = name;265a.href = URL.createObjectURL(new Blob([data], {type: "application/octet-stream"}));266a.click();267window.setTimeout(function() {268URL.revokeObjectURL(a.href);269}, 2000);270}271272function uploadFile(accept, callback) {273var input = document.createElement("input");274input.type = "file";275input.accept = accept;276input.onchange = function() {277readFile(this.files[0], function(data) {278callback(data);279});280}281input.click();282}283284// scripts285function getScript(url, callback, err) {286var script = document.createElement("script");287script.type = "text/javascript";288script.src = url;289script.onload = function() {290if (callback) callback();291}292script.onerror = function(e) {293document.body.removeChild(script);294if (err) err(e);295}296document.body.appendChild(script);297}298299function getCore(name, callback, err) {300getScript("./" + name + "_libretro.js", callback, err);301}302303// check for updates304function checkForUpdates() {305grab("https://cdn.jsdelivr.net/gh/BinBashBanana/webretro@latest/assets/info.json", "text", function(text) {306try {307var updateObj = JSON.parse(text);308if (updateObj.webretro) {309latestVersion = updateObj.webretro;310if (updateObj.versions[webretroVersion.toString()]) versionIndicator.title = "New features in this version:\n\n- " + updateObj.versions[webretroVersion.toString()].changeList.join("\n- ");311if (latestVersion > webretroVersion && updateObj.versions[latestVersion.toString()]) {312updateNotice.textContent = "New webretro version available: v" + latestVersion.toString() + ". Features:\n\n- " + updateObj.versions[latestVersion.toString()].changeList.join("\n- ") + "\n\nThe site owner(s) can apply the update.";313updateNotice.style.display = "initial";314}315}316} catch (e) {317log(e);318}319});320}321322// unzip file323function unzipFile(data, exts, callback, empty, notfound) {324new zip.ZipReader(new zip.Uint8ArrayReader(data)).getEntries().then(function(entries) {325if (entries.length) {326for (var i = 0; i < entries.length; i++) {327if (exts.split(", ").includes("." + u8atoutf8(entries[i].rawFilename).split(".").slice(-1)[0])) {328let name = u8atoutf8(entries[i].rawFilename);329entries[i].getData(new zip.Uint8ArrayWriter()).then(function(uzd) {330callback(name, uzd);331});332break;333}334if (i == entries.length - 1 && notfound) notfound();335}336} else if (empty) empty();337});338}339340// uauth uploads341function handleWebFile(data) {342if (data.message == "success") {343ffd.style.display = "none";344romUploadCallback(data.name, data.data);345} else if (data.message == "error") {346alert("There was an error with the file picker. This may mean that you have to allow popup windows.");347}348}349350function uploadWebFile(type, exts) {351uauth.open(type, exts.split(", "), handleWebFile);352}353354// rom upload355function readyRomUploads(exts) {356upload.setAttribute("accept", exts);357358// when a rom is uploaded359upload.onchange = function() {360ffd.style.display = "none";361let file = this.files[0];362readFile(file, function(data) {363log('Succesfully read ROM file "' + file.name + '"');364romUploadCallback(file.name, data);365});366}367368// web uploads369googleDriveUpload.onclick = function() {370uploadWebFile("drive", exts);371}372dropboxUpload.onclick = function() {373uploadWebFile("dropbox", exts);374}375oneDriveUpload.onclick = function() {376uploadWebFile("onedrive", exts);377}378379// file drop380document.ondragenter = function(e) {381if (e.dataTransfer.types.includes("Files")) ffd.classList.add("filehover");382}383document.ondragover = function(e) {384e.preventDefault();385}386document.ondrop = function(e) {387if (e.dataTransfer.types.includes("Files")) {388e.preventDefault();389ffd.style.display = "none";390let file = event.dataTransfer.files[0];391readFile(file, function(data) {392log('Succesfully read ROM file "' + file.name + '"');393romUploadCallback(file.name, data);394});395}396}397}398399// rom fetch400function readyRomFetch() {401var romloc = /^(http:\/\/|https:\/\/|\/\/)/i.test(queries.rom) ? queries.rom : "roms/" + queries.rom;402var romFilename = queries.rom.split("/").slice(-1)[0];403grab(romloc, "arraybuffer", function(data) {404log("Succesfully fetched ROM from " + romloc);405romMode = "querystring";406romUploadCallback(romFilename, data);407}, function(error) {408alert("Could not get ROM at " + romloc + " (Error " + error + ")");409romMode = "upload";410ffd.style.display = "block";411});412}413414// console window415var conw = new jswindow({title: "Console", icon: "assets/terminal.svg"});416417var wconsole = document.createElement("textarea");418wconsole.classList.add("console");419wconsole.setAttribute("spellcheck", "false");420wconsole.setAttribute("readonly", "");421422wconsole.wconsolemarker = document.createElement("span");423wconsole.wconsolemarker.classList.add("consolemarker");424425wconsole.wconsoleinput = document.createElement("input");426wconsole.wconsoleinput.type = "text";427wconsole.wconsoleinput.classList.add("consoleinput");428wconsole.wconsoleinput.title = "You can type things here as though you were using the browser console.";429wconsole.wconsoleinput.setAttribute("spellcheck", "false");430wconsole.wconsolemarker.onclick = function() { wconsole.wconsoleinput.focus(); }431wconsole.wconsoleinput.onkeydown = function(e) {432e.stopPropagation();433if (e.keyCode == 13) {434log(eval(this.value), this.value);435this.value = "";436}437}438439conw.innerWindow.appendChild(wconsole);440conw.innerWindow.appendChild(wconsole.wconsolemarker);441conw.innerWindow.appendChild(wconsole.wconsoleinput);442443consoleButton.onclick = function() {444conw.open({width: 450, height: 250, left: 100, top: 50});445wconsole.wconsoleinput.focus();446wconsole.scrollTo({top: wconsole.scrollHeight});447}448449if (queries.hasOwnProperty("console")) conw.open({width: 450, height: 250, left: 100, top: 50});450451// ---------- START LOAD ----------452(function() {453// ?system query454if (!queries.core && queries.system) {455var detectedCore = Object.keys(systems).find(k => systems[k].toLowerCase() == queries.system.toLowerCase());456if (installedCores.includes(detectedCore)) {457queries.core = detectedCore;458} else if (queries.system.toLowerCase() == "autodetect") {459queries.core = "autodetect";460} else {461alert("Invalid core (" + detectedCore + ")");462}463}464465// ?core query466if (queries.core) {467if (!window.navigator.userAgent.toLowerCase().includes("chrom")) alert("Best performance on Chrome!");468469// show hover menu470hoverMenu.style.display = "block";471472versionIndicator.textContent = "v" + webretroVersion.toString();473checkForUpdates();474475if (queries.core.toLowerCase() == "autodetect") {476romUploadCallback = autodetectCoreHandler;477systemName.textContent = "";478readyRomUploads(".zip, " + allFileExts);479} else {480romUploadCallback = initFromFile;481core = queries.core;482483setStatus("Getting core");484if (core == "desmume") sramExt = ".dsv";485// detect system for ROM upload486systemName.textContent = systems[core] || "";487488getCore(core, function() {489removeStatus("Getting core");490log("Got core: " + core);491if (romMode != "querystring") document.title = core + " | webretro";492493readyRomUploads(".zip, .bin, " + fileExts[systems[core]]);494}, function() {495// core loading error496alert('Could not load specified core "' + core + '". Here is a list of available cores.');497ffdContent.innerHTML = "<ul>" + aCoreList + "</ul>";498ffd.style.display = "block";499});500}501502// ?rom query503if (queries.rom) {504readyRomFetch();505} else {506// prompt user to upload ROM file507romMode = "upload";508ffd.style.display = "block";509}510} else {511// no core specified512ffdContent.innerHTML = "<ul>" + aCoreList + "</ul>";513ffd.style.display = "block";514}515})();516// ----------- END LOAD -----------517518// start emulator from file name and data519function initFromFile(name, data) {520var dataView = new Uint8Array(data);521if (name.split(".").slice(-1)[0] == "zip") {522log("Zip file detected, unzipping...");523524unzipFile(dataView, fileExts[systems[core]], function(name, contents) {525romName = name.split(".")[0];526readyForInit(contents);527}, function() {528alert("That zip file appears to be empty!");529}, function() {530alert("Couldn't find a valid ROM file in that zip file. Are you using the right core? This is " + systems[core] + ". (The ROM has to be at the base directory of the zip file)");531});532} else {533romName = name.split(".")[0];534readyForInit(dataView);535}536}537538// autodetect core mode539function autodetectCoreHandler(name, data) {540var dataView = new Uint8Array(data);541if (name.split(".").slice(-1)[0] == "zip") {542log("Zip file detected, unzipping...");543544unzipFile(dataView, allFileExts, function(name, contents) {545romName = name.split(".")[0];546autodetectCore(name, contents);547}, function() {548alert("That zip file appears to be empty!");549}, function() {550alert("Couldn't find a valid ROM file in that zip file. (The ROM has to be at the base directory of the zip file)");551});552} else {553romName = name.split(".")[0];554autodetectCore(name, dataView);555}556}557558function autodetectCore(name, data) {559var nameExt = "." + name.split(".").slice(-1)[0];560var detectedCore;561var fileExtsArray = Object.keys(fileExts);562for (var i = 0; i < fileExtsArray.length; i++) {563if (fileExts[fileExtsArray[i]].split(", ").includes(nameExt)) {564detectedCore = Object.keys(systems).find(k => systems[k] == fileExtsArray[i]);565break;566}567}568569var detectedSystem = systems[detectedCore] || "unknown";570detectedCore = detectedCore || "unknown";571572if (allValidFileExts.split(", ").includes(nameExt)) {573core = detectedCore;574575setStatus("Getting core");576if (core == "desmume") sramExt = ".dsv";577578getCore(core, function() {579removeStatus("Getting core");580log("Got core: " + core);581readyForInit(data);582});583} else {584alert("That is a " + detectedSystem + " file! " + detectedCore + " (" + detectedSystem + ") is not currently supported.");585}586}587588// if the ROM is specified in the querystring, we will need to wait until the user has clicked to start the emulator589function readyForInit(data) {590document.title = romName + " | webretro";591592// do I want to put this in the docs?593if (queries.romshift) data = avShift(data, parseInt(queries.romshift));594595if (romMode == "querystring") {596startButton.style.display = "initial";597startButton.onclick = function() {598startButton.style.display = "none";599initFromData(data);600}601} else {602initFromData(data);603}604}605606// prepare FS with bundle607function prepareBundle() {608setStatus("Getting assets");609log("Starting bundle fetch");610let bundleSTime = performance.now();611fsBundleDirs = [['', 'assets'], ['/assets', 'menu_widgets'], ['/assets', 'ozone'], ['/assets/ozone', 'png'], ['/assets/ozone/png', 'dark'], ['/assets/ozone/png', 'sidebar'], ['/assets', 'xmb'], ['/assets/xmb', 'monochrome'], ['/assets/xmb/monochrome', 'png']]612FS.createPath("/", "home/web_user/retroarch/bundle", true, true);613for (var i = 0; i < fsBundleDirs.length; i++) {614FS.createPath(baseFsBundleDir + fsBundleDirs[i][0], fsBundleDirs[i][1], true, true);615}616617grab(bundleCdn + "bundle/indexedfiles.txt", "text", function(data) {618fsBundleFiles = data.split("\n");619for (let i = 0; i < fsBundleFiles.length; i++) {620grab(bundleCdn + "bundle" + fsBundleFiles[i], "arraybuffer", function(data) {621FS.writeFile(baseFsBundleDir + fsBundleFiles[i], new Uint8Array(data));622if (i == fsBundleFiles.length - 1) donePreparingBundle(performance.now() - bundleSTime);623}, function() {624bundleErrors += 1;625if (i == fsBundleFiles.length - 1) donePreparingBundle(performance.now() - bundleSTime);626});627}628}, function() {629log("Failed to get asset bundle, skipping");630bundleReady = true;631removeStatus("Getting assets");632});633}634635function donePreparingBundle(tooktime) {636bundleReady = true;637removeStatus("Getting assets");638log("Finished bundle fetch in " + (tooktime / 1000).toFixed(1) + " seconds, " + bundleErrors + " errors");639}640641// tell the user to not rename the rom642function doNotRename() {643if (romMode == "upload" && !window.localStorage.getItem("webretro_settings_pastFirstSave")) {644alert("WARNING: Do not rename your ROM file after this! The save data is specific to the ROM name!");645window.localStorage.setItem("webretro_settings_pastFirstSave", "true");646}647}648649// save game650function saveSRAM() {651Module._cmd_savefiles();652window.setTimeout(function() {653if (FS.analyzePath("/home/web_user/retroarch/userdata/saves/rom" + sramExt).exists) {654setIdbItem("RetroArch_saves_" + romName, FS.readFile("/home/web_user/retroarch/userdata/saves/rom" + sramExt));655new sideAlert("Saved", 3000);656readySaveReaders();657658doNotRename();659} else {660autosave.checked = false;661new sideAlert("This game does not save!", 3000);662}663}, 1000);664}665666// save state667function saveStateFunc() {668window.setTimeout(function() {669if (FS.analyzePath("/home/web_user/retroarch/userdata/states/rom.state").exists) {670setIdbItem("RetroArch_states_" + romName, FS.readFile("/home/web_user/retroarch/userdata/states/rom.state"));671672doNotRename();673} else {674new sideAlert("There was an error saving state. Please try again.", 5000);675}676}, 100);677}678679// autosaving680function autosaveSRAM() {681if (autosave.checked && !document.hidden && !isPaused) {682new sideAlert("Autosaving...", 3000);683saveSRAM();684}685window.setTimeout(function() {686autosaveSRAM();687}, 300000);688}689690// more functions for state buttons691function readyStateReaders() {692if (!stateReadersReady) {693stateReadersReady = true;694695loadState.classList.remove("disabled");696exportState.classList.remove("disabled");697undoSaveState.classList.remove("disabled");698699loadState.onclick = function() {700Module._cmd_load_state();701readyStateReaders2();702}703exportState.onclick = function() {704downloadFile(FS.readFile("/home/web_user/retroarch/userdata/states/rom.state"), "game-state-"+romName+"-"+dateTime.getFullYear().toString()+"-"+(dateTime.getMonth()+1).toString()+"-"+dateTime.getDate().toString()+"-"+dateTime.getHours().toString()+"-"+dateTime.getMinutes().toString() + ".state");705}706undoSaveState.onclick = function() {707Module._cmd_undo_save_state();708}709// also allow statereaders2 on F3 press710document.addEventListener("keydown", function(e) {711if (e.key == "F3") readyStateReaders2();712}, false);713}714}715716// even more functions for state buttons717function readyStateReaders2() {718if (!stateReaders2Ready) {719stateReaders2Ready = true;720721undoLoadState.classList.remove("disabled");722undoLoadState.onclick = function() {723Module._cmd_undo_load_state();724}725}726}727728// more functions for save buttons729function readySaveReaders() {730if (!saveReadersReady) {731saveReadersReady = true;732733exportSave.classList.remove("disabled");734735exportSave.onclick = function() {736downloadFile(FS.readFile("/home/web_user/retroarch/userdata/saves/rom" + sramExt), "game-sram-"+romName+"-"+dateTime.getFullYear().toString()+"-"+(dateTime.getMonth()+1).toString()+"-"+dateTime.getDate().toString()+"-"+dateTime.getHours().toString()+"-"+dateTime.getMinutes().toString() + sramExt);737}738}739}740741// runs after emulator starts742function afterStart() {743// remove loading text744canvas.style.background = "none";745746adjustCanvasSize();747748// functions for save and state buttons749saveState.classList.remove("disabled");750importState.classList.remove("disabled");751saveGame.classList.remove("disabled");752importSave.classList.remove("disabled");753autosave.removeAttribute("disabled");754autosave.parentElement.classList.remove("disabled");755756saveState.onclick = function() {757Module._cmd_save_state();758readyStateReaders();759}760importState.onclick = function() {761uploadFile(".bin, .state, .save, .dat, .gam, .sav, application/*", function(data) {762setIdbItem("RetroArch_states_" + romName, new Uint8Array(data));763FS.writeFile("/home/web_user/retroarch/userdata/states/rom.state", new Uint8Array(data));764new sideAlert("Imported state", 3000);765readyStateReaders();766});767}768769saveGame.onclick = function() {770new sideAlert("Saving...", 3000);771saveSRAM();772}773importSave.onclick = function() {774uploadFile(".bin, .srm, .sram, .ram, .gam, .sav, .dsv, application/*", function(data) {775autosave.checked = false;776setIdbItem("RetroArch_saves_" + romName, new Uint8Array(data));777if (confirm("Save imported. Reloading now for changes to take effect.")) {778window.onbeforeunload = function() {}779window.location.reload();780}781});782}783784// also allow state readers on F2 press785document.addEventListener("keydown", function(e) {786if (e.key == "F2") readyStateReaders();787}, false);788789// start autosave loop790window.setTimeout(function() {791autosaveSRAM();792}, 300000);793794// toggle between sharp and smooth canvas graphics795smooth.removeAttribute("disabled");796smooth.parentElement.classList.remove("disabled");797smooth.onclick = function() {798if (this.checked) {799canvas.className = "textureSmooth";800} else {801canvas.className = "texturePixelated";802}803}804805// higher resolution806doubleRes.removeAttribute("disabled");807doubleRes.parentElement.classList.remove("disabled");808doubleRes.onclick = function() {809if (this.checked) {810resModifier = 2;811adjustCanvasSize();812} else {813resModifier = 1;814adjustCanvasSize();815}816}817818// pause and resume819pause.classList.remove("disabled");820pause.onclick = function() {821if (this.textContent.trim() == "Pause") {822Module.pauseMainLoop();823isPaused = true;824this.textContent = "Resume";825document.body.classList.add("paused");826} else {827Module.resumeMainLoop();828isPaused = false;829this.textContent = "Pause";830document.body.classList.remove("paused");831}832}833resumeOverlay.onclick = function() {834pause.click();835}836837// toggle menu838menuButton.classList.remove("disabled");839menuButton.onclick = function() {840Module._cmd_toggle_menu();841}842843// flash the menu on first use844if (!window.localStorage.getItem("webretro_settings_pastFirstStart")) {845hoverMenu.classList.add("show");846hoverMenuIndicator.classList.add("show");847window.setTimeout(function() {848hoverMenu.classList.remove("show");849hoverMenuIndicator.classList.remove("show");850}, 3000);851window.localStorage.setItem("webretro_settings_pastFirstStart", "true");852}853854// ctrl+v inside canvas855document.addEventListener("keydown", function(e) {856if (e.ctrlKey && e.key == "v") {857navigator.clipboard.readText().then(function(text) {858fakeKeyPress({code: "Backspace"});859sendText(text);860});861}862}, false);863}864865// start866function initFromData(data) {867window.onbeforeunload = function() { return true; }868async function waitForReady() {869if (wasmReady && bundleReady) {870setStatus("Waiting for emulator");871log("Initializing with " + data.byteLength + " bytes of data");872updateNotice.style.display = "none";873canvas.addEventListener("contextmenu", function(e) {874e.preventDefault();875}, false);876window.addEventListener("resize", adjustCanvasSize, false);877adjustCanvasSize();878879// prevent defaults for key presses880document.addEventListener("keydown", function(e) {881if (pdKeys.includes(e.which)) e.preventDefault();882}, false);883884// move the saves and states from the old version (localStorage) to indexedDB885await tryLsToIdb();886887// rom888FS.writeFile("/rom.bin", data);889890// SMAS brick fix891if (systems[core] == "SNES") {892var hash = md5(u8atoutf8(data));893if (smasBrickFix.hasOwnProperty(hash)) {894FS.writeFile("/rom.ips", new Uint8Array(smasBrickFix[hash]));895new sideAlert("SMAS Bricks Fixed!", 5000);896}897}898899// load save900var cSave = await getIdbItem("RetroArch_saves_" + romName);901if (cSave) {902FS.createPath("/", "home/web_user/retroarch/userdata/saves", true, true);903FS.writeFile("/home/web_user/retroarch/userdata/saves/rom" + sramExt, cSave);904new sideAlert("Save loaded for " + romName, 5000);905log("Save loaded for " + romName);906readySaveReaders();907}908909// import state910var cState = await getIdbItem("RetroArch_states_" + romName);911if (cState) {912FS.createPath("/", "home/web_user/retroarch/userdata/states", true, true);913FS.writeFile("/home/web_user/retroarch/userdata/states/rom.state", cState);914new sideAlert("State imported for " + romName, 5000);915log("State imported for " + romName);916readyStateReaders();917}918919// config920FS.createPath("/", "home/web_user/retroarch/userdata", true, true);921FS.writeFile("/home/web_user/retroarch/userdata/retroarch.cfg", nulKeys + keybinds + extraConfig);922923// start924Module.callMain(Module.arguments);925adjustCanvasSize();926927window.setTimeout(afterStart, 2000);928} else {929window.setTimeout(waitForReady, 1000);930}931}932waitForReady();933}934935var Module = {936canvas: canvas,937noInitialRun: true,938arguments: ["/rom.bin", "--verbose"],939onRuntimeInitialized: function() {940wasmReady = true;941log("WASM compiled");942943// fetch asset bundle944if (queries.hasOwnProperty("nobundle")) {945bundleReady = true;946log("Skipping bundle");947} else {948prepareBundle();949}950},951print: function(text) {952log("stdout: " + text);953},954printErr: function(text) {955log("stderr: " + text);956}957};958959