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();
_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()

View file

@ -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<uint8_t> _originalPrgRom;

View file

@ -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;
}

View file

@ -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<uint32_t> _systemActionByFrame;
vector<uint8_t> _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;

View file

@ -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;
}

View file

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

View file

@ -1159,6 +1159,9 @@
<ClInclude Include="AutomaticRomTest.h">
<Filter>Misc</Filter>
</ClInclude>
<ClInclude Include="FceuxMovie.h">
<Filter>Movies</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="stdafx.cpp">
@ -1371,5 +1374,8 @@
<ClCompile Include="AutomaticRomTest.cpp">
<Filter>Misc</Filter>
</ClCompile>
<ClCompile Include="FceuxMovie.cpp">
<Filter>Movies</Filter>
</ClCompile>
</ItemGroup>
</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 "MesenMovie.h"
#include "BizhawkMovie.h"
#include "FceuxMovie.h"
shared_ptr<IMovie> 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<IMovie> movie(new FceuxMovie());
if(movie->Play(filestream, autoLoadRom)) {
_instance = movie;
return true;
}
}
return false;

View file

@ -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<uint8_t> RawData;
string Sha1;
string PrgChrMd5;
uint32_t Crc32 = 0;
uint32_t PrgCrc32 = 0;
uint32_t PrgChrCrc32 = 0;

View file

@ -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);

View file

@ -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<uint8_t>& 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);

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];
}
}
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(uint16_t addr);
static string ToHex(uint32_t addr);
static string ToHex(vector<uint8_t> &data);
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);
}
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();
}

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_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);