diff --git a/README.md b/README.md index 38c366234..bd4ed7fae 100644 --- a/README.md +++ b/README.md @@ -147,14 +147,17 @@ All systems must be contained within the tag.--> All subdirectories (and non-recursive links) will be included. --> ~/roms/snes - + .smc .sfc .SMC .SFC snesemulator %ROM% - + snes diff --git a/src/FileData.cpp b/src/FileData.cpp index 38a2acaf3..bfb508084 100644 --- a/src/FileData.cpp +++ b/src/FileData.cpp @@ -56,7 +56,7 @@ FileData::~FileData() std::string FileData::getCleanName() const { std::string stem = mPath.stem().generic_string(); - if(mSystem && mSystem->getPlatformId() == PlatformIds::ARCADE || mSystem->getPlatformId() == PlatformIds::NEOGEO) + if(mSystem && mSystem->hasPlatformId(PlatformIds::ARCADE) || mSystem->hasPlatformId(PlatformIds::NEOGEO)) stem = PlatformIds::getCleanMameName(stem.c_str()); return removeParenthesis(stem); diff --git a/src/SystemData.cpp b/src/SystemData.cpp index 72bcb5917..9cbafb2c6 100644 --- a/src/SystemData.cpp +++ b/src/SystemData.cpp @@ -18,7 +18,7 @@ std::vector SystemData::sSystemVector; namespace fs = boost::filesystem; SystemData::SystemData(const std::string& name, const std::string& fullName, const std::string& startPath, const std::vector& extensions, - const std::string& command, PlatformIds::PlatformId platformId) + const std::string& command, const std::vector& platformIds) { mName = name; mFullName = fullName; @@ -33,7 +33,7 @@ SystemData::SystemData(const std::string& name, const std::string& fullName, con mSearchExtensions = extensions; mLaunchCommand = command; - mPlatformId = platformId; + mPlatformIds = platformIds; mRootFolder = new FileData(FOLDER, mStartPath, this); mRootFolder->metadata.set("name", mFullName); @@ -200,6 +200,23 @@ void SystemData::populateFolder(FileData* folder) } } +std::vector readList(const std::string& str, const char* delims = " \t\r\n,") +{ + std::vector ret; + + size_t prevOff = str.find_first_not_of(delims, 0); + size_t off = str.find_first_of(delims, prevOff); + while(off != std::string::npos || prevOff != std::string::npos) + { + ret.push_back(str.substr(prevOff, off - prevOff)); + + prevOff = str.find_first_not_of(delims, off); + off = str.find_first_of(delims, prevOff); + } + + return ret; +} + //creates systems from information located in a config file bool SystemData::loadConfig() { @@ -244,26 +261,34 @@ bool SystemData::loadConfig() fullname = system.child("fullname").text().get(); path = system.child("path").text().get(); - //convert extensions list from a string into a vector of strings - const pugi::char_t* extStr = system.child("extension").text().get(); - std::vector extensions; - std::vector buff(strlen(extStr) + 1); - strcpy(buff.data(), extStr); - char* ext = strtok(buff.data(), " "); - while(ext != NULL) - { - extensions.push_back(ext); - ext = strtok(NULL, " "); - } + // convert extensions list from a string into a vector of strings + std::vector extensions = readList(system.child("extension").text().get()); cmd = system.child("command").text().get(); - const char* platformIdString = system.child("platform").text().as_string(); - platformId = PlatformIds::getPlatformId(platformIdString); + // platform id list + const char* platformList = system.child("platform").text().get(); + std::vector platformStrs = readList(platformList); + std::vector platformIds; + for(auto it = platformStrs.begin(); it != platformStrs.end(); it++) + { + const char* str = it->c_str(); + PlatformIds::PlatformId platformId = PlatformIds::getPlatformId(str); + + if(platformId == PlatformIds::PLATFORM_IGNORE) + { + // when platform is ignore, do not allow other platforms + platformIds.clear(); + platformIds.push_back(platformId); + break; + } - // if there appears to be an actual platform ID supplied but it didn't match the list, warn - if(platformIdString != NULL && platformIdString[0] != '\0' && platformId == PlatformIds::PLATFORM_UNKNOWN) - LOG(LogWarning) << " Unknown platform for system \"" << name << "\" (platform \"" << platformIdString << "\")"; + // if there appears to be an actual platform ID supplied but it didn't match the list, warn + if(str != NULL && str[0] != '\0' && platformId == PlatformIds::PLATFORM_UNKNOWN) + LOG(LogWarning) << " Unknown platform for system \"" << name << "\" (platform \"" << str << "\" from list \"" << platformList << "\")"; + else if(platformId != PlatformIds::PLATFORM_UNKNOWN) + platformIds.push_back(platformId); + } //validate if(name.empty() || path.empty() || extensions.empty() || cmd.empty()) @@ -276,7 +301,7 @@ bool SystemData::loadConfig() boost::filesystem::path genericPath(path); path = genericPath.generic_string(); - SystemData* newSys = new SystemData(name, fullname, path, extensions, cmd, platformId); + SystemData* newSys = new SystemData(name, fullname, path, extensions, cmd, platformIds); if(newSys->getRootFolder()->getChildren().size() == 0) { LOG(LogWarning) << "System \"" << name << "\" has no games! Ignoring it."; @@ -309,7 +334,8 @@ void SystemData::writeExampleConfig(const std::string& path) " \n" " ~/roms/nes\n" "\n" - " \n" + " \n" " .nes .NES\n" "\n" " \n" " retroarch -L ~/cores/libretro-fceumm.so %ROM%\n" "\n" - " \n" + " \n" " nes\n" "\n" " \n" diff --git a/src/SystemData.h b/src/SystemData.h index 6b9887ac8..075f8f1ad 100644 --- a/src/SystemData.h +++ b/src/SystemData.h @@ -1,5 +1,4 @@ -#ifndef _SYSTEMDATA_H_ -#define _SYSTEMDATA_H_ +#pragma once #include #include @@ -13,7 +12,7 @@ class SystemData { public: SystemData(const std::string& name, const std::string& fullName, const std::string& startPath, const std::vector& extensions, - const std::string& command, PlatformIds::PlatformId platformId = PlatformIds::PLATFORM_UNKNOWN); + const std::string& command, const std::vector& platformIds); ~SystemData(); inline FileData* getRootFolder() const { return mRootFolder; }; @@ -21,7 +20,10 @@ public: inline const std::string& getFullName() const { return mFullName; } inline const std::string& getStartPath() const { return mStartPath; } inline const std::vector& getExtensions() const { return mSearchExtensions; } - inline PlatformIds::PlatformId getPlatformId() const { return mPlatformId; } + + inline const std::vector& getPlatformIds() const { return mPlatformIds; } + inline bool hasPlatformId(PlatformIds::PlatformId id) { return std::find(mPlatformIds.begin(), mPlatformIds.end(), id) != mPlatformIds.end(); } + inline const std::shared_ptr& getTheme() const { return mTheme; } std::string getGamelistPath(bool forWrite) const; @@ -67,12 +69,10 @@ private: std::string mStartPath; std::vector mSearchExtensions; std::string mLaunchCommand; - PlatformIds::PlatformId mPlatformId; + std::vector mPlatformIds; std::shared_ptr mTheme; void populateFolder(FileData* folder); FileData* mRootFolder; }; - -#endif diff --git a/src/guis/GuiMetaDataEd.cpp b/src/guis/GuiMetaDataEd.cpp index 6c6c2a58d..7ce471ea1 100644 --- a/src/guis/GuiMetaDataEd.cpp +++ b/src/guis/GuiMetaDataEd.cpp @@ -129,7 +129,7 @@ GuiMetaDataEd::GuiMetaDataEd(Window* window, MetaDataList* md, const std::vector std::vector< std::shared_ptr > buttons; - if(scraperParams.system->getPlatformId() != PlatformIds::PLATFORM_IGNORE) + if(!scraperParams.system->hasPlatformId(PlatformIds::PLATFORM_IGNORE)) buttons.push_back(std::make_shared(mWindow, "SCRAPE", "scrape", std::bind(&GuiMetaDataEd::fetch, this))); buttons.push_back(std::make_shared(mWindow, "SAVE", "save", [&] { save(); delete this; })); diff --git a/src/guis/GuiScraperStart.cpp b/src/guis/GuiScraperStart.cpp index 188b56785..915a5c707 100644 --- a/src/guis/GuiScraperStart.cpp +++ b/src/guis/GuiScraperStart.cpp @@ -24,8 +24,8 @@ GuiScraperStart::GuiScraperStart(Window* window) : GuiComponent(window), mSystems = std::make_shared< OptionListComponent >(mWindow, "SCRAPE THESE SYSTEMS", true); for(auto it = SystemData::sSystemVector.begin(); it != SystemData::sSystemVector.end(); it++) { - if((*it)->getPlatformId() != PlatformIds::PLATFORM_IGNORE) - mSystems->add((*it)->getFullName(), *it, (*it)->getPlatformId() != PlatformIds::PLATFORM_UNKNOWN); + if(!(*it)->hasPlatformId(PlatformIds::PLATFORM_IGNORE)) + mSystems->add((*it)->getFullName(), *it, !(*it)->getPlatformIds().empty()); } mMenu.addWithLabel("Systems", mSystems); @@ -44,7 +44,7 @@ void GuiScraperStart::pressedStart() std::vector sys = mSystems->getSelectedObjects(); for(auto it = sys.begin(); it != sys.end(); it++) { - if((*it)->getPlatformId() == PlatformIds::PLATFORM_UNKNOWN) + if((*it)->getPlatformIds().empty()) { mWindow->pushGui(new GuiMsgBox(mWindow, strToUpper("Warning: some of your selected systems do not have a platform set. Results may be even more inaccurate than usual!\nContinue anyway?"), diff --git a/src/scrapers/GamesDBScraper.cpp b/src/scrapers/GamesDBScraper.cpp index fa35b1eca..c569595d0 100644 --- a/src/scrapers/GamesDBScraper.cpp +++ b/src/scrapers/GamesDBScraper.cpp @@ -70,20 +70,29 @@ void thegamesdb_generate_scraper_requests(const ScraperSearchParams& params, std path += "name=" + HttpReq::urlEncode(cleanName); - if(params.system->getPlatformId() != PLATFORM_UNKNOWN) + if(params.system->getPlatformIds().empty()) { - auto platformIt = gamesdb_platformid_map.find(params.system->getPlatformId()); - if(platformIt != gamesdb_platformid_map.end()) + // no platform specified, we're done + requests.push(std::unique_ptr(new ScraperHttpRequest(results, path, &thegamesdb_process_httpreq))); + }else{ + // go through the list, we need to split this into multiple requests + // because TheGamesDB API either sucks or I don't know how to use it properly... + std::string urlBase = path; + auto& platforms = params.system->getPlatformIds(); + for(auto platformIt = platforms.begin(); platformIt != platforms.end(); platformIt++) { - path += "&platform="; - path += HttpReq::urlEncode(platformIt->second); - } - else{ - LOG(LogWarning) << "TheGamesDB scraper warning - no support for platform " << getPlatformName(params.system->getPlatformId()); + path = urlBase; + auto mapIt = gamesdb_platformid_map.find(*platformIt); + if(mapIt != gamesdb_platformid_map.end()) + { + path += "&platform="; + path += HttpReq::urlEncode(mapIt->second); + }else{ + LOG(LogWarning) << "TheGamesDB scraper warning - no support for platform " << getPlatformName(*platformIt); + } + requests.push(std::unique_ptr(new ScraperHttpRequest(results, path, &thegamesdb_process_httpreq))); } } - - requests.push(std::unique_ptr(new ScraperHttpRequest(results, path, &thegamesdb_process_httpreq))); } void thegamesdb_process_httpreq(const std::unique_ptr& req, std::vector& results)