Added support for selecting alternative emulators per game.

Also made some changes to the system-wide alternative emulators logic.
This commit is contained in:
Leon Styhre 2021-09-04 11:21:55 +02:00
parent 69ad5cc56f
commit 5942b2815e
13 changed files with 228 additions and 90 deletions

View file

@ -748,36 +748,41 @@ void FileData::launchGame(Window* window)
LOG(LogInfo) << "Launching game \"" << this->metadata.get("name") << "\"..."; LOG(LogInfo) << "Launching game \"" << this->metadata.get("name") << "\"...";
std::string command = ""; std::string command = "";
std::string alternativeEmulator = getSystem()->getAlternativeEmulator();
// Check if there is a launch command override for the game // Check if there is a game-specific alternative emulator configured.
// and the corresponding option to use it has been set. // This takes precedence over any system-wide alternative emulator configuration.
if (Settings::getInstance()->getBool("LaunchCommandOverride") && if (Settings::getInstance()->getBool("AlternativeEmulatorPerGame") &&
!metadata.get("launchcommand").empty()) { !metadata.get("altemulator").empty()) {
command = metadata.get("launchcommand"); command = getSystem()->getLaunchCommandFromLabel(metadata.get("altemulator"));
if (command == "") {
LOG(LogWarning) << "Invalid alternative emulator \"" << metadata.get("altemulator")
<< "\" configured for game";
}
else {
LOG(LogDebug) << "FileData::launchGame(): Using alternative emulator \""
<< metadata.get("altemulator") << "\" as configured for the game";
}
} }
else {
std::string alternativeEmulator = getSystem()->getAlternativeEmulator();
for (auto launchCommand : mEnvData->mLaunchCommands) {
if (launchCommand.second == alternativeEmulator) {
command = launchCommand.first;
LOG(LogDebug) << "FileData::launchGame(): Using alternative emulator \""
<< alternativeEmulator << "\""
<< " for system \"" << this->getSystem()->getName() << "\"";
break;
}
}
if (!alternativeEmulator.empty() && command.empty()) {
LOG(LogWarning) << "The alternative emulator configured for system \""
<< getSystem()->getName()
<< "\" is invalid, falling back to the default command \""
<< getSystem()->getSystemEnvData()->mLaunchCommands.front().first
<< "\"";
}
if (command.empty()) // Check if there is a system-wide alternative emulator configured.
command = mEnvData->mLaunchCommands.front().first; if (command == "" && alternativeEmulator != "") {
command = getSystem()->getLaunchCommandFromLabel(alternativeEmulator);
if (command == "") {
LOG(LogWarning) << "Invalid alternative emulator \""
<< alternativeEmulator.substr(9, alternativeEmulator.length() - 9)
<< "\" configured for system \"" << getSystem()->getName() << "\"";
}
else {
LOG(LogDebug) << "FileData::launchGame(): Using alternative emulator \""
<< getSystem()->getAlternativeEmulator() << "\""
<< " as configured for system \"" << this->getSystem()->getName() << "\"";
}
} }
if (command.empty())
command = mEnvData->mLaunchCommands.front().first;
std::string commandRaw = command; std::string commandRaw = command;
const std::string romPath = Utils::FileSystem::getEscapedPath(getPath()); const std::string romPath = Utils::FileSystem::getEscapedPath(getPath());

View file

