Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
FogNetwork
GitHub Repository: FogNetwork/Tsunami
Path: blob/main/public/games/files/webretro/assets/base.js
1034 views
1
// Source Code: https://github.com/BinBashBanana/webretro
2
// please dont use IE
3
var indexedDB = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;
4
if (!window.fetch || !indexedDB) {
5
alert("Update your browser!");
6
throw "Update your browser!";
7
}
8
9
var fsBundleDirs, fsBundleFiles, loadStatus, romName, stateReadersReady, stateReaders2Ready, saveReadersReady, isPaused, wasmReady, bundleReady, romMode, core, wIdb, romUploadCallback, latestVersion;
10
var bundleCdn = "https://cdn.jsdelivr.net/gh/BinBashBanana/webretro/";
11
var 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';
12
var 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';
13
var extraConfig = 'rgui_show_start_screen = "false"\n';
14
var 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];
15
var webretroVersion = 6.3;
16
var updateNotice = document.getElementById("updatenotice");
17
var versionIndicator = document.getElementById("versionindicator");
18
var upload = document.getElementById("upload");
19
var googleDriveUpload = document.getElementById("googledriveupload");
20
var dropboxUpload = document.getElementById("dropboxupload");
21
var oneDriveUpload = document.getElementById("onedriveupload");
22
var startButton = document.getElementById("startbutton");
23
var smooth = document.getElementById("smooth");
24
var doubleRes = document.getElementById("doubleres");
25
var resModifier = 1;
26
var canvas = document.getElementById("canvas");
27
var canvasMask = document.getElementById("canvasmask");
28
var dateTime = new Date();
29
var saveState = document.getElementById("savestate");
30
var loadState = document.getElementById("loadstate");
31
var undoSaveState = document.getElementById("undosavestate");
32
var undoLoadState = document.getElementById("undoloadstate");
33
var exportState = document.getElementById("exportstate");
34
var importState = document.getElementById("importstate");
35
var ffd = document.getElementById("ffd");
36
var ffdContent = document.getElementById("ffdcontent");
37
var systemName = document.getElementById("systemname");
38
var consoleButton = document.getElementById("consolebutton");
39
var menuButton = document.getElementById("menubutton");
40
var pauseButton = document.getElementById("pause");
41
var resumeOverlay = document.getElementById("resume");
42
var sideAlertHolder = document.getElementById("sidealertholder");
43
var saveGame = document.getElementById("savegame");
44
var exportSave = document.getElementById("exportsave");
45
var importSave = document.getElementById("importsave");
46
var autosave = document.getElementById("autosave");
47
var mainArea = document.getElementById("mainarea");
48
var hoverMenu = document.getElementById("menu");
49
var hoverMenuIndicator = document.getElementById("menuindicator");
50
var search = decodeURIComponent(window.location.search).substring(1).split("&");
51
var 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"};
52
var installedCores = ["genesis_plus_gx", "mgba", "mupen64plus_next", "nestopia", "snes9x"];
53
var 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"};
54
var allFileExts = Object.values(fileExts).join(", ");
55
var allValidFileExts = [];
56
for (var i = 0; i < installedCores.length; i++) {
57
allValidFileExts.push(fileExts[systems[installedCores[i]]]);
58
}
59
allValidFileExts = allValidFileExts.join(", ");
60
var baseFsBundleDir = "/home/web_user/retroarch/bundle";
61
var awaitLogQueue = {};
62
var bundleErrors = 0;
63
var sramExt = ".srm";
64
var 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]
65
66
// make core lists
67
var aCoreList = '<li><b>Select a Core</b></li><li><a href="?core=autodetect" class="greyer">AutoDetect (Slower to load)</a></li>';
68
for (var i = 0; i < installedCores.length; i++) {
69
aCoreList += '<li><a href="?core=' + installedCores[i] + '">' + installedCores[i] + ' (' + systems[installedCores[i]] + ')</a></li>';
70
}
71
72
// query string into object
73
var queries = {};
74
for (var i = 0; i < search.length; i++) {
75
var p = search[i].split("=");
76
queries[p[0]] = p[1];
77
}
78
79
// Binary to UTF-8
80
function u8atoutf8(data) {
81
return new TextDecoder().decode(data);
82
}
83
84
function avShift(array, shift) {
85
for (var i = 0; i < array.length; i++) {
86
array[i] += shift;
87
}
88
return array;
89
}
90
91
// key press stuff
92
function fakeKey(type, info) {
93
var e = new KeyboardEvent(type, {code: info.code || undefined, key: info.key || undefined, shiftKey: info.shiftKey || undefined});
94
document.dispatchEvent(e);
95
}
96
97
function fakeKeyPress(info) {
98
fakeKey("keydown", info);
99
window.setTimeout(function() {
100
fakeKey("keyup", info);
101
}, 50);
102
}
103
104
function fakeCharPress(key) {
105
if (charToCodeMap.hasOwnProperty(key)) fakeKeyPress({code: charToCodeMap[key].code, key: charToKeyMap.hasOwnProperty(key) ? charToKeyMap[key].key : key, shiftKey: charToCodeMap[key].hasOwnProperty("shift") ? true : false});
106
}
107
108
function sendText(text) {
109
for (var i = 0; i < text.length; i++) {
110
fakeCharPress(text.charAt(i));
111
}
112
}
113
114
// indexedDB
115
function openIdb() {
116
var request = indexedDB.open("webretro", 1);
117
request.onsuccess = function(e) {
118
wIdb = e.target.result;
119
}
120
request.onupgradeneeded = function(e) {
121
var store = e.target.result.createObjectStore("main", {keyPath: "key"});
122
store.transaction.oncomplete = function(e2) {
123
wIdb = e.target.db;
124
}
125
}
126
}
127
128
openIdb();
129
130
function setIdbItem(key, value) {
131
wIdb.transaction("main", "readwrite").objectStore("main").put({key: key, value: value});
132
}
133
134
function getIdbItem(key) {
135
return new Promise(function(resolve) {
136
wIdb.transaction("main", "readwrite").objectStore("main").get(key).onsuccess = function(e) {
137
resolve(e.target.result ? e.target.result.value : null);
138
}
139
});
140
}
141
142
// localStorage to indexedDB
143
async function tryLsToIdb() {
144
var ls = Object.keys(window.localStorage);
145
for (var i = 0; i < ls.length; i++) {
146
if (ls[i].startsWith("RetroArch_")) {
147
setIdbItem(ls[i], new Uint8Array(JSON.parse(window.localStorage.getItem(ls[i]))));
148
window.localStorage.removeItem(ls[i]);
149
}
150
if (i == ls.length - 1) return;
151
}
152
}
153
154
// side alerts
155
function sideAlert(initialText, time) {
156
var p = document.createElement("p");
157
p.className = "sidealert";
158
p.appendChild(document.createTextNode(initialText));
159
sideAlertHolder.appendChild(p);
160
window.setTimeout(function() {
161
p.classList.add("on");
162
}, 10);
163
this.dismiss = function() {
164
p.classList.remove("on");
165
window.setTimeout(function() {
166
p.remove();
167
}, 100);
168
}
169
this.setText = function(text) {
170
p.textContent = text;
171
}
172
if (time) window.setTimeout(this.dismiss, time);
173
}
174
175
// change background for status messages
176
function setStatus(message) {
177
loadStatus = message;
178
canvas.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>') + '")';
179
}
180
181
// remove status messages
182
function removeStatus(message) {
183
if (loadStatus === message) setStatus("");
184
}
185
186
// adjust canvas size to window
187
function adjustCanvasSize() {
188
if (window.innerHeight >= window.innerWidth * (3/4)) {
189
var s = window.innerWidth;
190
var t = Math.floor(s * (3/4));
191
Module.setCanvasSize(s * resModifier, t * resModifier);
192
canvasMask.style.width = s + "px";
193
canvasMask.style.height = t + "px";
194
} else {
195
var s = window.innerHeight;
196
var t = Math.floor(s * (4/3));
197
Module.setCanvasSize(t * resModifier, s * resModifier);
198
canvasMask.style.width = t + "px";
199
canvasMask.style.height = s + "px";
200
}
201
}
202
203
// logging
204
function log(log, userInput) {
205
console.log(log);
206
wconsole.textContent += (userInput ? "> " + userInput + "\n\t" + JSON.stringify(log) : log) + "\n";
207
wconsole.scrollTo({top: wconsole.scrollHeight});
208
209
if (typeof log == "string") {
210
// export state
211
if (log.includes("New state file is ready to be read")) saveStateFunc();
212
213
// await log queue
214
if (Object.keys(awaitLogQueue).length) {
215
var lq = Object.keys(awaitLogQueue);
216
for (var i = 0; i < lq.length; i++) {
217
if (log.toLowerCase().includes(lq[i].toLowerCase())) {
218
awaitLogQueue[lq[i]](log);
219
delete awaitLogQueue[lq[i]];
220
}
221
}
222
}
223
}
224
}
225
226
function awaitLog(contains, callback, timeout, expire) {
227
awaitLogQueue[contains] = callback;
228
if (timeout && !isNaN(timeout)) {
229
window.setTimeout(function() {
230
if (awaitLogQueue[contains]) {
231
expire();
232
delete awaitLogQueue[contains];
233
}
234
}, timeout);
235
}
236
}
237
238
// xhr
239
function grab(url, type, success, fail) {
240
var req = new XMLHttpRequest();
241
req.open("GET", url, true);
242
req.overrideMimeType("text/plain; charset=x-user-defined");
243
req.responseType = type;
244
req.onload = function() {
245
if (req.status >= "400") {
246
if (fail) fail(req.status);
247
} else {
248
if (success) success(this.response);
249
}
250
}
251
req.send();
252
}
253
254
// file readers
255
function readFile(file, callback) {
256
var reader = new FileReader();
257
reader.onload = function() {
258
callback(this.result);
259
}
260
reader.readAsArrayBuffer(file);
261
}
262
263
function downloadFile(data, name) {
264
var a = document.createElement("a");
265
a.download = name;
266
a.href = URL.createObjectURL(new Blob([data], {type: "application/octet-stream"}));
267
a.click();
268
window.setTimeout(function() {
269
URL.revokeObjectURL(a.href);
270
}, 2000);
271
}
272
273
function uploadFile(accept, callback) {
274
var input = document.createElement("input");
275
input.type = "file";
276
input.accept = accept;
277
input.onchange = function() {
278
readFile(this.files[0], function(data) {
279
callback(data);
280
});
281
}
282
input.click();
283
}
284
285
// scripts
286
function getScript(url, callback, err) {
287
var script = document.createElement("script");
288
script.type = "text/javascript";
289
script.src = url;
290
script.onload = function() {
291
if (callback) callback();
292
}
293
script.onerror = function(e) {
294
document.body.removeChild(script);
295
if (err) err(e);
296
}
297
document.body.appendChild(script);
298
}
299
300
function getCore(name, callback, err) {
301
getScript("./" + name + "_libretro.js", callback, err);
302
}
303
304
// check for updates
305
function checkForUpdates() {
306
grab("https://cdn.jsdelivr.net/gh/BinBashBanana/webretro@latest/assets/info.json", "text", function(text) {
307
try {
308
var updateObj = JSON.parse(text);
309
if (updateObj.webretro) {
310
latestVersion = updateObj.webretro;
311
if (updateObj.versions[webretroVersion.toString()]) versionIndicator.title = "New features in this version:\n\n- " + updateObj.versions[webretroVersion.toString()].changeList.join("\n- ");
312
if (latestVersion > webretroVersion && updateObj.versions[latestVersion.toString()]) {
313
updateNotice.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.";
314
updateNotice.style.display = "initial";
315
}
316
}
317
} catch (e) {
318
log(e);
319
}
320
});
321
}
322
323
// unzip file
324
function unzipFile(data, exts, callback, empty, notfound) {
325
new zip.ZipReader(new zip.Uint8ArrayReader(data)).getEntries().then(function(entries) {
326
if (entries.length) {
327
for (var i = 0; i < entries.length; i++) {
328
if (exts.split(", ").includes("." + u8atoutf8(entries[i].rawFilename).split(".").slice(-1)[0])) {
329
let name = u8atoutf8(entries[i].rawFilename);
330
entries[i].getData(new zip.Uint8ArrayWriter()).then(function(uzd) {
331
callback(name, uzd);
332
});
333
break;
334
}
335
if (i == entries.length - 1 && notfound) notfound();
336
}
337
} else if (empty) empty();
338
});
339
}
340
341
// uauth uploads
342
function handleWebFile(data) {
343
if (data.message == "success") {
344
ffd.style.display = "none";
345
romUploadCallback(data.name, data.data);
346
} else if (data.message == "error") {
347
alert("There was an error with the file picker. This may mean that you have to allow popup windows.");
348
}
349
}
350
351
function uploadWebFile(type, exts) {
352
uauth.open(type, exts.split(", "), handleWebFile);
353
}
354
355
// rom upload
356
function readyRomUploads(exts) {
357
upload.setAttribute("accept", exts);
358
359
// when a rom is uploaded
360
upload.onchange = function() {
361
ffd.style.display = "none";
362
let file = this.files[0];
363
readFile(file, function(data) {
364
log('Succesfully read ROM file "' + file.name + '"');
365
romUploadCallback(file.name, data);
366
});
367
}
368
369
// web uploads
370
googleDriveUpload.onclick = function() {
371
uploadWebFile("drive", exts);
372
}
373
dropboxUpload.onclick = function() {
374
uploadWebFile("dropbox", exts);
375
}
376
oneDriveUpload.onclick = function() {
377
uploadWebFile("onedrive", exts);
378
}
379
380
// file drop
381
document.ondragenter = function(e) {
382
if (e.dataTransfer.types.includes("Files")) ffd.classList.add("filehover");
383
}
384
document.ondragover = function(e) {
385
e.preventDefault();
386
}
387
document.ondrop = function(e) {
388
if (e.dataTransfer.types.includes("Files")) {
389
e.preventDefault();
390
ffd.style.display = "none";
391
let file = event.dataTransfer.files[0];
392
readFile(file, function(data) {
393
log('Succesfully read ROM file "' + file.name + '"');
394
romUploadCallback(file.name, data);
395
});
396
}
397
}
398
}
399
400
// rom fetch
401
function readyRomFetch() {
402
var romloc = /^(http:\/\/|https:\/\/|\/\/)/i.test(queries.rom) ? queries.rom : "roms/" + queries.rom;
403
var romFilename = queries.rom.split("/").slice(-1)[0];
404
grab(romloc, "arraybuffer", function(data) {
405
log("Succesfully fetched ROM from " + romloc);
406
romMode = "querystring";
407
romUploadCallback(romFilename, data);
408
}, function(error) {
409
alert("Could not get ROM at " + romloc + " (Error " + error + ")");
410
romMode = "upload";
411
ffd.style.display = "block";
412
});
413
}
414
415
// console window
416
var conw = new jswindow({title: "Console", icon: "assets/terminal.svg"});
417
418
var wconsole = document.createElement("textarea");
419
wconsole.classList.add("console");
420
wconsole.setAttribute("spellcheck", "false");
421
wconsole.setAttribute("readonly", "");
422
423
wconsole.wconsolemarker = document.createElement("span");
424
wconsole.wconsolemarker.classList.add("consolemarker");
425
426
wconsole.wconsoleinput = document.createElement("input");
427
wconsole.wconsoleinput.type = "text";
428
wconsole.wconsoleinput.classList.add("consoleinput");
429
wconsole.wconsoleinput.title = "You can type things here as though you were using the browser console.";
430
wconsole.wconsoleinput.setAttribute("spellcheck", "false");
431
wconsole.wconsolemarker.onclick = function() { wconsole.wconsoleinput.focus(); }
432
wconsole.wconsoleinput.onkeydown = function(e) {
433
e.stopPropagation();
434
if (e.keyCode == 13) {
435
log(eval(this.value), this.value);
436
this.value = "";
437
}
438
}
439
440
conw.innerWindow.appendChild(wconsole);
441
conw.innerWindow.appendChild(wconsole.wconsolemarker);
442
conw.innerWindow.appendChild(wconsole.wconsoleinput);
443
444
consoleButton.onclick = function() {
445
conw.open({width: 450, height: 250, left: 100, top: 50});
446
wconsole.wconsoleinput.focus();
447
wconsole.scrollTo({top: wconsole.scrollHeight});
448
}
449
450
if (queries.hasOwnProperty("console")) conw.open({width: 450, height: 250, left: 100, top: 50});
451
452
// ---------- START LOAD ----------
453
(function() {
454
// ?system query
455
if (!queries.core && queries.system) {
456
var detectedCore = Object.keys(systems).find(k => systems[k].toLowerCase() == queries.system.toLowerCase());
457
if (installedCores.includes(detectedCore)) {
458
queries.core = detectedCore;
459
} else if (queries.system.toLowerCase() == "autodetect") {
460
queries.core = "autodetect";
461
} else {
462
alert("Invalid core (" + detectedCore + ")");
463
}
464
}
465
466
// ?core query
467
if (queries.core) {
468
if (!window.navigator.userAgent.toLowerCase().includes("chrom")) alert("Best performance on Chrome!");
469
470
// show hover menu
471
hoverMenu.style.display = "block";
472
473
versionIndicator.textContent = "v" + webretroVersion.toString();
474
checkForUpdates();
475
476
if (queries.core.toLowerCase() == "autodetect") {
477
romUploadCallback = autodetectCoreHandler;
478
systemName.textContent = "";
479
readyRomUploads(".zip, " + allFileExts);
480
} else {
481
romUploadCallback = initFromFile;
482
core = queries.core;
483
484
setStatus("Getting core");
485
if (core == "desmume") sramExt = ".dsv";
486
// detect system for ROM upload
487
systemName.textContent = systems[core] || "";
488
489
getCore(core, function() {
490
removeStatus("Getting core");
491
log("Got core: " + core);
492
if (romMode != "querystring") document.title = core + " | webretro";
493
494
readyRomUploads(".zip, .bin, " + fileExts[systems[core]]);
495
}, function() {
496
// core loading error
497
alert('Could not load specified core "' + core + '". Here is a list of available cores.');
498
ffdContent.innerHTML = "<ul>" + aCoreList + "</ul>";
499
ffd.style.display = "block";
500
});
501
}
502
503
// ?rom query
504
if (queries.rom) {
505
readyRomFetch();
506
} else {
507
// prompt user to upload ROM file
508
romMode = "upload";
509
ffd.style.display = "block";
510
}
511
} else {
512
// no core specified
513
ffdContent.innerHTML = "<ul>" + aCoreList + "</ul>";
514
ffd.style.display = "block";
515
}
516
})();
517
// ----------- END LOAD -----------
518
519
// start emulator from file name and data
520
function initFromFile(name, data) {
521
var dataView = new Uint8Array(data);
522
if (name.split(".").slice(-1)[0] == "zip") {
523
log("Zip file detected, unzipping...");
524
525
unzipFile(dataView, fileExts[systems[core]], function(name, contents) {
526
romName = name.split(".")[0];
527
readyForInit(contents);
528
}, function() {
529
alert("That zip file appears to be empty!");
530
}, function() {
531
alert("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)");
532
});
533
} else {
534
romName = name.split(".")[0];
535
readyForInit(dataView);
536
}
537
}
538
539
// autodetect core mode
540
function autodetectCoreHandler(name, data) {
541
var dataView = new Uint8Array(data);
542
if (name.split(".").slice(-1)[0] == "zip") {
543
log("Zip file detected, unzipping...");
544
545
unzipFile(dataView, allFileExts, function(name, contents) {
546
romName = name.split(".")[0];
547
autodetectCore(name, contents);
548
}, function() {
549
alert("That zip file appears to be empty!");
550
}, function() {
551
alert("Couldn't find a valid ROM file in that zip file. (The ROM has to be at the base directory of the zip file)");
552
});
553
} else {
554
romName = name.split(".")[0];
555
autodetectCore(name, dataView);
556
}
557
}
558
559
function autodetectCore(name, data) {
560
var nameExt = "." + name.split(".").slice(-1)[0];
561
var detectedCore;
562
var fileExtsArray = Object.keys(fileExts);
563
for (var i = 0; i < fileExtsArray.length; i++) {
564
if (fileExts[fileExtsArray[i]].split(", ").includes(nameExt)) {
565
detectedCore = Object.keys(systems).find(k => systems[k] == fileExtsArray[i]);
566
break;
567
}
568
}
569
570
var detectedSystem = systems[detectedCore] || "unknown";
571
detectedCore = detectedCore || "unknown";
572
573
if (allValidFileExts.split(", ").includes(nameExt)) {
574
core = detectedCore;
575
576
setStatus("Getting core");
577
if (core == "desmume") sramExt = ".dsv";
578
579
getCore(core, function() {
580
removeStatus("Getting core");
581
log("Got core: " + core);
582
readyForInit(data);
583
});
584
} else {
585
alert("That is a " + detectedSystem + " file! " + detectedCore + " (" + detectedSystem + ") is not currently supported.");
586
}
587
}
588
589
// if the ROM is specified in the querystring, we will need to wait until the user has clicked to start the emulator
590
function readyForInit(data) {
591
document.title = romName + " | webretro";
592
593
// do I want to put this in the docs?
594
if (queries.romshift) data = avShift(data, parseInt(queries.romshift));
595
596
if (romMode == "querystring") {
597
startButton.style.display = "initial";
598
startButton.onclick = function() {
599
startButton.style.display = "none";
600
initFromData(data);
601
}
602
} else {
603
initFromData(data);
604
}
605
}
606
607
// prepare FS with bundle
608
function prepareBundle() {
609
setStatus("Getting assets");
610
log("Starting bundle fetch");
611
let bundleSTime = performance.now();
612
fsBundleDirs = [['', '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']]
613
FS.createPath("/", "home/web_user/retroarch/bundle", true, true);
614
for (var i = 0; i < fsBundleDirs.length; i++) {
615
FS.createPath(baseFsBundleDir + fsBundleDirs[i][0], fsBundleDirs[i][1], true, true);
616
}
617
618
grab(bundleCdn + "bundle/indexedfiles.txt", "text", function(data) {
619
fsBundleFiles = data.split("\n");
620
for (let i = 0; i < fsBundleFiles.length; i++) {
621
grab(bundleCdn + "bundle" + fsBundleFiles[i], "arraybuffer", function(data) {
622
FS.writeFile(baseFsBundleDir + fsBundleFiles[i], new Uint8Array(data));
623
if (i == fsBundleFiles.length - 1) donePreparingBundle(performance.now() - bundleSTime);
624
}, function() {
625
bundleErrors += 1;
626
if (i == fsBundleFiles.length - 1) donePreparingBundle(performance.now() - bundleSTime);
627
});
628
}
629
}, function() {
630
log("Failed to get asset bundle, skipping");
631
bundleReady = true;
632
removeStatus("Getting assets");
633
});
634
}
635
636
function donePreparingBundle(tooktime) {
637
bundleReady = true;
638
removeStatus("Getting assets");
639
log("Finished bundle fetch in " + (tooktime / 1000).toFixed(1) + " seconds, " + bundleErrors + " errors");
640
}
641
642
// tell the user to not rename the rom
643
function doNotRename() {
644
if (romMode == "upload" && !window.localStorage.getItem("webretro_settings_pastFirstSave")) {
645
alert("WARNING: Do not rename your ROM file after this! The save data is specific to the ROM name!");
646
window.localStorage.setItem("webretro_settings_pastFirstSave", "true");
647
}
648
}
649
650
// save game
651
function saveSRAM() {
652
Module._cmd_savefiles();
653
window.setTimeout(function() {
654
if (FS.analyzePath("/home/web_user/retroarch/userdata/saves/rom" + sramExt).exists) {
655
setIdbItem("RetroArch_saves_" + romName, FS.readFile("/home/web_user/retroarch/userdata/saves/rom" + sramExt));
656
new sideAlert("Saved", 3000);
657
readySaveReaders();
658
659
doNotRename();
660
} else {
661
autosave.checked = false;
662
new sideAlert("This game does not save!", 3000);
663
}
664
}, 1000);
665
}
666
667
// save state
668
function saveStateFunc() {
669
window.setTimeout(function() {
670
if (FS.analyzePath("/home/web_user/retroarch/userdata/states/rom.state").exists) {
671
setIdbItem("RetroArch_states_" + romName, FS.readFile("/home/web_user/retroarch/userdata/states/rom.state"));
672
673
doNotRename();
674
} else {
675
new sideAlert("There was an error saving state. Please try again.", 5000);
676
}
677
}, 100);
678
}
679
680
// autosaving
681
function autosaveSRAM() {
682
if (autosave.checked && !document.hidden && !isPaused) {
683
new sideAlert("Autosaving...", 3000);
684
saveSRAM();
685
}
686
window.setTimeout(function() {
687
autosaveSRAM();
688
}, 300000);
689
}
690
691
// more functions for state buttons
692
function readyStateReaders() {
693
if (!stateReadersReady) {
694
stateReadersReady = true;
695
696
loadState.classList.remove("disabled");
697
exportState.classList.remove("disabled");
698
undoSaveState.classList.remove("disabled");
699
700
loadState.onclick = function() {
701
Module._cmd_load_state();
702
readyStateReaders2();
703
}
704
exportState.onclick = function() {
705
downloadFile(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");
706
}
707
undoSaveState.onclick = function() {
708
Module._cmd_undo_save_state();
709
}
710
// also allow statereaders2 on F3 press
711
document.addEventListener("keydown", function(e) {
712
if (e.key == "F3") readyStateReaders2();
713
}, false);
714
}
715
}
716
717
// even more functions for state buttons
718
function readyStateReaders2() {
719
if (!stateReaders2Ready) {
720
stateReaders2Ready = true;
721
722
undoLoadState.classList.remove("disabled");
723
undoLoadState.onclick = function() {
724
Module._cmd_undo_load_state();
725
}
726
}
727
}
728
729
// more functions for save buttons
730
function readySaveReaders() {
731
if (!saveReadersReady) {
732
saveReadersReady = true;
733
734
exportSave.classList.remove("disabled");
735
736
exportSave.onclick = function() {
737
downloadFile(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);
738
}
739
}
740
}
741
742
// runs after emulator starts
743
function afterStart() {
744
// remove loading text
745
canvas.style.background = "none";
746
747
adjustCanvasSize();
748
749
// functions for save and state buttons
750
saveState.classList.remove("disabled");
751
importState.classList.remove("disabled");
752
saveGame.classList.remove("disabled");
753
importSave.classList.remove("disabled");
754
autosave.removeAttribute("disabled");
755
autosave.parentElement.classList.remove("disabled");
756
757
saveState.onclick = function() {
758
Module._cmd_save_state();
759
readyStateReaders();
760
}
761
importState.onclick = function() {
762
uploadFile(".bin, .state, .save, .dat, .gam, .sav, application/*", function(data) {
763
setIdbItem("RetroArch_states_" + romName, new Uint8Array(data));
764
FS.writeFile("/home/web_user/retroarch/userdata/states/rom.state", new Uint8Array(data));
765
new sideAlert("Imported state", 3000);
766
readyStateReaders();
767
});
768
}
769
770
saveGame.onclick = function() {
771
new sideAlert("Saving...", 3000);
772
saveSRAM();
773
}
774
importSave.onclick = function() {
775
uploadFile(".bin, .srm, .sram, .ram, .gam, .sav, .dsv, application/*", function(data) {
776
autosave.checked = false;
777
setIdbItem("RetroArch_saves_" + romName, new Uint8Array(data));
778
if (confirm("Save imported. Reloading now for changes to take effect.")) {
779
window.onbeforeunload = function() {}
780
window.location.reload();
781
}
782
});
783
}
784
785
// also allow state readers on F2 press
786
document.addEventListener("keydown", function(e) {
787
if (e.key == "F2") readyStateReaders();
788
}, false);
789
790
// start autosave loop
791
window.setTimeout(function() {
792
autosaveSRAM();
793
}, 300000);
794
795
// toggle between sharp and smooth canvas graphics
796
smooth.removeAttribute("disabled");
797
smooth.parentElement.classList.remove("disabled");
798
smooth.onclick = function() {
799
if (this.checked) {
800
canvas.className = "textureSmooth";
801
} else {
802
canvas.className = "texturePixelated";
803
}
804
}
805
806
// higher resolution
807
doubleRes.removeAttribute("disabled");
808
doubleRes.parentElement.classList.remove("disabled");
809
doubleRes.onclick = function() {
810
if (this.checked) {
811
resModifier = 2;
812
adjustCanvasSize();
813
} else {
814
resModifier = 1;
815
adjustCanvasSize();
816
}
817
}
818
819
// pause and resume
820
pause.classList.remove("disabled");
821
pause.onclick = function() {
822
if (this.textContent.trim() == "Pause") {
823
Module.pauseMainLoop();
824
isPaused = true;
825
this.textContent = "Resume";
826
document.body.classList.add("paused");
827
} else {
828
Module.resumeMainLoop();
829
isPaused = false;
830
this.textContent = "Pause";
831
document.body.classList.remove("paused");
832
}
833
}
834
resumeOverlay.onclick = function() {
835
pause.click();
836
}
837
838
// toggle menu
839
menuButton.classList.remove("disabled");
840
menuButton.onclick = function() {
841
Module._cmd_toggle_menu();
842
}
843
844
// flash the menu on first use
845
if (!window.localStorage.getItem("webretro_settings_pastFirstStart")) {
846
hoverMenu.classList.add("show");
847
hoverMenuIndicator.classList.add("show");
848
window.setTimeout(function() {
849
hoverMenu.classList.remove("show");
850
hoverMenuIndicator.classList.remove("show");
851
}, 3000);
852
window.localStorage.setItem("webretro_settings_pastFirstStart", "true");
853
}
854
855
// ctrl+v inside canvas
856
document.addEventListener("keydown", function(e) {
857
if (e.ctrlKey && e.key == "v") {
858
navigator.clipboard.readText().then(function(text) {
859
fakeKeyPress({code: "Backspace"});
860
sendText(text);
861
});
862
}
863
}, false);
864
}
865
866
// start
867
function initFromData(data) {
868
window.onbeforeunload = function() { return true; }
869
async function waitForReady() {
870
if (wasmReady && bundleReady) {
871
setStatus("Waiting for emulator");
872
log("Initializing with " + data.byteLength + " bytes of data");
873
updateNotice.style.display = "none";
874
canvas.addEventListener("contextmenu", function(e) {
875
e.preventDefault();
876
}, false);
877
window.addEventListener("resize", adjustCanvasSize, false);
878
adjustCanvasSize();
879
880
// prevent defaults for key presses
881
document.addEventListener("keydown", function(e) {
882
if (pdKeys.includes(e.which)) e.preventDefault();
883
}, false);
884
885
// move the saves and states from the old version (localStorage) to indexedDB
886
await tryLsToIdb();
887
888
// rom
889
FS.writeFile("/rom.bin", data);
890
891
// SMAS brick fix
892
if (systems[core] == "SNES") {
893
var hash = md5(u8atoutf8(data));
894
if (smasBrickFix.hasOwnProperty(hash)) {
895
FS.writeFile("/rom.ips", new Uint8Array(smasBrickFix[hash]));
896
new sideAlert("SMAS Bricks Fixed!", 5000);
897
}
898
}
899
900
// load save
901
var cSave = await getIdbItem("RetroArch_saves_" + romName);
902
if (cSave) {
903
FS.createPath("/", "home/web_user/retroarch/userdata/saves", true, true);
904
FS.writeFile("/home/web_user/retroarch/userdata/saves/rom" + sramExt, cSave);
905
new sideAlert("Save loaded for " + romName, 5000);
906
log("Save loaded for " + romName);
907
readySaveReaders();
908
}
909
910
// import state
911
var cState = await getIdbItem("RetroArch_states_" + romName);
912
if (cState) {
913
FS.createPath("/", "home/web_user/retroarch/userdata/states", true, true);
914
FS.writeFile("/home/web_user/retroarch/userdata/states/rom.state", cState);
915
new sideAlert("State imported for " + romName, 5000);
916
log("State imported for " + romName);
917
readyStateReaders();
918
}
919
920
// config
921
FS.createPath("/", "home/web_user/retroarch/userdata", true, true);
922
FS.writeFile("/home/web_user/retroarch/userdata/retroarch.cfg", nulKeys + keybinds + extraConfig);
923
924
// start
925
Module.callMain(Module.arguments);
926
adjustCanvasSize();
927
928
window.setTimeout(afterStart, 2000);
929
} else {
930
window.setTimeout(waitForReady, 1000);
931
}
932
}
933
waitForReady();
934
}
935
936
var Module = {
937
canvas: canvas,
938
noInitialRun: true,
939
arguments: ["/rom.bin", "--verbose"],
940
onRuntimeInitialized: function() {
941
wasmReady = true;
942
log("WASM compiled");
943
944
// fetch asset bundle
945
if (queries.hasOwnProperty("nobundle")) {
946
bundleReady = true;
947
log("Skipping bundle");
948
} else {
949
prepareBundle();
950
}
951
},
952
print: function(text) {
953
log("stdout: " + text);
954
},
955
printErr: function(text) {
956
log("stderr: " + text);
957
}
958
};
959