<p>The SF2000 supports save states for games, but it bundles the save state data into a custom format including a thumbnail and metadata; this bundle can't be directly used as save state data for other emulator platforms (e.g., Retroarch). This tool allows you to extract raw save-state data and thumbnails from SF2000 save-state bundles, in case you want to use them with the same emulator on another device; it also allows you to take save states from another device, and convert them to a format the SF2000 can parse. Please note this tool is provided as-is; make sure you have backups of anything you care about before potentially replacing any files on your SF2000's microSD card! 🙂</p>
<p>This tool makes use of the <ahref="https://github.com/nodeca/pako">pako</a> JavaScript library.</p>
<p>This tool can operate in two main modes - you can use it to convert save states <em>from</em> the SF2000 format <em>to</em> raw save-state data (and optionally download the thumbnail), or you can use it to convert raw save state data <em>from</em> another emulator <em>to</em> the SF2000 format. Choose the mode you want, and follow the next instruction that appears.</p>
// Display a note about platform compatibility for save states...
setMessage("warning", "platformNote", "<strong><em>NOTE:</em></strong> The SF2000 is uses a MIPS processor; as a result, save states created on the SF2000 will likely only ever work on other MIPS devices, and will likely <strong>never</strong> work on any other kind of device (e.g., PCs, Android devices, Rockchip devices, ARM devices, etc.).")
setMessage("warning", "initialWarning", "<strong><em>NOTE:</em></strong> This tool will <em>not</em> convert save states from one emulator's format to another; it <em>only</em> gives you either the raw save state data the SF2000 generated (when converting <em>from</em> the SF2000), or allows you to take any random file and shove it into the container format the SF2000 uses for save states (when converting <em>to</em> the SF2000)… whether or not the SF2000 is able to understand the file you give it is up to the SF2000, not to me! If you're converting save states to the SF2000, and the SF2000 doesn't work with whatever kind of save state you provided, there's nothing I can do about that.<br><br>You can <ahref=\"https://vonmillhausen.github.io/sf2000/#emulators\"target=\"_blank\"rel=\"noreferrernoopener\">find a reference to all the specific emulators and versions used by the SF2000 here</a>; you'll probably only have success if you're using at least the same emulator, if not also the same version. Also, to have any chance of success, you must be using the exact same ROM on both devices, and make sure save state compression is turned off if your save state is coming from Retroarch!");
// Add the appropriate Step 2 depending on what was selected...
if (this.value == "fromSF2000") {
setupStepTwo_From();
}
else if (this.value == "toSF2000") {
setupStepTwo_To();
}
});
}
// This function sets up the HTML for "Convert from SF2000 > Step 2", selecting
// a save state file from the SF2000's microSD card that the user wants to
// convert to raw save state data and/or a thumbnail...
function setupStepTwo_From() {
// Create the new section, add our heading and our instruction paragraph...
var html = "<sectionid=\"selectSF2000File\"><h2>Step 2: Select SF2000 Save State File</h2><p>Select the SF2000 save state file you want to convert from. The save states are usually stored in the <code>save</code> subfolder where the ROM for the game is located. There can be up to four saves states per game, with the extensions <code>.sa0</code>, <code>.sa1</code>, <code>.sa2</code> and <code>.sa3</code> respectively.</p><divid=\"step2Messages\"></div>";
// Add our file chooser...
html += "<divclass=\"controlContainer\"><labelclass=\"control\"><inputid=\"inputSAFile\"type=\"file\"accept=\".sa0,.sa1,.sa2,.sa3,.skp,application/octet-stream\"></label></div>";
// Close off our section...
html += "</section>";
// Finally, add a <hr> separator after the last step, and append the new step...
// This function sets up the HTML for "Convert to SF2000 > Step 2", selecting
// the non-SF2000 save state file the user wants to convert to an SF2000 save
// state bundle...
function setupStepTwo_To() {
// Start our new section, add our header and our instructions...
var html = "<sectionid=\"selectStateFile\"><h2>Step 2: Save State File</h2><p>Select the save state file from your non-SF2000 emulator that you want to convert to an SF2000-compatible save state bundle.</p><divid=\"step2Messages\"></div>";
// Add our file chooser...
html += "<divclass=\"controlContainer\"><labelclass=\"control\"><inputid=\"inputStateFile\"type=\"file\"></label></div>";
// Close our section...
html += "</section>";
// Finally, add a <hr> separator after the last step, and append the new step...
setMessage("error", "step2Messages", "ERROR: The selected file does not appear to be a binary file, and therefore can't be a save state file; please make sure you're selecting a valid emulator save state file.");
// This function sets up the HTML for "Convert from SF2000 > Step 2 > Step 3"...
function setupStepThree_From() {
// In this section, we'll be presenting the user with the thumbnail of
// their save state, and a download button for downloading the save
// state data itself. Let's start building our HTML...
var html = "<sectionid=\"sf2000StateDownload\"><h2>Step 3: Download Save State Data</h2><p>Below you'll find the thumbnail for your chosen save state file, as well as a download button which will let you download the raw save state data for use with other emulators/devices. If you want to save the thumbnail as well, just right-click or tap-and-hold on it like any other image, and save it that way.</p>";
// Next, we'll add the image preview...
html += "<divclass=\"controlContainer\"><divclass=\"control\"><canvasid=\"thumbnailPreview\"></canvas></div></div>";
// ... and the Download button...
html += "<divclass=\"controlContainer\"><divclass=\"control\"><inputid=\"saveStateDownload\"type=\"button\"value=\"Download\"></div></div>";
// ... and lastly we'll close off our section...
html += "</section>";
// Add a <hr> separator after the previous step, and append the new step...
// This function sets up the HTML for "Convert to SF2000 > Step 2 > Step 3"...
function setupStepThree_To() {
// In this section, we'll be rendering the HTML for some controls - the
// user needs to select the ROM file their new save state is for (so we
// can name the save state file correctly), and choose whether their new
// save state should be stored in slot 1, 2, 3 or 4 (again, required for
// the file name). Let's start by creating our new section, and add its
// heading and instruction paragraph...
html = "<sectionid=\"processUserFile\"><h2>Step 3: Select Game ROM And Slot Number</h2><p>To name your new SF2000 save state properly, this tool needs to know two things - the name of the game ROM file the save state is for, and which save slot (1, 2, 3 or 4) the save state should take up. Use the controls below to select your game ROM file from your SF2000's microSD card, and to choose which save slot you want.</p><p>When you've chosen a ROM file and a slot number, the Download button will become enabled, and can be used to download your new save state file. Put it in the <code>save</code> subfolder along-side wherever your ROM file is stored on the SF2000's microSD card (e.g., if your ROM file is <code>sd:/ROMS/Apotris.gba</code>, and you chose save slot 1, you'd put the resulting save state in <code>sd:/ROMS/save/Apotris.gba.sa0</code>).</p><p>The one special case is with arcade games; the ROM you need to select is one of the ones in the <code>sd:/ARCADE/bin/</code> folder, and the resulting save state bundle goes into <code>sd:/ARCADE/save/</code>. As an example, if you wanted to transfer a save state to the SF2000 for the game \"Metal Slug\" in slot 3, you'd select <code>sd:/ARCADE/bin/mslug.zip</code> and Slot 3, and the final location to put the save state would be <code>sd:/ARCADE/save/mslug.zip.sa2</code> - I hope that makes sense! You can <ahref=\"https://vonmillhausen.github.io/sf2000/arcade/DataFrog_SF2000_FBA.html\"target=\"_blank\"rel=\"noreferrernoopener\">find a list of all potential arcade zip-file names and the full name of the game they represent here</a>, if it helps - the first column (\"rom\") is the name of the zip-file without the <code>.zip</code> part, and the second column (\"fullname\") is the full name of the game/romset.</p><divid=\"step3Messages\"></div>";
// Now let's add our controls (file browser for the game ROM, and four
// radio button inputs for the save state slot number); we'll group them
// in one of our control containers for neatness...
html += "<divclass=\"controlContainer\">";
// ROM file browser...
html += "<divclass=\"control\"><label>Select game ROM: <inputid=\"inputROMFile\"type=\"file\"></label></div>";
// Save state slot number...
html += "<divid=\"slotSelector\"class=\"control\"><label><inputtype=\"radio\"name=\"saveSlot\"value=\"0\"> Save Slot 1</label><label><inputtype=\"radio\"name=\"saveSlot\"value=\"1\"> Save Slot 2</label><label><inputtype=\"radio\"name=\"saveSlot\"value=\"2\"> Save Slot 3</label><label><inputtype=\"radio\"name=\"saveSlot\"value=\"3\"> Save Slot 4</label></div>";
html += "</div>";
// ... and our Download button...
html += "<divclass=\"controlContainer\"><divclass=\"control\"><inputid=\"saveStateDownload\"type=\"button\"value=\"Download\"disabled></div></div>";
// ... and lastly we'll close off our section...
html += "</section>";
// Add a <hr> separator after the previous step, and append the new step...
setMessage("error", "step3Messages", "ERROR: The selected file does not appear to be a binary file, and therefore can't be a game ROM file; please make sure you're selecting a valid game ROM file.");