@ -132,7 +132,7 @@ void parseGamelist(SystemData* system)
<< "\" has a valid alternativeEmulator entry: \"" << label << "\""; << "\" has a valid alternativeEmulator entry: \"" << label << "\"";
} }
else { else {
system->setAlternativeEmulator("<INVALID>"); system->setAlternativeEmulator("<INVALID>" + label);
LOG(LogWarning) << "System \"" << system->getName() LOG(LogWarning) << "System \"" << system->getName()
<< "\" has an invalid alternativeEmulator entry that does " << "\" has an invalid alternativeEmulator entry that does "
"not match any command tag in es_systems.xml: \"" "not match any command tag in es_systems.xml: \""

View file

@ -15,6 +15,8 @@
#include <pugixml.hpp> #include <pugixml.hpp>
// clang-format off // clang-format off
// The statistic entries must be placed at the bottom or otherwise there will be problems with
// saving the values in GuiMetaDataEd.
MetaDataDecl gameDecls[] = { MetaDataDecl gameDecls[] = {
// key, type, default, statistic, name in GuiMetaDataEd, prompt in GuiMetaDataEd, shouldScrape // key, type, default, statistic, name in GuiMetaDataEd, prompt in GuiMetaDataEd, shouldScrape
{"name", MD_STRING, "", false, "name", "enter name", true}, {"name", MD_STRING, "", false, "name", "enter name", true},
@ -34,9 +36,8 @@ MetaDataDecl gameDecls[] = {
{"nogamecount", MD_BOOL, "false", false, "exclude from game counter", "enter don't count as game off/on", false}, {"nogamecount", MD_BOOL, "false", false, "exclude from game counter", "enter don't count as game off/on", false},
{"nomultiscrape", MD_BOOL, "false", false, "exclude from multi-scraper", "enter no multi-scrape off/on", false}, {"nomultiscrape", MD_BOOL, "false", false, "exclude from multi-scraper", "enter no multi-scrape off/on", false},
{"hidemetadata", MD_BOOL, "false", false, "hide metadata fields", "enter hide metadata off/on", false}, {"hidemetadata", MD_BOOL, "false", false, "hide metadata fields", "enter hide metadata off/on", false},
{"launchcommand", MD_LAUNCHCOMMAND, "", false, "launch command", "enter game launch command "
"(emulator override)", false},
{"playcount", MD_INT, "0", false, "times played", "enter number of times played", false}, {"playcount", MD_INT, "0", false, "times played", "enter number of times played", false},
{"altemulator", MD_ALT_EMULATOR, "", false, "alternative emulator", "select alternative emulator", false},
{"lastplayed", MD_TIME, "0", true, "last played", "enter last played date", false} {"lastplayed", MD_TIME, "0", true, "last played", "enter last played date", false}
}; };

View file

@ -32,7 +32,7 @@ enum MetaDataType {
// Specialized types. // Specialized types.
MD_MULTILINE_STRING, MD_MULTILINE_STRING,
MD_LAUNCHCOMMAND, MD_ALT_EMULATOR,
MD_PATH, MD_PATH,
MD_RATING, MD_RATING,
MD_DATE, MD_DATE,

View file

@ -501,10 +501,9 @@ bool SystemData::loadConfig()
} }
else if (!commands.empty() && commands.back().second == "") { else if (!commands.empty() && commands.back().second == "") {
// There are more than one command tags and the first tag did not have a label. // There are more than one command tags and the first tag did not have a label.
LOG(LogError) LOG(LogError) << "Missing mandatory label attribute for alternative emulator "
<< "Missing mandatory label attribute for alternative emulator " "entry, only the first command tag will be processed for system \""
"entry, only the first command tag will be processed for system \"" << name << "\"";
<< name << "\"";
break; break;
} }
commands.push_back( commands.push_back(
@ -615,6 +614,18 @@ bool SystemData::loadConfig()
return false; return false;
} }
std::string SystemData::getLaunchCommandFromLabel(const std::string& label)
{
auto commandIter = std::find_if(
mEnvData->mLaunchCommands.cbegin(), mEnvData->mLaunchCommands.cend(),
[label](std::pair<std::string, std::string> command) { return (command.second == label); });
if (commandIter != mEnvData->mLaunchCommands.cend())
return (*commandIter).first;
return "";
}
void SystemData::deleteSystems() void SystemData::deleteSystems()
{ {
for (unsigned int i = 0; i < sSystemVector.size(); i++) for (unsigned int i = 0; i < sSystemVector.size(); i++)

View file

@ -99,6 +99,7 @@ public:
std::string getAlternativeEmulator() { return mAlternativeEmulator; } std::string getAlternativeEmulator() { return mAlternativeEmulator; }
void setAlternativeEmulator(const std::string& command) { mAlternativeEmulator = command; } void setAlternativeEmulator(const std::string& command) { mAlternativeEmulator = command; }
std::string getLaunchCommandFromLabel(const std::string& label);
static void deleteSystems(); static void deleteSystems();
// Loads the systems configuration file at getConfigPath() and creates the systems. // Loads the systems configuration file at getConfigPath() and creates the systems.

View file

@ -30,7 +30,7 @@ GuiAlternativeEmulators::GuiAlternativeEmulators(Window* window)
// Only include systems that have at least two command entries, unless the system // Only include systems that have at least two command entries, unless the system
// has an invalid entry. // has an invalid entry.
if ((*it)->getAlternativeEmulator() != "<INVALID>" && if ((*it)->getAlternativeEmulator().substr(0, 9) != "<INVALID>" &&
(*it)->getSystemEnvData()->mLaunchCommands.size() < 2) (*it)->getSystemEnvData()->mLaunchCommands.size() < 2)
continue; continue;
@ -68,7 +68,7 @@ GuiAlternativeEmulators::GuiAlternativeEmulators(Window* window)
bool invalidEntry = false; bool invalidEntry = false;
if (label.empty()) { if (label.empty()) {
label = "<INVALID ENTRY>"; label = ViewController::EXCLAMATION_CHAR + " INVALID ENTRY";
invalidEntry = true; invalidEntry = true;
} }
@ -94,7 +94,11 @@ GuiAlternativeEmulators::GuiAlternativeEmulators(Window* window)
labelText->setSize(labelSizeX, labelText->getSize().y); labelText->setSize(labelSizeX, labelText->getSize().y);
row.addElement(labelText, false); row.addElement(labelText, false);
row.makeAcceptInputHandler([this, it] { selectorWindow(*it); }); row.makeAcceptInputHandler([this, it, labelText] {
if (labelText->getValue() == "<REMOVED ENTRY>")
return;
selectorWindow(*it);
});
mMenu.addRow(row); mMenu.addRow(row);
mHasSystems = true; mHasSystems = true;
@ -104,9 +108,9 @@ GuiAlternativeEmulators::GuiAlternativeEmulators(Window* window)
// es_systems.xml. // es_systems.xml.
if (!mHasSystems) { if (!mHasSystems) {
ComponentListRow row; ComponentListRow row;
std::shared_ptr<TextComponent> systemText = std::shared_ptr<TextComponent> systemText = std::make_shared<TextComponent>(
std::make_shared<TextComponent>(mWindow, "<NO ALTERNATIVE EMULATORS DEFINED>", mWindow, ViewController::EXCLAMATION_CHAR + " NO ALTERNATIVE EMULATORS DEFINED",
Font::get(FONT_SIZE_MEDIUM), 0x777777FF, ALIGN_CENTER); Font::get(FONT_SIZE_MEDIUM), 0x777777FF, ALIGN_CENTER);
row.addElement(systemText, true); row.addElement(systemText, true);
mMenu.addRow(row); mMenu.addRow(row);
} }
@ -150,13 +154,16 @@ void GuiAlternativeEmulators::selectorWindow(SystemData* system)
ComponentListRow row; ComponentListRow row;
if (entry.second == "") if (entry.second == "")
label = "<REMOVE INVALID ENTRY>"; label = "<CLEAR INVALID ENTRY>";
else else
label = entry.second; label = entry.second;
std::shared_ptr<TextComponent> labelText = std::make_shared<TextComponent>( std::shared_ptr<TextComponent> labelText = std::make_shared<TextComponent>(
mWindow, label, Font::get(FONT_SIZE_MEDIUM), 0x777777FF, ALIGN_CENTER); mWindow, label, Font::get(FONT_SIZE_MEDIUM), 0x777777FF, ALIGN_CENTER);
if (system->getSystemEnvData()->mLaunchCommands.front().second == label)
labelText->setValue(labelText->getValue().append(" [DEFAULT]"));
row.addElement(labelText, true); row.addElement(labelText, true);
row.makeAcceptInputHandler([this, s, system, labelText, entry, selectedLabel] { row.makeAcceptInputHandler([this, s, system, labelText, entry, selectedLabel] {
if (entry.second != selectedLabel) { if (entry.second != selectedLabel) {
@ -165,9 +172,25 @@ void GuiAlternativeEmulators::selectorWindow(SystemData* system)
else else
system->setAlternativeEmulator(entry.second); system->setAlternativeEmulator(entry.second);
updateGamelist(system, true); updateGamelist(system, true);
updateMenu(
system->getName(), labelText->getValue(), if (entry.second == system->getSystemEnvData()->mLaunchCommands.front().second) {
(entry.second == system->getSystemEnvData()->mLaunchCommands.front().second)); if (system->getSystemEnvData()->mLaunchCommands.front().second == "") {
updateMenu(system->getName(), "<REMOVED ENTRY>",
(entry.second ==
system->getSystemEnvData()->mLaunchCommands.front().second));
}
else {
updateMenu(system->getName(),
system->getSystemEnvData()->mLaunchCommands.front().second,
(entry.second ==
system->getSystemEnvData()->mLaunchCommands.front().second));
}
}
else {
updateMenu(system->getName(), labelText->getValue(),
(entry.second ==
system->getSystemEnvData()->mLaunchCommands.front().second));
}
} }
delete s; delete s;
}); });

View file

@ -1021,16 +1021,17 @@ void GuiMenu::openOtherOptions()
} }
}); });
// Allow overriding of the launch command per game (the option to disable this is // Whether to enable alternative emulators per game (the option to disable this is intended
// intended primarily for testing purposes). // primarily for testing purposes).
auto launchcommand_override = std::make_shared<SwitchComponent>(mWindow); auto alternativeEmulatorPerGame = std::make_shared<SwitchComponent>(mWindow);
launchcommand_override->setState(Settings::getInstance()->getBool("LaunchCommandOverride")); alternativeEmulatorPerGame->setState(
s->addWithLabel("PER GAME LAUNCH COMMAND OVERRIDE", launchcommand_override); Settings::getInstance()->getBool("AlternativeEmulatorPerGame"));
s->addSaveFunc([launchcommand_override, s] { s->addWithLabel("ENABLE ALTERNATIVE EMULATORS PER GAME", alternativeEmulatorPerGame);
if (launchcommand_override->getState() != s->addSaveFunc([alternativeEmulatorPerGame, s] {
Settings::getInstance()->getBool("LaunchCommandOverride")) { if (alternativeEmulatorPerGame->getState() !=
Settings::getInstance()->setBool("LaunchCommandOverride", Settings::getInstance()->getBool("AlternativeEmulatorPerGame")) {
launchcommand_override->getState()); Settings::getInstance()->setBool("AlternativeEmulatorPerGame",
alternativeEmulatorPerGame->getState());
s->setNeedsSaving(); s->setNeedsSaving();
} }
}); });

