From ea59d9f9c4d28831a3ccc43febed14589c5b0029 Mon Sep 17 00:00:00 2001 From: Leon Styhre Date: Tue, 28 Jul 2020 15:19:54 +0200 Subject: [PATCH] Fixed multiple issues with random selection of systems and games. --- NEWS.md | 3 + es-app/src/CollectionSystemManager.cpp | 8 +- es-app/src/FileData.cpp | 4 +- es-app/src/FileData.h | 2 +- es-app/src/SystemData.cpp | 116 ++++++++++++++---- es-app/src/SystemData.h | 5 +- es-app/src/views/SystemView.cpp | 2 +- .../views/gamelist/ISimpleGameListView.cpp | 10 +- 8 files changed, 115 insertions(+), 35 deletions(-) diff --git a/NEWS.md b/NEWS.md index bc16ec1ac..3cbf6ba2a 100644 --- a/NEWS.md +++ b/NEWS.md @@ -62,6 +62,9 @@ Many bugs have been fixed, and numerous features that were only partially implem * Toggling the screensaver didn't work as expected * The setting to enable or disable audio for the video screensaver only worked on Raspberry Pi * The screensaver random function did not consider the previously selected game and could potentially show the same image or video over and over again +* The random system selection did not consider the currently selected system +* The random game selection did not consider the currently selected game +* The random game selection traversed folders, i.e. a game could be selected inside a subdirectory and vice versa * Deleting a game did not delete the game media files or its entry in the gamelist.xml file * SystemView didn't properly loop the systems if only two systems were available * Hidden files still showed up if they had a gamelist.xml entry diff --git a/es-app/src/CollectionSystemManager.cpp b/es-app/src/CollectionSystemManager.cpp index 44fc728e4..ee6af7cd5 100644 --- a/es-app/src/CollectionSystemManager.cpp +++ b/es-app/src/CollectionSystemManager.cpp @@ -729,9 +729,11 @@ void CollectionSystemManager::updateCollectionFolderMetadata(SystemData* sys) FileData* randomGame = sys->getRandomGame(); - video = randomGame->getVideoPath(); - thumbnail = randomGame->getThumbnailPath(); - image = randomGame->getImagePath(); + if (randomGame) { + video = randomGame->getVideoPath(); + thumbnail = randomGame->getThumbnailPath(); + image = randomGame->getImagePath(); + } } rootFolder->metadata.set("desc", desc); diff --git a/es-app/src/FileData.cpp b/es-app/src/FileData.cpp index 33d2b728e..a2bd8270b 100644 --- a/es-app/src/FileData.cpp +++ b/es-app/src/FileData.cpp @@ -114,7 +114,7 @@ const bool FileData::getHidden() return false; } -const std::vector FileData::getChildrenRercursive() const +const std::vector FileData::getChildrenRecursive() const { std::vector childrenRecursive; @@ -123,7 +123,7 @@ const std::vector FileData::getChildrenRercursive() const childrenRecursive.push_back((*it).second); // Recurse through any subdirectories. if ((*it).second->getType() == FOLDER) { - std::vector childrenSubdirectory = (*it).second->getChildrenRercursive(); + std::vector childrenSubdirectory = (*it).second->getChildrenRecursive(); childrenRecursive.insert(childrenRecursive.end(), childrenSubdirectory.begin(), childrenSubdirectory.end()); } diff --git a/es-app/src/FileData.h b/es-app/src/FileData.h index 9353e81d6..c42308118 100644 --- a/es-app/src/FileData.h +++ b/es-app/src/FileData.h @@ -48,7 +48,7 @@ public: const std::string& getSortName(); const bool getFavorite(); const bool getHidden(); - const std::vector getChildrenRercursive() const; + const std::vector getChildrenRecursive() const; inline FileType getType() const { return mType; } inline const std::string& getPath() const { return mPath; } inline FileData* getParent() const { return mParent; } diff --git a/es-app/src/SystemData.cpp b/es-app/src/SystemData.cpp index 1a0a39cbb..69a66ff34 100644 --- a/es-app/src/SystemData.cpp +++ b/es-app/src/SystemData.cpp @@ -329,7 +329,7 @@ bool SystemData::loadConfig() // games for the system are hidden. That will flag the system as empty. if (!Settings::getInstance()->getBool("ShowHiddenGames")) { std::vector recursiveGames = - newSys->getRootFolder()->getChildrenRercursive(); + newSys->getRootFolder()->getChildrenRecursive(); onlyHidden = true; for (auto it = recursiveGames.cbegin(); it != recursiveGames.cend(); it++) { if ((*it)->getType() != FOLDER) { @@ -490,44 +490,110 @@ unsigned int SystemData::getGameCount() const return (unsigned int)mRootFolder->getFilesRecursive(GAME).size(); } -SystemData* SystemData::getRandomSystem() +SystemData* SystemData::getRandomSystem(const SystemData* currentSystem) { - // This is a bit brute force. - // It might be more efficient to just do a while (!gameSystem) do random again... unsigned int total = 0; for (auto it = sSystemVector.cbegin(); it != sSystemVector.cend(); it++) { if ((*it)->isGameSystem()) total++; } - // Get a random number in range. - int target = (int)Math::round((std::rand() / (float)RAND_MAX) * (total - 1)); - for (auto it = sSystemVector.cbegin(); it != sSystemVector.cend(); it++) - { - if ((*it)->isGameSystem()) { - if (target > 0) - target--; - else - return (*it); + if (total < 2) + return nullptr; + + SystemData* randomSystem; + + do { + // Get a random number in range. + int target = (int)Math::round((std::rand() / (float)RAND_MAX) * (total - 1)); + + for (auto it = sSystemVector.cbegin(); it != sSystemVector.cend(); it++) { + if ((*it)->isGameSystem()) { + if (target > 0) { + target--; + } + else { + randomSystem = (*it); + break; + } + } + } + } + while (randomSystem == currentSystem); + + return randomSystem; +} + +FileData* SystemData::getRandomCollectionFolder(const FileData* currentFolder) +{ + if (!currentFolder) + return nullptr; + + std::vector collectionFolders = currentFolder->getParent()->getChildren(); + + unsigned int total = collectionFolders.size(); + int target = 0; + + if (total < 2) + return nullptr; + + do { + // Get a random number in range. + target = (int)Math::round((std::rand() / (float)RAND_MAX) * (total - 1)); + } + while (collectionFolders.at(target) == currentFolder); + + return collectionFolders.at(target); +} + +FileData* SystemData::getRandomGame(const FileData* currentGame) +{ + std::vector gameList = mRootFolder->getFilesRecursive(GAME, true); + + if (currentGame) { + // If the game is inside a folder, update gameList to only contain the games + // inside this folder. + if (currentGame->getParent()->getFullPath() != + currentGame->getSystem()->getRootFolder()->getFullPath()) { + std::vector folderList; + + for (auto it = gameList.cbegin(); it != gameList.cend(); it++) { + if ((*it)->getParent()->getFullPath() == currentGame->getParent()->getFullPath()) + folderList.push_back((*it)); + } + + gameList.erase(gameList.cbegin(), gameList.cend()); + gameList.reserve(folderList.size()); + gameList.insert(gameList.cend(), folderList.cbegin(), folderList.cend()); + } + // If the game is not inside a folder, update gameList to exclude all folders. + else { + std::vector childrenList = mRootFolder->getChildren(); + std::vector noFolderList; + + for (auto it = childrenList.cbegin(); it != childrenList.cend(); it++) { + if ((*it)->getType() == GAME) + noFolderList.push_back((*it)); + } + gameList.erase(gameList.cbegin(), gameList.cend()); + gameList.reserve(noFolderList.size()); + gameList.insert(gameList.cend(), noFolderList.cbegin(), noFolderList.cend()); } } - // If we end up here, there is no valid system. - return nullptr; -} - -FileData* SystemData::getRandomGame() -{ - std::vector list = mRootFolder->getFilesRecursive(GAME, true); - unsigned int total = (int)list.size(); + unsigned int total = (int)gameList.size(); int target = 0; - // Get a random number in range. - if (total == 0) + if (total < 2) return nullptr; - target = (int)Math::round((std::rand() / (float)RAND_MAX) * (total - 1)); - return list.at(target); + do { + // Get a random number in range. + target = (int)Math::round((std::rand() / (float)RAND_MAX) * (total - 1)); + } + while (currentGame && gameList.at(target) == currentGame); + + return gameList.at(target); } unsigned int SystemData::getDisplayedGameCount() const diff --git a/es-app/src/SystemData.h b/es-app/src/SystemData.h index 6251adf9f..160d82f21 100644 --- a/es-app/src/SystemData.h +++ b/es-app/src/SystemData.h @@ -86,8 +86,9 @@ public: SystemData* getNext() const; SystemData* getPrev() const; - static SystemData* getRandomSystem(); - FileData* getRandomGame(); + static SystemData* getRandomSystem(const SystemData* currentSystem); + static FileData* getRandomCollectionFolder(const FileData* currentFolder); + FileData* getRandomGame(const FileData* currentGame = nullptr); // Load or re-load theme. void loadTheme(); diff --git a/es-app/src/views/SystemView.cpp b/es-app/src/views/SystemView.cpp index 2a549e11a..8db830d3a 100644 --- a/es-app/src/views/SystemView.cpp +++ b/es-app/src/views/SystemView.cpp @@ -195,7 +195,7 @@ bool SystemView::input(InputConfig* config, Input input) // Get random system. // Go to system. NavigationSounds::getInstance()->playThemeNavigationSound(SYSTEMBROWSESOUND); - setCursor(SystemData::getRandomSystem()); + setCursor(SystemData::getRandomSystem(getSelected())); return true; } } diff --git a/es-app/src/views/gamelist/ISimpleGameListView.cpp b/es-app/src/views/gamelist/ISimpleGameListView.cpp index c10ec9f36..033545e9e 100644 --- a/es-app/src/views/gamelist/ISimpleGameListView.cpp +++ b/es-app/src/views/gamelist/ISimpleGameListView.cpp @@ -141,9 +141,17 @@ bool ISimpleGameListView::input(InputConfig* config, Input input) if (mRoot->getSystem()->isGameSystem()) { // Go to random system game. NavigationSounds::getInstance()->playThemeNavigationSound(SCROLLSOUND); - FileData* randomGame = getCursor()->getSystem()->getRandomGame(); + FileData* randomGame = getCursor()->getSystem()->getRandomGame(getCursor()); if (randomGame) setCursor(randomGame); + // If it's not a game, maybe it's a folder for an unthemed collection. + else if (getCursor()->getSystem()->isCollection()) { + FileData* randomFolder = + mRoot->getSystem()->getRandomCollectionFolder(getCursor()); + if (randomFolder) + setCursor(randomFolder); + } + return true; } }