Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

mia, desktop-ui: Add basic error handling to ROM loading #1785

Merged
merged 2 commits into from
Jan 27, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 11 additions & 7 deletions desktop-ui/emulator/arcade.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
struct Arcade : Emulator {
Arcade();
auto load() -> bool override;
auto load() -> LoadResult override;
auto save() -> bool override;
auto pak(ares::Node::Object) -> shared_pointer<vfs::directory> override;
auto group() -> string override { return "Arcade"; }
Expand Down Expand Up @@ -33,29 +33,33 @@ Arcade::Arcade() {
}
}

auto Arcade::load() -> bool {
auto Arcade::load() -> LoadResult {
game = mia::Medium::create("Arcade");
if(!game->load(Emulator::load(game, configuration.game))) return false;
string location = Emulator::load(game, configuration.game);
if(!location) return noFileSelected;
LoadResult result = game->load(location);
if(result != successful) return result;

system = mia::System::create("Arcade");
if(!system->load()) return false;
result = system->load();
if(result != successful) return result;

//Determine from the game manifest which core to use for the given arcade rom
#ifdef CORE_SG
if(game->pak->attribute("board") == "sega/sg1000a") {
if(!ares::SG1000::load(root, {"[Sega] SG-1000A"})) return false;
if(!ares::SG1000::load(root, {"[Sega] SG-1000A"})) return otherError;
systemPakName = "SG-1000A";
gamePakName = "Arcade Cartridge";

if(auto port = root->find<ares::Node::Port>("Cartridge Slot")) {
port->allocate();
port->connect();
}
return true;
return successful;
}
#endif

return false;
return otherError;
}

auto Arcade::save() -> bool {
Expand Down
16 changes: 10 additions & 6 deletions desktop-ui/emulator/atari-2600.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
struct Atari2600 : Emulator {
Atari2600();
auto load() -> bool override;
auto load() -> LoadResult override;
auto save() -> bool override;
auto pak(ares::Node::Object) -> shared_pointer<vfs::directory> override;
};
Expand Down Expand Up @@ -38,15 +38,19 @@ Atari2600::Atari2600() {
}
}

auto Atari2600::load() -> bool {
auto Atari2600::load() -> LoadResult {
game = mia::Medium::create("Atari 2600");
if(!game->load(Emulator::load(game, configuration.game))) return false;
string location = Emulator::load(game, configuration.game);
if(!location) return couldNotParseManifest;
LoadResult result = game->load(location);
if(result != successful) return result;

system = mia::System::create("Atari 2600");
if(!system->load()) return false;
result = system->load();
if(result != successful) return result;

auto region = Emulator::region();
if(!ares::Atari2600::load(root, {"[Atari] Atari 2600 (", region, ")"})) return false;
if(!ares::Atari2600::load(root, {"[Atari] Atari 2600 (", region, ")"})) return otherError;

if(auto port = root->find<ares::Node::Port>("Cartridge Slot")) {
port->allocate();
Expand All @@ -63,7 +67,7 @@ auto Atari2600::load() -> bool {
port->connect();
}

return true;
return successful;
}

auto Atari2600::save() -> bool {
Expand Down
21 changes: 15 additions & 6 deletions desktop-ui/emulator/colecovision.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
struct ColecoVision : Emulator {
ColecoVision();
auto load() -> bool override;
auto load() -> LoadResult override;
auto save() -> bool override;
auto pak(ares::Node::Object) -> shared_pointer<vfs::directory> override;
};
Expand Down Expand Up @@ -39,15 +39,24 @@ ColecoVision::ColecoVision() {
}
}

auto ColecoVision::load() -> bool {
auto ColecoVision::load() -> LoadResult {
game = mia::Medium::create("ColecoVision");
if(!game->load(Emulator::load(game, configuration.game))) return false;
string location = Emulator::load(game, configuration.game);
if(!location) return noFileSelected;
LoadResult result = game->load(location);
if(result != successful) return result;

system = mia::System::create("ColecoVision");
if(!system->load(firmware[0].location)) return errorFirmware(firmware[0]), false;
if(system->load(firmware[0].location) != successful) {
result.firmwareSystemName = "ColecoVision";
result.firmwareType = firmware[0].type;
result.firmwareRegion = firmware[0].region;
result.result = noFirmware;
return result;
}

auto region = Emulator::region();
if(!ares::ColecoVision::load(root, {"[Coleco] ColecoVision (", region, ")"})) return false;
if(!ares::ColecoVision::load(root, {"[Coleco] ColecoVision (", region, ")"})) return otherError;

if(auto port = root->find<ares::Node::Port>("Cartridge Slot")) {
port->allocate();
Expand All @@ -64,7 +73,7 @@ auto ColecoVision::load() -> bool {
port->connect();
}

return true;
return successful;
}

auto ColecoVision::save() -> bool {
Expand Down
75 changes: 59 additions & 16 deletions desktop-ui/emulator/emulator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,12 +54,67 @@ auto Emulator::region() -> string {
return {};
}

auto Emulator::handleLoadResult(LoadResult result) -> void {
string errorText;

switch (result.result) {
case successful:
return;
case noFileSelected:
return;
case invalidROM:
errorText = { "There was an error trying to parse the selected ROM. \n",
"Your ROM may be corrupt or contain a bad dump." };
break;
case couldNotParseManifest:
errorText = { "An error occurred while parsing the database file. You \n",
"may need to reinstall ares." };
break;
case databaseNotFound:
errorText = { "The database file for the system was not found. \n",
"Make sure that you have installed or packaged ares correctly. \n",
"Missing database file: " };
break;
case noFirmware:
errorText = { "Error: firmware is missing or invalid.\n",
result.firmwareSystemName, " - ", result.firmwareType, " (", result.firmwareRegion, ") is required to play this game.\n",
"Would you like to configure firmware settings now?" };
break;
case romNotFound:
errorText = "The selected ROM file was not found or could not be opened.";
break;
case romNotFoundInDatabase:
errorText = { "The required manifest for this ROM was not found in the database. \n",
"This title may not be currently supported by ares." };
break;
case otherError:
errorText = "An internal error occurred when initializing the emulator core.";
break;
}

if(result.info) {
errorText = { errorText, result.info };
}

switch (result.result) {
case noFirmware:
if(MessageDialog().setText({
errorText
}).question() == "Yes") {
settingsWindow.show("Firmware");
firmwareSettings.select(emulator->name, result.firmwareType, result.firmwareRegion);
}
default:
error(errorText);
}
}

auto Emulator::load(const string& location) -> bool {
if(inode::exists(location)) locationQueue.append(location);

if(!load()) {
error("Failed to load system! Database files may have been incorrectly \n"
"installed. Make sure you have packaged or installed ares correctly.");
LoadResult result = load();
handleLoadResult(result);
if(result != successful) {
return false;
}
setBoolean("Color Emulation", settings.video.colorEmulation);
Expand Down Expand Up @@ -178,18 +233,6 @@ auto Emulator::error(const string& text) -> void {
MessageDialog().setTitle("Error").setText(text).setAlignment(presentation).error();
}

auto Emulator::errorFirmware(const Firmware& firmware, string system) -> void {
if(!system) system = emulator->name;
if(MessageDialog().setText({
"Error: firmware is missing or invalid.\n",
system, " - ", firmware.type, " (", firmware.region, ") is required to play this game.\n"
"Would you like to configure firmware settings now?"
}).question() == "Yes") {
settingsWindow.show("Firmware");
firmwareSettings.select(system, firmware.type, firmware.region);
}
}

auto Emulator::input(ares::Node::Input::Input input) -> void {
//looking up inputs is very time-consuming; skip call if input was called too recently
//note: allow rumble to be polled at full speed to prevent missed motor events
Expand Down
4 changes: 2 additions & 2 deletions desktop-ui/emulator/emulator.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,13 @@ struct Emulator {
auto setOverscan(bool value) -> bool;
auto setColorBleed(bool value) -> bool;
auto error(const string& text) -> void;
auto errorFirmware(const Firmware&, string system = "") -> void;
auto load(mia::Pak& node, string name) -> bool;
auto save(mia::Pak& node, string name) -> bool;
virtual auto input(ares::Node::Input::Input) -> void;
auto inputKeyboard(string name) -> bool;
auto handleLoadResult(LoadResult result) -> void;
virtual auto load(Menu) -> void {}
virtual auto load() -> bool = 0;
virtual auto load() -> LoadResult = 0;
virtual auto save() -> bool { return true; }
virtual auto pak(ares::Node::Object) -> shared_pointer<vfs::directory> = 0;
virtual auto notify(const string& message) -> void {}
Expand Down
25 changes: 18 additions & 7 deletions desktop-ui/emulator/famicom-disk-system.cpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
struct FamicomDiskSystem : Emulator {
FamicomDiskSystem();
auto load(Menu) -> void override;
auto load() -> bool override;
auto load() -> LoadResult override;
auto save() -> bool override;
auto pak(ares::Node::Object) -> shared_pointer<vfs::directory> override;
auto notify(const string& message) -> void override;
Expand Down Expand Up @@ -65,17 +65,28 @@ auto FamicomDiskSystem::load(Menu menu) -> void {
return (void)disk1sideA.setChecked();
}

auto FamicomDiskSystem::load() -> bool {
auto FamicomDiskSystem::load() -> LoadResult {
game = mia::Medium::create("Famicom Disk System");
if(!game->load(Emulator::load(game, configuration.game))) return false;
string location = Emulator::load(game, configuration.game);
if(!location) return noFileSelected;
LoadResult result = game->load(location);
if(result != successful) return result;

bios = mia::Medium::create("Famicom");
if(!bios->load(firmware[0].location)) return errorFirmware(firmware[0]), false;
result = bios->load(firmware[0].location);
if(result != successful) {
result.firmwareSystemName = "Famicom";
result.firmwareType = firmware[0].type;
result.firmwareRegion = firmware[0].region;
result.result = noFirmware;
return result;
}

system = mia::System::create("Famicom");
if(!system->load()) return false;
result = system->load();
if(result != successful) return result;

if(!ares::Famicom::load(root, "[Nintendo] Famicom (NTSC-J)")) return false;
if(!ares::Famicom::load(root, "[Nintendo] Famicom (NTSC-J)")) return otherError;

if(auto port = root->find<ares::Node::Port>("Cartridge Slot")) {
port->allocate();
Expand All @@ -101,7 +112,7 @@ auto FamicomDiskSystem::load() -> bool {
port->connect();
}

return true;
return successful;
}

auto FamicomDiskSystem::save() -> bool {
Expand Down
16 changes: 10 additions & 6 deletions desktop-ui/emulator/famicom.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
struct Famicom : Emulator {
Famicom();
auto load() -> bool override;
auto load() -> LoadResult override;
auto save() -> bool override;
auto pak(ares::Node::Object) -> shared_pointer<vfs::directory> override;
};
Expand Down Expand Up @@ -35,15 +35,19 @@ Famicom::Famicom() {
}
}

auto Famicom::load() -> bool {
auto Famicom::load() -> LoadResult {
game = mia::Medium::create("Famicom");
if(!game->load(Emulator::load(game, configuration.game))) return false;
string location = Emulator::load(game, configuration.game);
if(!location) return noFileSelected;
LoadResult result = game->load(location);
if(result != successful) return result;

system = mia::System::create("Famicom");
if(!system->load()) return false;
result = system->load();
if(result != successful) return result;

auto region = Emulator::region();
if(!ares::Famicom::load(root, {"[Nintendo] Famicom (", region, ")"})) return false;
if(!ares::Famicom::load(root, {"[Nintendo] Famicom (", region, ")"})) return otherError;

if(auto port = root->find<ares::Node::Port>("Cartridge Slot")) {
port->allocate();
Expand All @@ -67,7 +71,7 @@ auto Famicom::load() -> bool {
}
}

return true;
return successful;
}

auto Famicom::save() -> bool {
Expand Down
21 changes: 15 additions & 6 deletions desktop-ui/emulator/game-boy-advance.cpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
struct GameBoyAdvance : Emulator {
GameBoyAdvance();
auto load(Menu) -> void override;
auto load() -> bool override;
auto load() -> LoadResult override;
auto save() -> bool override;
auto pak(ares::Node::Object) -> shared_pointer<vfs::directory> override;
};
Expand Down Expand Up @@ -50,23 +50,32 @@ auto GameBoyAdvance::load(Menu menu) -> void {
}
}

auto GameBoyAdvance::load() -> bool {
auto GameBoyAdvance::load() -> LoadResult {
game = mia::Medium::create("Game Boy Advance");
if(!game->load(Emulator::load(game, configuration.game))) return false;
string location = Emulator::load(game, configuration.game);
if(!location) return noFileSelected;
LoadResult result = game->load(location);
if(result != successful) return result;

system = mia::System::create("Game Boy Advance");
if(!system->load(firmware[0].location)) return errorFirmware(firmware[0]), false;
if(system->load(firmware[0].location) != successful) {
result.firmwareSystemName = "Game Boy Advance";
result.firmwareType = firmware[0].type;
result.firmwareRegion = firmware[0].region;
result.result = noFirmware;
return result;
}

ares::GameBoyAdvance::option("Pixel Accuracy", settings.video.pixelAccuracy);

if(!ares::GameBoyAdvance::load(root, "[Nintendo] Game Boy Advance")) return false;
if(!ares::GameBoyAdvance::load(root, "[Nintendo] Game Boy Advance")) return otherError;

if(auto port = root->find<ares::Node::Port>("Cartridge Slot")) {
port->allocate();
port->connect();
}

return true;
return successful;
}

auto GameBoyAdvance::save() -> bool {
Expand Down
Loading
Loading