
This change provides the ability to upload save states. When a state is downloaded, the state (savestate.state), screenshot (screenshot.jpg), and a json file (rominfo.json) describing the save state are zipped and downloaded. The json file description is defined as follows: ```json { "Name": "Super Mario Bros. (1985-09-13)(Nintendo)(JP-US).zip", "StateDateTime": "2024-06-24T05:34:38", "StateName": "", "MD5": "7d158dcd242e77ba249ac8342474aa77", "SHA1": "3d4b04dc78f9d998f17d9fe9ad982a83b5ed72df", "Type": "ROM" } ``` | Attribute | Value | | -------- | ------| | Name | The name of the ROM that the state belongs to. This is merely a convenience attribute. | | StateDateTime | The date and time (in UTC) when the state was initially saved. | | StateName | The name of the state | | MD5 | The MD5 hash of the ROM that the state belongs to. | | SHA1 | The SHA1 hash of the ROM that the state belongs to. | | Type | Whether the state belongs to a ROM or ROM Group | If the zip is re-uploaded, the above json file will be used to automatically match the saved state to the ROM that created it. If a zip is uploaded without the above three files, the upload will fail. If a file is uploaded that is not a zip, it will be stored against the currently running ROM and a warning will be displayed that Gaseous was unable to verify that the state belongs to the ROM, and may not function as expected. Closes #336
195 lines
9.5 KiB
HTML
195 lines
9.5 KiB
HTML
<div id="saved_states">
|
|
|
|
</div>
|
|
<div>
|
|
<span>Upload state file: </span><input type="file" id="stateFile" />
|
|
</div>
|
|
|
|
<script text="text/javascript">
|
|
document.getElementById('modal-heading').innerHTML = "Load saved state";
|
|
|
|
console.log(modalVariables);
|
|
|
|
var statesUrl = '/api/v1.1/StateManager/' + modalVariables.romId + '?IsMediaGroup=' + modalVariables.IsMediaGroup;
|
|
console.log(statesUrl);
|
|
function LoadStates() {
|
|
ajaxCall(
|
|
statesUrl,
|
|
'GET',
|
|
function (result) {
|
|
var statesBox = document.getElementById('saved_states');
|
|
statesBox.innerHTML = '';
|
|
document.getElementById('stateFile').value = '';
|
|
|
|
for (var i = 0; i < result.length; i++) {
|
|
var stateBox = document.createElement('div');
|
|
stateBox.id = 'stateBox_' + result[i].id;
|
|
stateBox.className = 'saved_state_box';
|
|
|
|
// screenshot panel
|
|
var stateImageBox = document.createElement('div');
|
|
stateImageBox.id = 'stateImageBox_' + result[i].id;
|
|
stateImageBox.className = 'saved_state_image_box';
|
|
|
|
if (result[i].hasScreenshot == true) {
|
|
var stateImage = document.createElement('img');
|
|
stateImage.className = 'saved_state_image_image';
|
|
stateImage.src = '/api/v1.1/StateManager/' + modalVariables.romId + '/' + result[i].id + '/Screenshot/image.png?IsMediaGroup=' + modalVariables.IsMediaGroup;
|
|
stateImageBox.appendChild(stateImage);
|
|
}
|
|
stateBox.appendChild(stateImageBox);
|
|
|
|
// main panel
|
|
var stateMainPanel = document.createElement('div');
|
|
stateMainPanel.id = 'stateMainPanel_' + result[i].id;
|
|
stateMainPanel.className = 'saved_state_main_box';
|
|
|
|
var stateName = document.createElement('input');
|
|
stateName.id = 'stateName_' + result[i].id;
|
|
stateName.type = 'text';
|
|
stateName.className = 'saved_state_name';
|
|
stateName.setAttribute('onblur', 'UpdateStateSave(' + result[i].id + ', ' + modalVariables.IsMediaGroup + ');');
|
|
if (result[i].name) {
|
|
stateName.value = result[i].name;
|
|
} else {
|
|
stateName.setAttribute('placeholder', "Untitled");
|
|
}
|
|
stateMainPanel.appendChild(stateName);
|
|
|
|
var stateTime = document.createElement('div');
|
|
stateTime.id = 'stateTime_' + result[i].id;
|
|
stateTime.className = 'saved_state_date';
|
|
stateTime.innerHTML = moment(result[i].saveTime).format("YYYY-MM-DD h:mm:ss a");
|
|
stateMainPanel.appendChild(stateTime);
|
|
|
|
var stateControls = document.createElement('div');
|
|
stateControls.id = 'stateControls_' + result[i].id;
|
|
stateControls.className = 'saved_state_controls';
|
|
|
|
var stateControlsLaunch = document.createElement('span');
|
|
stateControlsLaunch.id = 'stateControlsLaunch_' + result[i].id;
|
|
stateControlsLaunch.className = 'romstart';
|
|
var emulatorTarget = '/index.html?page=emulator&engine=@engine&core=@core&platformid=@platformid&gameid=@gameid&romid=@romid&mediagroup=@mediagroup&rompath=@rompath&stateid=' + result[i].id;
|
|
switch (getQueryString('page', 'string')) {
|
|
case 'emulator':
|
|
var mediagroupint = 0;
|
|
if (modalVariables.IsMediaGroup == true) {
|
|
mediagroupint = 1;
|
|
}
|
|
emulatorTarget = emulatorTarget.replaceAll('@engine', getQueryString('engine', 'string'));
|
|
emulatorTarget = emulatorTarget.replaceAll('@core', getQueryString('core', 'string'));
|
|
emulatorTarget = emulatorTarget.replaceAll('@platformid', getQueryString('platformid', 'string'));
|
|
emulatorTarget = emulatorTarget.replaceAll('@gameid', getQueryString('gameid', 'string'));
|
|
emulatorTarget = emulatorTarget.replaceAll('@romid', getQueryString('romid', 'string'));
|
|
emulatorTarget = emulatorTarget.replaceAll('@mediagroup', mediagroupint);
|
|
emulatorTarget = emulatorTarget.replaceAll('@rompath', getQueryString('rompath', 'string'));
|
|
stateControlsLaunch.setAttribute("onclick", 'window.location.replace("' + emulatorTarget + '")');
|
|
break;
|
|
case 'game':
|
|
console.log(modalVariables);
|
|
emulatorTarget = emulatorTarget.replaceAll('@engine', modalVariables.engine);
|
|
emulatorTarget = emulatorTarget.replaceAll('@core', modalVariables.core);
|
|
emulatorTarget = emulatorTarget.replaceAll('@platformid', modalVariables.platformid);
|
|
emulatorTarget = emulatorTarget.replaceAll('@gameid', modalVariables.gameid);
|
|
emulatorTarget = emulatorTarget.replaceAll('@romid', modalVariables.romId);
|
|
emulatorTarget = emulatorTarget.replaceAll('@mediagroup', modalVariables.mediagroup);
|
|
emulatorTarget = emulatorTarget.replaceAll('@rompath', modalVariables.rompath);
|
|
stateControlsLaunch.setAttribute("onclick", 'window.location.href = "' + emulatorTarget + '"');
|
|
break;
|
|
}
|
|
|
|
stateControlsLaunch.innerHTML = 'Launch';
|
|
stateControlsLaunch.style.float = 'right';
|
|
stateControls.appendChild(stateControlsLaunch);
|
|
|
|
var stateControlsDownload = document.createElement('a');
|
|
stateControlsDownload.id = 'stateControlsDownload_' + result[i].id;
|
|
stateControlsDownload.className = 'saved_state_buttonlink';
|
|
stateControlsDownload.href = '/api/v1.1/StateManager/' + modalVariables.romId + '/' + result[i].id + '/State/savestate.state?IsMediaGroup=' + modalVariables.IsMediaGroup;
|
|
stateControlsDownload.innerHTML = '<img src="/images/download.svg" class="banner_button_image" alt="Download" title="Download" />';
|
|
stateControls.appendChild(stateControlsDownload);
|
|
|
|
var stateControlsDelete = document.createElement('span');
|
|
stateControlsDelete.id = 'stateControlsDelete_' + result[i].id;
|
|
stateControlsDelete.className = 'saved_state_buttonlink';
|
|
stateControlsDelete.setAttribute('onclick', 'DeleteStateSave(' + result[i].id + ', ' + modalVariables.IsMediaGroup + ');');
|
|
stateControlsDelete.innerHTML = '<img src="/images/delete.svg" class="banner_button_image" alt="Delete" title="Delete" />';
|
|
stateControls.appendChild(stateControlsDelete);
|
|
|
|
stateMainPanel.appendChild(stateControls);
|
|
|
|
stateBox.appendChild(stateMainPanel);
|
|
|
|
statesBox.appendChild(stateBox);
|
|
}
|
|
}
|
|
);
|
|
}
|
|
|
|
LoadStates();
|
|
|
|
function DeleteStateSave(StateId, IsMediaGroup) {
|
|
ajaxCall(
|
|
'/api/v1.1/StateManager/' + modalVariables.romId + '/' + StateId + '?IsMediaGroup=' + IsMediaGroup,
|
|
'DELETE',
|
|
function (success) {
|
|
LoadStates();
|
|
},
|
|
function (error) {
|
|
LoadStates();
|
|
}
|
|
);
|
|
}
|
|
|
|
function UpdateStateSave(StateId, IsMediaGroup) {
|
|
var stateName = document.getElementById('stateName_' + StateId);
|
|
|
|
var model = {
|
|
"name": stateName.value
|
|
};
|
|
|
|
ajaxCall(
|
|
'/api/v1.1/StateManager/' + modalVariables.romId + '/' + StateId + '?IsMediaGroup=' + IsMediaGroup,
|
|
'PUT',
|
|
function (success) {
|
|
LoadStates();
|
|
},
|
|
function (error) {
|
|
LoadStates();
|
|
},
|
|
JSON.stringify(model)
|
|
);
|
|
}
|
|
|
|
document.getElementById('stateFile').addEventListener('change', function () {
|
|
let file = document.getElementById('stateFile').files[0];
|
|
let formData = new FormData();
|
|
formData.append('file', file);
|
|
|
|
console.log("Uploading state file");
|
|
|
|
fetch('/api/v1.1/StateManager/Upload?RomId=' + modalVariables.romId + '&IsMediaGroup=' + modalVariables.IsMediaGroup, {
|
|
method: 'POST',
|
|
body: formData
|
|
})
|
|
.then(response => response.json())
|
|
.then(data => {
|
|
console.log('Success:', data);
|
|
UploadAlert(data);
|
|
LoadStates();
|
|
})
|
|
.catch(error => {
|
|
console.error("Error:", error);
|
|
UploadAlert(error);
|
|
LoadStates();
|
|
});
|
|
});
|
|
|
|
function UploadAlert(data) {
|
|
if (data.Management == "Managed") {
|
|
alert("State uploaded successfully.");
|
|
} else {
|
|
alert("State uploaded successfully, but it might not function correctly for this platform and ROM.");
|
|
}
|
|
}
|
|
</script> |