Movies: FM2 file format support (incomplete, wip)

This commit is contained in:
Souryo 2017-04-24 18:28:50 -04:00
parent 0468e7b9ed
commit 211e6354c8
17 changed files with 163 additions and 38 deletions

View file

@ -520,8 +520,9 @@ void BaseMapper::Initialize(RomData &romData)
_hasChrBattery = romData.SaveChrRamSize > 0 || ForceChrBattery(); _hasChrBattery = romData.SaveChrRamSize > 0 || ForceChrBattery();
_gameSystem = romData.System; _gameSystem = romData.System;
_crc32 = romData.Crc32; _hashInfo.Crc32Hash = romData.Crc32;
_sha1Hash = romData.Sha1; _hashInfo.Sha1Hash = romData.Sha1;
_hashInfo.PrgChrMd5Hash = romData.PrgChrMd5;
_prgCrc32 = romData.PrgCrc32; _prgCrc32 = romData.PrgCrc32;
switch(romData.BusConflicts) { switch(romData.BusConflicts) {
case BusConflictType::Default: _hasBusConflicts = HasBusConflicts(); break; case BusConflictType::Default: _hasBusConflicts = HasBusConflicts(); break;
@ -710,7 +711,7 @@ RomFormat BaseMapper::GetRomFormat()
HashInfo BaseMapper::GetHashInfo() HashInfo BaseMapper::GetHashInfo()
{ {
return { _crc32, _sha1Hash }; return _hashInfo;
} }
uint32_t BaseMapper::GetPrgCrc32() uint32_t BaseMapper::GetPrgCrc32()

View file

@ -45,8 +45,7 @@ private:
uint32_t _prgPageNumbers[64]; uint32_t _prgPageNumbers[64];
uint32_t _chrPageNumbers[64]; uint32_t _chrPageNumbers[64];
uint32_t _crc32 = 0; HashInfo _hashInfo;
string _sha1Hash = "";
uint32_t _prgCrc32 = 0; uint32_t _prgCrc32 = 0;
vector<uint8_t> _originalPrgRom; vector<uint8_t> _originalPrgRom;

View file

@ -28,7 +28,7 @@ void BizhawkMovie::ProcessNotification(ConsoleNotificationType type, void* param
//Reset, not implemented yet //Reset, not implemented yet
} }
if(_gameSystem == GameSystem::FDS) { if(FDS::GetSideCount()) {
//FDS timings between NesHawk & Mesen are currently significantly different //FDS timings between NesHawk & Mesen are currently significantly different
//So FDS games will always go out of sync //So FDS games will always go out of sync
if(systemAction & 0x04) { if(systemAction & 0x04) {
@ -42,7 +42,7 @@ void BizhawkMovie::ProcessNotification(ConsoleNotificationType type, void* param
} }
FDS::InsertDisk(diskNumber); FDS::InsertDisk(diskNumber);
} }
} else if(_gameSystem == GameSystem::VsUniSystem) { } else if(VsControlManager::GetInstance()) {
if(VsControlManager::GetInstance()) { if(VsControlManager::GetInstance()) {
if(systemAction & 0x04) { if(systemAction & 0x04) {
VsControlManager::GetInstance()->InsertCoin(0); VsControlManager::GetInstance()->InsertCoin(0);
@ -74,8 +74,6 @@ bool BizhawkMovie::InitializeGameData(ZipReader & reader)
{ {
std::stringstream ss = reader.GetStream("Header.txt"); std::stringstream ss = reader.GetStream("Header.txt");
_gameSystem = GameSystem::NesNtsc;
bool result = false; bool result = false;
while(!ss.eof()) { while(!ss.eof()) {
string line; string line;
@ -87,14 +85,6 @@ bool BizhawkMovie::InitializeGameData(ZipReader & reader)
result = true; 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; return result;
@ -106,10 +96,10 @@ bool BizhawkMovie::InitializeInputData(ZipReader & reader)
std::stringstream ss = reader.GetStream("Input Log.txt"); std::stringstream ss = reader.GetStream("Input Log.txt");
int systemActionCount = 2; int systemActionCount = 2;
if(_gameSystem == GameSystem::FDS) { if(FDS::GetSideCount() > 0) {
//Eject disk + Insert Disk #XX //Eject disk + Insert Disk #XX
systemActionCount += FDS::GetSideCount() + 1; systemActionCount += FDS::GetSideCount() + 1;
} else if(_gameSystem == GameSystem::VsUniSystem) { } else if(VsControlManager::GetInstance()) {
//Insert coin 1, 2 + service button //Insert coin 1, 2 + service button
systemActionCount += 3; systemActionCount += 3;
} }

View file

@ -1,20 +1,19 @@
#include "../Utilities/ZipReader.h" #pragma once
#include "../Utilities/StringUtilities.h" #include "stdafx.h"
#include "Console.h"
#include "MovieManager.h" #include "MovieManager.h"
#include "PPU.h" #include "../Utilities/ZipReader.h"
class BizhawkMovie : public IMovie, public INotificationListener class BizhawkMovie : public IMovie, public INotificationListener
{ {
private: private:
bool InitializeGameData(ZipReader &reader);
bool InitializeInputData(ZipReader &reader);
protected:
vector<uint32_t> _systemActionByFrame; vector<uint32_t> _systemActionByFrame;
vector<uint8_t> _dataByFrame[4]; vector<uint8_t> _dataByFrame[4];
bool _isPlaying = false; bool _isPlaying = false;
RamPowerOnState _originalPowerOnState; RamPowerOnState _originalPowerOnState;
GameSystem _gameSystem;
bool InitializeGameData(ZipReader &reader);
bool InitializeInputData(ZipReader &reader);
public: public:
BizhawkMovie(); BizhawkMovie();
@ -25,7 +24,7 @@ public:
uint8_t GetState(uint8_t port) override; 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 IsRecording() override;
bool IsPlaying() override; bool IsPlaying() override;

View file

@ -122,13 +122,15 @@ bool Console::LoadROM(string filepath, stringstream *filestream, int32_t archive
bool Console::LoadROM(string romName, uint32_t crc32Hash) bool Console::LoadROM(string romName, uint32_t crc32Hash)
{ {
HashInfo hashInfo{ crc32Hash, "" }; HashInfo hashInfo;
hashInfo.Crc32Hash = crc32Hash;
return Console::LoadROM(romName, hashInfo); return Console::LoadROM(romName, hashInfo);
} }
bool Console::LoadROM(string romName, string sha1Hash) bool Console::LoadROM(string romName, string sha1Hash)
{ {
HashInfo hashInfo{ 0, sha1Hash }; HashInfo hashInfo;
hashInfo.Sha1Hash = sha1Hash;
return Console::LoadROM(romName, hashInfo); return Console::LoadROM(romName, hashInfo);
} }
@ -138,7 +140,7 @@ bool Console::LoadROM(string romName, HashInfo hashInfo)
string currentFolder = FolderUtilities::GetFolderName(currentRomFilepath); string currentFolder = FolderUtilities::GetFolderName(currentRomFilepath);
if(!currentRomFilepath.empty()) { if(!currentRomFilepath.empty()) {
HashInfo gameHashInfo = Instance->_mapper->GetHashInfo(); 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 //Current game matches, no need to do anything
return true; return true;
} }

View file

@ -411,6 +411,7 @@
<ClInclude Include="ArkanoidController.h" /> <ClInclude Include="ArkanoidController.h" />
<ClInclude Include="Assembler.h" /> <ClInclude Include="Assembler.h" />
<ClInclude Include="AutomaticRomTest.h" /> <ClInclude Include="AutomaticRomTest.h" />
<ClInclude Include="FceuxMovie.h" />
<ClInclude Include="RecordedRomTest.h" /> <ClInclude Include="RecordedRomTest.h" />
<ClInclude Include="AutoSaveManager.h" /> <ClInclude Include="AutoSaveManager.h" />
<ClInclude Include="AviRecorder.h" /> <ClInclude Include="AviRecorder.h" />
@ -766,6 +767,7 @@
<ClCompile Include="ArkanoidController.cpp" /> <ClCompile Include="ArkanoidController.cpp" />
<ClCompile Include="Assembler.cpp" /> <ClCompile Include="Assembler.cpp" />
<ClCompile Include="AutomaticRomTest.cpp" /> <ClCompile Include="AutomaticRomTest.cpp" />
<ClCompile Include="FceuxMovie.cpp" />
<ClCompile Include="RecordedRomTest.cpp" /> <ClCompile Include="RecordedRomTest.cpp" />
<ClCompile Include="AutoSaveManager.cpp" /> <ClCompile Include="AutoSaveManager.cpp" />
<ClCompile Include="AviRecorder.cpp" /> <ClCompile Include="AviRecorder.cpp" />

View file

@ -1159,6 +1159,9 @@
<ClInclude Include="AutomaticRomTest.h"> <ClInclude Include="AutomaticRomTest.h">
<Filter>Misc</Filter> <Filter>Misc</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="FceuxMovie.h">
<Filter>Movies</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="stdafx.cpp"> <ClCompile Include="stdafx.cpp">
@ -1371,5 +1374,8 @@
<ClCompile Include="AutomaticRomTest.cpp"> <ClCompile Include="AutomaticRomTest.cpp">
<Filter>Misc</Filter> <Filter>Misc</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="FceuxMovie.cpp">
<Filter>Movies</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
</Project> </Project>

87
Core/FceuxMovie.cpp Normal file
View file

@ -0,0 +1,87 @@
#include "stdafx.h"
#include "../Utilities/HexUtilities.h"
#include "FceuxMovie.h"
#include "Console.h"
vector<uint8_t> FceuxMovie::Base64Decode(string in)
{
vector<uint8_t> out;
vector<int> 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<uint8_t> 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;
}

15
Core/FceuxMovie.h Normal file
View file

@ -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<uint8_t> Base64Decode(string in);
bool InitializeData(stringstream &filestream);
public:
bool Play(stringstream &filestream, bool autoLoadRom) override;
};

View file

@ -3,6 +3,7 @@
#include "MovieManager.h" #include "MovieManager.h"
#include "MesenMovie.h" #include "MesenMovie.h"
#include "BizhawkMovie.h" #include "BizhawkMovie.h"
#include "FceuxMovie.h"
shared_ptr<IMovie> MovieManager::_instance; shared_ptr<IMovie> MovieManager::_instance;
@ -44,6 +45,12 @@ bool MovieManager::Play(std::stringstream &filestream, bool autoLoadRom)
_instance = movie; _instance = movie;
return true; return true;
} }
} else if(memcmp(header, "ver", 3) == 0) {
shared_ptr<IMovie> movie(new FceuxMovie());
if(movie->Play(filestream, autoLoadRom)) {
_instance = movie;
return true;
}
} }
return false; return false;

View file

@ -39,8 +39,9 @@ enum class BusConflictType
struct HashInfo struct HashInfo
{ {
uint32_t Crc32Hash; uint32_t Crc32Hash = 0;
string Sha1Hash; string Sha1Hash;
string PrgChrMd5Hash;
}; };
struct NESHeader struct NESHeader
@ -318,6 +319,7 @@ struct RomData
vector<uint8_t> RawData; vector<uint8_t> RawData;
string Sha1; string Sha1;
string PrgChrMd5;
uint32_t Crc32 = 0; uint32_t Crc32 = 0;
uint32_t PrgCrc32 = 0; uint32_t PrgCrc32 = 0;
uint32_t PrgChrCrc32 = 0; uint32_t PrgChrCrc32 = 0;

View file

@ -1,6 +1,7 @@
#pragma once #pragma once
#include "stdafx.h" #include "stdafx.h"
#include "../Utilities/CRC32.h" #include "../Utilities/CRC32.h"
#include "../Utilities/md5.h"
#include "../Utilities/HexUtilities.h" #include "../Utilities/HexUtilities.h"
#include "RomData.h" #include "RomData.h"
#include "GameDatabase.h" #include "GameDatabase.h"
@ -179,6 +180,7 @@ public:
romData.Format = RomFormat::Unif; romData.Format = RomFormat::Unif;
romData.PrgCrc32 = CRC32::GetCRC(romData.PrgRom.data(), romData.PrgRom.size()); romData.PrgCrc32 = CRC32::GetCRC(romData.PrgRom.data(), romData.PrgRom.size());
romData.PrgChrCrc32 = CRC32::GetCRC(fullRom.data(), fullRom.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("PRG+CHR CRC32: 0x" + HexUtilities::ToHex(romData.PrgChrCrc32));
MessageManager::Log("[UNIF] Board Name: " + _mapperName); MessageManager::Log("[UNIF] Board Name: " + _mapperName);

View file

@ -1,6 +1,7 @@
#include "stdafx.h" #include "stdafx.h"
#include "iNesLoader.h" #include "iNesLoader.h"
#include "../Utilities/CRC32.h" #include "../Utilities/CRC32.h"
#include "../Utilities/md5.h"
#include "../Utilities/HexUtilities.h" #include "../Utilities/HexUtilities.h"
#include "GameDatabase.h" #include "GameDatabase.h"
#include "EmulationSettings.h" #include "EmulationSettings.h"
@ -51,6 +52,7 @@ RomData iNesLoader::LoadRom(vector<uint8_t>& romFile, NESHeader *preloadedHeader
uint32_t romCrc = CRC32::GetCRC(buffer, romFile.size() - bytesRead); uint32_t romCrc = CRC32::GetCRC(buffer, romFile.size() - bytesRead);
romData.PrgChrCrc32 = romCrc; romData.PrgChrCrc32 = romCrc;
romData.PrgChrMd5 = GetMd5Sum(buffer, romFile.size() - bytesRead);
NESHeader dbHeader; NESHeader dbHeader;
GameDatabase::GetiNesHeader(romData.PrgChrCrc32, dbHeader); GameDatabase::GetiNesHeader(romData.PrgChrCrc32, dbHeader);

View file

@ -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]; return _hexCache[value >> 24] + _hexCache[(value >> 16) & 0xFF] + _hexCache[(value >> 8) & 0xFF] + _hexCache[value & 0xFF];
} }
} }
string HexUtilities::ToHex(vector<uint8_t> &data)
{
string result;
result.reserve(data.size() * 2);
for(uint8_t value : data) {
result += HexUtilities::ToHex(value);
}
return result;
}

View file

@ -10,6 +10,7 @@ public:
static string ToHex(uint8_t addr); static string ToHex(uint8_t addr);
static string ToHex(uint16_t addr); static string ToHex(uint16_t addr);
static string ToHex(uint32_t addr); static string ToHex(uint32_t addr);
static string ToHex(vector<uint8_t> &data);
static int FromHex(string hex); static int FromHex(string hex);
}; };

View file

@ -301,15 +301,15 @@ void GetMd5Sum(unsigned char* result, void* buffer, unsigned long size)
MD5_Final(result, &context); MD5_Final(result, &context);
} }
string GetMd5Sum(void* buffer, unsigned long size) string GetMd5Sum(void* buffer, size_t size)
{ {
unsigned char result[16]; unsigned char result[16];
GetMd5Sum(result, buffer, size); GetMd5Sum(result, buffer, (unsigned long)size);
std::stringstream ss; 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++) { for(int i = 0; i < 16; i++) {
ss << (int)result[i]; ss << std::setw(2) << (int)result[i];
} }
return ss.str(); return ss.str();
} }

View file

@ -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_Update(MD5_CTX *ctx, const void *data, unsigned long size);
extern void MD5_Final(unsigned char *result, MD5_CTX *ctx); extern void MD5_Final(unsigned char *result, MD5_CTX *ctx);
extern void GetMd5Sum(unsigned char *result, void* buffer, unsigned long size); 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);