View file

@ -49,6 +49,7 @@ GuiMetaDataEd::GuiMetaDataEd(Window* window,
, mClearGameFunc(clearGameFunc) , mClearGameFunc(clearGameFunc)
, mDeleteGameFunc(deleteGameFunc) , mDeleteGameFunc(deleteGameFunc)
, mMediaFilesUpdated(false) , mMediaFilesUpdated(false)
, mInvalidEmulatorEntry(false)
{ {
addChild(&mBackground); addChild(&mBackground);
addChild(&mGrid); addChild(&mGrid);
@ -99,9 +100,9 @@ GuiMetaDataEd::GuiMetaDataEd(Window* window,
if (iter->isStatistic) if (iter->isStatistic)
continue; continue;
// Don't show the launch command override entry if this option has been disabled. // Don't show the alternative emulator entry if the corresponding option has been disabled.
if (!Settings::getInstance()->getBool("LaunchCommandOverride") && if (!Settings::getInstance()->getBool("AlternativeEmulatorPerGame") &&
iter->type == MD_LAUNCHCOMMAND) { iter->type == MD_ALT_EMULATOR) {
ed = std::make_shared<TextComponent>( ed = std::make_shared<TextComponent>(
window, "", Font::get(FONT_SIZE_SMALL, FONT_PATH_LIGHT), 0x777777FF, ALIGN_RIGHT); window, "", Font::get(FONT_SIZE_SMALL, FONT_PATH_LIGHT), 0x777777FF, ALIGN_RIGHT);
assert(ed); assert(ed);
@ -170,7 +171,9 @@ GuiMetaDataEd::GuiMetaDataEd(Window* window,
std::placeholders::_2); std::placeholders::_2);
break; break;
} }
case MD_LAUNCHCOMMAND: { case MD_ALT_EMULATOR: {
mInvalidEmulatorEntry = false;
ed = std::make_shared<TextComponent>(window, "", ed = std::make_shared<TextComponent>(window, "",
Font::get(FONT_SIZE_SMALL, FONT_PATH_LIGHT), Font::get(FONT_SIZE_SMALL, FONT_PATH_LIGHT),
0x777777FF, ALIGN_RIGHT); 0x777777FF, ALIGN_RIGHT);
@ -189,44 +192,124 @@ GuiMetaDataEd::GuiMetaDataEd(Window* window,
const std::string title = iter->displayPrompt; const std::string title = iter->displayPrompt;
// OK callback (apply new value to ed). // OK callback (apply new value to ed).
auto updateVal = [ed, originalValue](const std::string& newVal) { auto updateVal = [this, ed, originalValue](const std::string& newVal) {
ed->setValue(newVal); ed->setValue(newVal);
if (newVal == originalValue) if (newVal == originalValue) {
ed->setColor(DEFAULT_TEXTCOLOR); ed->setColor(DEFAULT_TEXTCOLOR);
else }
else {
ed->setColor(TEXTCOLOR_USERMARKED); ed->setColor(TEXTCOLOR_USERMARKED);
mInvalidEmulatorEntry = false;
}
}; };
std::string staticTextString = "Default value from es_systems.xml:"; if (originalValue != "" &&
std::string defaultLaunchCommand; scraperParams.system->getLaunchCommandFromLabel(originalValue) == "") {
std::string alternativeEmulator = scraperParams.system->getAlternativeEmulator();
for (auto launchCommand :
scraperParams.system->getSystemEnvData()->mLaunchCommands) {
if (launchCommand.second == alternativeEmulator) {
defaultLaunchCommand = launchCommand.first;
break;
}
}
if (!alternativeEmulator.empty() && defaultLaunchCommand.empty()) {
LOG(LogWarning) LOG(LogWarning)
<< "The alternative emulator defined for system \"" << "GuiMetaDataEd: Invalid alternative emulator \"" << originalValue
<< scraperParams.system->getName() << "\" configured for game \"" << mScraperParams.game->getName() << "\"";
<< "\" is invalid, falling back to the default command \"" mInvalidEmulatorEntry = true;
<< scraperParams.system->getSystemEnvData()->mLaunchCommands.front().first
<< "\"";
} }
if (defaultLaunchCommand.empty()) if (scraperParams.system->getSystemEnvData()->mLaunchCommands.size() == 1) {
defaultLaunchCommand = lbl->setOpacity(DISABLED_OPACITY);
scraperParams.system->getSystemEnvData()->mLaunchCommands.front().first; bracket->setOpacity(DISABLED_OPACITY);
}
row.makeAcceptInputHandler([this, title, staticTextString, defaultLaunchCommand, ed, if (mInvalidEmulatorEntry ||
updateVal, multiLine] { scraperParams.system->getSystemEnvData()->mLaunchCommands.size() > 1) {
mWindow->pushGui(new GuiComplexTextEditPopup( row.makeAcceptInputHandler([this, title, scraperParams, ed, updateVal] {
mWindow, getHelpStyle(), title, staticTextString, defaultLaunchCommand, auto s = new GuiSettings(mWindow, title);
ed->getValue(), updateVal, multiLine, "APPLY", "APPLY CHANGES?"));
}); if (!mInvalidEmulatorEntry && ed->getValue() == "" &&
scraperParams.system->getSystemEnvData()->mLaunchCommands.size() == 1)
return;
std::vector<std::pair<std::string, std::string>> launchCommands =
scraperParams.system->getSystemEnvData()->mLaunchCommands;
if (ed->getValue() != "" && mInvalidEmulatorEntry)
launchCommands.push_back(std::make_pair("", "<CLEAR INVALID ENTRY>"));
else if (ed->getValue() != "")
launchCommands.push_back(std::make_pair("", "<CLEAR ENTRY>"));
for (auto entry : launchCommands) {
std::string selectedLabel = ed->getValue();
std::string label;
ComponentListRow row;
if (entry.second == "")
continue;
else
label = entry.second;
std::shared_ptr<TextComponent> labelText =
std::make_shared<TextComponent>(mWindow, label,
Font::get(FONT_SIZE_MEDIUM),
0x777777FF, ALIGN_CENTER);
if (scraperParams.system->getAlternativeEmulator() == "" &&
scraperParams.system->getSystemEnvData()
->mLaunchCommands.front()
.second == label)
labelText->setValue(labelText->getValue().append(" [SYSTEM-WIDE]"));
if (scraperParams.system->getAlternativeEmulator() == label)
labelText->setValue(labelText->getValue().append(" [SYSTEM-WIDE]"));
row.addElement(labelText, true);
row.makeAcceptInputHandler(
[this, s, updateVal, entry, selectedLabel, launchCommands] {
if (entry.second == launchCommands.back().second &&
launchCommands.back().first == "") {
updateVal("");
}
else if (entry.second != selectedLabel) {
updateVal(entry.second);
}
mInvalidEmulatorEntry = false;
delete s;
});
// This transparent bracket is only added to generate the correct help
// prompts.
auto bracket = std::make_shared<ImageComponent>(mWindow);
bracket->setImage(":/graphics/arrow.svg");
bracket->setOpacity(0);
bracket->setSize(bracket->getSize() / 3.0f);
row.addElement(bracket, false);
// Select the row that corresponds to the selected label.
if (selectedLabel == label)
s->addRow(row, true);
else
s->addRow(row, false);
}
// Adjust the width depending on the aspect ratio of the screen, to make the
// screen look somewhat coherent regardless of screen type. The 1.778 aspect
// ratio value is the 16:9 reference.
float aspectValue = 1.778f / Renderer::getScreenAspectRatio();
float maxWidthModifier = glm::clamp(0.70f * aspectValue, 0.50f, 0.92f);
float maxWidth =
static_cast<float>(Renderer::getScreenWidth()) * maxWidthModifier;
s->setMenuSize(glm::vec2{maxWidth, s->getMenuSize().y});
auto menuSize = s->getMenuSize();
auto menuPos = s->getMenuPosition();
s->setMenuPosition(glm::vec3{(s->getSize().x - menuSize.x) / 2.0f,
(s->getSize().y - menuSize.y) / 3.0f,
menuPos.z});
mWindow->pushGui(s);
});
}
else {
lbl->setOpacity(DISABLED_OPACITY);
bracket->setOpacity(DISABLED_OPACITY);
}
break; break;
} }
case MD_MULTILINE_STRING: case MD_MULTILINE_STRING:
@ -292,7 +375,12 @@ GuiMetaDataEd::GuiMetaDataEd(Window* window,
assert(ed); assert(ed);
mList->addRow(row); mList->addRow(row);
ed->setValue(mMetaData->get(iter->key));
if (iter->type == MD_ALT_EMULATOR && mInvalidEmulatorEntry == true)
ed->setValue(ViewController::EXCLAMATION_CHAR + " INVALID ENTRY ");
else
ed->setValue(mMetaData->get(iter->key));
mEditors.push_back(ed); mEditors.push_back(ed);
} }
@ -435,6 +523,9 @@ void GuiMetaDataEd::save()
if (mMetaDataDecl.at(i).isStatistic) if (mMetaDataDecl.at(i).isStatistic)
continue; continue;
if (mMetaDataDecl.at(i).key == "altemulator" && mInvalidEmulatorEntry == true)
continue;
if (!showHiddenGames && mMetaDataDecl.at(i).key == "hidden" && if (!showHiddenGames && mMetaDataDecl.at(i).key == "hidden" &&
mEditors.at(i)->getValue() != mMetaData->get("hidden")) mEditors.at(i)->getValue() != mMetaData->get("hidden"))
hideGameWhileHidden = true; hideGameWhileHidden = true;
@ -576,6 +667,9 @@ void GuiMetaDataEd::close()
std::string mMetaDataValue = mMetaData->get(key); std::string mMetaDataValue = mMetaData->get(key);
std::string mEditorsValue = mEditors.at(i)->getValue(); std::string mEditorsValue = mEditors.at(i)->getValue();
if (key == "altemulator" && mInvalidEmulatorEntry == true)
continue;
if (mMetaDataValue != mEditorsValue) { if (mMetaDataValue != mEditorsValue) {
metadataUpdated = true; metadataUpdated = true;
break; break;

View file

@ -15,6 +15,7 @@
#include "MetaData.h" #include "MetaData.h"
#include "components/ComponentGrid.h" #include "components/ComponentGrid.h"
#include "components/NinePatchComponent.h" #include "components/NinePatchComponent.h"
#include "guis/GuiSettings.h"
#include "scrapers/Scraper.h" #include "scrapers/Scraper.h"
class ComponentList; class ComponentList;
@ -64,6 +65,7 @@ private:
std::function<void()> mDeleteGameFunc; std::function<void()> mDeleteGameFunc;
bool mMediaFilesUpdated; bool mMediaFilesUpdated;
bool mInvalidEmulatorEntry;
}; };
#endif // ES_APP_GUIS_GUI_META_DATA_ED_H #endif // ES_APP_GUIS_GUI_META_DATA_ED_H

View file

@ -617,7 +617,7 @@ int main(int argc, char* argv[])
// which means that a label is present in the gamelist.xml file which is not matching // which means that a label is present in the gamelist.xml file which is not matching
// any command tag in es_systems.xml. // any command tag in es_systems.xml.
for (auto system : SystemData::sSystemVector) { for (auto system : SystemData::sSystemVector) {
if (system->getAlternativeEmulator() == "<INVALID>") { if (system->getAlternativeEmulator().substr(0, 9) == "<INVALID>") {
ViewController::get()->invalidAlternativeEmulatorDialog(); ViewController::get()->invalidAlternativeEmulatorDialog();
break; break;
} }

View file

@ -205,7 +205,7 @@ void ViewController::invalidAlternativeEmulatorDialog()
"WITH NO MATCHING ENTRY IN THE SYSTEMS\n" "WITH NO MATCHING ENTRY IN THE SYSTEMS\n"
"CONFIGURATION FILE, PLEASE REVIEW YOUR\n" "CONFIGURATION FILE, PLEASE REVIEW YOUR\n"
"SETUP USING THE 'ALTERNATIVE EMULATORS'\n" "SETUP USING THE 'ALTERNATIVE EMULATORS'\n"
"ENTRY UNDER THE 'OTHER SETTINGS' MENU")); "INTERFACE IN THE 'OTHER SETTINGS' MENU"));
} }
void ViewController::goToStart() void ViewController::goToStart()

View file

@ -240,7 +240,7 @@ void Settings::setDefaults()
mBoolMap["VideoHardwareDecoding"] = {false, false}; mBoolMap["VideoHardwareDecoding"] = {false, false};
#endif #endif
mBoolMap["VideoUpscaleFrameRate"] = {false, false}; mBoolMap["VideoUpscaleFrameRate"] = {false, false};
mBoolMap["LaunchCommandOverride"] = {true, true}; mBoolMap["AlternativeEmulatorPerGame"] = {true, true};
mBoolMap["ShowHiddenFiles"] = {true, true}; mBoolMap["ShowHiddenFiles"] = {true, true};
mBoolMap["ShowHiddenGames"] = {true, true}; mBoolMap["ShowHiddenGames"] = {true, true};
mBoolMap["CustomEventScripts"] = {false, false}; mBoolMap["CustomEventScripts"] = {false, false};