Savestates: Allow saving/loading to arbitrary files

This commit is contained in:
Souryo 2017-09-01 18:45:53 -04:00
parent 31502f6c16
commit 150d2eaec9
21 changed files with 191 additions and 55 deletions

View file

@ -173,19 +173,24 @@ bool Console::LoadROM(string romName, HashInfo hashInfo)
}
}
string lcRomname = romName;
std::transform(lcRomname.begin(), lcRomname.end(), lcRomname.begin(), ::tolower);
std::unordered_set<string> validExtensions = { { ".nes", ".fds", "*.unif", "*.unif", "*.nsf", "*.nsfe", "*.7z", "*.zip" } };
vector<string> romFiles;
for(string folder : FolderUtilities::GetKnownGameFolders()) {
string match = RomLoader::FindMatchingRomInFolder(folder, romName, hashInfo, true);
if(!match.empty()) {
return Console::LoadROM(match);
}
vector<string> files = FolderUtilities::GetFilesInFolder(folder, validExtensions, true);
romFiles.insert(romFiles.end(), files.begin(), files.end());
}
string match = RomLoader::FindMatchingRom(romFiles, romName, hashInfo, true);
if(!match.empty()) {
return Console::LoadROM(match);
}
//Perform slow CRC32 search for ROM
for(string folder : FolderUtilities::GetKnownGameFolders()) {
string match = RomLoader::FindMatchingRomInFolder(folder, romName, hashInfo, false);
if(!match.empty()) {
return Console::LoadROM(match);
}
match = RomLoader::FindMatchingRom(romFiles, romName, hashInfo, false);
if(!match.empty()) {
return Console::LoadROM(match);
}
return false;

View file

@ -501,7 +501,7 @@ int LuaApi::LoadSavestate(lua_State *lua)
checkstartframe();
stringstream ss;
ss << savestate;
l.Return(SaveStateManager::LoadState(ss));
l.Return(SaveStateManager::LoadState(ss, true));
return l.ReturnCount();
}

View file

