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

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
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
30 changes: 30 additions & 0 deletions ares/ares/ares.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -79,3 +79,33 @@ namespace ares {
#include <ares/memory/fixed-allocator.hpp>
#include <ares/memory/readable.hpp>
#include <ares/memory/writable.hpp>

enum ResultEnum {
successful,
noFileSelected,
databaseNotFound,
romNotFoundInDatabase,
romNotFound,
invalidRom,
couldNotParseManifest,
noFirmware,
otherError
};

struct LoadResult {
ResultEnum result;

string info;
string firmwareType;
string firmwareSystemName;
string firmwareRegion;

LoadResult(ResultEnum r) : result(r), info(0) {}

bool operator==(const LoadResult& other) {
return result == other.result;
}
bool operator!=(const LoadResult& other) {
return result != other.result;
}
};
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 LoadResult(noFileSelected);
LoadResult result = game->load(location);
if(result != LoadResult(successful)) return result;

system = mia::System::create("Arcade");
if(!system->load()) return false;
result = system->load();
if(result != LoadResult(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 LoadResult(otherError);
systemPakName = "SG-1000A";
gamePakName = "Arcade Cartridge";

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

return false;
return LoadResult(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 LoadResult(noFileSelected);
LoadResult result = game->load(location);
if(result != LoadResult(successful)) return result;

system = mia::System::create("Atari 2600");
if(!system->load()) return false;
result = system->load();
if(result != LoadResult(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 LoadResult(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 LoadResult(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 LoadResult(noFileSelected);
LoadResult result = game->load(location);
if(result != LoadResult(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) != LoadResult(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 LoadResult(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 LoadResult(successful);
}

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

auto Emulator::handleLoadResult(LoadResult result) -> void {
switch (result.result) {
case successful:
break;
case noFileSelected:
break;
case couldNotParseManifest:
error("An error was encountered while parsing the manifest. \n"
"");
break;
case databaseNotFound:
error("The database file for the system was not found. \n"
"Make sure that you have installed or packaged ares correctly.");
break;
case noFirmware:
if(MessageDialog().setText({
"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?"
}).question() == "Yes") {
settingsWindow.show("Firmware");
firmwareSettings.select(emulator->name, result.firmwareType, result.firmwareRegion);
}
break;
case romNotFound:
error("A required ROM file was not found.");
break;
case romNotFoundInDatabase:
error("The selected ROM was not found in the database.");
break;
case otherError:
error("Failed to load the selected system and ROM.");
break;
}
}

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 != LoadResult(successful)) {
return false;
}
setBoolean("Color Emulation", settings.video.colorEmulation);
Expand Down Expand Up @@ -178,18 +214,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 LoadResult(noFileSelected);
LoadResult result = game->load(location);
if(result != LoadResult(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 != LoadResult(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 != LoadResult(successful)) return result;

if(!ares::Famicom::load(root, "[Nintendo] Famicom (NTSC-J)")) return false;
if(!ares::Famicom::load(root, "[Nintendo] Famicom (NTSC-J)")) return LoadResult(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 LoadResult(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 LoadResult(noFileSelected);
LoadResult result = game->load(location);
if(result != LoadResult(successful)) return result;

system = mia::System::create("Famicom");
if(!system->load()) return false;
result = system->load();
if(result != LoadResult(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 LoadResult(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 LoadResult(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 LoadResult(noFileSelected);
LoadResult result = game->load(location);
if(result != LoadResult(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) != LoadResult(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 LoadResult(otherError);

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

return true;
return LoadResult(successful);
}

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