Play-/Source/ui_shared/ArcadeUtils.cpp

172 lines
5.4 KiB
C++
Raw Normal View History

2022-09-29 16:02:50 -04:00
#include "ArcadeUtils.h"
#include <nlohmann/json.hpp>
#include "string_format.h"
#include "StdStreamUtils.h"
#include "PS2VM.h"
#include "PS2VM_Preferences.h"
2022-09-30 16:59:19 -04:00
#include "DiskUtils.h"
2022-09-29 16:02:50 -04:00
#include "AppConfig.h"
#include "BootablesProcesses.h"
#include "iop/ioman/McDumpDevice.h"
2022-10-03 18:46:38 -04:00
#include "iop/Iop_NamcoArcade.h"
2022-10-10 17:10:28 -04:00
#include "iop/namco_arcade/Iop_NamcoAcCdvd.h"
2022-10-20 20:15:48 -04:00
#include "iop/namco_arcade/Iop_NamcoAcRam.h"
2022-09-29 16:02:50 -04:00
struct ARCADE_MACHINE_DEF
{
2022-09-30 18:20:56 -04:00
struct PATCH
{
uint32 address = 0;
uint32 value = 0;
};
2022-09-29 16:02:50 -04:00
std::string id;
std::string dongleFileName;
2022-09-30 16:59:19 -04:00
std::string cdvdFileName;
2022-09-29 16:02:50 -04:00
std::string boot;
2022-09-30 18:20:56 -04:00
std::vector<PATCH> patches;
2022-09-29 16:02:50 -04:00
};
2022-09-30 18:20:56 -04:00
uint32 ParseHexStringValue(const std::string& value)
{
uint32 result = 0;
int scanCount = sscanf(value.c_str(), "0x%x", &result);
assert(scanCount == 1);
return result;
}
2022-09-29 16:02:50 -04:00
ARCADE_MACHINE_DEF ReadArcadeMachineDefinition(const fs::path& arcadeDefPath)
{
2022-09-30 18:20:56 -04:00
auto parsePatches =
[](const nlohmann::json& patchesArray) {
std::vector<ARCADE_MACHINE_DEF::PATCH> patches;
for(const auto& jsonPatch : patchesArray)
{
ARCADE_MACHINE_DEF::PATCH patch;
2022-10-04 17:12:04 -04:00
if(!jsonPatch.contains("address") || !jsonPatch.contains("value")) continue;
2022-09-30 18:20:56 -04:00
patch.address = ParseHexStringValue(jsonPatch["address"]);
patch.value = ParseHexStringValue(jsonPatch["value"]);
patches.emplace_back(std::move(patch));
}
return patches;
};
2022-09-29 16:02:50 -04:00
auto defString =
[&arcadeDefPath]() {
auto defStream = Framework::CreateInputStdStream(arcadeDefPath.native());
return defStream.ReadString();
}();
auto defJson = nlohmann::json::parse(defString);
ARCADE_MACHINE_DEF def;
def.id = defJson["id"];
def.dongleFileName = defJson["dongle"]["name"];
2022-09-30 16:59:19 -04:00
if(defJson.contains("cdvd"))
{
def.cdvdFileName = defJson["cdvd"]["name"];
}
2022-09-29 16:02:50 -04:00
def.boot = defJson["boot"];
2022-09-30 18:20:56 -04:00
if(defJson.contains("patches"))
{
def.patches = parsePatches(defJson["patches"]);
}
2022-09-29 16:02:50 -04:00
return def;
}
void ArcadeUtils::BootArcadeMachine(CPS2VM* virtualMachine, const fs::path& arcadeDefPath)
{
auto def = ReadArcadeMachineDefinition(arcadeDefPath);
//Reset PS2VM
virtualMachine->Pause();
virtualMachine->Reset();
auto romArchiveFileName = string_format("%s.zip", def.id.c_str());
fs::path arcadeRomPath = CAppConfig::GetInstance().GetPreferencePath(PREF_PS2_ARCADEROMS_DIRECTORY);
fs::path arcadeRomArchivePath = arcadeRomPath / romArchiveFileName;
if(!fs::exists(arcadeRomArchivePath))
{
throw std::runtime_error(string_format("Failed to find '%s' in arcade ROMs directory.", romArchiveFileName.c_str()));
}
2022-09-30 16:59:19 -04:00
//Mount CDVD or HDD
if(!def.cdvdFileName.empty())
{
fs::path cdvdPath = arcadeRomPath / def.id / def.cdvdFileName;
if(!fs::exists(cdvdPath))
{
throw std::runtime_error(string_format("Failed to find '%s' in game's directory.", def.cdvdFileName.c_str()));
}
//Try to create the optical media for sanity checks (will throw exceptions on errors).
DiskUtils::CreateOpticalMediaFromPath(cdvdPath);
CAppConfig::GetInstance().SetPreferencePath(PREF_PS2_CDROM0_PATH, cdvdPath);
//We need to reset again to make sure updated CDVD has been picked up
virtualMachine->Reset();
}
2022-09-29 16:02:50 -04:00
std::vector<uint8> mcDumpContents;
{
auto inputStream = Framework::CreateInputStdStream(arcadeRomArchivePath.native());
Framework::CZipArchiveReader archiveReader(inputStream);
auto header = archiveReader.GetFileHeader(def.dongleFileName.c_str());
if(!header)
{
throw std::runtime_error("Failed to get header from ZIP archive.");
}
auto fileStream = archiveReader.BeginReadFile(def.dongleFileName.c_str());
mcDumpContents.resize(header->uncompressedSize);
fileStream->Read(mcDumpContents.data(), header->uncompressedSize);
}
//Override mc0 device with special device reading directly from zip file
{
auto device = std::make_shared<Iop::Ioman::CMcDumpDevice>(std::move(mcDumpContents));
auto iopBios = dynamic_cast<CIopBios*>(virtualMachine->m_iop->m_bios.get());
iopBios->GetIoman()->RegisterDevice("mc0", device);
2022-10-18 21:26:14 -04:00
iopBios->GetIoman()->RegisterDevice("ac0", device);
//Ridge Racer 5: Arcade Battle doesn't have any FILEIO in its IOPRP
//Assuming that the BIOS image for arcade boards is version 2.0.5
iopBios->SetDefaultImageVersion(2050);
2022-10-03 18:46:38 -04:00
2022-10-20 20:29:41 -04:00
auto acCdvdModule = std::make_shared<Iop::Namco::CAcCdvd>(*iopBios->GetSifman(), *iopBios->GetCdvdman(), virtualMachine->m_iop->m_ram);
acCdvdModule->SetOpticalMedia(virtualMachine->m_cdrom0.get());
iopBios->RegisterModule(acCdvdModule);
iopBios->RegisterHleModuleReplacement("ATA/ATAPI_driver", acCdvdModule);
iopBios->RegisterHleModuleReplacement("CD/DVD_Compatible", acCdvdModule);
auto acRam = std::make_shared<Iop::Namco::CAcRam>(virtualMachine->m_iop->m_ram);
iopBios->RegisterModule(acRam);
iopBios->RegisterHleModuleReplacement("Arcade_Ext._Memory", acRam);
2022-10-03 18:46:38 -04:00
{
2022-11-09 20:30:31 -05:00
auto namcoArcadeModule = std::make_shared<Iop::CNamcoArcade>(*iopBios->GetSifman(), *acRam, def.id);
2022-10-03 18:46:38 -04:00
iopBios->RegisterModule(namcoArcadeModule);
2022-10-15 11:41:38 -04:00
iopBios->RegisterHleModuleReplacement("rom0:DAEMON", namcoArcadeModule);
2022-10-09 10:22:01 -04:00
virtualMachine->m_pad->InsertListener(namcoArcadeModule.get());
2022-10-03 18:46:38 -04:00
}
2022-09-29 16:02:50 -04:00
}
//Boot mc0:/BOOT (from def)
2022-10-16 21:08:51 -04:00
virtualMachine->m_ee->m_os->BootFromVirtualPath(def.boot.c_str(), { "DANGLE" });
2022-09-29 16:02:50 -04:00
//Apply Patches
2022-09-30 18:20:56 -04:00
for(const auto& patch : def.patches)
{
assert(patch.address < PS2::EE_RAM_SIZE);
*reinterpret_cast<uint32*>(virtualMachine->m_ee->m_ram + patch.address) = patch.value;
}
2022-09-29 16:02:50 -04:00
#ifndef DEBUGGER_INCLUDED
virtualMachine->Resume();
#endif
2022-09-29 16:02:50 -04:00
TryUpdateLastBootedTime(arcadeDefPath);
}