@ -54,6 +54,7 @@ std::unordered_map<string, string> MessageManager::_enResources = {
{ "SaveStateIncompatibleVersion", u8"State #%1 is incompatible with this version of Mesen." },
{ "SaveStateInvalidFile", u8"Invalid save state file." },
{ "SaveStateLoaded", u8"State #%1 loaded." },
{ "SaveStateMissingRom", u8"Missing ROM required (%1) to load save state." },
{ "SaveStateNewerVersion", u8"Cannot load save states created by a more recent version of Mesen. Please download the latest version." },
{ "SaveStateSaved", u8"State #%1 saved." },
{ "SaveStateSlotSelected", u8"Slot #%1 selected." },
@ -123,6 +124,7 @@ std::unordered_map<string, string> MessageManager::_frResources = {
{ "SaveStateIncompatibleVersion", u8"La sauvegarde #%1 est incompatible avec cette version de Mesen." },
{ "SaveStateInvalidFile", u8"Fichier de sauvegarde invalide ou corrompu." },
{ "SaveStateLoaded", u8"Sauvegarde #%1 chargée." },
{ "SaveStateMissingRom", u8"Le rom (%1) correspondant à la sauvegarde rapide sélectionnée est introuvable." },
{ "SaveStateNewerVersion", u8"Impossible de charger une sauvegarde qui a été créée avec une version plus récente de Mesen. Veuillez mettre à jour Mesen." },
{ "SaveStateSaved", u8"Sauvegarde #%1 sauvegardée." },
{ "SaveStateSlotSelected", u8"Position de sauvegarde #%1 choisie." },
@ -192,6 +194,7 @@ std::unordered_map<string, string> MessageManager::_jaResources = {
{ "SaveStateIncompatibleVersion", u8"クイックセーブ%1は古いMesenのバージョンで作られたもので、ロードできませんでした。" },
{ "SaveStateInvalidFile", u8"クイックセーブデータを読めませんでした。" },
{ "SaveStateLoaded", u8"クイックセーブ%1をロードしました。" },
{ "SaveStateMissingRom", u8"クイックセーブデータをロードするためのゲームファイルを見つかりませんでした。(%1)" },
{ "SaveStateNewerVersion", u8"クイックセーブデータは使用中のMesenより新しいバージョンで作られたため、ロードできません。 Mesenのサイトで最新のバージョンをダウンロードしてください。" },
{ "SaveStateSaved", u8"クイックセーブ%1をセーブしました。" },
{ "SaveStateSlotSelected", u8"クイックセーブスロット%1。" },
@ -261,6 +264,7 @@ std::unordered_map<string, string> MessageManager::_ruResources = {
{ "SaveStateIncompatibleVersion", u8"Сохранение #%1 несовместимо с вашей версией Mesen." },
{ "SaveStateInvalidFile", u8"Некорректное сохранение." },
{ "SaveStateLoaded", u8"Сохранение #%1 загружено." },
{ "SaveStateMissingRom", u8"Missing ROM required (%1) to load save state." },
{ "SaveStateNewerVersion", u8"Сохранение создано в более новой версии Mesen. Пожалуйста загрузите последнюю версию." },
{ "SaveStateSaved", u8"Сохранено в #%1 слот." },
{ "ScanlineTimingWarning", u8"Тайминг PPU был изменён." },
@ -330,9 +334,10 @@ std::unordered_map<string, string> MessageManager::_esResources = {
{ "SaveStateIncompatibleVersion", u8"Partida guardada #%1 incompatible con esta versión de Mesen." },
{ "SaveStateInvalidFile", u8"Partida guardada no válida." },
{ "SaveStateLoaded", u8"Partida #%1 cargada." },
{ "SaveStateMissingRom", u8"Missing ROM required (%1) to load save state." },
{ "SaveStateNewerVersion", u8"No se puede cargar una partida creada con una versión mas reciente de Mesen. Por favor descargue la última versión." },
{ "SaveStateSaved", u8"Partida #%1 guardada." },
{ "SaveStateSlotSelected", u8"Espacio de guardado #%1 elegido." },
{ "SaveStateSlotSelected", u8"Espacio de guardado #%1 elegido." },
{ "ScanlineTimingWarning", u8"El timing de PPU ha sido cambiado." },
{ "ServerStarted", u8"Servidor iniciado (Puerto: %1)" },
{ "ServerStopped", u8"Servidor detenido" },
@ -400,6 +405,7 @@ std::unordered_map<string, string> MessageManager::_ukResources = {
{ "SaveStateIncompatibleVersion", u8"Збереження #%1 несумісне з вашою версією Mesen." },
{ "SaveStateInvalidFile", u8"Некоректне збереження." },
{ "SaveStateLoaded", u8"Збереження #%1 завантажено." },
{ "SaveStateMissingRom", u8"Missing ROM required (%1) to load save state." },
{ "SaveStateNewerVersion", u8"Збереження створено в більш нової версії Mesen. Будь ласка завантажте останню версію." },
{ "SaveStateSaved", u8"Збережено в #%1 слот." },
{ "ScanlineTimingWarning", u8"Таймiнг PPU був змінений." },
@ -469,6 +475,7 @@ std::unordered_map<string, string> MessageManager::_ptResources = {
{ "SaveStateIncompatibleVersion", u8"Save State #%1 incompatível com esta versão de Mesen." },
{ "SaveStateInvalidFile", u8"Save State inválido." },
{ "SaveStateLoaded", u8"Save State #%1 carregado." },
{ "SaveStateMissingRom", u8"Missing ROM required (%1) to load save state." },
{ "SaveStateNewerVersion", u8"Não se pode carregar um save state com uma versão mais recente de Mesen. Por favor baixe a última versão." },
{ "SaveStateSaved", u8"Save State #%1 salvo." },
{ "SaveStateSlotSelected", u8"Slot do Save State #%1 elegido." },
@ -538,6 +545,7 @@ std::unordered_map<string, string> MessageManager::_caResources = {
{ "SaveStateIncompatibleVersion", u8"La partida guardada nº%1 és incompatible amb aquesta versió de Mesen." },
{ "SaveStateInvalidFile", u8"Fitxer de partida guardada invàlid." },
{ "SaveStateLoaded", u8"Partida guardada nº%1 carregada." },
{ "SaveStateMissingRom", u8"Missing ROM required (%1) to load save state." },
{ "SaveStateNewerVersion", u8"Incapaç de carregar partides guardades creades per una versió més recent de Mesen. Si us plau, descarregueu-vos la darrera versió de Mesen." },
{ "SaveStateSaved", u8"Partida guardada nº%1 desada." },
{ "SaveStateSlotSelected", u8"Partida guardada nº%1 seleccionada." },

View file

@ -119,12 +119,8 @@ string RomLoader::FindMatchingRomInFile(string filePath, HashInfo hashInfo)
return "";
}
string RomLoader::FindMatchingRomInFolder(string folder, string romFilename, HashInfo hashInfo, bool useFastSearch)
string RomLoader::FindMatchingRom(vector<string> romFiles, string romFilename, HashInfo hashInfo, bool useFastSearch)
{
std::transform(romFilename.begin(), romFilename.end(), romFilename.begin(), ::tolower);
std::unordered_set<string> validExtensions = { { ".nes", ".fds", "*.unif", "*.unif", "*.nsf", "*.nsfe", "*.7z", "*.zip" } };
vector<string> romFiles = FolderUtilities::GetFilesInFolder(folder, validExtensions, true);
if(useFastSearch) {
for(string romFile : romFiles) {
//Quick search by filename

View file

@ -17,5 +17,5 @@ class RomLoader
bool LoadFile(string filename, vector<uint8_t> &fileData);
RomData GetRomData();
static string FindMatchingRomInFolder(string folder, string romFilename, HashInfo hashInfo, bool useFastSearch);
static string FindMatchingRom(vector<string> romFiles, string romFilename, HashInfo hashInfo, bool useFastSearch);
};

View file

@ -61,27 +61,42 @@ void SaveStateManager::SaveState(ostream &stream)
stream.write((char*)&emuVersion, sizeof(emuVersion));
stream.write((char*)&SaveStateManager::FileFormatVersion, sizeof(uint32_t));
string sha1Hash = Console::GetHashInfo().Sha1Hash;
stream.write(sha1Hash.c_str(), sha1Hash.size());
string romName = Console::GetRomName();
uint32_t nameLength = (uint32_t)romName.size();
stream.write((char*)&nameLength, sizeof(uint32_t));
stream.write(romName.c_str(), romName.size());
Console::SaveState(stream);
Console::Resume();
}
bool SaveStateManager::SaveState(string filepath)
{
ofstream file(filepath, ios::out | ios::binary);
if(file) {
SaveState(file);
file.close();
return true;
}
return false;
}
void SaveStateManager::SaveState(int stateIndex, bool displayMessage)
{
string filepath = SaveStateManager::GetStateFilepath(stateIndex);
ofstream file(filepath, ios::out | ios::binary);
if(file) {
if(SaveState(filepath)) {
_lastIndex = stateIndex;
SaveState(file);
file.close();
if(displayMessage) {
MessageManager::DisplayMessage("SaveStates", "SaveStateSaved", std::to_string(stateIndex));
}
}
}
bool SaveStateManager::LoadState(istream &stream)
bool SaveStateManager::LoadState(istream &stream, bool hashCheckRequired)
{
char header[3];
stream.read(header, 3);
@ -95,9 +110,35 @@ bool SaveStateManager::LoadState(istream &stream)
}
stream.read((char*)&fileFormatVersion, sizeof(fileFormatVersion));
if(fileFormatVersion != SaveStateManager::FileFormatVersion) {
MessageManager::DisplayMessage("SaveStates", "SaveStateIncompatibleVersion"); // , std::to_string(stateIndex));
if(fileFormatVersion < 5) {
MessageManager::DisplayMessage("SaveStates", "SaveStateIncompatibleVersion");
return false;
} else if(fileFormatVersion == 5) {
//No SHA1 field in version 5
if(hashCheckRequired) {
MessageManager::DisplayMessage("SaveStates", "SaveStateIncompatibleVersion");
return false;
}
} else {
char hash[41] = {};
stream.read(hash, 40);
uint32_t nameLength = 0;
stream.read((char*)&nameLength, sizeof(uint32_t));
vector<char> nameBuffer(nameLength);
stream.read(nameBuffer.data(), nameBuffer.size());
string romName(nameBuffer.data());
if(Console::GetHashInfo().Sha1Hash != string(hash)) {
//Wrong game
HashInfo info;
info.Sha1Hash = hash;
if(!Console::LoadROM(romName, info)) {
MessageManager::DisplayMessage("SaveStates", "SaveStateMissingRom", romName);
return false;
}
}
}
Console::Pause();
@ -106,32 +147,36 @@ bool SaveStateManager::LoadState(istream &stream)
return true;
}
MessageManager::DisplayMessage("SaveStates", "SaveStateInvalidFile");
return false;
}
bool SaveStateManager::LoadState(string filepath, bool hashCheckRequired)
{
ifstream file(filepath, ios::in | ios::binary);
bool result = false;
if(file.good()) {
if(LoadState(file, hashCheckRequired)) {
result = true;
}
file.close();
} else {
MessageManager::DisplayMessage("SaveStates", "SaveStateEmpty");
}
return result;
}
bool SaveStateManager::LoadState(int stateIndex)
{
string filepath = SaveStateManager::GetStateFilepath(stateIndex);
ifstream file(filepath, ios::in | ios::binary);
bool result = false;
if(file) {
if(LoadState(file)) {
_lastIndex = stateIndex;
MessageManager::DisplayMessage("SaveStates", "SaveStateLoaded", std::to_string(stateIndex));
result = true;
} else {
MessageManager::DisplayMessage("SaveStates", "SaveStateInvalidFile");
}
file.close();
}
if(!result) {
MessageManager::DisplayMessage("SaveStates", "SaveStateEmpty");
if(LoadState(filepath, true)) {
_lastIndex = stateIndex;
MessageManager::DisplayMessage("SaveStates", "SaveStateLoaded", std::to_string(stateIndex));
return true;
}
return result;
return false;
}
void SaveStateManager::SaveRecentGame(string romName, string romPath, string patchPath)
@ -173,7 +218,7 @@ void SaveStateManager::LoadRecentGame(string filename, bool resetGame)
try {
Console::LoadROM(romPath, patchPath);
if(!resetGame) {
SaveStateManager::LoadState(stateStream);
SaveStateManager::LoadState(stateStream, false);
}
} catch(std::exception ex) {
Console::GetInstance()->Stop();

View file

@ -11,7 +11,7 @@ private:
static string GetStateFilepath(int stateIndex);
public:
static const uint32_t FileFormatVersion = 5;
static const uint32_t FileFormatVersion = 6;
static uint64_t GetStateInfo(int stateIndex);
@ -19,8 +19,10 @@ public:
static bool LoadState();
static void SaveState(ostream &stream);
static bool SaveState(string filepath);
static void SaveState(int stateIndex, bool displayMessage = true);
static bool LoadState(istream &stream);
static bool LoadState(istream &stream, bool hashCheckRequired = true);
static bool LoadState(string filepath, bool hashCheckRequired = true);
static bool LoadState(int stateIndex);
static void SaveRecentGame(string romName, string romPath, string patchPath);

View file

@ -1160,7 +1160,7 @@ namespace Mesen.GUI.Debugger
//
this.mnuTraceLogger.Image = global::Mesen.GUI.Properties.Resources.LogWindow;
this.mnuTraceLogger.Name = "mnuTraceLogger";
this.mnuTraceLogger.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.L)));
this.mnuTraceLogger.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.N)));
this.mnuTraceLogger.Size = new System.Drawing.Size(196, 22);
this.mnuTraceLogger.Text = "Trace Logger";
this.mnuTraceLogger.Click += new System.EventHandler(this.mnuTraceLogger_Click);

View file

@ -586,6 +586,10 @@
<Message ID="FilterRomIps">Tots els formats suportats (*.nes, *.zip, *.7z, *.fds, *.nsf, *.nsfe, *.unf, *.ips, *.bps, *.ups)|*.NES;*.ZIP;*.7z;*.IPS;*.BPS;*.UPS;*.FDS;*.NSF;*.NSFE;*.UNF|Roms de NES(*.nes, *.unf)|*.NES;*.UNF|Roms de Famicom Disk System (*.fds)|*.FDS|Fitxers NSF (*.nsf, *.nsfe)|*.NSF;*.NSFE|Arxius comprimits (*.zip)|*.ZIP|Arxius 7-Zip (*.7z)|*.7z|Pedaços IPS/UPS/BPS (*.ips, *.bps, *.ups)|*.IPS;*.BPS;*.UPS|Tots els fitxers (*.*)|*.*</Message>
<Message ID="FilterTest">Fitxers de proves (*.mtp)|*.mtp|Tots els fitxers (*.*)|*.*</Message>
<Message ID="FilterCheat">Tots els formats suportats (*.cht, *.xml)|*.cht;*.xml</Message>
<Message ID="FilterSavestate">Mesen Savestates (*.mst)|*.mst|Tots els fitxers (*.*)|*.*</Message>
<Message ID="LoadFromFile">Load from file...</Message>
<Message ID="SaveToFile">Save to file...</Message>
<Message ID="Resume">Continua</Message>
<Message ID="Pause">Pausa</Message>

View file

@ -10,6 +10,10 @@
<Message ID="FilterRomIps">All supported formats (*.nes, *.zip, *.7z, *.fds, *.nsf, *.nsfe, *.unf, *.ips, *.bps, *.ups)|*.NES;*.ZIP;*.7z;*.IPS;*.BPS;*.UPS;*.FDS;*.NSF;*.NSFE;*.UNF|NES Roms (*.nes, *.unf)|*.NES;*.UNF|Famicom Disk System Roms (*.fds)|*.FDS|NSF files (*.nsf, *.nsfe)|*.nsf;*.nsfe|ZIP Archives (*.zip)|*.ZIP|7-Zip Archives (*.7z)|*.7z|IPS/UPS/BPS Patches (*.ips, *.bps, *.ups)|*.IPS;*.BPS;*.UPS|All (*.*)|*.*</Message>
<Message ID="FilterTest">Test files (*.mtp)|*.mtp|All (*.*)|*.*</Message>
<Message ID="FilterCheat">All supported formats (*.cht, *.xml)|*.cht;*.xml</Message>
<Message ID="FilterSavestate">Mesen Savestates (*.mst)|*.mst|All files (*.*)|*.*</Message>
<Message ID="LoadFromFile">Load from file...</Message>
<Message ID="SaveToFile">Save to file...</Message>
<Message ID="Resume">Resume</Message>
<Message ID="Pause">Pause</Message>

View file

@ -620,6 +620,10 @@
<Message ID="FilterRomIps">Todos los formatos soportados (*.nes, *.zip, *.7z, *.fds, *.nsf, *.nsfe, *.unf, *.ips, *.bps, *.ups)|*.NES;*.ZIP;*.7z;*.IPS;*.BPS;*.UPS;*.FDS;*.NSF;*.NSFE;*.UNF|Roms de NES(*.nes, *.unf)|*.NES;*.UNF|Roms de Famicom Disk System (*.fds)|*.FDS|Archivos NSF (*.nsf, *.nsfe)|*.NSF;*.NSFE|Archivos ZIP (*.zip)|*.ZIP|Archivos 7-Zip (*.7z)|*.7z|Archivos IPS/UPS/BPS (*.ips, *.bps, *.ups)|*.IPS;*.BPS;*.UPS|Todos los archivos (*.*)|*.*</Message>
<Message ID="FilterTest">Archivos de test (*.mtp)|*.mtp|Todos los archivos (*.*)|*.*</Message>
<Message ID="FilterCheat">Todos los formatos soportados (*.cht, *.xml)|*.cht;*.xml</Message>
<Message ID="FilterSavestate">Mesen Savestates (*.mst)|*.mst|Todos los archivos (*.*)|*.*</Message>
<Message ID="LoadFromFile">Load from file...</Message>
<Message ID="SaveToFile">Save to file...</Message>
<Message ID="Resume">Continuar</Message>
<Message ID="Pause">Pausa</Message>

View file

@ -634,7 +634,11 @@
<Message ID="FilterRomIps">Tous les formats supportés (*.nes, *.zip, *.7z, *.fds, *.nsf, *.nsfe, *.unf, *.ips, *.bps, *.ups)|*.NES;*.ZIP;*.7z;*.IPS;*.BPS;*.UPS;*.FDS;*.NSF;*.NSFE;*.UNF|Roms de NES (*.nes, *.unf)|*.NES;*.UNF|Roms du Famicom Disk System (*.fds)|*.FDS|Fichiers NSF (*.nsf, *.nsfe)|*.NSF;*.NSFE|Fichiers ZIP (*.zip)|*.ZIP|Fichiers 7-Zip (*.7z)|*.7z|Fichiers IPS/UPS/BPS (*.ips, *.bps, *.ups)|*.IPS;*.BPS;*.UPS|Tous les fichiers (*.*)|*.*</Message>
<Message ID="FilterTest">Fichiers de test (*.mtp)|*.mtp|Tous les fichiers (*.*)|*.*</Message>
<Message ID="FilterCheat">Tous les formats supportés (*.cht, *.xml)|*.cht;*.xml</Message>
<Message ID="FilterSavestate">Sauvegardes d'états Mesen (*.mst)|*.mst|Tous les fichiers (*.*)|*.*</Message>
<Message ID="LoadFromFile">Charger à partir d'un fichier...</Message>
<Message ID="SaveToFile">Sauvegarder dans un fichier...</Message>
<Message ID="Resume">Continuer</Message>
<Message ID="Pause">Pause</Message>
<Message ID="StartServer">Démarrer serveur</Message>

View file

@ -617,6 +617,10 @@
<Message ID="FilterRomIps">対応するすべてのファイル (*.nes, *.zip, *.7z, *.fds, *.nsf, *.nsfe, *.unf, *.ips, *.bps, *.ups)|*.NES;*.ZIP;*.7z;*.IPS;*.BPS;*.UPS;*.FDS;*.NSF;*.NSFE;*.UNF|ファミコンゲーム (*.nes, *.unf)|*.NES;*.UNF|ファミコンディスクシステムのゲーム (*.fds)|*.FDS|NSFファイル (*.nsf, *.nsfe)|*.NSF;*.NSFE|ZIPファイル (*.zip)|*.ZIP|7-Zipファイル (*.7z)|*.7z|パッチファイル (*.ips, *.bps, *.ups)|*.IPS;*.BPS;*.UPS|すべてのファイル (*.*)|*.*</Message>
<Message ID="FilterTest">テストファイル (*.mtp)|*.mtp|すべてのファイル (*.*)|*.*</Message>
<Message ID="FilterCheat">対応するすべてのファイル (*.cht, *.xml)|*.cht;*.xml</Message>
<Message ID="FilterSavestate">Mesenのクイックセーブデータ (*.mst)|*.mst|すべてのファイル (*.*)|*.*</Message>
<Message ID="LoadFromFile">ファイルからロードする…</Message>
<Message ID="SaveToFile">ファイルに保存する…</Message>
<Message ID="Resume">再開</Message>
<Message ID="Pause">ポーズ</Message>

View file

@ -620,6 +620,10 @@
<Message ID="FilterRomIps">Todos os formatos suportados (*.nes, *.zip, *.7z, *.fds, *.nsf, *.nsfe, *.unf, *.ips, *.bps, *.ups)|*.NES;*.ZIP;*.7z;*.IPS;*.BPS;*.UPS;*.FDS;*.NSF;*.NSFE;*.UNF|Roms de NES(*.nes, *.unf)|*.NES;*.UNF|Roms de Famicom Disk System (*.fds)|*.FDS|Arquivos NSF (*.nsf, *.nsfe)|*.NSF;*.NSFE|Arquivos ZIP (*.zip)|*.ZIP|Arquivos 7-Zip (*.7z)|*.7z|Arquivos IPS/UPS/BPS (*.ips, *.bps, *.ups)|*.IPS;*.BPS;*.UPS|Todos os arquivos (*.*)|*.*</Message>
<Message ID="FilterTest">Arquivos de teste (*.mtp)|*.mtp|Todos os arquivos (*.*)|*.*</Message>
<Message ID="FilterCheat">Todos os formatos suportados (*.cht, *.xml)|*.cht;*.xml</Message>
<Message ID="FilterSavestate">Mesen Savestates (*.mst)|*.mst|Todos os arquivos (*.*)|*.*</Message>
<Message ID="LoadFromFile">Load from file...</Message>
<Message ID="SaveToFile">Save to file...</Message>
<Message ID="Resume">Continuar</Message>
<Message ID="Pause">Pausar</Message>

View file

@ -624,7 +624,11 @@
<Message ID="FilterRomIps">Все поддерживаемые форматы (*.nes, *.zip, *.7z, *.fds, *.nsf, *.nsfe, *.unf, *.ips, *.bps, *.ups)|*.NES;*.ZIP;*.7z;*.IPS;*.BPS;*.UPS;*.FDS;*.NSF;*.NSFE;*.UNF|NES Roms (*.nes, *.unf)|*.NES;*.UNF|Famicom Disk System Roms (*.fds)|*.FDS|NSF files (*.nsf, *.nsfe)|*.nsf;*.nsfe|ZIP Archives (*.zip)|*.ZIP|7-Zip Archives (*.7z)|*.7z|IPS/UPS/BPS Patches (*.ips, *.bps, *.ups)|*.IPS;*.BPS;*.UPS|All (*.*)|*.*</Message>
<Message ID="FilterTest">Test files (*.mtp)|*.mtp|All (*.*)|*.*</Message>
<Message ID="FilterCheat">Все поддерживаемые форматы (*.cht, *.xml)|*.cht;*.xml</Message>
<Message ID="FilterSavestate">Mesen Savestates (*.mst)|*.mst|All Files (*.*)|*.*</Message>
<Message ID="LoadFromFile">Load from file...</Message>
<Message ID="SaveToFile">Save to file...</Message>
<Message ID="Resume">Продолжить</Message>
<Message ID="Pause">Пауза</Message>
<Message ID="StartServer">Запустить сервер</Message>

View file

@ -624,7 +624,11 @@
<Message ID="FilterRomIps">Всі підтримувані формати (*.nes, *.zip, *.7z, *.fds, *.nsf, *.nsfe, *.unf, *.ips, *.bps, *.ups)|*.NES;*.ZIP;*.7z;*.IPS;*.BPS;*.UPS;*.FDS;*.NSF;*.NSFE;*.UNF|NES Roms (*.nes, *.unf)|*.NES;*.UNF|Famicom Disk System Roms (*.fds)|*.FDS|NSF files (*.nsf, *.nsfe)|*.nsf;*.nsfe|ZIP Archives (*.zip)|*.ZIP|7-Zip Archives (*.7z)|*.7z|IPS/UPS/BPS Patches (*.ips, *.bps, *.ups)|*.IPS;*.BPS;*.UPS|All (*.*)|*.*</Message>
<Message ID="FilterTest">Test files (*.mtp)|*.mtp|All (*.*)|*.*</Message>
<Message ID="FilterCheat">Всі підтримувані формати (*.cht, *.xml)|*.cht;*.xml</Message>
<Message ID="FilterSavestate">Mesen Savestates (*.mst)|*.mst|All Files (*.*)|*.*</Message>
<Message ID="LoadFromFile">Load from file...</Message>
<Message ID="SaveToFile">Save to file...</Message>
<Message ID="Resume">Продовжити</Message>
<Message ID="Pause">Пауза</Message>
<Message ID="StartServer">Запустити сервер</Message>

View file

@ -1507,7 +1507,7 @@ namespace Mesen.GUI.Forms
//
this.mnuTraceLogger.Image = global::Mesen.GUI.Properties.Resources.LogWindow;
this.mnuTraceLogger.Name = "mnuTraceLogger";
this.mnuTraceLogger.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.L)));
this.mnuTraceLogger.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.N)));
this.mnuTraceLogger.Size = new System.Drawing.Size(196, 22);
this.mnuTraceLogger.Text = "Trace Logger";
this.mnuTraceLogger.Click += new System.EventHandler(this.mnuTraceLogger_Click);

