-Movies now record what game (name & CRC32) they were recorded from and attempt to load the same rom when played

-Movies/NetPlay now use the recent files list to look for roms to load
This commit is contained in:
Souryo 2015-07-05 22:23:44 -04:00
parent 586b72e081
commit 7b0fac672d
12 changed files with 242 additions and 149 deletions

View file

@ -8,21 +8,17 @@
#include "../Utilities/FolderUtilities.h"
#include "../Core/MessageManager.h"
shared_ptr<Console> Console::Instance = nullptr;
shared_ptr<Console> Console::Instance(new Console());
uint32_t Console::Flags = 0;
uint32_t Console::CurrentFPS = 0;
Console::Console(wstring filename)
Console::Console()
{
Initialize(filename);
}
Console::~Console()
{
Movie::Stop();
if(Console::Instance.get() == this) {
Console::Instance.reset();
}
}
shared_ptr<Console> Console::GetInstance()
@ -33,10 +29,6 @@ shared_ptr<Console> Console::GetInstance()
void Console::Initialize(wstring filename)
{
MessageManager::SendNotification(ConsoleNotificationType::GameStopped);
if(Console::Instance == nullptr) {
Console::Instance.reset(this);
}
shared_ptr<BaseMapper> mapper = MapperFactory::InitializeFromFile(filename);
if(mapper) {
_romFilepath = filename;
@ -56,28 +48,56 @@ void Console::Initialize(wstring filename)
ResetComponents(false);
_initialized = true;
FolderUtilities::AddKnowGameFolder(FolderUtilities::GetFolderName(filename));
MessageManager::DisplayMessage(L"Game loaded", FolderUtilities::GetFilename(filename, false));
} else {
MessageManager::DisplayMessage(L"Error", wstring(L"Could not load file: ") + FolderUtilities::GetFilename(filename, true));
}
}
void Console::LoadROM(wstring filename)
void Console::LoadROM(wstring filepath)
{
if(!Instance) {
new Console(filename);
} else {
Console::Pause();
Instance->Initialize(filename);
Console::Resume();
Console::Pause();
Instance->Initialize(filepath);
Console::Resume();
}
bool Console::LoadROM(wstring filename, uint32_t crc32Hash)
{
wstring currentRomFilepath = Console::GetROMPath();
wstring currentFolder = FolderUtilities::GetFolderName(currentRomFilepath);
if(!currentRomFilepath.empty()) {
if(ROMLoader::GetCRC32(Console::GetROMPath()) == crc32Hash) {
//Current game matches, no need to do anything
return true;
}
//Try to find the game in the same folder as the current game's folder
wstring match = ROMLoader::FindMatchingRomInFolder(currentFolder, filename, crc32Hash);
if(!match.empty()) {
Console::LoadROM(match);
return true;
}
}
for(wstring folder : FolderUtilities::GetKnowGameFolders()) {
if(folder != currentFolder) {
wstring match = ROMLoader::FindMatchingRomInFolder(folder, filename, crc32Hash);
if(!match.empty()) {
Console::LoadROM(match);
return true;
}
}
}
return false;
}
wstring Console::GetROMPath()
{
wstring filepath;
if(Instance) {
if(Instance->_initialized) {
filepath = Instance->_romFilepath;
}
return filepath;
@ -86,7 +106,7 @@ wstring Console::GetROMPath()
void Console::Reset(bool softReset)
{
Movie::Stop();
if(Instance) {
if(Instance->_initialized) {
Console::Pause();
Instance->ResetComponents(softReset);
Console::Resume();
@ -95,6 +115,8 @@ void Console::Reset(bool softReset)
void Console::ResetComponents(bool softReset)
{
Movie::Stop();
_ppu->Reset();
_apu->Reset();
_cpu->Reset(softReset);
@ -117,19 +139,15 @@ void Console::Stop()
void Console::Pause()
{
if(Console::Instance) {
Console::Instance->_pauseLock.Acquire();
//Spin wait until emu pauses
Console::Instance->_runLock.Acquire();
}
Console::Instance->_pauseLock.Acquire();
//Spin wait until emu pauses
Console::Instance->_runLock.Acquire();
}
void Console::Resume()
{
if(Console::Instance) {
Console::Instance->_runLock.Release();
Console::Instance->_pauseLock.Release();
}
Console::Instance->_runLock.Release();
Console::Instance->_pauseLock.Release();
}
void Console::SetFlags(int flags)
@ -229,7 +247,7 @@ void Console::Run()
void Console::SaveState(ostream &saveStream)
{
if(Instance) {
if(Instance->_initialized) {
Instance->_cpu->SaveSnapshot(&saveStream);
Instance->_ppu->SaveSnapshot(&saveStream);
Instance->_memoryManager->SaveSnapshot(&saveStream);
@ -241,7 +259,7 @@ void Console::SaveState(ostream &saveStream)
void Console::LoadState(istream &loadStream)
{
if(Instance) {
if(Instance->_initialized) {
Instance->_cpu->LoadSnapshot(&loadStream);
Instance->_ppu->LoadSnapshot(&loadStream);
Instance->_memoryManager->LoadSnapshot(&loadStream);

View file

@ -38,12 +38,14 @@ class Console
bool _stop = false;
bool _reset = false;
bool _initialized = false;
void ResetComponents(bool softReset);
void Initialize(wstring filename);
public:
Console(wstring filename);
Console();
~Console();
void Run();
void Stop();
@ -61,7 +63,9 @@ class Console
static void LoadState(istream &loadStream);
static void LoadState(uint8_t *buffer, uint32_t bufferSize);
static void LoadROM(wstring filename);
static void LoadROM(wstring filepath);
static bool LoadROM(wstring romName, uint32_t crc32Hash);
static wstring FindMatchingRomInFolder(wstring folder, wstring romFilename, uint32_t crc32Hash);
static wstring GetROMPath();
static bool CheckFlag(int flag);

View file

@ -39,7 +39,7 @@ public:
{
wstring filename = _romFilename;
if(filename.size() > 0) {
if(AttemptLoadROM(filename, _crc32Hash)) {
if(Console::LoadROM(filename, _crc32Hash)) {
return true;
} else {
MessageManager::DisplayMessage(L"Net Play", L"Could not find matching game ROM.");
@ -59,39 +59,4 @@ public:
return _paused;
}
bool AttemptLoadROM(wstring filename, uint32_t crc32Hash)
{
if(!Console::GetROMPath().empty()) {
if(ROMLoader::GetCRC32(Console::GetROMPath()) == crc32Hash) {
//Current game matches, no need to do anything
return true;
}
}
vector<wstring> romFiles = FolderUtilities::GetFilesInFolder(L"D:\\Users\\Saitoh Hajime\\Desktop\\CPPApp\\NES\\Games", L"*.nes", true);
for(wstring zipFile : FolderUtilities::GetFilesInFolder(L"D:\\Users\\Saitoh Hajime\\Desktop\\CPPApp\\NES\\Games", L"*.zip", true)) {
romFiles.push_back(zipFile);
}
for(wstring romFile : romFiles) {
//Quick search by filename
if(FolderUtilities::GetFilename(romFile, true).compare(filename) == 0) {
if(ROMLoader::GetCRC32(romFile) == crc32Hash) {
//Matching ROM found
Console::LoadROM(romFile);
return true;
}
}
}
for(wstring romFile : romFiles) {
//Slower search by CRC value
if(ROMLoader::GetCRC32(romFile) == crc32Hash) {
//Matching ROM found
Console::LoadROM(romFile);
return true;
}
}
return false;
}
};

View file

@ -3,6 +3,7 @@
#include "Movie.h"
#include "Console.h"
#include "../Utilities/FolderUtilities.h"
#include "ROMLoader.h"
Movie* Movie::Instance = new Movie();
@ -45,7 +46,7 @@ uint8_t Movie::GetState(uint8_t port)
if(_readPosition[port] >= _data.DataSize[port]) {
//End of movie file
MessageManager::DisplayMessage(L"Movie ended.");
MessageManager::DisplayMessage(L"Movies", L"Movie ended.");
_playing = false;
}
@ -69,6 +70,7 @@ void Movie::Reset()
void Movie::StartRecording(wstring filename, bool reset)
{
_filename = filename;
_file = ofstream(filename, ios::out | ios::binary);
if(_file) {
@ -86,7 +88,7 @@ void Movie::StartRecording(wstring filename, bool reset)
Console::Resume();
MessageManager::DisplayMessage(L"Recording...");
MessageManager::DisplayMessage(L"Movies", L"Recording to: " + FolderUtilities::GetFilename(filename, true));
}
}
@ -97,9 +99,12 @@ void Movie::StopAll()
for(int i = 0; i < 4; i++) {
PushState(i);
}
_data.Save(_file, _startState);
Save();
}
if(_playing) {
MessageManager::DisplayMessage(L"Movies", L"Movie stopped.");
_playing = false;
}
_playing = false;
}
void Movie::PlayMovie(wstring filename)
@ -108,7 +113,7 @@ void Movie::PlayMovie(wstring filename)
Reset();
if(_data.Load(filename, _startState)) {
if(Load(filename)) {
Console::Pause();
if(_startState.tellp() > 0) {
//Restore state if one was present in the movie
@ -118,7 +123,7 @@ void Movie::PlayMovie(wstring filename)
}
_playing = true;
Console::Resume();
MessageManager::DisplayMessage(L"Playing movie: " + FolderUtilities::GetFilename(filename, true));
MessageManager::DisplayMessage(L"Movies", L"Playing movie: " + FolderUtilities::GetFilename(filename, true));
}
}
@ -145,4 +150,103 @@ bool Movie::Playing()
bool Movie::Recording()
{
return Instance->_recording;
}
}
bool Movie::Save()
{
_file.write("MMO", 3);
_data.SaveStateSize = (uint32_t)_startState.tellp();
wstring romFilepath = Console::GetROMPath();
wstring romFilename = FolderUtilities::GetFilename(romFilepath, true);
uint32_t romCrc32 = ROMLoader::GetCRC32(romFilepath);
_file.write((char*)&romCrc32, sizeof(romCrc32));
uint32_t romNameSize = romFilename.size();
_file.write((char*)&romNameSize, sizeof(uint32_t));
_file.write((char*)romFilename.c_str(), romNameSize * sizeof(wchar_t));
_file.write((char*)&_data.SaveStateSize, sizeof(uint32_t));
if(_data.SaveStateSize > 0) {
_startState.seekg(0, ios::beg);
uint8_t *stateBuffer = new uint8_t[_data.SaveStateSize];
_startState.read((char*)stateBuffer, _data.SaveStateSize);
_file.write((char*)stateBuffer, _data.SaveStateSize);
delete[] stateBuffer;
}
for(int i = 0; i < 4; i++) {
_data.DataSize[i] = _data.PortData[i].size();
_file.write((char*)&_data.DataSize[i], sizeof(uint32_t));
if(_data.DataSize[i] > 0) {
_file.write((char*)&_data.PortData[i][0], _data.DataSize[i] * sizeof(uint16_t));
}
}
_file.close();
MessageManager::DisplayMessage(L"Movies", L"Movie saved to file: " + FolderUtilities::GetFilename(_filename, true));
return true;
}
bool Movie::Load(wstring filename)
{
ifstream file(filename, ios::in | ios::binary);
if(file) {
char header[3];
file.read((char*)&header, 3);
if(memcmp((char*)&header, "MMO", 3) != 0) {
//Invalid movie file
return false;
}
uint32_t romCrc32;
file.read((char*)&romCrc32, sizeof(romCrc32));
uint32_t romNameSize;
file.read((char*)&romNameSize, sizeof(uint32_t));
wchar_t* romFilename = new wchar_t[romNameSize + 1];
memset(romFilename, 0, (romNameSize+1)*sizeof(wchar_t));
file.read((char*)romFilename, romNameSize * sizeof(wchar_t));
wstring currentRom = Console::GetROMPath();
bool loadedGame = true;
if(currentRom.empty() || romCrc32 != ROMLoader::GetCRC32(currentRom)) {
//Loaded game isn't the same as the game used for the movie, attempt to load the correct game
loadedGame = Console::LoadROM(romFilename, romCrc32);
}
if(loadedGame) {
file.read((char*)&_data.SaveStateSize, sizeof(uint32_t));
if(_data.SaveStateSize > 0) {
uint8_t *stateBuffer = new uint8_t[_data.SaveStateSize];
file.read((char*)stateBuffer, _data.SaveStateSize);
_startState.write((char*)stateBuffer, _data.SaveStateSize);
delete[] stateBuffer;
}
for(int i = 0; i < 4; i++) {
file.read((char*)&_data.DataSize[i], sizeof(uint32_t));
uint16_t* readBuffer = new uint16_t[_data.DataSize[i]];
file.read((char*)readBuffer, _data.DataSize[i] * sizeof(uint16_t));
_data.PortData[i] = vector<uint16_t>(readBuffer, readBuffer + _data.DataSize[i]);
delete[] readBuffer;
}
} else {
MessageManager::DisplayMessage(L"Movies", L"Missing ROM required (" + wstring(romFilename) + L") to play movie.");
}
file.close();
return loadedGame;
}
return false;
}

View file

@ -7,72 +7,6 @@ struct MovieData
uint32_t SaveStateSize = 0;
uint32_t DataSize[4];
vector<uint16_t> PortData[4];
bool Save(ofstream &file, stringstream &startState)
{
file.write("MMO", 3);
SaveStateSize = (uint32_t)startState.tellp();
file.write((char*)&SaveStateSize, sizeof(uint32_t));
if(SaveStateSize > 0) {
startState.seekg(0, ios::beg);
uint8_t *stateBuffer = new uint8_t[SaveStateSize];
startState.read((char*)stateBuffer, SaveStateSize);
file.write((char*)stateBuffer, SaveStateSize);
delete[] stateBuffer;
}
for(int i = 0; i < 4; i++) {
DataSize[i] = PortData[i].size();
file.write((char*)&DataSize[i], sizeof(uint32_t));
if(DataSize[i] > 0) {
file.write((char*)&PortData[i][0], DataSize[i] * sizeof(uint16_t));
}
}
file.close();
return true;
}
bool Load(wstring filename, stringstream &startState)
{
ifstream file(filename, ios::in | ios::binary);
if(file) {
char header[3];
file.read((char*)&header, 3);
if(memcmp((char*)&header, "MMO", 3) != 0) {
//Invalid movie file
return false;
}
file.read((char*)&SaveStateSize, sizeof(uint32_t));
if(SaveStateSize > 0) {
uint8_t *stateBuffer = new uint8_t[SaveStateSize];
file.read((char*)stateBuffer, SaveStateSize);
startState.write((char*)stateBuffer, SaveStateSize);
delete[] stateBuffer;
}
for(int i = 0; i < 4; i++) {
file.read((char*)&DataSize[i], sizeof(uint32_t));
uint16_t* readBuffer = new uint16_t[DataSize[i]];
file.read((char*)readBuffer, DataSize[i] * sizeof(uint16_t));
PortData[i] = vector<uint16_t>(readBuffer, readBuffer + DataSize[i]);
delete[] readBuffer;
}
file.close();
return true;
}
return false;
}
};
class Movie
@ -87,6 +21,7 @@ class Movie
uint8_t _lastState[4];
uint32_t _readPosition[4];
ofstream _file;
wstring _filename;
stringstream _startState;
MovieData _data;
@ -99,6 +34,9 @@ class Movie
void RecordState(uint8_t port, uint8_t state);
uint8_t GetState(uint8_t port);
bool Save();
bool Load(wstring filename);
public:
static void Record(wstring filename, bool reset);

View file

@ -232,5 +232,31 @@ class ROMLoader
}
return crc;
}
static wstring FindMatchingRomInFolder(wstring folder, wstring romFilename, uint32_t crc32Hash)
{
vector<wstring> romFiles = FolderUtilities::GetFilesInFolder(folder, L"*.nes", true);
for(wstring zipFile : FolderUtilities::GetFilesInFolder(folder, L"*.zip", true)) {
romFiles.push_back(zipFile);
}
for(wstring romFile : romFiles) {
//Quick search by filename
if(FolderUtilities::GetFilename(romFile, true).compare(romFilename) == 0) {
if(ROMLoader::GetCRC32(romFile) == crc32Hash) {
return romFile;
}
}
}
for(wstring romFile : romFiles) {
//Slower search by CRC value
if(ROMLoader::GetCRC32(romFile) == crc32Hash) {
//Matching ROM found
return romFile;
}
}
return L"";
}
};

View file

@ -31,8 +31,7 @@ namespace Mesen.GUI.Forms
_notifListener = new InteropEmu.NotificationListener();
_notifListener.OnNotification += _notifListener_OnNotification;
InteropEmu.InitializeEmu(ConfigManager.HomeFolder, this.Handle, this.dxViewer.Handle);
InteropEmu.SetFlags((int)EmulationFlags.LimitFPS);
InitializeEmu();
UpdateMenus();
UpdateRecentFiles();
@ -43,6 +42,16 @@ namespace Mesen.GUI.Forms
}
}
void InitializeEmu()
{
InteropEmu.InitializeEmu(ConfigManager.HomeFolder, this.Handle, this.dxViewer.Handle);
foreach(string romPath in ConfigManager.Config.RecentFiles) {
InteropEmu.AddKnowGameFolder(System.IO.Path.GetDirectoryName(romPath).ToLowerInvariant());
}
InteropEmu.SetFlags((int)EmulationFlags.LimitFPS);
}
void Application_ThreadException(object sender, ThreadExceptionEventArgs e)
{
MessageBox.Show(e.Exception.ToString(), "Unexpected Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
@ -73,7 +82,7 @@ namespace Mesen.GUI.Forms
private void LoadROM(string filename)
{
ConfigManager.Config.AddRecentFile(filename);
InteropEmu.LoadROM(filename);
InteropEmu.LoadROM(filename.ToLowerInvariant());
UpdateRecentFiles();
}
@ -96,7 +105,7 @@ namespace Mesen.GUI.Forms
bool moviePlaying = InteropEmu.MoviePlaying();
bool movieRecording = InteropEmu.MovieRecording();
mnuPlayMovie.Enabled = _emuThread != null && !netPlay && !moviePlaying && !movieRecording;
mnuPlayMovie.Enabled = !netPlay && !moviePlaying && !movieRecording;
mnuStopMovie.Enabled = _emuThread != null && !netPlay && (moviePlaying || movieRecording);
mnuRecordFrom.Enabled = _emuThread != null && !moviePlaying && !movieRecording;
mnuRecordFromStart.Enabled = _emuThread != null && !InteropEmu.IsConnected() && !moviePlaying && !movieRecording;

View file

@ -14,7 +14,10 @@ namespace Mesen.GUI
private const string DLLPath = "WinMesen.dll";
[DllImport(DLLPath)] public static extern void InitializeEmu([MarshalAs(UnmanagedType.LPWStr)]string homeFolder, IntPtr windowHandle, IntPtr dxViewerHandle);
[DllImport(DLLPath)] public static extern void Release();
[DllImport(DLLPath)] public static extern void LoadROM([MarshalAs(UnmanagedType.LPWStr)]string filename);
[DllImport(DLLPath)] public static extern void AddKnowGameFolder([MarshalAs(UnmanagedType.LPWStr)]string folder);
[DllImport(DLLPath)] public static extern void Run();
[DllImport(DLLPath)] public static extern void Pause();
[DllImport(DLLPath)] public static extern void Resume();

View file

@ -54,6 +54,8 @@ namespace InteropEmu {
DllExport void __stdcall LoadROM(wchar_t* filename) { Console::LoadROM(filename); }
DllExport void __stdcall AddKnowGameFolder(wchar_t* folder) { FolderUtilities::AddKnowGameFolder(folder); }
DllExport void __stdcall Run()
{
if(Console::GetInstance()) {

View file

@ -103,7 +103,4 @@ Global
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(Performance) = preSolution
HasPerformanceSessions = true
EndGlobalSection
EndGlobal

View file

@ -4,6 +4,7 @@
#include "FolderUtilities.h"
wstring FolderUtilities::_homeFolder = L"";
vector<wstring> FolderUtilities::_gameFolders = vector<wstring>();
void FolderUtilities::SetHomeFolder(wstring homeFolder)
{
@ -19,6 +20,26 @@ wstring FolderUtilities::GetHomeFolder()
return _homeFolder;
}
void FolderUtilities::AddKnowGameFolder(wstring gameFolder)
{
bool alreadyExists = false;
for(wstring folder : _gameFolders) {
if(folder.compare(gameFolder) == 0) {
alreadyExists = true;
break;
}
}
if(!alreadyExists) {
_gameFolders.push_back(gameFolder);
}
}
vector<wstring> FolderUtilities::GetKnowGameFolders()
{
return _gameFolders;
}
wstring FolderUtilities::GetSaveFolder()
{
wstring folder = CombinePath(GetHomeFolder(), L"Saves\\");

View file

@ -6,9 +6,15 @@ class FolderUtilities
{
private:
static wstring _homeFolder;
static vector<wstring> _gameFolders;
public:
static void SetHomeFolder(wstring homeFolder);
static wstring GetHomeFolder();
static void AddKnowGameFolder(wstring gameFolder);
static vector<wstring> GetKnowGameFolders();
static wstring GetSaveFolder();
static wstring GetSaveStateFolder();
static wstring GetMovieFolder();