mirror of https://github.com/bsnes-emu/bsnes.git
177 lines
4.9 KiB
C++
177 lines
4.9 KiB
C++
auto Program::managedStates() -> vector<string> {
|
|
if(!emulator->loaded()) return {};
|
|
|
|
if(gamePath().endsWith("/")) {
|
|
return directory::ifiles({statePath(), "managed/"}, "*.bst");
|
|
} else {
|
|
Decode::ZIP input;
|
|
if(input.open(statePath())) {
|
|
vector<string> filenames;
|
|
for(auto& file : input.file) {
|
|
if(file.name.match("managed/*.bst")) filenames.append(file.name.trimLeft("managed/", 1L));
|
|
}
|
|
filenames.isort();
|
|
return filenames;
|
|
}
|
|
}
|
|
|
|
return {};
|
|
}
|
|
|
|
auto Program::loadState(string filename) -> bool {
|
|
if(!emulator->loaded()) return false;
|
|
|
|
string prefix = Location::file(filename);
|
|
vector<uint8_t> memory;
|
|
|
|
if(gamePath().endsWith("/")) {
|
|
string location = {statePath(), filename, ".bst"};
|
|
if(!file::exists(location)) return showMessage({"[", prefix, "] not found"}), false;
|
|
if(filename != "quick/undo") saveUndoState();
|
|
if(filename == "quick/undo") saveRedoState();
|
|
memory = file::read(location);
|
|
} else {
|
|
string location = {filename, ".bst"};
|
|
Decode::ZIP input;
|
|
if(input.open(statePath())) {
|
|
for(auto& file : input.file) {
|
|
if(file.name != location) continue;
|
|
memory = input.extract(file);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if(memory) {
|
|
serializer s{memory.data(), memory.size()};
|
|
if(!emulator->unserialize(s)) return showMessage({"[", prefix, "] is in incompatible format"}), false;
|
|
return showMessage({"Loaded [", prefix, "]"}), true;
|
|
} else {
|
|
return showMessage({"[", prefix, "] not found"}), false;
|
|
}
|
|
}
|
|
|
|
auto Program::saveState(string filename) -> bool {
|
|
if(!emulator->loaded()) return false;
|
|
|
|
string prefix = Location::file(filename);
|
|
serializer s = emulator->serialize();
|
|
if(!s.size()) return showMessage({"Failed to save [", prefix, "]"}), false;
|
|
|
|
if(gamePath().endsWith("/")) {
|
|
string location = {statePath(), filename, ".bst"};
|
|
directory::create(Location::path(location));
|
|
if(!file::write(location, s.data(), s.size())) return showMessage({"Unable to write [", prefix, "] to disk"}), false;
|
|
} else {
|
|
string location = {filename, ".bst"};
|
|
|
|
struct State { string name; vector<uint8_t> memory; };
|
|
vector<State> states;
|
|
|
|
Decode::ZIP input;
|
|
if(input.open(statePath())) {
|
|
for(auto& file : input.file) {
|
|
if(!file.name.endsWith(".bst")) continue;
|
|
if(file.name == location) continue;
|
|
states.append({file.name, input.extract(file)});
|
|
}
|
|
}
|
|
input.close();
|
|
|
|
Encode::ZIP output{statePath()};
|
|
for(auto& state : states) {
|
|
output.append(state.name, state.memory.data(), state.memory.size());
|
|
}
|
|
output.append(location, s.data(), s.size());
|
|
}
|
|
|
|
return showMessage({"Saved [", prefix, "]"}), true;
|
|
}
|
|
|
|
auto Program::saveUndoState() -> bool {
|
|
auto statusTime = this->statusTime;
|
|
auto statusMessage = this->statusMessage;
|
|
auto result = saveState("quick/undo");
|
|
this->statusTime = statusTime;
|
|
this->statusMessage = statusMessage;
|
|
return result;
|
|
}
|
|
|
|
auto Program::saveRedoState() -> bool {
|
|
auto statusTime = this->statusTime;
|
|
auto statusMessage = this->statusMessage;
|
|
auto result = saveState("quick/redo");
|
|
this->statusTime = statusTime;
|
|
this->statusMessage = statusMessage;
|
|
return result;
|
|
}
|
|
|
|
auto Program::removeState(string filename) -> bool {
|
|
if(!emulator->loaded()) return false;
|
|
|
|
if(gamePath().endsWith("/")) {
|
|
string location = {statePath(), filename, ".bst"};
|
|
return file::remove(location);
|
|
} else {
|
|
bool found = false;
|
|
string location = {filename, ".bst"};
|
|
|
|
struct State { string name; vector<uint8_t> memory; };
|
|
vector<State> states;
|
|
|
|
Decode::ZIP input;
|
|
if(input.open(statePath())) {
|
|
for(auto& file : input.file) {
|
|
if(file.name == location) { found = true; continue; }
|
|
states.append({file.name, input.extract(file)});
|
|
}
|
|
}
|
|
input.close();
|
|
|
|
if(states) {
|
|
Encode::ZIP output{statePath()};
|
|
for(auto& state : states) {
|
|
output.append(state.name, state.memory.data(), state.memory.size());
|
|
}
|
|
} else {
|
|
//remove .bsz file if there are no states left in the archive
|
|
file::remove(statePath());
|
|
}
|
|
|
|
return found;
|
|
}
|
|
}
|
|
|
|
auto Program::renameState(string from, string to) -> bool {
|
|
if(!emulator->loaded()) return false;
|
|
|
|
if(gamePath().endsWith("/")) {
|
|
from = {statePath(), from, ".bst"};
|
|
to = {statePath(), to, ".bst."};
|
|
return file::rename(from, to);
|
|
} else {
|
|
bool found = false;
|
|
from = {from, ".bst"};
|
|
to = {to, ".bst"};
|
|
|
|
struct State { string name; vector<uint8_t> memory; };
|
|
vector<State> states;
|
|
|
|
Decode::ZIP input;
|
|
if(input.open(statePath())) {
|
|
for(auto& file : input.file) {
|
|
if(file.name == from) { found = true; file.name = to; }
|
|
states.append({file.name, input.extract(file)});
|
|
}
|
|
}
|
|
input.close();
|
|
|
|
Encode::ZIP output{statePath()};
|
|
for(auto& state : states) {
|
|
output.append(state.name, state.memory.data(), state.memory.size());
|
|
}
|
|
|
|
return found;
|
|
}
|
|
}
|