View file

@ -7,6 +7,7 @@ using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using Mesen.GUI.Config;
using Mesen.GUI.Properties;
namespace Mesen.GUI.Forms
{
@ -58,10 +59,48 @@ namespace Mesen.GUI.Forms
if(!forSave) {
menu.DropDownItems.Add("-");
addSaveStateInfo(NumberOfSaveSlots+1);
menu.DropDownItems.Add("-");
ToolStripMenuItem loadFromFile = new ToolStripMenuItem(ResourceHelper.GetMessage("LoadFromFile"), Resources.FolderOpen);
loadFromFile.ShortcutKeys = Keys.Control | Keys.L;
loadFromFile.Click += LoadFromFile_Click;
menu.DropDownItems.Add(loadFromFile);
} else {
menu.DropDownItems.Add("-");
ToolStripMenuItem saveToFile = new ToolStripMenuItem(ResourceHelper.GetMessage("SaveToFile"), Resources.Floppy);
saveToFile.ShortcutKeys = Keys.Control | Keys.S;
saveToFile.Click += SaveToFile_Click;
menu.DropDownItems.Add(saveToFile);
}
}
}
private void LoadFromFile_Click(object sender, EventArgs e)
{
if(_emuThread != null) {
using(OpenFileDialog ofd = new OpenFileDialog()) {
ofd.InitialDirectory = ConfigManager.SaveStateFolder;
ofd.SetFilter(ResourceHelper.GetMessage("FilterSavestate"));
if(ofd.ShowDialog() == DialogResult.OK) {
InteropEmu.LoadStateFile(ofd.FileName);
}
}
}
}
private void SaveToFile_Click(object sender, EventArgs e)
{
if(_emuThread != null) {
using(SaveFileDialog sfd = new SaveFileDialog()) {
sfd.InitialDirectory = ConfigManager.SaveStateFolder;
sfd.FileName = InteropEmu.GetRomInfo().GetRomName() + ".mst";
sfd.SetFilter(ResourceHelper.GetMessage("FilterSavestate"));
if(sfd.ShowDialog() == DialogResult.OK) {
InteropEmu.SaveStateFile(sfd.FileName);
}
}
}
}
private void mnuExit_Click(object sender, EventArgs e)
{
this.Close();

View file

@ -113,6 +113,8 @@ namespace Mesen.GUI
[DllImport(DLLPath)] public static extern void SaveState(UInt32 stateIndex);
[DllImport(DLLPath)] public static extern void LoadState(UInt32 stateIndex);
[DllImport(DLLPath)] public static extern void SaveStateFile([MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(UTF8Marshaler))]string filepath);
[DllImport(DLLPath)] public static extern void LoadStateFile([MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(UTF8Marshaler))]string filepath);
[DllImport(DLLPath)] public static extern Int64 GetStateInfo(UInt32 stateIndex);
[DllImport(DLLPath)] [return: MarshalAs(UnmanagedType.I1)] public static extern bool IsNsf();

