Browse Source

Add map database for neosu-imported maps

kiwec 3 months ago
parent
commit
4e94e9abc6

+ 3 - 2
src/App/Osu/Changelog.cpp

@@ -29,8 +29,9 @@ Changelog::Changelog() : ScreenBackable() {
     CHANGELOG latest;
     CHANGELOG latest;
     latest.title =
     latest.title =
         UString::format("%.2f (%s, %s)", convar->getConVarByName("osu_version")->getFloat(), __DATE__, __TIME__);
         UString::format("%.2f (%s, %s)", convar->getConVarByName("osu_version")->getFloat(), __DATE__, __TIME__);
-    latest.changes.push_back("- Added ability to drag-and-drop .osk and .osz files onto neosu");
-    latest.changes.push_back("- Added local skin folder");
+    latest.changes.push_back("- Added ability to import .osk and .osz files (drop them onto the neosu window)");
+    latest.changes.push_back("- Added persistent map database (downloaded or imported maps stay after restarting the game)");
+    latest.changes.push_back("- Added skin folder");
     latest.changes.push_back("- Fixed songs failing to restart");
     latest.changes.push_back("- Fixed songs failing to restart");
     changelogs.push_back(latest);
     changelogs.push_back(latest);
 
 

File diff suppressed because it is too large
+ 421 - 471
src/App/Osu/Database.cpp


+ 8 - 11
src/App/Osu/Database.h

@@ -15,6 +15,7 @@ typedef DatabaseBeatmap BeatmapDifficulty;
 typedef DatabaseBeatmap BeatmapSet;
 typedef DatabaseBeatmap BeatmapSet;
 
 
 #define STARS_CACHE_VERSION 20240430
 #define STARS_CACHE_VERSION 20240430
+#define NEOSU_MAPS_DB_VERSION 20240628
 
 
 // Field ordering matters here
 // Field ordering matters here
 #pragma pack(push, 1)
 #pragma pack(push, 1)
@@ -90,7 +91,7 @@ class Database {
     inline bool isFinished() const { return (getProgress() >= 1.0f); }
     inline bool isFinished() const { return (getProgress() >= 1.0f); }
     inline bool foundChanges() const { return m_bFoundChanges; }
     inline bool foundChanges() const { return m_bFoundChanges; }
 
 
-    inline const std::vector<DatabaseBeatmap *> getDatabaseBeatmaps() const { return m_databaseBeatmaps; }
+    inline const std::vector<DatabaseBeatmap *> getDatabaseBeatmaps() const { return m_beatmapsets; }
     DatabaseBeatmap *getBeatmapDifficulty(const MD5Hash &md5hash);
     DatabaseBeatmap *getBeatmapDifficulty(const MD5Hash &md5hash);
     DatabaseBeatmap *getBeatmapDifficulty(i32 map_id);
     DatabaseBeatmap *getBeatmapDifficulty(i32 map_id);
     DatabaseBeatmap *getBeatmapSet(i32 set_id);
     DatabaseBeatmap *getBeatmapSet(i32 set_id);
@@ -105,7 +106,7 @@ class Database {
 
 
     BeatmapSet *loadRawBeatmap(std::string beatmapPath);  // only used for raw loading without db
     BeatmapSet *loadRawBeatmap(std::string beatmapPath);  // only used for raw loading without db
 
 
-    void loadDB(Packet *db, bool &fallbackToRawLoad);
+    void loadDB(Packet *db);
 
 
     // stars.cache
     // stars.cache
     struct STARS_CACHE_ENTRY {
     struct STARS_CACHE_ENTRY {
@@ -125,7 +126,8 @@ class Database {
     void addScoreRaw(const MD5Hash &beatmapMD5Hash, const FinishedScore &score);
     void addScoreRaw(const MD5Hash &beatmapMD5Hash, const FinishedScore &score);
 
 
     std::string parseLegacyCfgBeatmapDirectoryParameter();
     std::string parseLegacyCfgBeatmapDirectoryParameter();
-    void scheduleLoadRaw();
+
+    void saveMaps();
 
 
     void loadStars();
     void loadStars();
     void saveStars();
     void saveStars();
@@ -144,7 +146,9 @@ class Database {
     int m_iNumBeatmapsToLoad;
     int m_iNumBeatmapsToLoad;
     std::atomic<float> m_fLoadingProgress;
     std::atomic<float> m_fLoadingProgress;
     std::atomic<bool> m_bInterruptLoad;
     std::atomic<bool> m_bInterruptLoad;
-    std::vector<DatabaseBeatmap *> m_databaseBeatmaps;
+    std::vector<BeatmapSet *> m_beatmapsets;
+    std::vector<BeatmapSet *> m_neosu_sets;
+    bool m_neosu_maps_loaded = false;
 
 
     // osu!.db
     // osu!.db
     int m_iVersion;
     int m_iVersion;
@@ -158,11 +162,4 @@ class Database {
     unsigned long long m_iSortHackCounter;
     unsigned long long m_iSortHackCounter;
     PlayerStats m_prevPlayerStats;
     PlayerStats m_prevPlayerStats;
     std::vector<SCORE_SORTING_METHOD> m_scoreSortingMethods;
     std::vector<SCORE_SORTING_METHOD> m_scoreSortingMethods;
-
-    // raw load
-    bool m_bRawBeatmapLoadScheduled;
-    int m_iCurRawBeatmapLoadIndex;
-    std::string m_sRawBeatmapLoadOsuSongFolder;
-    std::vector<std::string> m_rawBeatmapFolders;
-    std::vector<std::string> m_rawLoadBeatmapFolders;
 };
 };

+ 0 - 2
src/App/Osu/Downloader.cpp

@@ -403,7 +403,6 @@ DatabaseBeatmap* download_beatmap(i32 beatmap_id, MD5Hash beatmap_md5, float* pr
     if(*progress != 1.f) return NULL;
     if(*progress != 1.f) return NULL;
 
 
     auto mapset_path = UString::format(MCENGINE_DATA_DIR "maps/%d/", set_id);
     auto mapset_path = UString::format(MCENGINE_DATA_DIR "maps/%d/", set_id);
-    // XXX: Make a permanent database for auto-downloaded songs, so we can load them like osu!.db's
     osu->m_songBrowser2->getDatabase()->addBeatmap(mapset_path.toUtf8());
     osu->m_songBrowser2->getDatabase()->addBeatmap(mapset_path.toUtf8());
     osu->m_songBrowser2->updateSongButtonSorting();
     osu->m_songBrowser2->updateSongButtonSorting();
     debugLog("Finished loading beatmapset %d.\n", set_id);
     debugLog("Finished loading beatmapset %d.\n", set_id);
@@ -475,7 +474,6 @@ DatabaseBeatmap* download_beatmap(i32 beatmap_id, i32 beatmapset_id, float* prog
     if(*progress != 1.f) return NULL;
     if(*progress != 1.f) return NULL;
 
 
     auto mapset_path = UString::format(MCENGINE_DATA_DIR "maps/%d/", set_id);
     auto mapset_path = UString::format(MCENGINE_DATA_DIR "maps/%d/", set_id);
-    // XXX: Make a permanent database for auto-downloaded songs, so we can load them like osu!.db's
     osu->m_songBrowser2->getDatabase()->addBeatmap(mapset_path.toUtf8());
     osu->m_songBrowser2->getDatabase()->addBeatmap(mapset_path.toUtf8());
     osu->m_songBrowser2->updateSongButtonSorting();
     osu->m_songBrowser2->updateSongButtonSorting();
     debugLog("Finished loading beatmapset %d.\n", set_id);
     debugLog("Finished loading beatmapset %d.\n", set_id);

+ 9 - 4
src/App/Osu/MainMenu.cpp

@@ -1031,18 +1031,23 @@ void MainMenu::selectRandomBeatmap() {
         osu->getSongBrowser()->selectRandomBeatmap();
         osu->getSongBrowser()->selectRandomBeatmap();
     } else {
     } else {
         // Database is not loaded yet, load a random map and select it
         // Database is not loaded yet, load a random map and select it
-        // XXX: Also pick from neosu maps/ directory
         auto songs_folder = osu->getSongBrowser()->getDatabase()->getOsuSongsFolder();
         auto songs_folder = osu->getSongBrowser()->getDatabase()->getOsuSongsFolder();
         auto mapset_folders = env->getFoldersInFolder(songs_folder);
         auto mapset_folders = env->getFoldersInFolder(songs_folder);
+        auto mapset_folders2 = env->getFoldersInFolder(MCENGINE_DATA_DIR "maps/");
         auto nb_mapsets = mapset_folders.size();
         auto nb_mapsets = mapset_folders.size();
-        if(nb_mapsets == 0) return;
+        auto nb_mapsets2 = mapset_folders2.size();
+        if(nb_mapsets + nb_mapsets2 == 0) return;
 
 
         osu->getSongBrowser()->getSelectedBeatmap()->deselect();
         osu->getSongBrowser()->getSelectedBeatmap()->deselect();
         SAFE_DELETE(preloaded_beatmapset);
         SAFE_DELETE(preloaded_beatmapset);
 
 
         for(int i = 0; i < 10; i++) {
         for(int i = 0; i < 10; i++) {
-            auto mapset_folder = songs_folder;
-            mapset_folder.append(mapset_folders[rand() % nb_mapsets]);
+            u32 lucky_number = rand() % (nb_mapsets + nb_mapsets2);
+            bool is_neosu_set = lucky_number > nb_mapsets;
+            if(is_neosu_set) lucky_number -= nb_mapsets;
+
+            auto mapset_folder = is_neosu_set ? MCENGINE_DATA_DIR "maps/" : songs_folder;
+            mapset_folder.append((is_neosu_set ? mapset_folders2 : mapset_folders)[lucky_number]);
             mapset_folder.append("/");
             mapset_folder.append("/");
 
 
             BeatmapSet *set = osu->getSongBrowser()->getDatabase()->loadRawBeatmap(mapset_folder);
             BeatmapSet *set = osu->getSongBrowser()->getDatabase()->loadRawBeatmap(mapset_folder);

+ 0 - 80
src/App/Osu/SongBrowser/SongBrowser.cpp

@@ -900,7 +900,6 @@ bool SongBrowser::selectBeatmapset(i32 set_id) {
     if(beatmapset == NULL) {
     if(beatmapset == NULL) {
         // Pasted from Downloader::download_beatmap
         // Pasted from Downloader::download_beatmap
         auto mapset_path = UString::format(MCENGINE_DATA_DIR "maps/%d/", set_id);
         auto mapset_path = UString::format(MCENGINE_DATA_DIR "maps/%d/", set_id);
-        // XXX: Make a permanent database for auto-downloaded songs, so we can load them like osu!.db's
         osu->m_songBrowser2->getDatabase()->addBeatmap(mapset_path.toUtf8());
         osu->m_songBrowser2->getDatabase()->addBeatmap(mapset_path.toUtf8());
         osu->m_songBrowser2->updateSongButtonSorting();
         osu->m_songBrowser2->updateSongButtonSorting();
         debugLog("Finished loading beatmapset %d.\n", set_id);
         debugLog("Finished loading beatmapset %d.\n", set_id);
@@ -1816,85 +1815,6 @@ void SongBrowser::addBeatmap(DatabaseBeatmap *beatmap) {
     }
     }
 }
 }
 
 
-void SongBrowser::readdBeatmap(DatabaseBeatmap *diff2) {
-    // this function readds updated diffs to the correct groups
-    // i.e. when stars and length are calculated in background
-
-    // NOTE: the difficulty and length groups only contain diffs (and no parent wrapper objects), makes searching for
-    // the button way easier
-
-    // difficulty group
-    {
-        // remove from difficulty group
-        Button *difficultyGroupButton = NULL;
-        for(size_t i = 0; i < m_difficultyCollectionButtons.size(); i++) {
-            CollectionButton *groupButton = m_difficultyCollectionButtons[i];
-            std::vector<Button *> &children = groupButton->getChildren();
-            for(size_t c = 0; c < children.size(); c++) {
-                if(children[c]->getDatabaseBeatmap() == diff2) {
-                    difficultyGroupButton = children[c];
-
-                    // remove
-                    children.erase(children.begin() + c);
-
-                    break;
-                }
-            }
-        }
-
-        // add to new difficulty group
-        if(difficultyGroupButton != NULL) {
-            // HACKHACK: partial code duplication, see addBeatmap()
-            if(m_difficultyCollectionButtons.size() == 12) {
-                const int index = clamp<int>((int)diff2->getStarsNomod(), 0, 11);
-                m_difficultyCollectionButtons[index]->getChildren().push_back(difficultyGroupButton);
-            }
-        }
-    }
-
-    // length group
-    {
-        // remove from length group
-        Button *lengthGroupButton = NULL;
-        for(size_t i = 0; i < m_lengthCollectionButtons.size(); i++) {
-            CollectionButton *groupButton = m_lengthCollectionButtons[i];
-            std::vector<Button *> &children = groupButton->getChildren();
-            for(size_t c = 0; c < children.size(); c++) {
-                if(children[c]->getDatabaseBeatmap() == diff2) {
-                    lengthGroupButton = children[c];
-
-                    // remove
-                    children.erase(children.begin() + c);
-
-                    break;
-                }
-            }
-        }
-
-        // add to new length group
-        if(lengthGroupButton != NULL) {
-            // HACKHACK: partial code duplication, see addBeatmap()
-            if(m_lengthCollectionButtons.size() == 7) {
-                const unsigned long lengthMS = diff2->getLengthMS();
-                if(lengthMS <= 1000 * 60)
-                    m_lengthCollectionButtons[0]->getChildren().push_back(lengthGroupButton);
-                else if(lengthMS <= 1000 * 60 * 2)
-                    m_lengthCollectionButtons[1]->getChildren().push_back(lengthGroupButton);
-                else if(lengthMS <= 1000 * 60 * 3)
-                    m_lengthCollectionButtons[2]->getChildren().push_back(lengthGroupButton);
-                else if(lengthMS <= 1000 * 60 * 4)
-                    m_lengthCollectionButtons[3]->getChildren().push_back(lengthGroupButton);
-                else if(lengthMS <= 1000 * 60 * 5)
-                    m_lengthCollectionButtons[4]->getChildren().push_back(lengthGroupButton);
-                else if(lengthMS <= 1000 * 60 * 10)
-                    m_lengthCollectionButtons[5]->getChildren().push_back(lengthGroupButton);
-                else
-                    m_lengthCollectionButtons[6]->getChildren().push_back(lengthGroupButton);
-            }
-        }
-    }
-}
-
 void SongBrowser::requestNextScrollToSongButtonJumpFix(SongDifficultyButton *diffButton) {
 void SongBrowser::requestNextScrollToSongButtonJumpFix(SongDifficultyButton *diffButton) {
     if(diffButton == NULL) return;
     if(diffButton == NULL) return;
 
 

+ 0 - 1
src/App/Osu/SongBrowser/SongBrowser.h

@@ -122,7 +122,6 @@ class SongBrowser : public ScreenBackable {
 
 
     void refreshBeatmaps();
     void refreshBeatmaps();
     void addBeatmap(DatabaseBeatmap *beatmap);
     void addBeatmap(DatabaseBeatmap *beatmap);
-    void readdBeatmap(DatabaseBeatmap *diff2);
 
 
     void requestNextScrollToSongButtonJumpFix(SongDifficultyButton *diffButton);
     void requestNextScrollToSongButtonJumpFix(SongDifficultyButton *diffButton);
     void scrollToSongButton(Button *songButton, bool alignOnTop = false);
     void scrollToSongButton(Button *songButton, bool alignOnTop = false);

+ 9 - 0
src/Engine/Main/main_Windows.cpp

@@ -196,6 +196,15 @@ LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
                 if(!extension.compare("osz")) {
                 if(!extension.compare("osz")) {
                     File osz(utf8filepath);
                     File osz(utf8filepath);
                     i32 set_id = extract_beatmapset_id(osz.readFile(), osz.getFileSize());
                     i32 set_id = extract_beatmapset_id(osz.readFile(), osz.getFileSize());
+                    if(set_id < 0) {
+                        // special case: legacy fallback behavior for invalid beatmapSetID, try to parse the ID from the path
+                        auto mapset_name = UString(env->getFileNameFromFilePath(utf8filepath).c_str());
+                        const std::vector<UString> tokens = mapset_name.split(" ");
+                        for(auto token : tokens) {
+                            i32 id = token.toInt();
+                            if(id > 0) set_id = id;
+                        }
+                    }
                     if(set_id == -1) {
                     if(set_id == -1) {
                         osu->getNotificationOverlay()->addNotification("Beatmapset doesn't have a valid ID.");
                         osu->getNotificationOverlay()->addNotification("Beatmapset doesn't have a valid ID.");
                         continue;
                         continue;

Some files were not shown because too many files changed in this diff