1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327 |
- // Source Code: https://github.com/BinBashBanana/webretro
- // please dont use IE
- var indexedDB = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;
- if (!window.fetch || !indexedDB) {
- alert("Update your browser!");
- throw "Update your browser!";
- }
- var fsBundleDirs, fsBundleFiles, loadStatus, romName, stateReadersReady, stateReaders2Ready, saveReadersReady, isPaused, wasmReady, bundleReady, romMode, core, wIdb, romUploadCallback, latestVersion, emulatorStarted, currentManager, romUploadsReady;
- var bundleCdn = "https://cdn.jsdelivr.net/gh/BinBashBanana/webretro/";
- var bundleCdnLatest = "https://cdn.jsdelivr.net/gh/BinBashBanana/webretro@latest/";
- var defaultKeybinds = '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"\ninput_screenshot = "f4"\ninput_hold_fast_forward = "nul"\ninput_toggle_fast_forward = "nul"\n';
- 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_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_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_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';
- var extraConfig = 'rgui_show_start_screen = "false"\n';
- 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];
- var webretroVersion = 6.4;
- var updateNotice = document.getElementById("updatenotice");
- var versionIndicator = document.getElementById("versionindicator");
- var upload = document.getElementById("upload");
- var googleDriveUpload = document.getElementById("googledriveupload");
- var dropboxUpload = document.getElementById("dropboxupload");
- var oneDriveUpload = document.getElementById("onedriveupload");
- var startButton = document.getElementById("startbutton");
- var smooth = document.getElementById("smooth");
- var doubleRes = document.getElementById("doubleres");
- var resModifier = 1;
- var canvas = document.getElementById("canvas");
- var canvasMask = document.getElementById("canvasmask");
- var saveState = document.getElementById("savestate");
- var loadState = document.getElementById("loadstate");
- var undoSaveState = document.getElementById("undosavestate");
- var undoLoadState = document.getElementById("undoloadstate");
- var exportState = document.getElementById("exportstate");
- var importState = document.getElementById("importstate");
- var ffd = document.getElementById("ffd");
- var ffdContent = document.getElementById("ffdcontent");
- var systemName = document.getElementById("systemname");
- var consoleButton = document.getElementById("consolebutton");
- var menuButton = document.getElementById("menubutton");
- var pauseButton = document.getElementById("pause");
- var resumeOverlay = document.getElementById("resume");
- var sideAlertHolder = document.getElementById("sidealertholder");
- var saveGame = document.getElementById("savegame");
- var exportSave = document.getElementById("exportsave");
- var importSave = document.getElementById("importsave");
- var autosave = document.getElementById("autosave");
- var mainArea = document.getElementById("mainarea");
- var hoverMenu = document.getElementById("menu");
- var hoverMenuIndicator = document.getElementById("menuindicator");
- var takeScreenshot = document.getElementById("takescreenshot");
- var modals = document.getElementById("modals");
- var keybindTable = document.getElementById("keybindtable");
- var saveKeybinds = document.getElementById("savekeybinds");
- var resetKeybinds = document.getElementById("resetkeybinds");
- var keybindsButton = document.getElementById("keybindsbutton");
- var screenshotsButton = document.getElementById("screenshotsbutton");
- var savesButton = document.getElementById("savesbutton");
- var statesButton = document.getElementById("statesbutton");
- var downloadAllScreenshots = document.getElementById("downloadallscreenshots");
- var screenshotsDiv = document.getElementById("screenshotsdiv");
- var saveTable = document.getElementById("savetable");
- var managers = {};
- managers.keybind = document.getElementById("keybindmanager");
- managers.screenshot = document.getElementById("screenshotmanager");
- managers.save = document.getElementById("savemanager");
- var managerNames = {"save": "Saves & States"};
- var managerTitle = document.getElementById("managertitle");
- var managerClose = document.getElementById("managerclose");
- var screenshotDatas = [];
- var screenshotObjUrls = [];
- var saveIDs = [];
- var quotaText = document.getElementById("quotatext");
- var search = decodeURIComponent(window.location.search).substring(1).split("&");
- var systems = {"citra": "Nintendo 3DS", "desmume": "Nintendo DS", "dolphin": "GC/Wii", "genesis_plus_gx": "Genesis", "mednafen_psx": "PS1", "mgba": "GBA", "mupen64plus_next": "Nintendo 64", "nestopia": "NES", "parallel_n64": "Nintendo 64", "ppsspp": "PSP", "snes9x": "SNES"};
- var installedCores = ["genesis_plus_gx", "mgba", "mupen64plus_next", "nestopia", "snes9x"];
- 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"};
- var allFileExts = Object.values(fileExts).join(", ");
- var allValidFileExts = [];
- for (var i = 0; i < installedCores.length; i++) {
- allValidFileExts.push(fileExts[systems[installedCores[i]]]);
- }
- allValidFileExts = allValidFileExts.join(", ");
- var baseFsBundleDir = "/home/web_user/retroarch/bundle";
- var awaitLogQueue = {};
- var bundleErrors = 0;
- var sramExt = ".srm";
- 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]
- // disable webcam for gameboy camera
- var disableWebCam = true;
- // make core lists
- var aCoreList = '<li><b>Select a Core</b></li><li><a href="?core=autodetect" class="greyer">AutoDetect (Slower to load)</a></li>';
- for (var i = 0; i < installedCores.length; i++) {
- aCoreList += '<li><a href="?core=' + installedCores[i] + '">' + installedCores[i] + ' (' + systems[installedCores[i]] + ')</a></li>';
- }
- // query string into object
- var queries = {};
- for (var i = 0; i < search.length; i++) {
- var p = search[i].split("=");
- queries[p[0]] = p[1];
- }
- // Binary to UTF-8
- function u8atoutf8(data) {
- return new TextDecoder().decode(data);
- }
- function avShift(array, shift) {
- for (var i = 0; i < array.length; i++) {
- array[i] += shift;
- }
- return array;
- }
- // date time
- function getTime() {
- var dateTime = new Date();
- return dateTime.getFullYear().toString()+"-"+(dateTime.getMonth()+1).toString()+"-"+dateTime.getDate().toString()+"-"+dateTime.getHours().toString()+"-"+dateTime.getMinutes().toString();
- }
- // bytes to human-readable string
- function bytesToHumanReadable(bytes) {
- bytes = bytes || 0;
- var extension = -1;
- while (bytes >= 1000) {
- bytes /= 1000;
- extension++;
- }
- return bytes.toFixed(2) + " " + "KMGTPEZY".charAt(extension) + "B";
- }
- // js has no built-in capitalization function
- function capitalize(str) {
- return str.charAt(0).toUpperCase() + str.slice(1);
- }
- // key press stuff
- function fakeKey(type, info) {
- var e = new KeyboardEvent(type, {code: info.code || undefined, key: info.key || undefined, shiftKey: info.shiftKey || undefined});
- document.dispatchEvent(e);
- }
- function fakeKeyPress(info) {
- fakeKey("keydown", info);
- window.setTimeout(function() {
- fakeKey("keyup", info);
- }, 50);
- }
- function fakeCharPress(key) {
- if (charToCodeMap.hasOwnProperty(key)) fakeKeyPress({code: charToCodeMap[key].code, key: charToKeyMap.hasOwnProperty(key) ? charToKeyMap[key].key : key, shiftKey: charToCodeMap[key].hasOwnProperty("shift") ? true : false});
- }
- function sendText(text) {
- for (var i = 0; i < text.length; i++) {
- fakeCharPress(text.charAt(i));
- }
- }
- // indexedDB
- function openIdb() {
- var request = indexedDB.open("webretro", 1);
- request.onsuccess = function(e) {
- wIdb = e.target.result;
- }
- request.onupgradeneeded = function(e) {
- var store = e.target.result.createObjectStore("main", {keyPath: "key"});
- store.transaction.oncomplete = function(e2) {
- wIdb = e.target.db;
- }
- }
- }
- openIdb();
- function setIdbItem(key, value) {
- wIdb.transaction("main", "readwrite").objectStore("main").put({key: key, value: value});
- }
- function getIdbItem(key) {
- return new Promise(function(resolve) {
- wIdb.transaction("main", "readwrite").objectStore("main").get(key).onsuccess = function(e) {
- resolve(e.target.result ? e.target.result.value : null);
- }
- });
- }
- function getAllIdbItems() {
- return new Promise(function(resolve) {
- wIdb.transaction("main", "readwrite").objectStore("main").getAll().onsuccess = function(e) {
- resolve(e.target.result ? e.target.result : null);
- }
- });
- }
- function removeIdbItem(key) {
- wIdb.transaction("main", "readwrite").objectStore("main").delete(key);
- }
- // localStorage to indexedDB
- async function tryLsToIdb() {
- var ls = Object.keys(window.localStorage);
- for (var i = 0; i < ls.length; i++) {
- if (ls[i].startsWith("RetroArch_saves_")) {
- setIdbItem(ls[i], new Uint8Array(JSON.parse(window.localStorage.getItem(ls[i]))));
- window.localStorage.removeItem(ls[i]);
- }
- if (i == ls.length - 1) return;
- }
- }
- // side alerts
- function sideAlert(initialText, time) {
- var p = document.createElement("p");
- p.className = "sidealert";
- p.appendChild(document.createTextNode(initialText));
- sideAlertHolder.appendChild(p);
- window.setTimeout(function() {
- p.classList.add("on");
- }, 10);
- this.dismiss = function() {
- p.classList.remove("on");
- window.setTimeout(function() {
- p.remove();
- }, 100);
- }
- this.setText = function(text) {
- p.textContent = text;
- }
- if (time) window.setTimeout(this.dismiss, time);
- }
- // change background for status messages
- function setStatus(message) {
- loadStatus = message;
- 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>') + '")';
- }
- // remove status messages
- function removeStatus(message) {
- if (loadStatus === message) setStatus("");
- }
- // adjust canvas size to window
- function adjustCanvasSize() {
- if (window.innerHeight >= window.innerWidth * (3/4)) {
- var s = window.innerWidth;
- var t = Math.floor(s * (3/4));
- Module.setCanvasSize(s * resModifier, t * resModifier);
- canvasMask.style.width = s + "px";
- canvasMask.style.height = t + "px";
- } else {
- var s = window.innerHeight;
- var t = Math.floor(s * (4/3));
- Module.setCanvasSize(t * resModifier, s * resModifier);
- canvasMask.style.width = t + "px";
- canvasMask.style.height = s + "px";
- }
- }
- // logging
- function log(log, userInput) {
- console.log(log);
- wconsole.textContent += (userInput ? "> " + userInput + "\n\t" + JSON.stringify(log) : log) + "\n";
- wconsole.scrollTo({top: wconsole.scrollHeight});
-
- if (typeof log == "string") {
- // export state
- if (log.includes("New state file is ready to be read")) saveStateFunc();
-
- // await log queue
- if (Object.keys(awaitLogQueue).length) {
- var lq = Object.keys(awaitLogQueue);
- for (var i = 0; i < lq.length; i++) {
- if (log.toLowerCase().includes(lq[i].toLowerCase())) {
- awaitLogQueue[lq[i]](log);
- delete awaitLogQueue[lq[i]];
- }
- }
- }
- }
- }
- function awaitLog(contains, callback, timeout, expire) {
- awaitLogQueue[contains] = callback;
- if (timeout && !isNaN(timeout)) {
- window.setTimeout(function() {
- if (awaitLogQueue[contains]) {
- expire();
- delete awaitLogQueue[contains];
- }
- }, timeout);
- }
- }
- // xhr
- function grab(url, type, success, fail) {
- var req = new XMLHttpRequest();
- req.open("GET", url, true);
- req.overrideMimeType("text/plain; charset=x-user-defined");
- req.responseType = type;
- req.onload = function() {
- if (req.status >= "400") {
- if (fail) fail(req.status);
- } else {
- if (success) success(this.response);
- }
- }
- req.send();
- }
- // file readers
- function readFile(file, callback) {
- var reader = new FileReader();
- reader.onload = function() {
- callback(this.result);
- }
- reader.readAsArrayBuffer(file);
- }
- function downloadFile(data, name, mime) {
- var a = document.createElement("a");
- a.download = name;
- a.href = URL.createObjectURL(new Blob([data], {type: mime || "application/octet-stream"}));
- a.click();
- window.setTimeout(function() {
- URL.revokeObjectURL(a.href);
- }, 2000);
- }
- function uploadFile(accept, callback) {
- var input = document.createElement("input");
- input.type = "file";
- input.accept = accept;
- input.onchange = function() {
- let file = this.files[0];
- readFile(file, function(data) {
- callback({name: file.name, data: data});
- });
- }
- input.click();
- }
- // scripts
- function getScript(url, callback, err) {
- var script = document.createElement("script");
- script.type = "text/javascript";
- script.src = url;
- script.onload = function() {
- if (callback) callback();
- }
- script.onerror = function(e) {
- document.body.removeChild(script);
- if (err) err(e);
- }
- document.body.appendChild(script);
- }
- function getCore(name, callback, err) {
- getScript("./" + name + "_libretro.js", callback, err);
- }
- // check for updates
- function checkForUpdates() {
- grab("https://cdn.jsdelivr.net/gh/BinBashBanana/webretro@latest/assets/info.json", "text", function(text) {
- try {
- var updateObj = JSON.parse(text);
- if (updateObj.webretro) {
- latestVersion = updateObj.webretro;
- if (updateObj.versions[webretroVersion.toString()]) versionIndicator.title = "New features in this version:\n\n- " + updateObj.versions[webretroVersion.toString()].changeList.join("\n- ");
- if (latestVersion > webretroVersion && updateObj.versions[latestVersion.toString()]) {
- 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.";
- updateNotice.style.display = "initial";
- }
- }
- } catch (e) {
- log(e);
- }
- });
- }
- // unzip file
- function unzipFile(data, exts, callback, empty, notfound) {
- new zip.ZipReader(new zip.Uint8ArrayReader(data)).getEntries().then(function(entries) {
- if (entries.length) {
- for (var i = 0; i < entries.length; i++) {
- if (exts.split(", ").includes("." + u8atoutf8(entries[i].rawFilename).split(".").slice(-1)[0])) {
- let name = u8atoutf8(entries[i].rawFilename);
- entries[i].getData(new zip.Uint8ArrayWriter()).then(function(uzd) {
- callback(name, uzd);
- });
- break;
- }
- if (i == entries.length - 1 && notfound) notfound();
- }
- } else if (empty) empty();
- });
- }
- // zip files
- async function zipFiles(files, callback, replaceName) {
- var u8aWriter = new zip.Uint8ArrayWriter("application/zip");
- var writer = new zip.ZipWriter(u8aWriter);
- for (var i = 0; i < files.length; i++) {
- await writer.add(replaceName ? files[i].name.replace("rom", romName) : files[i].name, new zip.Uint8ArrayReader(files[i].data));
- }
- await writer.close();
- var zipped = await u8aWriter.getData();
- callback(zipped);
- }
- // uauth uploads
- function handleWebFile(data) {
- if (data.message == "success") {
- ffd.style.display = "none";
- romUploadCallback(data.name, data.data);
- } else if (data.message == "error") {
- alert("There was an error with the file picker. This may mean that you have to allow popup windows.");
- }
- }
- function uploadWebFile(type, exts) {
- uauth.open(type, exts.split(", "), handleWebFile);
- }
- // rom upload
- function readyRomUploads(exts) {
- romUploadsReady = true;
-
- // when a rom file is chosen
- upload.onclick = function() {
- uploadFile(exts, function(file) {
- ffd.style.display = "none";
- log('Succesfully read ROM file "' + file.name + '"');
- romUploadCallback(file.name, file.data);
- });
- }
-
- // web uploads
- googleDriveUpload.onclick = function() {
- uploadWebFile("drive", exts);
- }
- dropboxUpload.onclick = function() {
- uploadWebFile("dropbox", exts);
- }
- oneDriveUpload.onclick = function() {
- uploadWebFile("onedrive", exts);
- }
-
- // file drop (we need these to be global so they can be removed later)
- window.fileDragEnter = function(e) {
- if (e.dataTransfer.types.includes("Files")) ffd.classList.add("filehover");
- }
- window.fileDragOver = function(e) {
- e.preventDefault();
- }
- window.fileDropped = function(e) {
- if (e.dataTransfer.types.includes("Files")) {
- e.preventDefault();
- ffd.style.display = "none";
- let file = event.dataTransfer.files[0];
- readFile(file, function(data) {
- log('Succesfully read ROM file "' + file.name + '"');
- romUploadCallback(file.name, data);
- });
- }
- }
- document.addEventListener("dragenter", fileDragEnter, false);
- document.addEventListener("dragover", fileDragOver, false);
- document.addEventListener("drop", fileDropped, false);
- }
- // rom fetch
- function readyRomFetch() {
- var romloc = (/^(http:\/\/|https:\/\/|\/\/)/i).test(queries.rom) ? queries.rom : "roms/" + queries.rom;
- var romFilename = queries.rom.split("/").slice(-1)[0];
- grab(romloc, "arraybuffer", function(data) {
- log("Succesfully fetched ROM from " + romloc);
- romMode = "querystring";
- romUploadCallback(romFilename, data);
- }, function(error) {
- alert("Could not get ROM at " + romloc + " (Error " + error + ")");
- romMode = "upload";
- ffd.style.display = "block";
- });
- }
- // console window
- var conw = new jswindow({title: "Console", icon: "assets/terminal.svg"});
- var wconsole = document.createElement("textarea");
- wconsole.classList.add("console");
- wconsole.setAttribute("spellcheck", "false");
- wconsole.setAttribute("readonly", "");
- wconsole.wconsolemarker = document.createElement("span");
- wconsole.wconsolemarker.classList.add("consolemarker");
- wconsole.wconsoleinput = document.createElement("input");
- wconsole.wconsoleinput.type = "text";
- wconsole.wconsoleinput.classList.add("consoleinput");
- wconsole.wconsoleinput.title = "You can type things here as though you were using the browser console.";
- wconsole.wconsoleinput.setAttribute("spellcheck", "false");
- wconsole.wconsolemarker.onclick = function() { wconsole.wconsoleinput.focus(); }
- wconsole.wconsoleinput.onkeydown = function(e) {
- e.stopPropagation();
- if (e.keyCode == 13) {
- log(eval(this.value), this.value);
- this.value = "";
- }
- }
- conw.innerWindow.appendChild(wconsole);
- conw.innerWindow.appendChild(wconsole.wconsolemarker);
- conw.innerWindow.appendChild(wconsole.wconsoleinput);
- consoleButton.onclick = function() {
- conw.open({width: 450, height: 250, left: 100, top: 50});
- wconsole.wconsoleinput.focus();
- wconsole.scrollTo({top: wconsole.scrollHeight});
- }
- if (queries.hasOwnProperty("console")) conw.open({width: 450, height: 250, left: 100, top: 50});
- // modal windows (managers)
- function openManager(type) {
- if (managers[type]) {
- if (managerClosed[currentManager]) managerClosed[currentManager]();
- currentManager = type;
- if (managerOpened[type]) managerOpened[type]();
- managerTitle.textContent = managerNames[type] || type + "s";
- clearManagers();
- managers[type].style.display = "block";
- modals.style.display = "block";
- }
- }
- function clearManagers() {
- Object.values(managers).forEach(function(e) {
- e.style.display = "none";
- });
- }
- managerClose.onclick = function() {
- modals.style.display = "none";
- clearManagers();
- managerTitle.textContent = "";
- if (managerClosed[currentManager]) managerClosed[currentManager]();
- currentManager = undefined;
- }
- // --- code for the keybind manager ---
- // convert between config strings and objects
- function configStrToObj(str) {
- var convert1 = str.slice(0, -1).split("\n");
- var convert2 = {};
- for (var i = 0; i < convert1.length; i++) {
- var convert3 = convert1[i].split(" = ");
- convert2[convert3[0]] = convert3[1].slice(1, -1);
- }
- return convert2;
- }
- function configObjToStr(obj) {
- var convert1 = Object.keys(obj);
- var convert2 = "";
- for (var i = 0; i < convert1.length; i++) {
- convert2 += convert1[i] + ' = "' + obj[convert1[i]] + '"\n';
- }
- return convert2;
- }
- // load config saved in localStorage
- var defaultKeybindsObj = configStrToObj(defaultKeybinds);
- var savedKeybindsObj = window.localStorage.getItem("RetroArch_settings_keybinds") ? configStrToObj(window.localStorage.getItem("RetroArch_settings_keybinds")) : Object.assign({}, defaultKeybindsObj);
- var keybindsObj = Object.assign({}, savedKeybindsObj);
- var validKeybinds = Object.keys(defaultKeybindsObj);
- // update the config list
- function createConfigList() {
- keybindTable.innerHTML = "";
- // make the list
- for (var i = 0; i < validKeybinds.length; i++) {
- keybindTable.innerHTML += "<tr><td>" + validKeybinds[i] + "</td><td>" + keybindsObj[validKeybinds[i]] + "</td></tr>";
- }
- // highlight conflicting keys
- var keysList = Object.values(keybindsObj);
- for (var i = 0; i < validKeybinds.length; i++) {
- var matches = keysList.filter(v => v == keybindsObj[validKeybinds[i]]);
- if (matches.length > 1 && !(matches[0] == "nul")) keybindTable.children[i].lastElementChild.classList.add("conflict");
- }
- }
- // rebinding a key
- keybindTable.onclick = function(e) {
- if (e.target.tagName == "TD" && !e.target.nextElementSibling) {
- let valueElement = e.target;
- let keyNo = Array.from(keybindTable.children).indexOf(e.target.parentElement);
- valueElement.classList.remove("conflict");
- valueElement.textContent = "press a key (escape to unbind)";
-
- function newKeyHandler(e) {
- if (e.code == "Escape") {
- keybindsObj[validKeybinds[keyNo]] = "nul";
- createConfigList();
- } else {
- keybindsObj[validKeybinds[keyNo]] = codeToConfigIDMap[e.code] || "nul";
- createConfigList();
- }
- finishKeybindInput();
- }
- function cancelKeybindInput() {
- finishKeybindInput();
- createConfigList();
- }
- function finishKeybindInput() {
- document.removeEventListener("keydown", newKeyHandler);
- document.removeEventListener("mousedown", cancelKeybindInput);
- }
- document.addEventListener("keydown", newKeyHandler, false);
- document.addEventListener("mousedown", cancelKeybindInput, false);
- }
- }
- function tryApplyConfig() {
- if (emulatorStarted) {
- FS.writeFile("/home/web_user/retroarch/userdata/retroarch.cfg", nulKeys + configObjToStr(savedKeybindsObj) + extraConfig);
- Module._cmd_reload_config();
- }
- }
- // save the keybinds to localStorage, and apply them
- saveKeybinds.onclick = function() {
- savedKeybindsObj = Object.assign({}, keybindsObj);
- window.localStorage.setItem("RetroArch_settings_keybinds", configObjToStr(savedKeybindsObj));
- tryApplyConfig();
- alert("Saved!");
- }
- resetKeybinds.onclick = function() {
- if (confirm("Are you sure you want to reset all of the keybinds to their default values?")) {
- savedKeybindsObj = Object.assign({}, defaultKeybindsObj);
- keybindsObj = Object.assign({}, savedKeybindsObj);
- window.localStorage.removeItem("RetroArch_settings_keybinds");
- createConfigList();
- tryApplyConfig();
- }
- }
- // --- code for the screenshot manager ---
- // zip and download all of the screenshots in the list
- downloadAllScreenshots.onclick = function() {
- if (screenshotDatas.length) {
- zipFiles(screenshotDatas, function(zd) {
- downloadFile(zd, "screenshots-" + getTime() + ".zip", "application/zip");
- }, true);
- } else {
- alert("There are no screenshots to download!");
- }
- }
- // update the screenshot list
- function createScreenshotList() {
- var screenshots = FS.analyzePath("/home/web_user/retroarch/userdata/screenshots/").exists ? FS.readdir("/home/web_user/retroarch/userdata/screenshots/").filter(k => ![".", ".."].includes(k)) : [];
- screenshotsDiv.innerHTML = "";
-
- for (var i = 0; i < screenshots.length; i++) {
- var screenshotData = FS.readFile("/home/web_user/retroarch/userdata/screenshots/" + screenshots[i]);
- var blobUrl = window.URL.createObjectURL(new Blob([screenshotData], {type: "image/png"}));
- screenshotDatas[i] = {name: screenshots[i], data: screenshotData};
- screenshotObjUrls[i] = blobUrl;
- screenshotsDiv.innerHTML += '<div class="screenshot"><img src="' + blobUrl + '"><input type="button" data-action="download" value="Download"><input type="button" data-action="delete" value="Delete">' + "</div>";
- }
- }
- // why I didn't just use the DOM? I don't know
- screenshotsDiv.onclick = function(e) {
- if (e.target.tagName == "INPUT") {
- var screenshotNo = Array.from(screenshotsDiv.children).indexOf(e.target.parentElement);
- switch(e.target.dataset.action) {
- case "download":
- downloadFile(screenshotDatas[screenshotNo].data, screenshotDatas[screenshotNo].name.replace("rom", romName), "image/png");
- break;
- case "delete":
- if (confirm("Are you sure you want to delete this screenshot?")) {
- // doing all this is probably more efficient then reloading all of the screenshots
- window.URL.revokeObjectURL(screenshotObjUrls[screenshotNo]);
- FS.unlink("/home/web_user/retroarch/userdata/screenshots/" + screenshotDatas[screenshotNo].name);
- screenshotObjUrls.splice(screenshotNo, 1);
- screenshotDatas.splice(screenshotNo, 1);
- e.target.parentElement.remove();
- }
- break;
- }
- }
- }
- // --- code for the save/state manager ---
- function updateQuotaDisplay() {
- navigator.storage.estimate().then(function(info) {
- quotaText.textContent = "Storage used (estimate): " + bytesToHumanReadable(info.usage) + " / " + bytesToHumanReadable(info.quota) + " (" + (info.usage / info.quota).toFixed(2) + "%)";
- });
- }
- // update the save list
- function createSaveList() {
- updateQuotaDisplay();
- getAllIdbItems().then(function(items) {
- saveTable.innerHTML = "";
- // make the list
- for (var i = 0; i < items.length; i++) {
- if ((/^RetroArch_(saves|states)_/).test(items[i].key)) {
- var sName = items[i].key.replace(/^RetroArch_(saves|states)_/, "");
- var sType = (/^RetroArch_saves_/).test(items[i].key) ? "save" : "state";
- saveIDs.push({id: items[i].key, name: sName, type: sType});
- saveTable.innerHTML += "<tr><td>" + capitalize(sType) + ": " + sName + '</td><td><span data-action="download">Download</span><span data-action="delete">Delete</span></td></tr>';
- }
- }
- });
- }
- saveTable.onclick = function(e) {
- if (e.target.tagName == "SPAN") {
- let saveNo = Array.from(saveTable.children).indexOf(e.target.parentElement.parentElement);
- switch(e.target.dataset.action) {
- case "download":
- getIdbItem(saveIDs[saveNo].id).then(function(data) {
- downloadFile(data, "game-" + saveIDs[saveNo].type + "-" + saveIDs[saveNo].name + "-" + getTime() + (saveIDs[saveNo].type == "save" ? ".srm" : ".state"));
- });
- break;
- case "delete":
- if (confirm("Are you sure you want to delete this " + saveIDs[saveNo].type + ' for "' + saveIDs[saveNo].name + '"?') && confirm("Really really sure?")) {
- removeIdbItem(saveIDs[saveNo].id);
- saveIDs.splice(saveNo, 1);
- e.target.parentElement.parentElement.remove();
- updateQuotaDisplay();
- }
- break;
- }
- }
- }
- // --- end manager-specific code ---
- var managerOpened = {
- "keybind": function() {
- createConfigList();
- },
- "screenshot": function() {
- createScreenshotList();
- },
- "save": function() {
- createSaveList();
- }
- };
- var managerClosed = {
- "keybind": function() {
- keybindsObj = Object.assign({}, savedKeybindsObj);
- },
- "screenshot": function() {
- // clear the blob: urls used for the screenshots
- for (var i = 0; i < screenshotObjUrls.length; i++) {
- window.URL.revokeObjectURL(screenshotObjUrls[i]);
- }
- screenshotObjUrls = [];
- screenshotDatas = [];
- },
- "save": function() {
- saveIDs = [];
- }
- };
- // opening the managers
- keybindsButton.onclick = function(e) {
- e.preventDefault();
- openManager("keybind");
- }
- screenshotsButton.onclick = function() {
- openManager("screenshot");
- }
- savesButton.onclick = function(e) {
- e.preventDefault();
- openManager("save");
- }
- statesButton.onclick = function(e) {
- e.preventDefault();
- openManager("save");
- };
- // ---------- START LOAD ----------
- (function() {
- checkForUpdates();
-
- // ?system query
- if (!queries.core && queries.system) {
- var detectedCore = Object.keys(systems).find(k => systems[k].toLowerCase() == queries.system.toLowerCase());
- if (installedCores.includes(detectedCore)) {
- queries.core = detectedCore;
- } else if (queries.system.toLowerCase() == "autodetect") {
- queries.core = "autodetect";
- } else {
- alert("Invalid core (" + detectedCore + ")");
- }
- }
-
- // ?core query
- if (queries.core) {
- if (!window.navigator.userAgent.toLowerCase().includes("chrom")) alert("Best performance on Chrome!");
-
- // show hover menu
- hoverMenu.style.display = "block";
-
- versionIndicator.textContent = "v" + webretroVersion.toString();
-
- if (queries.core.toLowerCase() == "autodetect") {
- romUploadCallback = autodetectCoreHandler;
- systemName.textContent = "";
- readyRomUploads(".zip, " + allFileExts);
- } else {
- romUploadCallback = initFromFile;
- core = queries.core;
-
- setStatus("Getting core");
- if (core == "desmume") sramExt = ".dsv";
- // detect system for ROM upload
- systemName.textContent = systems[core] || "";
-
- getCore(core, function() {
- removeStatus("Getting core");
- log("Got core: " + core);
- if (romMode != "querystring") document.title = core + " | webretro";
-
- readyRomUploads(".zip, .bin, " + fileExts[systems[core]]);
- }, function() {
- // core loading error
- alert('Could not load specified core "' + core + '". Here is a list of available cores.');
- ffdContent.innerHTML = "<ul>" + aCoreList + "</ul>";
- ffd.style.display = "block";
- });
- }
-
- // ?rom query
- if (queries.rom) {
- readyRomFetch();
- } else {
- // prompt user to upload ROM file
- romMode = "upload";
- ffd.style.display = "block";
- }
- } else {
- // no core specified
- ffdContent.innerHTML = "<ul>" + aCoreList + "</ul>";
- ffd.style.display = "block";
- }
- })();
- // ----------- END LOAD -----------
- // start emulator from file name and data
- function initFromFile(name, data) {
- var dataView = new Uint8Array(data);
- if (name.split(".").slice(-1)[0] == "zip") {
- log("Zip file detected, unzipping...");
-
- unzipFile(dataView, fileExts[systems[core]], function(name, contents) {
- romName = name.split(".")[0];
- readyForInit(contents);
- }, function() {
- alert("That zip file appears to be empty!");
- }, function() {
- 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)");
- });
- } else {
- romName = name.split(".")[0];
- readyForInit(dataView);
- }
- }
- // autodetect core mode
- function autodetectCoreHandler(name, data) {
- var dataView = new Uint8Array(data);
- if (name.split(".").slice(-1)[0] == "zip") {
- log("Zip file detected, unzipping...");
-
- unzipFile(dataView, allFileExts, function(name, contents) {
- romName = name.split(".")[0];
- autodetectCore(name, contents);
- }, function() {
- alert("That zip file appears to be empty!");
- }, function() {
- 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)");
- });
- } else {
- romName = name.split(".")[0];
- autodetectCore(name, dataView);
- }
- }
- function autodetectCore(name, data) {
- var nameExt = "." + name.split(".").slice(-1)[0];
- var detectedCore;
- var fileExtsArray = Object.keys(fileExts);
- for (var i = 0; i < fileExtsArray.length; i++) {
- if (fileExts[fileExtsArray[i]].split(", ").includes(nameExt)) {
- detectedCore = Object.keys(systems).find(k => systems[k] == fileExtsArray[i]);
- break;
- }
- }
-
- var detectedSystem = systems[detectedCore] || "unknown";
- detectedCore = detectedCore || "unknown";
-
- if (allValidFileExts.split(", ").includes(nameExt)) {
- core = detectedCore;
-
- setStatus("Getting core");
- if (core == "desmume") sramExt = ".dsv";
-
- getCore(core, function() {
- removeStatus("Getting core");
- log("Got core: " + core);
- readyForInit(data);
- });
- } else {
- alert("That is a " + detectedSystem + " file! " + detectedCore + " (" + detectedSystem + ") is not currently supported.");
- }
- }
- // if the ROM is specified in the querystring, we will need to wait until the user has clicked to start the emulator
- function readyForInit(data) {
- document.title = romName + " | webretro";
-
- if (queries.romshift) data = avShift(data, parseInt(queries.romshift));
-
- // remove the file drop listeners
- if (romUploadsReady) {
- document.removeEventListener("dragenter", fileDragEnter);
- document.removeEventListener("dragover", fileDragOver);
- document.removeEventListener("drop", fileDropped);
- }
-
- if (romMode == "querystring") {
- // start button (don't delete this section, audio contexts are not allowed to start until a user gesture on the page, in this case, clicking the start button)
- startButton.style.display = "initial";
- startButton.onclick = function() {
- startButton.style.display = "none";
- initFromData(data);
- }
- } else {
- initFromData(data);
- }
- }
- // prepare FS with bundle
- function prepareBundle() {
- setStatus("Getting assets");
- log("Starting bundle fetch");
- let bundleSTime = performance.now();
-
- grab(bundleCdnLatest + "bundle/indexedfiles-v2.txt", "text", function(data) {
- var splitData = data.split(",,,\n");
- fsBundleDirs = JSON.parse(splitData[0]);
- fsBundleFiles = splitData[1].split("\n");
-
- // make the paths
- FS.createPath("/", "home/web_user/retroarch/bundle", true, true);
- for (var i = 0; i < fsBundleDirs.length; i++) {
- FS.createPath(baseFsBundleDir + fsBundleDirs[i][0], fsBundleDirs[i][1], true, true);
- }
-
- // make the files
- for (let i = 0; i < fsBundleFiles.length; i++) {
- grab(bundleCdn + "bundle" + fsBundleFiles[i], "arraybuffer", function(data) {
- FS.writeFile(baseFsBundleDir + fsBundleFiles[i], new Uint8Array(data));
- if (i == fsBundleFiles.length - 1) donePreparingBundle(performance.now() - bundleSTime);
- }, function() {
- bundleErrors += 1;
- if (i == fsBundleFiles.length - 1) donePreparingBundle(performance.now() - bundleSTime);
- });
- }
- }, function() {
- log("Failed to get asset bundle, skipping");
- bundleReady = true;
- removeStatus("Getting assets");
- });
- }
- function donePreparingBundle(tooktime) {
- bundleReady = true;
- removeStatus("Getting assets");
- log("Finished bundle fetch in " + (tooktime / 1000).toFixed(1) + " seconds, " + bundleErrors + " errors");
- }
- // tell the user to not rename the rom
- function doNotRename() {
- if (romMode == "upload" && !window.localStorage.getItem("webretro_settings_pastFirstSave")) {
- alert("WARNING: Do not rename your ROM file after this! The save data is specific to the ROM name!");
- window.localStorage.setItem("webretro_settings_pastFirstSave", "true");
- }
- }
- // save game
- function saveSRAM() {
- Module._cmd_savefiles();
- window.setTimeout(function() {
- if (FS.analyzePath("/home/web_user/retroarch/userdata/saves/rom" + sramExt).exists) {
- setIdbItem("RetroArch_saves_" + romName, FS.readFile("/home/web_user/retroarch/userdata/saves/rom" + sramExt));
- new sideAlert("Saved", 3000);
- readySaveReaders();
-
- doNotRename();
- } else {
- autosave.checked = false;
- new sideAlert("This game does not save!", 3000);
- }
- }, 1000);
- }
- // save state
- function saveStateFunc() {
- window.setTimeout(function() {
- if (FS.analyzePath("/home/web_user/retroarch/userdata/states/rom.state").exists) {
- setIdbItem("RetroArch_states_" + romName, FS.readFile("/home/web_user/retroarch/userdata/states/rom.state"));
-
- doNotRename();
- } else {
- new sideAlert("There was an error saving state. Please try again.", 5000);
- }
- }, 100);
- }
- // autosaving
- function autosaveSRAM() {
- if (autosave.checked && !document.hidden && !isPaused) {
- new sideAlert("Autosaving...", 3000);
- saveSRAM();
- }
- window.setTimeout(function() {
- autosaveSRAM();
- }, 300000);
- }
- // more functions for state buttons
- function readyStateReaders() {
- if (!stateReadersReady) {
- stateReadersReady = true;
-
- loadState.classList.remove("disabled");
- exportState.classList.remove("disabled");
- undoSaveState.classList.remove("disabled");
-
- loadState.onclick = function() {
- Module._cmd_load_state();
- readyStateReaders2();
- }
- exportState.onclick = function() {
- downloadFile(FS.readFile("/home/web_user/retroarch/userdata/states/rom.state"), "game-state-" + romName + "-" + getTime() + ".state");
- }
- undoSaveState.onclick = function() {
- Module._cmd_undo_save_state();
- }
- // also allow statereaders2 on load state press
- document.addEventListener("keydown", function(e) {
- if (!stateReaders2Ready && (e.code == Object.keys(codeToConfigIDMap).find(k => codeToConfigIDMap[k] == savedKeybindsObj.input_load_state))) readyStateReaders2();
- }, false);
- }
- }
- // even more functions for state buttons
- function readyStateReaders2() {
- if (!stateReaders2Ready) {
- stateReaders2Ready = true;
-
- undoLoadState.classList.remove("disabled");
- undoLoadState.onclick = function() {
- Module._cmd_undo_load_state();
- }
- }
- }
- // more functions for save buttons
- function readySaveReaders() {
- if (!saveReadersReady) {
- saveReadersReady = true;
-
- exportSave.classList.remove("disabled");
-
- exportSave.onclick = function() {
- downloadFile(FS.readFile("/home/web_user/retroarch/userdata/saves/rom" + sramExt), "game-sram-" + romName + "-" + getTime() + sramExt);
- }
- }
- }
- // runs after emulator starts
- function afterStart() {
- emulatorStarted = true;
-
- // remove loading text
- canvas.style.background = "none";
-
- adjustCanvasSize();
-
- // functions for save and state buttons
- saveState.classList.remove("disabled");
- importState.classList.remove("disabled");
- saveGame.classList.remove("disabled");
- importSave.classList.remove("disabled");
- autosave.removeAttribute("disabled");
- autosave.parentElement.classList.remove("disabled");
-
- saveState.onclick = function() {
- Module._cmd_save_state();
- readyStateReaders();
- }
- importState.onclick = function() {
- uploadFile(".bin, .state, .save, .dat, .gam, .sav, application/*", function(file) {
- setIdbItem("RetroArch_states_" + romName, new Uint8Array(file.data));
- FS.writeFile("/home/web_user/retroarch/userdata/states/rom.state", new Uint8Array(file.data));
- new sideAlert("Imported state (Now press load state)", 3000);
- readyStateReaders();
- });
- }
-
- saveGame.onclick = function() {
- new sideAlert("Saving...", 3000);
- saveSRAM();
- }
- importSave.onclick = function() {
- uploadFile(".bin, .srm, .sram, .ram, .gam, .sav, .dsv, application/*", function(file) {
- autosave.checked = false;
- setIdbItem("RetroArch_saves_" + romName, new Uint8Array(file.data));
- if (confirm("Save imported. Reloading now for changes to take effect.")) {
- window.onbeforeunload = function() {}
- window.location.reload();
- }
- });
- }
-
- // also allow state readers on save state press
- document.addEventListener("keydown", function(e) {
- if (!stateReadersReady && (e.code == Object.keys(codeToConfigIDMap).find(k => codeToConfigIDMap[k] == savedKeybindsObj.input_save_state))) readyStateReaders();
- }, false);
-
- // start autosave loop
- window.setTimeout(function() {
- autosaveSRAM();
- }, 300000);
-
- // toggle between sharp and smooth canvas graphics
- smooth.removeAttribute("disabled");
- smooth.parentElement.classList.remove("disabled");
- smooth.onclick = function() {
- if (this.checked) {
- canvas.className = "textureSmooth";
- } else {
- canvas.className = "texturePixelated";
- }
- }
-
- // higher resolution
- doubleRes.removeAttribute("disabled");
- doubleRes.parentElement.classList.remove("disabled");
- doubleRes.onclick = function() {
- if (this.checked) {
- resModifier = 2;
- adjustCanvasSize();
- } else {
- resModifier = 1;
- adjustCanvasSize();
- }
- }
-
- // pause and resume
- pause.classList.remove("disabled");
- pause.onclick = function() {
- if (this.textContent.trim() == "Pause") {
- Module.pauseMainLoop();
- isPaused = true;
- this.textContent = "Resume";
- document.body.classList.add("paused");
- } else {
- Module.resumeMainLoop();
- isPaused = false;
- this.textContent = "Pause";
- document.body.classList.remove("paused");
- }
- }
- resumeOverlay.onclick = function() {
- pause.click();
- }
-
- // toggle menu
- menuButton.classList.remove("disabled");
- menuButton.onclick = function() {
- Module._cmd_toggle_menu();
- }
-
- // screenshot button
- takeScreenshot.classList.remove("disabled");
- takeScreenshot.onclick = function() {
- Module._cmd_take_screenshot();
- }
-
- // flash the menu on first use
- if (!window.localStorage.getItem("webretro_settings_pastFirstStart")) {
- hoverMenu.classList.add("show");
- hoverMenuIndicator.classList.add("show");
- window.setTimeout(function() {
- hoverMenu.classList.remove("show");
- hoverMenuIndicator.classList.remove("show");
- }, 3000);
- window.localStorage.setItem("webretro_settings_pastFirstStart", "true");
- }
-
- // ctrl+v inside canvas
- document.addEventListener("keydown", function(e) {
- if (e.ctrlKey && e.key == "v") {
- fakeKeyPress({code: "Backspace"});
- navigator.clipboard.readText().then(function(text) {
- sendText(text);
- });
- }
- }, false);
- }
- // start
- function initFromData(data) {
- window.onbeforeunload = function() { return true; }
- async function waitForReady() {
- if (wasmReady && bundleReady) {
- setStatus("Waiting for emulator");
- log("Initializing with " + data.byteLength + " bytes of data");
- updateNotice.style.display = "none";
- canvas.addEventListener("contextmenu", function(e) {
- e.preventDefault();
- }, false);
- window.addEventListener("resize", adjustCanvasSize, false);
- adjustCanvasSize();
-
- // prevent defaults for key presses
- document.addEventListener("keydown", function(e) {
- if (pdKeys.includes(e.which)) e.preventDefault();
- }, false);
-
- // move the saves and states from the old version (localStorage) to indexedDB
- await tryLsToIdb();
-
- // rom
- FS.writeFile("/rom.bin", data);
-
- // SMAS brick fix
- if (systems[core] == "SNES") {
- var hash = md5(u8atoutf8(data));
- if (smasBrickFix.hasOwnProperty(hash)) {
- FS.writeFile("/rom.ips", new Uint8Array(smasBrickFix[hash]));
- new sideAlert("SMAS Bricks Fixed!", 5000);
- }
- }
-
- // load save
- var cSave = await getIdbItem("RetroArch_saves_" + romName);
- if (cSave) {
- FS.createPath("/", "home/web_user/retroarch/userdata/saves", true, true);
- FS.writeFile("/home/web_user/retroarch/userdata/saves/rom" + sramExt, cSave);
- new sideAlert("Save loaded for " + romName, 5000);
- log("Save loaded for " + romName);
- readySaveReaders();
- }
-
- // import state
- var cState = await getIdbItem("RetroArch_states_" + romName);
- if (cState) {
- FS.createPath("/", "home/web_user/retroarch/userdata/states", true, true);
- FS.writeFile("/home/web_user/retroarch/userdata/states/rom.state", cState);
- new sideAlert("State imported for " + romName, 5000);
- log("State imported for " + romName);
- readyStateReaders();
- }
-
- // config
- FS.createPath("/", "home/web_user/retroarch/userdata", true, true);
- FS.writeFile("/home/web_user/retroarch/userdata/retroarch.cfg", nulKeys + configObjToStr(savedKeybindsObj) + extraConfig);
-
- // start
- Module.callMain(Module.arguments);
- adjustCanvasSize();
-
- window.setTimeout(afterStart, 2000);
- } else {
- window.setTimeout(waitForReady, 1000);
- }
- }
- waitForReady();
- }
- var Module = {
- canvas: canvas,
- noInitialRun: true,
- arguments: ["/rom.bin", "--verbose"],
- onRuntimeInitialized: function() {
- wasmReady = true;
- log("WASM ready");
-
- // fetch asset bundle
- if (queries.hasOwnProperty("nobundle")) {
- bundleReady = true;
- log("Skipping bundle");
- } else {
- prepareBundle();
- }
- },
- print: function(text) {
- log("stdout: " + text);
- },
- printErr: function(text) {
- log("stderr: " + text);
- }
- };
|