View file

@ -312,7 +312,9 @@ namespace InteropEmu {
}
DllExport void __stdcall SaveState(uint32_t stateIndex) { SaveStateManager::SaveState(stateIndex); }
DllExport uint32_t __stdcall LoadState(uint32_t stateIndex) { return SaveStateManager::LoadState(stateIndex); }
DllExport void __stdcall LoadState(uint32_t stateIndex) { SaveStateManager::LoadState(stateIndex); }
DllExport void __stdcall SaveStateFile(char* filepath) { SaveStateManager::SaveState(filepath); }
DllExport void __stdcall LoadStateFile(char* filepath) { SaveStateManager::LoadState(filepath); }
DllExport int64_t __stdcall GetStateInfo(uint32_t stateIndex) { return SaveStateManager::GetStateInfo(stateIndex); }
DllExport void __stdcall MoviePlay(char* filename) { MovieManager::Play(filename); }

View file

@ -37,7 +37,7 @@ void FolderUtilities::AddKnownGameFolder(string gameFolder)
for(string folder : _gameFolders) {
std::transform(folder.begin(), folder.end(), folder.begin(), ::tolower);
if(folder.compare(gameFolder) == 0) {
if(folder.compare(lowerCaseFolder) == 0) {
alreadyExists = true;
break;
}
@ -131,8 +131,13 @@ vector<string> FolderUtilities::GetFolders(string rootFolder)
}
for(fs::recursive_directory_iterator i(fs::u8path(rootFolder)), end; i != end; i++) {
if(fs::is_directory(i->path())) {
folders.push_back(i->path().u8string());
if(i.depth() > 1) {
//Prevent excessive recursion
i.disable_recursion_pending();
} else {
if(fs::is_directory(i->path())) {
folders.push_back(i->path().u8string());
}
}
}