Movies: FM2 file format support (incomplete, wip)
This commit is contained in:
parent
0468e7b9ed
commit
211e6354c8
17 changed files with 163 additions and 38 deletions
|
@ -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()
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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" />
|
||||
|
|
|
@ -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
87
Core/FceuxMovie.cpp
Normal 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
15
Core/FceuxMovie.h
Normal 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;
|
||||
};
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
||||
};
|
|
@ -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();
|
||||
}
|
|
@ -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);
|
||||
|
|
Loading…
Add table
Reference in a new issue