Wow the ROM Header was just completely busted. Game list view works now
This commit is contained in:
+10
-9
@@ -2,7 +2,7 @@
|
|||||||
#include <Core.hpp>
|
#include <Core.hpp>
|
||||||
|
|
||||||
namespace n64 {
|
namespace n64 {
|
||||||
const char *regionCodeToReadable(char r) {
|
const char *GameDB::regionCodeToReadable(char r) {
|
||||||
switch (r) {
|
switch (r) {
|
||||||
case 0:
|
case 0:
|
||||||
return "Region-free";
|
return "Region-free";
|
||||||
@@ -52,20 +52,22 @@ std::string GameDB::match(ROM &rom) {
|
|||||||
std::string result = "";
|
std::string result = "";
|
||||||
|
|
||||||
for (const auto &[code, regions, saveType, name] : gamedb) {
|
for (const auto &[code, regions, saveType, name] : gamedb) {
|
||||||
bool matches_region = false;
|
bool matchesRegion = false;
|
||||||
|
|
||||||
|
if (code != rom.code)
|
||||||
|
continue;
|
||||||
|
|
||||||
if (code == rom.code) {
|
|
||||||
for (int j = 0; j < regions.size(); j++) {
|
for (int j = 0; j < regions.size(); j++) {
|
||||||
if (j == regions.size() - 1)
|
if (j == regions.size() - 1)
|
||||||
result += regionCodeToReadable(regions[j]);
|
result += regionCodeToReadable(regions[j]);
|
||||||
else
|
else
|
||||||
result += std::string(regionCodeToReadable(regions[j])) + ", ";
|
result += std::string(regionCodeToReadable(regions[j])) + ", ";
|
||||||
|
|
||||||
if (regions[j] == rom.header.countryCode[0])
|
if (regions[j] == rom.header.countryCode)
|
||||||
matches_region = true;
|
matchesRegion = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (matches_region) {
|
if (matchesRegion) {
|
||||||
rom.saveType = saveType;
|
rom.saveType = saveType;
|
||||||
rom.gameNameDB = name;
|
rom.gameNameDB = name;
|
||||||
return result;
|
return result;
|
||||||
@@ -73,14 +75,13 @@ std::string GameDB::match(ROM &rom) {
|
|||||||
|
|
||||||
info("Matched code for {}, but not region! Game supposedly exists in regions [{}] but this image has "
|
info("Matched code for {}, but not region! Game supposedly exists in regions [{}] but this image has "
|
||||||
"region {}",
|
"region {}",
|
||||||
name, regions, rom.header.countryCode[0]);
|
name, regions, rom.header.countryCode);
|
||||||
rom.saveType = saveType;
|
rom.saveType = saveType;
|
||||||
rom.gameNameDB = name;
|
rom.gameNameDB = name;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
info("Did not match any Game DB entries. Code: {} Region: {}", rom.code, rom.header.countryCode[0]);
|
info("Did not match any Game DB entries. Code: {} Region: {}", rom.code, rom.header.countryCode);
|
||||||
|
|
||||||
rom.gameNameDB = "";
|
rom.gameNameDB = "";
|
||||||
rom.saveType = SAVE_NONE;
|
rom.saveType = SAVE_NONE;
|
||||||
|
|||||||
+21
-20
@@ -14,23 +14,24 @@ struct GameDBEntry {
|
|||||||
|
|
||||||
namespace GameDB {
|
namespace GameDB {
|
||||||
std::string match(ROM &);
|
std::string match(ROM &);
|
||||||
}
|
const char *regionCodeToReadable(char);
|
||||||
|
} // namespace GameDB
|
||||||
|
|
||||||
static const GameDBEntry gamedb[] = {
|
static const GameDBEntry gamedb[] = {
|
||||||
{"NNM", "E", SAVE_NONE, "Namco Museum 64"},
|
{"NNM", "E", SAVE_NONE, "Namco Museum 64"},
|
||||||
{"NDM", "E", SAVE_NONE, "Doom 64"},
|
{"NDM", "E", SAVE_NONE, "Doom 64"},
|
||||||
{"NGN", "E", SAVE_EEPROM_4k, "GoldenEye 007"},
|
{"NGN", "E", SAVE_EEPROM_4k, "GoldenEye 007"},
|
||||||
// Copied from CEN64 with small edits: https://github.com/n64dev/cen64/blob/master/device/cart_db.c
|
// Copied from CEN64 with small edits: https://github.com/n64dev/cen64/blob/master/device/cart_db.c
|
||||||
{"CFZ", "EJ", SAVE_SRAM_256k, "F-Zero X (NTSC)"},
|
{"CFZ", "EJ", SAVE_SRAM_256k, "F-Zero X"},
|
||||||
{"CLB", "EJ", SAVE_EEPROM_4k, "Mario Party (NTSC)"},
|
{"CLB", "EJ", SAVE_EEPROM_4k, "Mario Party"},
|
||||||
{"CP2", "J", SAVE_FLASH_1m, "Pokémon Stadium 2 (Japan)"},
|
{"CP2", "J", SAVE_FLASH_1m, "Pokémon Stadium 2"},
|
||||||
{"CPS", "J", SAVE_SRAM_256k, "Pokémon Stadium (Japan)"},
|
{"CPS", "J", SAVE_SRAM_256k, "Pokémon Stadium"},
|
||||||
{"CZL", "EJ", SAVE_SRAM_256k, "Legend of Zelda: Ocarina of Time (NTSC)"},
|
{"CZL", "EJ", SAVE_SRAM_256k, "Legend of Zelda: Ocarina of Time"},
|
||||||
{"N3D", "J", SAVE_EEPROM_16k, "Doraemon 3: Nobita no Machi SOS!"},
|
{"N3D", "J", SAVE_EEPROM_16k, "Doraemon 3: Nobita no Machi SOS!"},
|
||||||
{"N3H", "J", SAVE_SRAM_256k, "Ganbare! Nippon! Olympics 2000"},
|
{"N3H", "J", SAVE_SRAM_256k, "Ganbare! Nippon! Olympics 2000"},
|
||||||
{"NA2", "J", SAVE_SRAM_256k, "Virtual Pro Wrestling 2"},
|
{"NA2", "J", SAVE_SRAM_256k, "Virtual Pro Wrestling 2"},
|
||||||
{"NAB", "JP", SAVE_EEPROM_4k, "Air Boarder 64"},
|
{"NAB", "JP", SAVE_EEPROM_4k, "Air Boarder 64"},
|
||||||
{"NAD", "E", SAVE_EEPROM_4k, "Worms Armageddon (USA)"},
|
{"NAD", "E", SAVE_EEPROM_4k, "Worms Armageddon"},
|
||||||
{"NAF", "J", SAVE_FLASH_1m, "Doubutsu no Mori"},
|
{"NAF", "J", SAVE_FLASH_1m, "Doubutsu no Mori"},
|
||||||
{"NAG", "EJP", SAVE_EEPROM_4k, "AeroGauge"},
|
{"NAG", "EJP", SAVE_EEPROM_4k, "AeroGauge"},
|
||||||
{"NAL", "EJPU", SAVE_SRAM_256k, "Super Smash Bros"},
|
{"NAL", "EJPU", SAVE_SRAM_256k, "Super Smash Bros"},
|
||||||
@@ -67,7 +68,7 @@ static const GameDBEntry gamedb[] = {
|
|||||||
{"NDY", "EJP", SAVE_EEPROM_4k, "Diddy Kong Racing"},
|
{"NDY", "EJP", SAVE_EEPROM_4k, "Diddy Kong Racing"},
|
||||||
{"NEA", "EP", SAVE_EEPROM_4k, "PGA European Tour"},
|
{"NEA", "EP", SAVE_EEPROM_4k, "PGA European Tour"},
|
||||||
{"NEP", "EJP", SAVE_EEPROM_16k, "Star Wars Episode I: Racer"},
|
{"NEP", "EJP", SAVE_EEPROM_16k, "Star Wars Episode I: Racer"},
|
||||||
{"NER", "E", SAVE_EEPROM_4k, "AeroFighters Assault (USA)"},
|
{"NER", "E", SAVE_EEPROM_4k, "AeroFighters Assault"},
|
||||||
{"NEV", "J", SAVE_EEPROM_16k, "Neon Genesis Evangelion"},
|
{"NEV", "J", SAVE_EEPROM_16k, "Neon Genesis Evangelion"},
|
||||||
{"NF2", "P", SAVE_EEPROM_4k, "F-1 World Grand Prix II"},
|
{"NF2", "P", SAVE_EEPROM_4k, "F-1 World Grand Prix II"},
|
||||||
{"NFG", "E", SAVE_EEPROM_4k, "Fighter Destiny 2"},
|
{"NFG", "E", SAVE_EEPROM_4k, "Fighter Destiny 2"},
|
||||||
@@ -76,7 +77,7 @@ static const GameDBEntry gamedb[] = {
|
|||||||
{"NFW", "DEFJP", SAVE_EEPROM_4k, "F-1 World Grand Prix"},
|
{"NFW", "DEFJP", SAVE_EEPROM_4k, "F-1 World Grand Prix"},
|
||||||
{"NFX", "EJPU", SAVE_EEPROM_4k, "Star Fox 64"},
|
{"NFX", "EJPU", SAVE_EEPROM_4k, "Star Fox 64"},
|
||||||
{"NFY", "J", SAVE_EEPROM_4k, "Kakutou Denshou: F-Cup Maniax"},
|
{"NFY", "J", SAVE_EEPROM_4k, "Kakutou Denshou: F-Cup Maniax"},
|
||||||
{"NFZ", "P", SAVE_SRAM_256k, "F-Zero X (PAL)"},
|
{"NFZ", "P", SAVE_SRAM_256k, "F-Zero X"},
|
||||||
{"NG6", "J", SAVE_SRAM_256k, "Ganbare Goemon: Dero Dero Douchuu Obake Tenkomori"},
|
{"NG6", "J", SAVE_SRAM_256k, "Ganbare Goemon: Dero Dero Douchuu Obake Tenkomori"},
|
||||||
{"NGC", "EP", SAVE_EEPROM_16k, "GT 64: Championship Edition"},
|
{"NGC", "EP", SAVE_EEPROM_16k, "GT 64: Championship Edition"},
|
||||||
{"NGE", "EJP", SAVE_EEPROM_4k, "GoldenEye 007"},
|
{"NGE", "EJP", SAVE_EEPROM_4k, "GoldenEye 007"},
|
||||||
@@ -85,10 +86,10 @@ static const GameDBEntry gamedb[] = {
|
|||||||
{"NGT", "J", SAVE_EEPROM_16k, "City-Tour GP: Zen-Nihon GT Senshuken"},
|
{"NGT", "J", SAVE_EEPROM_16k, "City-Tour GP: Zen-Nihon GT Senshuken"},
|
||||||
{"NGU", "J", SAVE_EEPROM_4k, "Tsumi to Batsu: Hoshi no Keishousha"},
|
{"NGU", "J", SAVE_EEPROM_4k, "Tsumi to Batsu: Hoshi no Keishousha"},
|
||||||
{"NGV", "EP", SAVE_EEPROM_4k, "Glover"},
|
{"NGV", "EP", SAVE_EEPROM_4k, "Glover"},
|
||||||
{"NHA", "J", SAVE_EEPROM_4k, "Bomber Man 64 (Japan)"},
|
{"NHA", "J", SAVE_EEPROM_4k, "Bomber Man 64"},
|
||||||
{"NHF", "J", SAVE_EEPROM_4k, "64 Hanafuda: Tenshi no Yakusoku"},
|
{"NHF", "J", SAVE_EEPROM_4k, "64 Hanafuda: Tenshi no Yakusoku"},
|
||||||
{"NHP", "J", SAVE_EEPROM_4k, "Heiwa Pachinko World 64"},
|
{"NHP", "J", SAVE_EEPROM_4k, "Heiwa Pachinko World 64"},
|
||||||
{"NHY", "J", SAVE_SRAM_256k, "Hybrid Heaven (Japan)"},
|
{"NHY", "J", SAVE_SRAM_256k, "Hybrid Heaven"},
|
||||||
{"NIB", "J", SAVE_SRAM_256k, "Itoi Shigesato no Bass Tsuri No. 1 Kettei Ban!"},
|
{"NIB", "J", SAVE_SRAM_256k, "Itoi Shigesato no Bass Tsuri No. 1 Kettei Ban!"},
|
||||||
{"NIC", "E", SAVE_EEPROM_4k, "Indy Racing 2000"},
|
{"NIC", "E", SAVE_EEPROM_4k, "Indy Racing 2000"},
|
||||||
{"NIJ", "EP", SAVE_EEPROM_4k, "Indiana Jones and the Infernal Machine"},
|
{"NIJ", "EP", SAVE_EEPROM_4k, "Indiana Jones and the Infernal Machine"},
|
||||||
@@ -106,7 +107,7 @@ static const GameDBEntry gamedb[] = {
|
|||||||
{"NKI", "EP", SAVE_EEPROM_4k, "Killer Instinct Gold"},
|
{"NKI", "EP", SAVE_EEPROM_4k, "Killer Instinct Gold"},
|
||||||
{"NKJ", "E", SAVE_FLASH_1m, "Ken Griffey Jr.'s Slugfest"},
|
{"NKJ", "E", SAVE_FLASH_1m, "Ken Griffey Jr.'s Slugfest"},
|
||||||
{"NKT", "EJP", SAVE_EEPROM_4k, "Mario Kart 64"},
|
{"NKT", "EJP", SAVE_EEPROM_4k, "Mario Kart 64"},
|
||||||
{"NLB", "P", SAVE_EEPROM_4k, "Mario Party (PAL)"},
|
{"NLB", "P", SAVE_EEPROM_4k, "Mario Party"},
|
||||||
{"NLL", "J", SAVE_EEPROM_4k, "Last Legion UX"},
|
{"NLL", "J", SAVE_EEPROM_4k, "Last Legion UX"},
|
||||||
{"NLR", "EJP", SAVE_EEPROM_4k, "Lode Runner 3D"},
|
{"NLR", "EJP", SAVE_EEPROM_4k, "Lode Runner 3D"},
|
||||||
{"NM6", "E", SAVE_FLASH_1m, "Mega Man 64"},
|
{"NM6", "E", SAVE_FLASH_1m, "Mega Man 64"},
|
||||||
@@ -139,7 +140,7 @@ static const GameDBEntry gamedb[] = {
|
|||||||
{"NPH", "E", SAVE_FLASH_1m, "Pokémon Snap Station (Kiosk Demo)"},
|
{"NPH", "E", SAVE_FLASH_1m, "Pokémon Snap Station (Kiosk Demo)"},
|
||||||
{"NPM", "P", SAVE_SRAM_256k, "Premier Manager 64"},
|
{"NPM", "P", SAVE_SRAM_256k, "Premier Manager 64"},
|
||||||
{"NPN", "DEFP", SAVE_FLASH_1m, "Pokémon Puzzle League"},
|
{"NPN", "DEFP", SAVE_FLASH_1m, "Pokémon Puzzle League"},
|
||||||
{"NPO", "DEFIPS", SAVE_FLASH_1m, "Pokémon Stadium (USA, PAL)"},
|
{"NPO", "DEFIPS", SAVE_FLASH_1m, "Pokémon Stadium"},
|
||||||
{"NPP", "J", SAVE_EEPROM_16k, "Parlor! Pro 64: Pachinko Jikki Simulation Game"},
|
{"NPP", "J", SAVE_EEPROM_16k, "Parlor! Pro 64: Pachinko Jikki Simulation Game"},
|
||||||
{"NPS", "J", SAVE_SRAM_256k, "Jikkyou J.League 1999: Perfect Striker 2"},
|
{"NPS", "J", SAVE_SRAM_256k, "Jikkyou J.League 1999: Perfect Striker 2"},
|
||||||
{"NPT", "J", SAVE_EEPROM_4k, "Puyo Puyon Party"},
|
{"NPT", "J", SAVE_EEPROM_4k, "Puyo Puyon Party"},
|
||||||
@@ -155,7 +156,7 @@ static const GameDBEntry gamedb[] = {
|
|||||||
{"NRZ", "EP", SAVE_EEPROM_16k, "Ridge Racer 64"},
|
{"NRZ", "EP", SAVE_EEPROM_16k, "Ridge Racer 64"},
|
||||||
{"NS4", "J", SAVE_SRAM_256k, "Super Robot Taisen 64"},
|
{"NS4", "J", SAVE_SRAM_256k, "Super Robot Taisen 64"},
|
||||||
{"NS6", "EJ", SAVE_EEPROM_4k, "Star Soldier: Vanishing Earth"},
|
{"NS6", "EJ", SAVE_EEPROM_4k, "Star Soldier: Vanishing Earth"},
|
||||||
{"NSA", "JP", SAVE_EEPROM_4k, "AeroFighters Assault (PAL, Japan)"},
|
{"NSA", "JP", SAVE_EEPROM_4k, "AeroFighters Assault"},
|
||||||
{"NSC", "EP", SAVE_EEPROM_4k, "Starshot: Space Circus Fever"},
|
{"NSC", "EP", SAVE_EEPROM_4k, "Starshot: Space Circus Fever"},
|
||||||
{"NSI", "J", SAVE_SRAM_256k, "Fushigi no Dungeon: Fuurai no Shiren 2"},
|
{"NSI", "J", SAVE_SRAM_256k, "Fushigi no Dungeon: Fuurai no Shiren 2"},
|
||||||
{"NSM", "EJP", SAVE_EEPROM_4k, "Super Mario 64"},
|
{"NSM", "EJP", SAVE_EEPROM_4k, "Super Mario 64"},
|
||||||
@@ -175,30 +176,30 @@ static const GameDBEntry gamedb[] = {
|
|||||||
{"NTM", "EJP", SAVE_EEPROM_4k, "Mischief Makers"},
|
{"NTM", "EJP", SAVE_EEPROM_4k, "Mischief Makers"},
|
||||||
{"NTN", "EP", SAVE_EEPROM_4k, "All-Star Tennis 99"},
|
{"NTN", "EP", SAVE_EEPROM_4k, "All-Star Tennis 99"},
|
||||||
{"NTP", "EP", SAVE_EEPROM_4k, "Tetrisphere"},
|
{"NTP", "EP", SAVE_EEPROM_4k, "Tetrisphere"},
|
||||||
{"NTR", "JP", SAVE_EEPROM_4k, "Top Gear Rally (PAL, Japan)"},
|
{"NTR", "JP", SAVE_EEPROM_4k, "Top Gear Rally"},
|
||||||
{"NTW", "J", SAVE_EEPROM_4k, "64 de Hakken!! Tamagotchi"},
|
{"NTW", "J", SAVE_EEPROM_4k, "64 de Hakken!! Tamagotchi"},
|
||||||
{"NTX", "EP", SAVE_EEPROM_4k, "Taz Express"},
|
{"NTX", "EP", SAVE_EEPROM_4k, "Taz Express"},
|
||||||
{"NUB", "J", SAVE_EEPROM_16k, "PD Ultraman Battle Collection 64"},
|
{"NUB", "J", SAVE_EEPROM_16k, "PD Ultraman Battle Collection 64"},
|
||||||
{"NUM", "J", SAVE_SRAM_256k, "Nushi Zuri 64: Shiokaze ni Notte"},
|
{"NUM", "J", SAVE_SRAM_256k, "Nushi Zuri 64: Shiokaze ni Notte"},
|
||||||
{"NUT", "J", SAVE_SRAM_256k, "Nushi Zuri 64"},
|
{"NUT", "J", SAVE_SRAM_256k, "Nushi Zuri 64"},
|
||||||
{"NVB", "J", SAVE_SRAM_256k, "Bass Rush: ECOGEAR PowerWorm Championship"},
|
{"NVB", "J", SAVE_SRAM_256k, "Bass Rush: ECOGEAR PowerWorm Championship"},
|
||||||
{"NVL", "EP", SAVE_EEPROM_4k, "V-Rally 99 (USA, PAL)"},
|
{"NVL", "EP", SAVE_EEPROM_4k, "V-Rally 99"},
|
||||||
{"NVP", "J", SAVE_SRAM_256k, "Virtual Pro Wrestling 64"},
|
{"NVP", "J", SAVE_SRAM_256k, "Virtual Pro Wrestling 64"},
|
||||||
{"NVY", "J", SAVE_EEPROM_4k, "V-Rally 99 (Japan)"},
|
{"NVY", "J", SAVE_EEPROM_4k, "V-Rally 99"},
|
||||||
{"NW2", "EP", SAVE_SRAM_256k, "WCW/nWo Revenge"},
|
{"NW2", "EP", SAVE_SRAM_256k, "WCW/nWo Revenge"},
|
||||||
{"NW4", "EP", SAVE_FLASH_1m, "WWF No Mercy"},
|
{"NW4", "EP", SAVE_FLASH_1m, "WWF No Mercy"},
|
||||||
{"NWC", "J", SAVE_EEPROM_4k, "Wild Choppers"},
|
{"NWC", "J", SAVE_EEPROM_4k, "Wild Choppers"},
|
||||||
{"NWL", "EP", SAVE_SRAM_256k, "Waialae Country Club: True Golf Classics"},
|
{"NWL", "EP", SAVE_SRAM_256k, "Waialae Country Club: True Golf Classics"},
|
||||||
{"NWQ", "E", SAVE_EEPROM_4k, "Rally Challenge 2000"},
|
{"NWQ", "E", SAVE_EEPROM_4k, "Rally Challenge 2000"},
|
||||||
{"NWR", "EJP", SAVE_EEPROM_4k, "Wave Race 64"},
|
{"NWR", "EJP", SAVE_EEPROM_4k, "Wave Race 64"},
|
||||||
{"NWT", "J", SAVE_EEPROM_4k, "Wetrix (Japan)"},
|
{"NWT", "J", SAVE_EEPROM_4k, "Wetrix"},
|
||||||
{"NWU", "P", SAVE_EEPROM_4k, "Worms Armageddon (PAL)"},
|
{"NWU", "P", SAVE_EEPROM_4k, "Worms Armageddon"},
|
||||||
{"NWX", "EJP", SAVE_SRAM_256k, "WWF WrestleMania 2000"},
|
{"NWX", "EJP", SAVE_SRAM_256k, "WWF WrestleMania 2000"},
|
||||||
{"NXO", "E", SAVE_EEPROM_4k, "Cruis'n Exotica"},
|
{"NXO", "E", SAVE_EEPROM_4k, "Cruis'n Exotica"},
|
||||||
{"NYK", "J", SAVE_EEPROM_4k, "Yakouchuu II: Satsujin Kouro"},
|
{"NYK", "J", SAVE_EEPROM_4k, "Yakouchuu II: Satsujin Kouro"},
|
||||||
{"NYS", "EJP", SAVE_EEPROM_16k, "Yoshi's Story"},
|
{"NYS", "EJP", SAVE_EEPROM_16k, "Yoshi's Story"},
|
||||||
{"NYW", "EJ", SAVE_SRAM_256k, "Harvest Moon 64"},
|
{"NYW", "EJ", SAVE_SRAM_256k, "Harvest Moon 64"},
|
||||||
{"NZL", "P", SAVE_SRAM_256k, "Legend of Zelda: Ocarina of Time (PAL)"},
|
{"NZL", "P", SAVE_SRAM_256k, "Legend of Zelda: Ocarina of Time"},
|
||||||
{"NZS", "EJP", SAVE_FLASH_1m, "Legend of Zelda: Majora's Mask"},
|
{"NZS", "EJP", SAVE_FLASH_1m, "Legend of Zelda: Majora's Mask"},
|
||||||
};
|
};
|
||||||
} // namespace n64
|
} // namespace n64
|
||||||
|
|||||||
+24
-28
@@ -91,9 +91,9 @@ FORCE_INLINE void SetROMCIC(u32 checksum, ROM &rom) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ROM Mem::LoadROM(const bool isArchive, const std::string &filename) {
|
ROM Mem::LoadROM(const bool isArchive, const std::string &filename) {
|
||||||
ROM rom;
|
ROM res;
|
||||||
rom.cart.resize(CART_SIZE);
|
res.cart.resize(CART_SIZE);
|
||||||
std::ranges::fill(rom.cart, 0);
|
std::ranges::fill(res.cart, 0);
|
||||||
u32 endianness;
|
u32 endianness;
|
||||||
{
|
{
|
||||||
size_t sizeAdjusted;
|
size_t sizeAdjusted;
|
||||||
@@ -107,37 +107,33 @@ ROM Mem::LoadROM(const bool isArchive, const std::string &filename) {
|
|||||||
endianness = std::byteswap(ircolib::ReadAccess<u32>(buf, 0));
|
endianness = std::byteswap(ircolib::ReadAccess<u32>(buf, 0));
|
||||||
Util::SwapN64Rom<true>(buf, endianness);
|
Util::SwapN64Rom<true>(buf, endianness);
|
||||||
|
|
||||||
std::ranges::copy(buf, rom.cart.begin());
|
std::ranges::copy(buf, res.cart.begin());
|
||||||
rom.mask = sizeAdjusted - 1;
|
res.mask = sizeAdjusted - 1;
|
||||||
memcpy(&rom.header, buf.data(), sizeof(ROMHeader));
|
memcpy(&res.header, buf.data(), sizeof(ROMHeader));
|
||||||
}
|
}
|
||||||
memcpy(rom.gameNameCart, rom.header.imageName, sizeof(rom.header.imageName));
|
memcpy(res.gameNameCart, res.header.imageName, sizeof(res.header.imageName));
|
||||||
|
|
||||||
rom.header.clockRate = std::byteswap(rom.header.clockRate);
|
res.header.clockRate = std::byteswap(res.header.clockRate);
|
||||||
rom.header.programCounter = std::byteswap(rom.header.programCounter);
|
res.header.programCounter = std::byteswap(res.header.programCounter);
|
||||||
rom.header.release = std::byteswap(rom.header.release);
|
res.header.release = std::byteswap(res.header.release);
|
||||||
rom.header.crc1 = std::byteswap(rom.header.crc1);
|
res.header.unknown = std::byteswap(res.header.unknown);
|
||||||
rom.header.crc2 = std::byteswap(rom.header.crc2);
|
res.header.unknown2 = std::byteswap(res.header.unknown2);
|
||||||
rom.header.unknown = std::byteswap(rom.header.unknown);
|
|
||||||
rom.header.unknown2 = std::byteswap(rom.header.unknown2);
|
|
||||||
rom.header.manufacturerId = std::byteswap(rom.header.manufacturerId);
|
|
||||||
rom.header.cartridgeId = std::byteswap(rom.header.cartridgeId);
|
|
||||||
|
|
||||||
rom.code[0] = rom.header.manufacturerId & 0xFF;
|
res.code[0] = res.header.categoryCode;
|
||||||
rom.code[1] = (rom.header.cartridgeId >> 8) & 0xFF;
|
res.code[1] = res.header.uniqueCode[0];
|
||||||
rom.code[2] = rom.header.cartridgeId & 0xFF;
|
res.code[2] = res.header.uniqueCode[1];
|
||||||
rom.code[3] = '\0';
|
res.code[3] = '\0';
|
||||||
|
|
||||||
for (int i = sizeof(rom.header.imageName) - 1; rom.gameNameCart[i] == ' '; i--) {
|
for (int i = sizeof(res.header.imageName) - 1; res.gameNameCart[i] == ' '; i--) {
|
||||||
rom.gameNameCart[i] = '\0';
|
res.gameNameCart[i] = '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
const u32 checksum = SDL_crc32(0, &rom.cart[0x40], 0x9C0);
|
const u32 checksum = SDL_crc32(0, &res.cart[0x40], 0x9C0);
|
||||||
SetROMCIC(checksum, rom);
|
SetROMCIC(checksum, res);
|
||||||
endianness = std::byteswap(ircolib::ReadAccess<u32>(rom.cart, 0));
|
endianness = std::byteswap(ircolib::ReadAccess<u32>(res.cart, 0));
|
||||||
Util::SwapN64Rom(rom.cart, endianness);
|
Util::SwapN64Rom(res.cart, endianness);
|
||||||
rom.pal = IsROMPAL(rom);
|
res.pal = IsROMPAL(res);
|
||||||
return rom;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
|
|||||||
@@ -11,17 +11,17 @@
|
|||||||
namespace n64 {
|
namespace n64 {
|
||||||
struct ROMHeader {
|
struct ROMHeader {
|
||||||
u8 initialValues[4];
|
u8 initialValues[4];
|
||||||
char imageName[20];
|
|
||||||
char countryCode[2];
|
|
||||||
u16 cartridgeId;
|
|
||||||
u32 clockRate;
|
u32 clockRate;
|
||||||
u32 programCounter;
|
u32 programCounter;
|
||||||
u32 release;
|
u32 release;
|
||||||
u32 crc1;
|
|
||||||
u32 crc2;
|
|
||||||
u32 unknown2;
|
|
||||||
u32 manufacturerId;
|
|
||||||
u64 unknown;
|
u64 unknown;
|
||||||
|
u64 unknown2;
|
||||||
|
char imageName[20];
|
||||||
|
char unknown3[7];
|
||||||
|
u8 categoryCode;
|
||||||
|
char uniqueCode[2];
|
||||||
|
u8 countryCode;
|
||||||
|
u8 version;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ROM {
|
struct ROM {
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ void KaizenGui::populateRomsList(const std::string &romsPath) {
|
|||||||
if (!file.is_regular_file())
|
if (!file.is_regular_file())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
auto filename = file.path().lexically_normal().string();
|
auto filename = file.path().string();
|
||||||
|
|
||||||
bool isPlain = std::ranges::any_of(std::array{".n64", ".z64", ".v64"},
|
bool isPlain = std::ranges::any_of(std::array{".n64", ".z64", ".v64"},
|
||||||
[&](const std::string &ext) { return file.path().extension() == ext; });
|
[&](const std::string &ext) { return file.path().extension() == ext; });
|
||||||
@@ -36,9 +36,18 @@ void KaizenGui::populateRomsList(const std::string &romsPath) {
|
|||||||
auto rom = n64::Mem::LoadROM(isArchive, filename);
|
auto rom = n64::Mem::LoadROM(isArchive, filename);
|
||||||
auto regions = n64::GameDB::match(rom);
|
auto regions = n64::GameDB::match(rom);
|
||||||
|
|
||||||
|
if (rom.gameNameDB.empty())
|
||||||
|
rom.gameNameDB = fs::path(filename).stem();
|
||||||
|
|
||||||
romsListPaths.push_back(filename);
|
romsListPaths.push_back(filename);
|
||||||
romsList->insertRow(i);
|
romsList->insertRow(i);
|
||||||
romsList->setItem(i, 0, new QTableWidgetItem(core.mem->rom.gameNameDB.c_str()));
|
|
||||||
|
romsList->setItem(
|
||||||
|
i, 0,
|
||||||
|
new QTableWidgetItem(std::format("{} ({}) (Rev {})", rom.gameNameDB,
|
||||||
|
n64::GameDB::regionCodeToReadable(rom.header.countryCode),
|
||||||
|
rom.header.version)
|
||||||
|
.c_str()));
|
||||||
romsList->setItem(i, 1, new QTableWidgetItem(regions.c_str()));
|
romsList->setItem(i, 1, new QTableWidgetItem(regions.c_str()));
|
||||||
romsList->setItem(i, 2, new QTableWidgetItem("Never"));
|
romsList->setItem(i, 2, new QTableWidgetItem("Never"));
|
||||||
romsList->setItem(i, 3, new QTableWidgetItem("0h 0m 0s"));
|
romsList->setItem(i, 3, new QTableWidgetItem("0h 0m 0s"));
|
||||||
@@ -51,6 +60,7 @@ void KaizenGui::populateRomsList(const std::string &romsPath) {
|
|||||||
KaizenGui::KaizenGui() noexcept : QMainWindow(nullptr), settings(QSettings::UserScope) {
|
KaizenGui::KaizenGui() noexcept : QMainWindow(nullptr), settings(QSettings::UserScope) {
|
||||||
SDL_InitSubSystem(SDL_INIT_GAMEPAD);
|
SDL_InitSubSystem(SDL_INIT_GAMEPAD);
|
||||||
|
|
||||||
|
SDL_AddGamepadMapping(gamecontrollerdb_str);
|
||||||
hide();
|
hide();
|
||||||
|
|
||||||
romsList->verticalHeader()->hide();
|
romsList->verticalHeader()->hide();
|
||||||
@@ -60,10 +70,10 @@ KaizenGui::KaizenGui() noexcept : QMainWindow(nullptr), settings(QSettings::User
|
|||||||
romsList->setEditTriggers(QAbstractItemView::NoEditTriggers);
|
romsList->setEditTriggers(QAbstractItemView::NoEditTriggers);
|
||||||
romsList->setSortingEnabled(true);
|
romsList->setSortingEnabled(true);
|
||||||
romsList->setColumnCount(4);
|
romsList->setColumnCount(4);
|
||||||
romsList->setHorizontalHeaderItem(0, romName);
|
romsList->setHorizontalHeaderItem(0, new QTableWidgetItem("Name"));
|
||||||
romsList->setHorizontalHeaderItem(1, romRegions);
|
romsList->setHorizontalHeaderItem(1, new QTableWidgetItem("Regions"));
|
||||||
romsList->setHorizontalHeaderItem(2, romLastPlayed);
|
romsList->setHorizontalHeaderItem(2, new QTableWidgetItem("Last played"));
|
||||||
romsList->setHorizontalHeaderItem(3, romTimePlayed);
|
romsList->setHorizontalHeaderItem(3, new QTableWidgetItem("Time played"));
|
||||||
|
|
||||||
vulkanWidget = new RenderWidget();
|
vulkanWidget = new RenderWidget();
|
||||||
vulkanWidget->hide();
|
vulkanWidget->hide();
|
||||||
@@ -105,9 +115,36 @@ KaizenGui::KaizenGui() noexcept : QMainWindow(nullptr), settings(QSettings::User
|
|||||||
|
|
||||||
setAcceptDrops(true);
|
setAcceptDrops(true);
|
||||||
|
|
||||||
|
SDLeventsTimer = new QTimer();
|
||||||
|
SDLeventsTimer->setInterval(1);
|
||||||
statusBarTimer = new QTimer();
|
statusBarTimer = new QTimer();
|
||||||
statusBarTimer->setInterval(500);
|
statusBarTimer->setInterval(500);
|
||||||
|
|
||||||
|
connect(SDLeventsTimer, &QTimer::timeout, this, [&] {
|
||||||
|
SDL_Event e;
|
||||||
|
while (SDL_PollEvent(&e)) {
|
||||||
|
if (e.type == SDL_EVENT_GAMEPAD_ADDED) {
|
||||||
|
if (!gamepad) {
|
||||||
|
const auto index = e.gdevice.which;
|
||||||
|
|
||||||
|
gamepad = SDL_OpenGamepad(index);
|
||||||
|
warn("Found controller!");
|
||||||
|
warn("Name: {}", SDL_GetGamepadName(gamepad));
|
||||||
|
warn("Vendor: {}", SDL_GetGamepadVendor(gamepad));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (e.type == SDL_EVENT_GAMEPAD_REMOVED) {
|
||||||
|
if (gamepad) {
|
||||||
|
SDL_CloseGamepad(gamepad);
|
||||||
|
gamepad = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
SDLeventsTimer->start();
|
||||||
|
|
||||||
connect(statusBarTimer, &QTimer::timeout, this, [&] {
|
connect(statusBarTimer, &QTimer::timeout, this, [&] {
|
||||||
pause->setText("Pause");
|
pause->setText("Pause");
|
||||||
fpsLabel->setText(std::format("FPS: {:.2f}", 1000.f / elapsed).c_str());
|
fpsLabel->setText(std::format("FPS: {:.2f}", 1000.f / elapsed).c_str());
|
||||||
@@ -234,6 +271,28 @@ KaizenGui::~KaizenGui() { cleanup(); }
|
|||||||
|
|
||||||
void KaizenGui::updateKeys() {
|
void KaizenGui::updateKeys() {
|
||||||
auto &pif = core.mem->mmio.si.pif;
|
auto &pif = core.mem->mmio.si.pif;
|
||||||
|
if (gamepad) {
|
||||||
|
pif.UpdateButton(0, n64::Controller::Z,
|
||||||
|
SDL_GetGamepadAxis(gamepad, SDL_GAMEPAD_AXIS_LEFT_TRIGGER) == SDL_JOYSTICK_AXIS_MAX);
|
||||||
|
pif.UpdateButton(0, n64::Controller::A, SDL_GetGamepadButton(gamepad, SDL_GAMEPAD_BUTTON_SOUTH));
|
||||||
|
pif.UpdateButton(0, n64::Controller::B, SDL_GetGamepadButton(gamepad, SDL_GAMEPAD_BUTTON_WEST));
|
||||||
|
pif.UpdateButton(0, n64::Controller::LT, SDL_GetGamepadButton(gamepad, SDL_GAMEPAD_BUTTON_LEFT_SHOULDER));
|
||||||
|
pif.UpdateButton(0, n64::Controller::RT, SDL_GetGamepadButton(gamepad, SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER));
|
||||||
|
pif.UpdateButton(0, n64::Controller::Start, SDL_GetGamepadButton(gamepad, SDL_GAMEPAD_BUTTON_START));
|
||||||
|
pif.UpdateButton(0, n64::Controller::DUp, SDL_GetGamepadButton(gamepad, SDL_GAMEPAD_BUTTON_DPAD_UP));
|
||||||
|
pif.UpdateButton(0, n64::Controller::DDown, SDL_GetGamepadButton(gamepad, SDL_GAMEPAD_BUTTON_DPAD_DOWN));
|
||||||
|
pif.UpdateButton(0, n64::Controller::DLeft, SDL_GetGamepadButton(gamepad, SDL_GAMEPAD_BUTTON_DPAD_LEFT));
|
||||||
|
pif.UpdateButton(0, n64::Controller::DRight, SDL_GetGamepadButton(gamepad, SDL_GAMEPAD_BUTTON_DPAD_RIGHT));
|
||||||
|
pif.UpdateButton(0, n64::Controller::CUp,
|
||||||
|
SDL_GetGamepadAxis(gamepad, SDL_GAMEPAD_AXIS_RIGHTY) == SDL_JOYSTICK_AXIS_MIN);
|
||||||
|
pif.UpdateButton(0, n64::Controller::CDown,
|
||||||
|
SDL_GetGamepadAxis(gamepad, SDL_GAMEPAD_AXIS_RIGHTY) == SDL_JOYSTICK_AXIS_MAX);
|
||||||
|
pif.UpdateButton(0, n64::Controller::CLeft,
|
||||||
|
SDL_GetGamepadAxis(gamepad, SDL_GAMEPAD_AXIS_RIGHTX) == SDL_JOYSTICK_AXIS_MIN);
|
||||||
|
pif.UpdateButton(0, n64::Controller::CRight,
|
||||||
|
SDL_GetGamepadAxis(gamepad, SDL_GAMEPAD_AXIS_RIGHTX) == SDL_JOYSTICK_AXIS_MAX);
|
||||||
|
return;
|
||||||
|
}
|
||||||
pif.UpdateButton(0, n64::Controller::Z, pressedKeys.test(0));
|
pif.UpdateButton(0, n64::Controller::Z, pressedKeys.test(0));
|
||||||
pif.UpdateButton(0, n64::Controller::A, pressedKeys.test(1));
|
pif.UpdateButton(0, n64::Controller::A, pressedKeys.test(1));
|
||||||
pif.UpdateButton(0, n64::Controller::B, pressedKeys.test(2));
|
pif.UpdateButton(0, n64::Controller::B, pressedKeys.test(2));
|
||||||
@@ -251,8 +310,34 @@ void KaizenGui::updateKeys() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void KaizenGui::updateAxis() {
|
void KaizenGui::updateAxis() {
|
||||||
s16 x = 0, y = 0;
|
|
||||||
auto &pif = core.mem->mmio.si.pif;
|
auto &pif = core.mem->mmio.si.pif;
|
||||||
|
|
||||||
|
if (gamepad) {
|
||||||
|
float xclamped = SDL_GetGamepadAxis(gamepad, SDL_GAMEPAD_AXIS_LEFTX);
|
||||||
|
if (xclamped < 0) {
|
||||||
|
xclamped /= static_cast<float>(std::abs(SDL_JOYSTICK_AXIS_MAX));
|
||||||
|
} else {
|
||||||
|
xclamped /= SDL_JOYSTICK_AXIS_MAX;
|
||||||
|
}
|
||||||
|
|
||||||
|
xclamped *= 86;
|
||||||
|
|
||||||
|
float yclamped = SDL_GetGamepadAxis(gamepad, SDL_GAMEPAD_AXIS_LEFTY);
|
||||||
|
if (yclamped < 0) {
|
||||||
|
yclamped /= static_cast<float>(std::abs(SDL_JOYSTICK_AXIS_MIN));
|
||||||
|
} else {
|
||||||
|
yclamped /= SDL_JOYSTICK_AXIS_MAX;
|
||||||
|
}
|
||||||
|
|
||||||
|
yclamped *= 86;
|
||||||
|
|
||||||
|
pif.UpdateAxis(0, n64::Controller::Axis::Y, static_cast<s8>(-yclamped));
|
||||||
|
pif.UpdateAxis(0, n64::Controller::Axis::X, static_cast<s8>(xclamped));
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
s16 x = 0, y = 0;
|
||||||
if (pressedKeys.test(14)) // up
|
if (pressedKeys.test(14)) // up
|
||||||
y += 86;
|
y += 86;
|
||||||
|
|
||||||
|
|||||||
+27
-33
@@ -19,6 +19,33 @@ class KaizenGui final : QMainWindow {
|
|||||||
void updateAxis();
|
void updateAxis();
|
||||||
bool eventFilter(QObject *, QEvent *) override;
|
bool eventFilter(QObject *, QEvent *) override;
|
||||||
void populateRomsList(const std::string &);
|
void populateRomsList(const std::string &);
|
||||||
|
bool fastForward = false;
|
||||||
|
bool minimized = false;
|
||||||
|
|
||||||
|
std::vector<std::string> romsListPaths{};
|
||||||
|
|
||||||
|
SDL_Gamepad *gamepad = nullptr;
|
||||||
|
bool gamepadConnected;
|
||||||
|
float elapsed = 0.f;
|
||||||
|
n64::Core &core = n64::Core::GetInstance();
|
||||||
|
std::bitset<18> pressedKeys{};
|
||||||
|
std::atomic_bool unlockFrameratePressed = false;
|
||||||
|
|
||||||
|
QWidget *currentHomeWidget;
|
||||||
|
QLabel *romPathNotSet = new QLabel(R"(Kaizen could not find any ROMs. Set the path in "Settings -> General")");
|
||||||
|
QTableWidget *romsList = new QTableWidget();
|
||||||
|
QStackedWidget *centralWidget = new QStackedWidget();
|
||||||
|
SettingsWindow *settingsWindow;
|
||||||
|
RenderWidget *vulkanWidget;
|
||||||
|
QSettings settings;
|
||||||
|
QThread *emuThread;
|
||||||
|
QTimer *statusBarTimer, *SDLeventsTimer;
|
||||||
|
QLabel *fpsLabel;
|
||||||
|
QLabel *cpuTypeLabel;
|
||||||
|
QLabel *idleSkipLabel;
|
||||||
|
QAction *pause = new QAction("Pause");
|
||||||
|
QAction *reset = new QAction("Reset");
|
||||||
|
QAction *stop = new QAction("Stop");
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit KaizenGui() noexcept;
|
explicit KaizenGui() noexcept;
|
||||||
@@ -30,41 +57,8 @@ class KaizenGui final : QMainWindow {
|
|||||||
void keyPressEvent(QKeyEvent *) override;
|
void keyPressEvent(QKeyEvent *) override;
|
||||||
void keyReleaseEvent(QKeyEvent *) override;
|
void keyReleaseEvent(QKeyEvent *) override;
|
||||||
|
|
||||||
bool fastForward = false;
|
|
||||||
bool minimized = false;
|
|
||||||
|
|
||||||
std::vector<std::string> romsListPaths{};
|
|
||||||
|
|
||||||
QWidget *currentHomeWidget;
|
|
||||||
QLabel *romPathNotSet = new QLabel(R"(Kaizen could not find any ROMs. Set the path in "Settings -> General")");
|
|
||||||
QTableWidget *romsList = new QTableWidget();
|
|
||||||
QTableWidgetItem *romName = new QTableWidgetItem("Name");
|
|
||||||
QTableWidgetItem *romRegions = new QTableWidgetItem("Regions");
|
|
||||||
QTableWidgetItem *romLastPlayed = new QTableWidgetItem("Last played");
|
|
||||||
QTableWidgetItem *romTimePlayed = new QTableWidgetItem("Time played");
|
|
||||||
QStackedWidget *centralWidget = new QStackedWidget();
|
|
||||||
SettingsWindow *settingsWindow;
|
|
||||||
RenderWidget *vulkanWidget;
|
|
||||||
QSettings settings;
|
|
||||||
QThread *emuThread;
|
|
||||||
QTimer *statusBarTimer;
|
|
||||||
QLabel *fpsLabel;
|
|
||||||
QLabel *cpuTypeLabel;
|
|
||||||
QLabel *idleSkipLabel;
|
|
||||||
QAction *pause = new QAction("Pause");
|
|
||||||
QAction *reset = new QAction("Reset");
|
|
||||||
QAction *stop = new QAction("Stop");
|
|
||||||
|
|
||||||
SDL_Gamepad *gamepad = nullptr;
|
|
||||||
|
|
||||||
void LoadTAS(const std::string &path) noexcept;
|
void LoadTAS(const std::string &path) noexcept;
|
||||||
void LoadROM(const std::string &path) noexcept;
|
void LoadROM(const std::string &path) noexcept;
|
||||||
signals:
|
signals:
|
||||||
void paused();
|
void paused();
|
||||||
|
|
||||||
private:
|
|
||||||
float elapsed = 0.f;
|
|
||||||
n64::Core &core = n64::Core::GetInstance();
|
|
||||||
std::bitset<18> pressedKeys{};
|
|
||||||
std::atomic_bool unlockFrameratePressed = false;
|
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user