diff --git a/Core/BaseMapper.cpp b/Core/BaseMapper.cpp index 65db9efe..c5b77f44 100644 --- a/Core/BaseMapper.cpp +++ b/Core/BaseMapper.cpp @@ -520,8 +520,9 @@ void BaseMapper::Initialize(RomData &romData) _hasChrBattery = romData.SaveChrRamSize > 0 || ForceChrBattery(); _gameSystem = romData.System; - _crc32 = romData.Crc32; - _sha1Hash = romData.Sha1; + _hashInfo.Crc32Hash = romData.Crc32; + _hashInfo.Sha1Hash = romData.Sha1; + _hashInfo.PrgChrMd5Hash = romData.PrgChrMd5; _prgCrc32 = romData.PrgCrc32; switch(romData.BusConflicts) { case BusConflictType::Default: _hasBusConflicts = HasBusConflicts(); break; @@ -710,7 +711,7 @@ RomFormat BaseMapper::GetRomFormat() HashInfo BaseMapper::GetHashInfo() { - return { _crc32, _sha1Hash }; + return _hashInfo; } uint32_t BaseMapper::GetPrgCrc32() diff --git a/Core/BaseMapper.h b/Core/BaseMapper.h index 628bb778..f638572f 100644 --- a/Core/BaseMapper.h +++ b/Core/BaseMapper.h @@ -45,8 +45,7 @@ private: uint32_t _prgPageNumbers[64]; uint32_t _chrPageNumbers[64]; - uint32_t _crc32 = 0; - string _sha1Hash = ""; + HashInfo _hashInfo; uint32_t _prgCrc32 = 0; vector _originalPrgRom; diff --git a/Core/BizhawkMovie.cpp b/Core/BizhawkMovie.cpp index f41d0728..fea87000 100644 --- a/Core/BizhawkMovie.cpp +++ b/Core/BizhawkMovie.cpp @@ -28,7 +28,7 @@ void BizhawkMovie::ProcessNotification(ConsoleNotificationType type, void* param //Reset, not implemented yet } - if(_gameSystem == GameSystem::FDS) { + if(FDS::GetSideCount()) { //FDS timings between NesHawk & Mesen are currently significantly different //So FDS games will always go out of sync if(systemAction & 0x04) { @@ -42,7 +42,7 @@ void BizhawkMovie::ProcessNotification(ConsoleNotificationType type, void* param } FDS::InsertDisk(diskNumber); } - } else if(_gameSystem == GameSystem::VsUniSystem) { + } else if(VsControlManager::GetInstance()) { if(VsControlManager::GetInstance()) { if(systemAction & 0x04) { VsControlManager::GetInstance()->InsertCoin(0); @@ -74,8 +74,6 @@ bool BizhawkMovie::InitializeGameData(ZipReader & reader) { std::stringstream ss = reader.GetStream("Header.txt"); - _gameSystem = GameSystem::NesNtsc; - bool result = false; while(!ss.eof()) { string line; @@ -87,14 +85,6 @@ bool BizhawkMovie::InitializeGameData(ZipReader & reader) result = true; } } - } else if(line.compare(0, 9, "BoardName", 9) == 0) { - if(line.compare(10, 8, "MAPPER99", 8) == 0) { - //VS System - _gameSystem = GameSystem::VsUniSystem; - } else if(line.compare(10, 3, "FDS", 3) == 0) { - //FDS - _gameSystem = GameSystem::FDS; - } } } return result; @@ -106,10 +96,10 @@ bool BizhawkMovie::InitializeInputData(ZipReader & reader) std::stringstream ss = reader.GetStream("Input Log.txt"); int systemActionCount = 2; - if(_gameSystem == GameSystem::FDS) { + if(FDS::GetSideCount() > 0) { //Eject disk + Insert Disk #XX systemActionCount += FDS::GetSideCount() + 1; - } else if(_gameSystem == GameSystem::VsUniSystem) { + } else if(VsControlManager::GetInstance()) { //Insert coin 1, 2 + service button systemActionCount += 3; } diff --git a/Core/BizhawkMovie.h b/Core/BizhawkMovie.h index f3e895f5..985538bb 100644 --- a/Core/BizhawkMovie.h +++ b/Core/BizhawkMovie.h @@ -1,20 +1,19 @@ -#include "../Utilities/ZipReader.h" -#include "../Utilities/StringUtilities.h" -#include "Console.h" +#pragma once +#include "stdafx.h" #include "MovieManager.h" -#include "PPU.h" +#include "../Utilities/ZipReader.h" class BizhawkMovie : public IMovie, public INotificationListener { private: + bool InitializeGameData(ZipReader &reader); + bool InitializeInputData(ZipReader &reader); + +protected: vector _systemActionByFrame; vector _dataByFrame[4]; bool _isPlaying = false; RamPowerOnState _originalPowerOnState; - GameSystem _gameSystem; - - bool InitializeGameData(ZipReader &reader); - bool InitializeInputData(ZipReader &reader); public: BizhawkMovie(); @@ -25,7 +24,7 @@ public: uint8_t GetState(uint8_t port) override; - bool Play(stringstream &filestream, bool autoLoadRom) override; + virtual bool Play(stringstream &filestream, bool autoLoadRom) override; bool IsRecording() override; bool IsPlaying() override; diff --git a/Core/Console.cpp b/Core/Console.cpp index c9e950a5..8e143508 100644 --- a/Core/Console.cpp +++ b/Core/Console.cpp @@ -122,13 +122,15 @@ bool Console::LoadROM(string filepath, stringstream *filestream, int32_t archive bool Console::LoadROM(string romName, uint32_t crc32Hash) { - HashInfo hashInfo{ crc32Hash, "" }; + HashInfo hashInfo; + hashInfo.Crc32Hash = crc32Hash; return Console::LoadROM(romName, hashInfo); } bool Console::LoadROM(string romName, string sha1Hash) { - HashInfo hashInfo{ 0, sha1Hash }; + HashInfo hashInfo; + hashInfo.Sha1Hash = sha1Hash; return Console::LoadROM(romName, hashInfo); } @@ -138,7 +140,7 @@ bool Console::LoadROM(string romName, HashInfo hashInfo) string currentFolder = FolderUtilities::GetFolderName(currentRomFilepath); if(!currentRomFilepath.empty()) { HashInfo gameHashInfo = Instance->_mapper->GetHashInfo(); - if(gameHashInfo.Crc32Hash == hashInfo.Crc32Hash || gameHashInfo.Sha1Hash.compare(hashInfo.Sha1Hash) == 0) { + if(gameHashInfo.Crc32Hash == hashInfo.Crc32Hash || gameHashInfo.Sha1Hash.compare(hashInfo.Sha1Hash) == 0 || gameHashInfo.PrgChrMd5Hash.compare(hashInfo.PrgChrMd5Hash) == 0) { //Current game matches, no need to do anything return true; } diff --git a/Core/Core.vcxproj b/Core/Core.vcxproj index aa74f7ea..43274c83 100644 --- a/Core/Core.vcxproj +++ b/Core/Core.vcxproj @@ -411,6 +411,7 @@ + @@ -766,6 +767,7 @@ + diff --git a/Core/Core.vcxproj.filters b/Core/Core.vcxproj.filters index 7be3550d..035de055 100644 --- a/Core/Core.vcxproj.filters +++ b/Core/Core.vcxproj.filters @@ -1159,6 +1159,9 @@ Misc + + Movies + @@ -1371,5 +1374,8 @@ Misc + + Movies + \ No newline at end of file diff --git a/Core/FceuxMovie.cpp b/Core/FceuxMovie.cpp new file mode 100644 index 00000000..6c366122 --- /dev/null +++ b/Core/FceuxMovie.cpp @@ -0,0 +1,87 @@ +#include "stdafx.h" +#include "../Utilities/HexUtilities.h" +#include "FceuxMovie.h" +#include "Console.h" + +vector FceuxMovie::Base64Decode(string in) +{ + vector out; + + vector T(256, -1); + for(int i = 0; i<64; i++) T["ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[i]] = i; + + int val = 0, valb = -8; + for(uint8_t c : in) { + if(T[c] == -1) break; + val = (val << 6) + T[c]; + valb += 6; + if(valb >= 0) { + out.push_back(val >> valb); + valb -= 8; + } + } + return out; +} + +bool FceuxMovie::InitializeData(stringstream &filestream) +{ + const uint8_t orValues[8] = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 }; + uint32_t systemActionCount = 0; + + bool result = false; + while(!filestream.eof()) { + string line; + std::getline(filestream, line); + if(line.compare(0, 19, "romChecksum base64:", 19) == 0) { + vector md5array = Base64Decode(line.substr(19, line.size() - 20)); + HashInfo hashInfo; + hashInfo.PrgChrMd5Hash = HexUtilities::ToHex(md5array); + if(Console::LoadROM("", hashInfo)) { + result = true; + } else { + return false; + } + } else if(line.size() > 0 && line[0] == '|') { + line.erase(std::remove(line.begin(), line.end(), '|'), line.end()); + line = line.substr(1, line.size() - 2); + + //Read power/reset/FDS/VS/etc. commands + /*uint32_t systemAction = 0; + for(int i = 0; i < systemActionCount; i++) { + if(line[i] != '.') { + systemAction |= (1 << i); + } + } + _systemActionByFrame.push_back(systemAction);*/ + + //Only supports regular controllers (up to 4 of them) + for(int i = 0; i < 8 * 4; i++) { + uint8_t port = i / 8; + + if(port <= 3) { + uint8_t portValue = 0; + for(int j = 0; j < 8 && i + j + systemActionCount < line.size(); j++) { + if(line[i + j + systemActionCount] != '.') { + portValue |= orValues[j]; + } + } + i += 7; + _dataByFrame[port].push_back(portValue); + } + } + } + } + return result; +} + +bool FceuxMovie::Play(stringstream & filestream, bool autoLoadRom) +{ + Console::Pause(); + if(InitializeData(filestream)) { + EmulationSettings::SetRamPowerOnState(RamPowerOnState::AllZeros); + Console::Reset(false); + _isPlaying = true; + } + Console::Resume(); + return _isPlaying; +} \ No newline at end of file diff --git a/Core/FceuxMovie.h b/Core/FceuxMovie.h new file mode 100644 index 00000000..e79a6978 --- /dev/null +++ b/Core/FceuxMovie.h @@ -0,0 +1,15 @@ +#pragma once +#include "stdafx.h" +#include "../Utilities/ZipReader.h" +#include "MovieManager.h" +#include "BizhawkMovie.h" + +class FceuxMovie : public BizhawkMovie +{ +private: + vector Base64Decode(string in); + bool InitializeData(stringstream &filestream); + +public: + bool Play(stringstream &filestream, bool autoLoadRom) override; +}; \ No newline at end of file diff --git a/Core/MovieManager.cpp b/Core/MovieManager.cpp index f42f157d..c7d114e0 100644 --- a/Core/MovieManager.cpp +++ b/Core/MovieManager.cpp @@ -3,6 +3,7 @@ #include "MovieManager.h" #include "MesenMovie.h" #include "BizhawkMovie.h" +#include "FceuxMovie.h" shared_ptr MovieManager::_instance; @@ -44,6 +45,12 @@ bool MovieManager::Play(std::stringstream &filestream, bool autoLoadRom) _instance = movie; return true; } + } else if(memcmp(header, "ver", 3) == 0) { + shared_ptr movie(new FceuxMovie()); + if(movie->Play(filestream, autoLoadRom)) { + _instance = movie; + return true; + } } return false; diff --git a/Core/RomData.h b/Core/RomData.h index 72541f1f..cb1e95c9 100644 --- a/Core/RomData.h +++ b/Core/RomData.h @@ -39,8 +39,9 @@ enum class BusConflictType struct HashInfo { - uint32_t Crc32Hash; + uint32_t Crc32Hash = 0; string Sha1Hash; + string PrgChrMd5Hash; }; struct NESHeader @@ -318,6 +319,7 @@ struct RomData vector RawData; string Sha1; + string PrgChrMd5; uint32_t Crc32 = 0; uint32_t PrgCrc32 = 0; uint32_t PrgChrCrc32 = 0; diff --git a/Core/UnifLoader.h b/Core/UnifLoader.h index 0fb4582f..fd6751d9 100644 --- a/Core/UnifLoader.h +++ b/Core/UnifLoader.h @@ -1,6 +1,7 @@ #pragma once #include "stdafx.h" #include "../Utilities/CRC32.h" +#include "../Utilities/md5.h" #include "../Utilities/HexUtilities.h" #include "RomData.h" #include "GameDatabase.h" @@ -179,6 +180,7 @@ public: romData.Format = RomFormat::Unif; romData.PrgCrc32 = CRC32::GetCRC(romData.PrgRom.data(), romData.PrgRom.size()); romData.PrgChrCrc32 = CRC32::GetCRC(fullRom.data(), fullRom.size()); + romData.PrgChrMd5 = GetMd5Sum(fullRom.data(), fullRom.size()); MessageManager::Log("PRG+CHR CRC32: 0x" + HexUtilities::ToHex(romData.PrgChrCrc32)); MessageManager::Log("[UNIF] Board Name: " + _mapperName); diff --git a/Core/iNesLoader.cpp b/Core/iNesLoader.cpp index a84917b2..70205719 100644 --- a/Core/iNesLoader.cpp +++ b/Core/iNesLoader.cpp @@ -1,6 +1,7 @@ #include "stdafx.h" #include "iNesLoader.h" #include "../Utilities/CRC32.h" +#include "../Utilities/md5.h" #include "../Utilities/HexUtilities.h" #include "GameDatabase.h" #include "EmulationSettings.h" @@ -51,6 +52,7 @@ RomData iNesLoader::LoadRom(vector& romFile, NESHeader *preloadedHeader uint32_t romCrc = CRC32::GetCRC(buffer, romFile.size() - bytesRead); romData.PrgChrCrc32 = romCrc; + romData.PrgChrMd5 = GetMd5Sum(buffer, romFile.size() - bytesRead); NESHeader dbHeader; GameDatabase::GetiNesHeader(romData.PrgChrCrc32, dbHeader); diff --git a/Utilities/HexUtilities.cpp b/Utilities/HexUtilities.cpp index 7e3a8017..e0df04f9 100644 --- a/Utilities/HexUtilities.cpp +++ b/Utilities/HexUtilities.cpp @@ -58,3 +58,13 @@ string HexUtilities::ToHex(uint32_t value) return _hexCache[value >> 24] + _hexCache[(value >> 16) & 0xFF] + _hexCache[(value >> 8) & 0xFF] + _hexCache[value & 0xFF]; } } + +string HexUtilities::ToHex(vector &data) +{ + string result; + result.reserve(data.size() * 2); + for(uint8_t value : data) { + result += HexUtilities::ToHex(value); + } + return result; +} \ No newline at end of file diff --git a/Utilities/HexUtilities.h b/Utilities/HexUtilities.h index df7faddb..e51aaa31 100644 --- a/Utilities/HexUtilities.h +++ b/Utilities/HexUtilities.h @@ -10,6 +10,7 @@ public: static string ToHex(uint8_t addr); static string ToHex(uint16_t addr); static string ToHex(uint32_t addr); - + static string ToHex(vector &data); + static int FromHex(string hex); }; \ No newline at end of file diff --git a/Utilities/md5.cpp b/Utilities/md5.cpp index 4e1bd050..f7c1f7cc 100644 --- a/Utilities/md5.cpp +++ b/Utilities/md5.cpp @@ -301,15 +301,15 @@ void GetMd5Sum(unsigned char* result, void* buffer, unsigned long size) MD5_Final(result, &context); } -string GetMd5Sum(void* buffer, unsigned long size) +string GetMd5Sum(void* buffer, size_t size) { unsigned char result[16]; - GetMd5Sum(result, buffer, size); + GetMd5Sum(result, buffer, (unsigned long)size); std::stringstream ss; - ss << std::hex << std::setfill('0') << std::setw(2); + ss << std::hex << std::uppercase << std::setfill('0'); for(int i = 0; i < 16; i++) { - ss << (int)result[i]; + ss << std::setw(2) << (int)result[i]; } return ss.str(); } \ No newline at end of file diff --git a/Utilities/md5.h b/Utilities/md5.h index 430c81c8..ed006edf 100644 --- a/Utilities/md5.h +++ b/Utilities/md5.h @@ -39,4 +39,4 @@ extern void MD5_Init(MD5_CTX *ctx); extern void MD5_Update(MD5_CTX *ctx, const void *data, unsigned long size); extern void MD5_Final(unsigned char *result, MD5_CTX *ctx); extern void GetMd5Sum(unsigned char *result, void* buffer, unsigned long size); -extern string GetMd5Sum(void* buffer, unsigned long size); +extern string GetMd5Sum(void* buffer, size_t size);