mirror of
https://github.com/RetroDECK/ES-DE.git
synced 2024-11-24 23:25:38 +00:00
Added the ability to make complementary game systems customizations.
This commit is contained in:
parent
1ad55cdcec
commit
8a51919f31
|
@ -1320,8 +1320,13 @@ void CollectionSystemsManager::addEnabledCollectionsToDisplayedSystems(
|
||||||
std::vector<std::string> CollectionSystemsManager::getSystemsFromConfig()
|
std::vector<std::string> CollectionSystemsManager::getSystemsFromConfig()
|
||||||
{
|
{
|
||||||
std::vector<std::string> systems;
|
std::vector<std::string> systems;
|
||||||
std::string path = SystemData::getConfigPath(false);
|
std::vector<std::string> configPaths = SystemData::getConfigPath(false);
|
||||||
|
|
||||||
|
// Here we don't honor the <loadExclusive> tag which may be present in the custom es_systems.xml
|
||||||
|
// file under ~/.emulationstation/custom_systems as we really want to include all the themes
|
||||||
|
// supported by ES-DE. Otherwise a user may accidentally create a custom collection that
|
||||||
|
// corresponds to a supported theme.
|
||||||
|
for (auto path : configPaths) {
|
||||||
if (!Utils::FileSystem::exists(path))
|
if (!Utils::FileSystem::exists(path))
|
||||||
return systems;
|
return systems;
|
||||||
|
|
||||||
|
@ -1345,8 +1350,11 @@ std::vector<std::string> CollectionSystemsManager::getSystemsFromConfig()
|
||||||
system = system.next_sibling("system")) {
|
system = system.next_sibling("system")) {
|
||||||
// Theme folder.
|
// Theme folder.
|
||||||
std::string themeFolder = system.child("theme").text().get();
|
std::string themeFolder = system.child("theme").text().get();
|
||||||
|
if (std::find(systems.cbegin(), systems.cend(), themeFolder) == systems.cend())
|
||||||
systems.push_back(themeFolder);
|
systems.push_back(themeFolder);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
std::sort(systems.begin(), systems.end());
|
std::sort(systems.begin(), systems.end());
|
||||||
return systems;
|
return systems;
|
||||||
}
|
}
|
||||||
|
|
|
@ -387,9 +387,17 @@ bool SystemData::loadConfig()
|
||||||
|
|
||||||
LOG(LogInfo) << "Populating game systems...";
|
LOG(LogInfo) << "Populating game systems...";
|
||||||
|
|
||||||
std::string path = getConfigPath(true);
|
std::vector<std::string> configPaths = getConfigPath(true);
|
||||||
const std::string rompath = FileData::getROMDirectory();
|
const std::string rompath = FileData::getROMDirectory();
|
||||||
|
|
||||||
|
bool onlyProcessCustomFile = false;
|
||||||
|
|
||||||
|
for (auto path : configPaths) {
|
||||||
|
// If the loadExclusive tag is present in the custom es_systems.xml file, then skip
|
||||||
|
// processing of the bundled configuration file.
|
||||||
|
if (onlyProcessCustomFile)
|
||||||
|
break;
|
||||||
|
|
||||||
LOG(LogInfo) << "Parsing systems configuration file \"" << path << "\"...";
|
LOG(LogInfo) << "Parsing systems configuration file \"" << path << "\"...";
|
||||||
|
|
||||||
pugi::xml_document doc;
|
pugi::xml_document doc;
|
||||||
|
@ -404,6 +412,19 @@ bool SystemData::loadConfig()
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pugi::xml_node loadExclusive = doc.child("loadExclusive");
|
||||||
|
if (loadExclusive) {
|
||||||
|
if (path == configPaths.front() && configPaths.size() > 1) {
|
||||||
|
LOG(LogInfo) << "Only loading custom file as the <loadExclusive> tag is present";
|
||||||
|
onlyProcessCustomFile = true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
LOG(LogWarning) << "A <loadExclusive> tag is present in the bundled es_systems.xml "
|
||||||
|
"file, ignoring it as this is only supposed to be used for the "
|
||||||
|
"custom es_systems.xml file";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Actually read the file.
|
// Actually read the file.
|
||||||
pugi::xml_node systemList = doc.child("systemList");
|
pugi::xml_node systemList = doc.child("systemList");
|
||||||
|
|
||||||
|
@ -448,10 +469,12 @@ bool SystemData::loadConfig()
|
||||||
#endif
|
#endif
|
||||||
path = Utils::String::replace(path, "//", "/");
|
path = Utils::String::replace(path, "//", "/");
|
||||||
|
|
||||||
// Check that the ROM directory for the system is valid or otherwise abort the processing.
|
// Check that the ROM directory for the system is valid or otherwise abort the
|
||||||
|
// processing.
|
||||||
if (!Utils::FileSystem::exists(path)) {
|
if (!Utils::FileSystem::exists(path)) {
|
||||||
LOG(LogDebug) << "SystemData::loadConfig(): Skipping system \"" << name
|
LOG(LogDebug) << "SystemData::loadConfig(): Skipping system \"" << name
|
||||||
<< "\" as the defined ROM directory \"" << path << "\" does not exist";
|
<< "\" as the defined ROM directory \"" << path
|
||||||
|
<< "\" does not exist";
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (!Utils::FileSystem::isDirectory(path)) {
|
if (!Utils::FileSystem::isDirectory(path)) {
|
||||||
|
@ -465,9 +488,9 @@ bool SystemData::loadConfig()
|
||||||
// as that would lead to an infite loop, meaning the application would never start.
|
// as that would lead to an infite loop, meaning the application would never start.
|
||||||
std::string resolvedRompath = Utils::FileSystem::getCanonicalPath(rompath);
|
std::string resolvedRompath = Utils::FileSystem::getCanonicalPath(rompath);
|
||||||
if (resolvedRompath.find(Utils::FileSystem::getCanonicalPath(path)) == 0) {
|
if (resolvedRompath.find(Utils::FileSystem::getCanonicalPath(path)) == 0) {
|
||||||
LOG(LogWarning) << "Skipping system \"" << name
|
LOG(LogWarning)
|
||||||
<< "\" as the defined ROM directory \"" << path
|
<< "Skipping system \"" << name << "\" as the defined ROM directory \""
|
||||||
<< "\" is an infinitely recursive symlink";
|
<< path << "\" is an infinitely recursive symlink";
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -501,7 +524,8 @@ 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) << "Missing mandatory label attribute for alternative emulator "
|
LOG(LogError)
|
||||||
|
<< "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;
|
||||||
|
@ -582,7 +606,8 @@ bool SystemData::loadConfig()
|
||||||
// If the option to show hidden games has been disabled, then check whether all
|
// If the option to show hidden games has been disabled, then check whether all
|
||||||
// games for the system are hidden. That will flag the system as empty.
|
// games for the system are hidden. That will flag the system as empty.
|
||||||
if (!Settings::getInstance()->getBool("ShowHiddenGames")) {
|
if (!Settings::getInstance()->getBool("ShowHiddenGames")) {
|
||||||
std::vector<FileData*> recursiveGames = newSys->getRootFolder()->getChildrenRecursive();
|
std::vector<FileData*> recursiveGames =
|
||||||
|
newSys->getRootFolder()->getChildrenRecursive();
|
||||||
onlyHidden = true;
|
onlyHidden = true;
|
||||||
for (auto it = recursiveGames.cbegin(); it != recursiveGames.cend(); it++) {
|
for (auto it = recursiveGames.cbegin(); it != recursiveGames.cend(); it++) {
|
||||||
if ((*it)->getType() != FOLDER) {
|
if ((*it)->getType() != FOLDER) {
|
||||||
|
@ -602,6 +627,7 @@ bool SystemData::loadConfig()
|
||||||
sSystemVector.push_back(newSys);
|
sSystemVector.push_back(newSys);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Sort systems by their full names.
|
// Sort systems by their full names.
|
||||||
std::sort(std::begin(sSystemVector), std::end(sSystemVector),
|
std::sort(std::begin(sSystemVector), std::end(sSystemVector),
|
||||||
|
@ -634,8 +660,10 @@ void SystemData::deleteSystems()
|
||||||
sSystemVector.clear();
|
sSystemVector.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string SystemData::getConfigPath(bool legacyWarning)
|
std::vector<std::string> SystemData::getConfigPath(bool legacyWarning)
|
||||||
{
|
{
|
||||||
|
std::vector<std::string> paths;
|
||||||
|
|
||||||
if (legacyWarning) {
|
if (legacyWarning) {
|
||||||
std::string legacyConfigFile =
|
std::string legacyConfigFile =
|
||||||
Utils::FileSystem::getHomePath() + "/.emulationstation/es_systems.cfg";
|
Utils::FileSystem::getHomePath() + "/.emulationstation/es_systems.cfg";
|
||||||
|
@ -662,7 +690,7 @@ std::string SystemData::getConfigPath(bool legacyWarning)
|
||||||
|
|
||||||
if (Utils::FileSystem::exists(path)) {
|
if (Utils::FileSystem::exists(path)) {
|
||||||
LOG(LogInfo) << "Found custom systems configuration file";
|
LOG(LogInfo) << "Found custom systems configuration file";
|
||||||
return path;
|
paths.push_back(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(_WIN64)
|
#if defined(_WIN64)
|
||||||
|
@ -674,18 +702,16 @@ std::string SystemData::getConfigPath(bool legacyWarning)
|
||||||
path = ResourceManager::getInstance()->getResourcePath(":/systems/unix/es_systems.xml", true);
|
path = ResourceManager::getInstance()->getResourcePath(":/systems/unix/es_systems.xml", true);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return path;
|
paths.push_back(path);
|
||||||
|
return paths;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SystemData::createSystemDirectories()
|
bool SystemData::createSystemDirectories()
|
||||||
{
|
{
|
||||||
std::string path = getConfigPath(false);
|
std::vector<std::string> configPaths = getConfigPath(true);
|
||||||
const std::string rompath = FileData::getROMDirectory();
|
const std::string rompath = FileData::getROMDirectory();
|
||||||
|
|
||||||
if (!Utils::FileSystem::exists(path)) {
|
bool onlyProcessCustomFile = false;
|
||||||
LOG(LogInfo) << "Systems configuration file does not exist, aborting";
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
LOG(LogInfo) << "Generating ROM directory structure...";
|
LOG(LogInfo) << "Generating ROM directory structure...";
|
||||||
|
|
||||||
|
@ -706,13 +732,42 @@ bool SystemData::createSystemDirectories()
|
||||||
LOG(LogInfo) << "Base ROM directory \"" << rompath << "\" already exists";
|
LOG(LogInfo) << "Base ROM directory \"" << rompath << "\" already exists";
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG(LogInfo) << "Parsing systems configuration file \"" << path << "\"...";
|
if (configPaths.size() > 1) {
|
||||||
|
// If the loadExclusive tag is present in the custom es_systems.xml file, then skip
|
||||||
|
// processing of the bundled configuration file.
|
||||||
|
pugi::xml_document doc;
|
||||||
|
#if defined(_WIN64)
|
||||||
|
pugi::xml_parse_result res =
|
||||||
|
doc.load_file(Utils::String::stringToWideString(configPath).c_str());
|
||||||
|
#else
|
||||||
|
pugi::xml_parse_result res = doc.load_file(configPaths.front().c_str());
|
||||||
|
#endif
|
||||||
|
if (res) {
|
||||||
|
pugi::xml_node loadExclusive = doc.child("loadExclusive");
|
||||||
|
if (loadExclusive)
|
||||||
|
onlyProcessCustomFile = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process the custom es_systems.xml file after the bundled file, as any systems with identical
|
||||||
|
// <path> tags will be overwritten by the last occurrence.
|
||||||
|
std::reverse(configPaths.begin(), configPaths.end());
|
||||||
|
|
||||||
|
std::vector<std::pair<std::string, std::string>> systemsVector;
|
||||||
|
|
||||||
|
for (auto configPath : configPaths) {
|
||||||
|
// If the loadExclusive tag is present.
|
||||||
|
if (onlyProcessCustomFile && configPath == configPaths.front())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
LOG(LogInfo) << "Parsing systems configuration file \"" << configPath << "\"...";
|
||||||
|
|
||||||
pugi::xml_document doc;
|
pugi::xml_document doc;
|
||||||
#if defined(_WIN64)
|
#if defined(_WIN64)
|
||||||
pugi::xml_parse_result res = doc.load_file(Utils::String::stringToWideString(path).c_str());
|
pugi::xml_parse_result res =
|
||||||
|
doc.load_file(Utils::String::stringToWideString(configPath).c_str());
|
||||||
#else
|
#else
|
||||||
pugi::xml_parse_result res = doc.load_file(path.c_str());
|
pugi::xml_parse_result res = doc.load_file(configPath.c_str());
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (!res) {
|
if (!res) {
|
||||||
|
@ -729,8 +784,6 @@ bool SystemData::createSystemDirectories()
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::string> systemsVector;
|
|
||||||
|
|
||||||
for (pugi::xml_node system = systemList.child("system"); system;
|
for (pugi::xml_node system = systemList.child("system"); system;
|
||||||
system = system.next_sibling("system")) {
|
system = system.next_sibling("system")) {
|
||||||
std::string systemDir;
|
std::string systemDir;
|
||||||
|
@ -799,7 +852,8 @@ bool SystemData::createSystemDirectories()
|
||||||
|
|
||||||
#if defined(_WIN64)
|
#if defined(_WIN64)
|
||||||
systemInfoFile.open(
|
systemInfoFile.open(
|
||||||
Utils::String::stringToWideString(rompath + systemDir + systemInfoFileName).c_str());
|
Utils::String::stringToWideString(rompath + systemDir + systemInfoFileName)
|
||||||
|
.c_str());
|
||||||
#else
|
#else
|
||||||
systemInfoFile.open(rompath + systemDir + systemInfoFileName);
|
systemInfoFile.open(rompath + systemDir + systemInfoFileName);
|
||||||
#endif
|
#endif
|
||||||
|
@ -813,6 +867,9 @@ bool SystemData::createSystemDirectories()
|
||||||
}
|
}
|
||||||
|
|
||||||
systemInfoFile << "System name:" << std::endl;
|
systemInfoFile << "System name:" << std::endl;
|
||||||
|
if (configPaths.size() != 1 && configPath == configPaths.back())
|
||||||
|
systemInfoFile << name << " (custom system)" << std::endl << std::endl;
|
||||||
|
else
|
||||||
systemInfoFile << name << std::endl << std::endl;
|
systemInfoFile << name << std::endl << std::endl;
|
||||||
systemInfoFile << "Full system name:" << std::endl;
|
systemInfoFile << "Full system name:" << std::endl;
|
||||||
systemInfoFile << fullname << std::endl << std::endl;
|
systemInfoFile << fullname << std::endl << std::endl;
|
||||||
|
@ -835,7 +892,18 @@ bool SystemData::createSystemDirectories()
|
||||||
systemInfoFile << themeFolder << std::endl;
|
systemInfoFile << themeFolder << std::endl;
|
||||||
systemInfoFile.close();
|
systemInfoFile.close();
|
||||||
|
|
||||||
systemsVector.push_back(systemDir + ": " + fullname);
|
auto systemIter = std::find_if(systemsVector.cbegin(), systemsVector.cend(),
|
||||||
|
[systemDir](std::pair<std::string, std::string> system) {
|
||||||
|
return system.first == systemDir;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (systemIter != systemsVector.cend())
|
||||||
|
systemsVector.erase(systemIter);
|
||||||
|
|
||||||
|
if (configPaths.size() != 1 && configPath == configPaths.back())
|
||||||
|
systemsVector.push_back(std::make_pair(systemDir + " (custom system)", fullname));
|
||||||
|
else
|
||||||
|
systemsVector.push_back(std::make_pair(systemDir, fullname));
|
||||||
|
|
||||||
if (replaceInfoFile) {
|
if (replaceInfoFile) {
|
||||||
LOG(LogInfo) << "Replaced existing system information file \""
|
LOG(LogInfo) << "Replaced existing system information file \""
|
||||||
|
@ -846,6 +914,7 @@ bool SystemData::createSystemDirectories()
|
||||||
<< rompath + systemDir + systemInfoFileName << "\"";
|
<< rompath + systemDir + systemInfoFileName << "\"";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Also generate a systems.txt file directly in the ROM directory root that contains the
|
// Also generate a systems.txt file directly in the ROM directory root that contains the
|
||||||
// mappings between the system directory names and the full system names. This makes it
|
// mappings between the system directory names and the full system names. This makes it
|
||||||
|
@ -870,8 +939,10 @@ bool SystemData::createSystemDirectories()
|
||||||
systemsFileSuccess = false;
|
systemsFileSuccess = false;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
for (std::string systemEntry : systemsVector) {
|
std::sort(systemsVector.begin(), systemsVector.end());
|
||||||
systemsFile << systemEntry << std::endl;
|
for (auto systemEntry : systemsVector) {
|
||||||
|
systemsFile << systemEntry.first.append(": ").append(systemEntry.second)
|
||||||
|
<< std::endl;
|
||||||
}
|
}
|
||||||
systemsFile.close();
|
systemsFile.close();
|
||||||
}
|
}
|
||||||
|
|
|
@ -102,9 +102,9 @@ public:
|
||||||
std::string getLaunchCommandFromLabel(const std::string& label);
|
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(s) at getConfigPath() and creates the systems.
|
||||||
static bool loadConfig();
|
static bool loadConfig();
|
||||||
static std::string getConfigPath(bool legacyWarning);
|
static std::vector<std::string> getConfigPath(bool legacyWarning);
|
||||||
|
|
||||||
// Generates the game system directories and information files based on es_systems.xml.
|
// Generates the game system directories and information files based on es_systems.xml.
|
||||||
static bool createSystemDirectories();
|
static bool createSystemDirectories();
|
||||||
|
|
Loading…
Reference in a new issue