5 Commits 2bbdbeb472 ... b9574d7f0a

Author SHA1 Message Date
  kiwec b9574d7f0a Add keybind to toggle current map background 2 months ago
  kiwec 9a8affc533 Fix mods not getting restored properly 2 months ago
  kiwec 3902e0a442 Fix beatmapset selection 2 months ago
  kiwec bb5f880f0f Draw context menus on top of back button 2 months ago
  kiwec 3bb0d43dfa Fix startup crash when osu! folder couldn't be found 2 months ago

+ 1 - 1
src/App/Osu/BackgroundImageHandler.cpp

@@ -126,7 +126,7 @@ void BackgroundImageHandler::handleLoadImageForEntry(ENTRY &entry) {
 }
 
 Image *BackgroundImageHandler::getLoadBackgroundImage(const DatabaseBeatmap *beatmap) {
-    if(beatmap == NULL || !osu_load_beatmap_background_images.getBool()) return NULL;
+    if(beatmap == NULL || !osu_load_beatmap_background_images.getBool() || !beatmap->draw_background) return NULL;
 
     // NOTE: no references to beatmap are kept anywhere (database can safely be deleted/reloaded without having to
     // notify the BackgroundImageHandler)

+ 3 - 4
src/App/Osu/Beatmap.cpp

@@ -752,7 +752,7 @@ bool Beatmap::watch(FinishedScore score, double start_percent) {
     m_bContinueScheduled = false;
     unloadObjects();
 
-    osu->previous_mod_flags = osu->getScore()->getModsLegacy();
+    osu->previous_mods = osu->getModSelector()->getModSelection();
 
     osu->watched_user_name = score.playerName.c_str();
     osu->watched_user_id = score.player_id;
@@ -789,7 +789,7 @@ bool Beatmap::spectate() {
     osu->watched_user_name = user_info->name;
     is_spectating = true;
 
-    osu->previous_mod_flags = osu->getScore()->getModsLegacy();
+    osu->previous_mods = osu->getModSelector()->getModSelection();
 
     FinishedScore score;
     score.isLegacyScore = true;
@@ -1166,8 +1166,7 @@ void Beatmap::stop(bool quit) {
     }
 
     if(is_watching || is_spectating) {
-        osu->m_modSelector->resetMods();
-        osu->m_modSelector->enableModsFromFlags(osu->previous_mod_flags);
+        osu->getModSelector()->restoreMods(osu->previous_mods);
     }
 
     is_spectating = false;

+ 14 - 5
src/App/Osu/Changelog.cpp

@@ -29,13 +29,22 @@ Changelog::Changelog() : ScreenBackable() {
     CHANGELOG latest;
     latest.title =
         UString::format("%.2f (%s, %s)", convar->getConVarByName("osu_version")->getFloat(), __DATE__, __TIME__);
-    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("- Now publishing 32-bit releases (for PCs running Windows 7)");
-    latest.changes.push_back("- Fixed songs failing to restart");
+    latest.changes.push_back("- Added keybind to toggle current map background");
+    latest.changes.push_back("- Fixed beatmaps not getting selected properly in some cases");
+    latest.changes.push_back("- Fixed crash when osu! folder couldn't be found");
+    latest.changes.push_back("- Fixed mod selection not being restored properly");
+    latest.changes.push_back("- Fixed skin selection menu being drawn behind back button");
     changelogs.push_back(latest);
 
+    CHANGELOG v35_08;
+    v35_08.title = "35.08 (2024-06-28)";
+    v35_08.changes.push_back("- Added ability to import .osk and .osz files (drop them onto the neosu window)");
+    v35_08.changes.push_back("- Added persistent map database (downloaded or imported maps stay after restarting the game)");
+    v35_08.changes.push_back("- Added skin folder");
+    v35_08.changes.push_back("- Now publishing 32-bit releases (for PCs running Windows 7)");
+    v35_08.changes.push_back("- Fixed songs failing to restart");
+    changelogs.push_back(v35_08);
+
     CHANGELOG v35_07;
     v35_07.title = "35.07 (2024-06-27)";
     v35_07.changes.push_back("- Added sort_skins_by_name convar");

+ 6 - 0
src/App/Osu/Database.cpp

@@ -1248,6 +1248,10 @@ void Database::loadDB(Packet *db) {
                 diff->m_timingpoints.resize(numTimingPoints);
                 read_bytes(&neosu_maps, (u8 *)diff->m_timingpoints.data(), sizeof(TIMINGPOINT) * numTimingPoints);
 
+                if(version >= 20240703) {
+                    diff->draw_background = read<u8>(&neosu_maps);
+                }
+
                 diffs->push_back(diff);
             }
 
@@ -1402,6 +1406,8 @@ void Database::saveMaps() {
             u32 numTimingPoints = diff->m_timingpoints.size();
             write<u32>(&maps, numTimingPoints);
             write_bytes(&maps, (u8 *)diff->m_timingpoints.data(), sizeof(TIMINGPOINT) * numTimingPoints);
+
+            write<u8>(&maps, diff->draw_background);
         }
     }
 

+ 1 - 1
src/App/Osu/Database.h

@@ -15,7 +15,7 @@ typedef DatabaseBeatmap BeatmapDifficulty;
 typedef DatabaseBeatmap BeatmapSet;
 
 #define STARS_CACHE_VERSION 20240430
-#define NEOSU_MAPS_DB_VERSION 20240628
+#define NEOSU_MAPS_DB_VERSION 20240703
 
 // Field ordering matters here
 #pragma pack(push, 1)

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

@@ -189,6 +189,7 @@ class DatabaseBeatmap {
     inline long getLocalOffset() const { return m_iLocalOffset; }
     inline long getOnlineOffset() const { return m_iOnlineOffset; }
 
+    bool draw_background = true;
     bool do_not_store = false;
 
     // song select mod-adjusted pp/stars

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

@@ -35,6 +35,7 @@ ConVar KeyBindings::INSTANT_REPLAY("osu_key_instant_replay", (int)KEY_F2, FCVAR_
 ConVar KeyBindings::TOGGLE_CHAT("osu_key_toggle_chat", (int)KEY_F8, FCVAR_DEFAULT);
 ConVar KeyBindings::SAVE_SCREENSHOT("osu_key_save_screenshot", (int)KEY_F12, FCVAR_DEFAULT);
 ConVar KeyBindings::DISABLE_MOUSE_BUTTONS("osu_key_disable_mouse_buttons", (int)KEY_F10, FCVAR_DEFAULT);
+ConVar KeyBindings::TOGGLE_MAP_BACKGROUND("key_toggle_map_background", 0, FCVAR_DEFAULT);
 ConVar KeyBindings::BOSS_KEY("osu_key_boss", (int)KEY_INSERT, FCVAR_DEFAULT);
 
 ConVar KeyBindings::TOGGLE_MODSELECT("osu_key_toggle_modselect", (int)KEY_F1, FCVAR_DEFAULT);
@@ -80,6 +81,7 @@ std::vector<ConVar*> KeyBindings::ALL = {&KeyBindings::LEFT_CLICK,
                                          &KeyBindings::TOGGLE_CHAT,
                                          &KeyBindings::SAVE_SCREENSHOT,
                                          &KeyBindings::DISABLE_MOUSE_BUTTONS,
+                                         &KeyBindings::TOGGLE_MAP_BACKGROUND,
                                          &KeyBindings::BOSS_KEY,
 
                                          &KeyBindings::TOGGLE_MODSELECT,

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

@@ -41,6 +41,7 @@ class KeyBindings {
     static ConVar TOGGLE_CHAT;
     static ConVar SAVE_SCREENSHOT;
     static ConVar DISABLE_MOUSE_BUTTONS;
+    static ConVar TOGGLE_MAP_BACKGROUND;
     static ConVar BOSS_KEY;
 
     static ConVar TOGGLE_MODSELECT;

+ 55 - 0
src/App/Osu/ModSelector.cpp

@@ -1218,6 +1218,59 @@ u32 ModSelector::getModFlags() {
     return osu->getScore()->getModsLegacy();
 }
 
+ModSelection ModSelector::getModSelection() {
+    ModSelection selection;
+
+    selection.flags = getModFlags();
+    selection.fposu = convar->getConVarByName("osu_mod_fposu")->getBool();
+
+    for(auto slider : m_overrideSliders) {
+        selection.override_locks.push_back(slider.lock ? slider.lock->isChecked() : false);
+        selection.override_values.push_back(slider.cvar ? slider.cvar->getFloat() + 1.0f : 0.f);
+    }
+
+    for(auto mod : m_experimentalMods) {
+        selection.experimental.push_back(mod.cvar ? mod.cvar->getBool() : false);
+    }
+
+    return selection;
+}
+
+void ModSelector::restoreMods(ModSelection selection) {
+    // Reset buttons and sliders to clean state
+    resetMods();
+
+    // Override sliders
+    for(int i = 0; i < m_overrideSliders.size(); i++) {
+        if(m_overrideSliders[i].lock != NULL) {
+            m_overrideSliders[i].lock->setChecked(selection.override_locks[i]);
+        }
+        if(m_overrideSliders[i].cvar != NULL) {
+            m_overrideSliders[i].slider->setValue(selection.override_values[i], m_bVisible);
+        }
+    }
+
+    // Non-experimental mods
+    convar->getConVarByName("osu_mod_fposu")->setValue(selection.fposu);
+
+    // Experimental mods
+    for(int i = 0; i < m_experimentalMods.size(); i++) {
+        ConVar *cvar = m_experimentalMods[i].cvar;
+        CBaseUICheckbox *checkboxPointer = dynamic_cast<CBaseUICheckbox *>(m_experimentalMods[i].element);
+        if(checkboxPointer != NULL) {
+            // HACKHACK: we update both just in case because if the mod selector was not yet visible after a convar
+            // change (e.g. because of "Use mods") then the checkbox has not yet updated its internal state
+            checkboxPointer->setChecked(selection.experimental[i]);
+            if(cvar != NULL) cvar->setValue(selection.experimental[i]);
+        }
+    }
+
+    // Legacy mods
+    enableModsFromFlags(selection.flags);
+
+    // osu->updateMods() is already called by enableModsFromFlags()
+}
+
 void ModSelector::enableModsFromFlags(u32 flags) {
     if(flags & ModFlags::DoubleTime) {
         m_modButtonDoubletime->setOn(true, true);
@@ -1250,6 +1303,8 @@ void ModSelector::enableModsFromFlags(u32 flags) {
     getModButtonOnGrid(4, 2)->setOn(flags & ModFlags::Target, true);
     m_modButtonFlashlight->setOn(flags & ModFlags::Flashlight, true);
     m_modButtonScoreV2->setOn(flags & ModFlags::ScoreV2, true);
+
+    osu->updateMods();
 }
 
 void ModSelector::close() {

+ 11 - 0
src/App/Osu/ModSelector.h

@@ -19,6 +19,14 @@ class UICheckbox;
 
 class ConVar;
 
+struct ModSelection {
+    u32 flags;
+    bool fposu;
+    std::vector<bool> override_locks;
+    std::vector<float> override_values;
+    std::vector<bool> experimental;
+};
+
 class ModSelector : public OsuScreen {
    public:
     ModSelector();
@@ -41,6 +49,9 @@ class ModSelector : public OsuScreen {
     u32 getModFlags();
     void enableModsFromFlags(u32 flags);
 
+    ModSelection getModSelection();
+    void restoreMods(ModSelection selection);
+
     void setWaitForF1KeyUp(bool waitForF1KeyUp) { m_bWaitForF1KeyUp = waitForF1KeyUp; }
 
     bool isInCompactMode();

+ 7 - 23
src/App/Osu/OptionsMenu.cpp

@@ -530,18 +530,6 @@ OptionsMenu::OptionsMenu() : ScreenBackable() {
 
     CBaseUIElement *sectionGeneral = addSection("General");
 
-    addSubSection("");
-    UIButton *downloadOsuButton = addButton("Download osu! and get some beatmaps!");
-    downloadOsuButton->setClickCallback(fastdelegate::MakeDelegate(this, &OptionsMenu::onDownloadOsuClicked));
-    downloadOsuButton->setColor(0xff00ff00);
-    downloadOsuButton->setTextColor(0xffffffff);
-
-    addLabel("... or ...")->setCenterText(true);
-    UIButton *manuallyManageBeatmapsButton = addButton("Manually manage beatmap files?");
-    manuallyManageBeatmapsButton->setClickCallback(
-        fastdelegate::MakeDelegate(this, &OptionsMenu::onManuallyManageBeatmapsClicked));
-    manuallyManageBeatmapsButton->setColor(0xff10667b);
-
     addSubSection("osu!folder");
     addLabel("1) If you have an existing osu! installation:")->setTextColor(0xff666666);
     addLabel("2) osu! > Options > \"Open osu! folder\"")->setTextColor(0xff666666);
@@ -1003,6 +991,7 @@ OptionsMenu::OptionsMenu() : ScreenBackable() {
     addKeyBindButton("Increase Volume", &KeyBindings::INCREASE_VOLUME);
     addKeyBindButton("Decrease Volume", &KeyBindings::DECREASE_VOLUME);
     addKeyBindButton("Disable Mouse Buttons", &KeyBindings::DISABLE_MOUSE_BUTTONS);
+    addKeyBindButton("Toggle Map Background", &KeyBindings::TOGGLE_MAP_BACKGROUND);
     addKeyBindButton("Boss Key (Minimize)", &KeyBindings::BOSS_KEY);
     addSubSection("Keys - Song Select", keyboardSectionTags);
     addKeyBindButton("Toggle Mod Selection Screen", &KeyBindings::TOGGLE_MODSELECT)
@@ -1446,8 +1435,13 @@ void OptionsMenu::draw(Graphics *g) {
         if(!isPlayingBeatmap) osu->getHUD()->drawDummy(g);
     } else if(m_playfieldBorderSizeSlider->isActive()) {
         osu->getHUD()->drawPlayfieldBorder(g, GameRules::getPlayfieldCenter(), GameRules::getPlayfieldSize(), 100);
-    } else
+    } else {
         ScreenBackable::draw(g);
+    }
+
+    // Re-drawing context menu to make sure it's drawn on top of the back button
+    // Context menu input still gets processed first, so this is fine
+    m_contextMenu->draw(g);
 
     if(m_cursorSizeSlider->getFloat() < 0.15f) engine->getMouse()->drawDebug(g);
 
@@ -2641,16 +2635,6 @@ void OptionsMenu::onLogInClicked() {
     }
 }
 
-void OptionsMenu::onDownloadOsuClicked() {
-    osu->getNotificationOverlay()->addNotification("Opening browser, please wait ...", 0xffffffff, false, 0.75f);
-    env->openURLInDefaultBrowser("https://osu.ppy.sh/");
-}
-
-void OptionsMenu::onManuallyManageBeatmapsClicked() {
-    osu->getNotificationOverlay()->addNotification("Opening browser, please wait ...", 0xffffffff, false, 0.75f);
-    env->openURLInDefaultBrowser("https://steamcommunity.com/sharedfiles/filedetails/?id=880768265");
-}
-
 void OptionsMenu::onCM360CalculatorLinkClicked() {
     osu->getNotificationOverlay()->addNotification("Opening browser, please wait ...", 0xffffffff, false, 0.75f);
     env->openURLInDefaultBrowser("https://www.mouse-sensitivity.com/");

+ 0 - 2
src/App/Osu/OptionsMenu.h

@@ -124,8 +124,6 @@ class OptionsMenu : public ScreenBackable, public NotificationOverlayKeyListener
     void onOutputDeviceResetUpdate();
     void onOutputDeviceRestart();
     void onLogInClicked();
-    void onDownloadOsuClicked();
-    void onManuallyManageBeatmapsClicked();
     void onCM360CalculatorLinkClicked();
     void onNotelockSelect();
     void onNotelockSelect2(UString notelockType, int id = -1);

+ 10 - 1
src/App/Osu/Osu.cpp

@@ -59,7 +59,7 @@ Osu *osu = NULL;
 
 // release configuration
 ConVar auto_update("auto_update", true, FCVAR_DEFAULT);
-ConVar osu_version("osu_version", 35.08f, FCVAR_DEFAULT | FCVAR_HIDDEN);
+ConVar osu_version("osu_version", 35.09f, FCVAR_DEFAULT | FCVAR_HIDDEN);
 
 #ifdef _DEBUG
 ConVar osu_debug("osu_debug", true, FCVAR_DEFAULT);
@@ -1238,6 +1238,15 @@ void Osu::onKeyDown(KeyboardEvent &key) {
         }
     }
 
+    if(key == (KEYCODE)KeyBindings::TOGGLE_MAP_BACKGROUND.getInt()) {
+        auto diff = getSelectedBeatmap()->getSelectedDifficulty2();
+        if(!diff) {
+            m_notificationOverlay->addNotification("No beatmap is currently selected.");
+        } else {
+            diff->draw_background = !diff->draw_background;
+        }
+    }
+
     // F8 toggle chat
     if(key == (KEYCODE)KeyBindings::TOGGLE_CHAT.getInt()) {
         // When options menu is open, instead of toggling chat, close options menu and open chat

+ 2 - 2
src/App/Osu/Osu.h

@@ -1,6 +1,7 @@
 #pragma once
 #include "App.h"
 #include "BanchoNetworking.h"
+#include "ModSelector.h"
 #include "MouseListener.h"
 #include "score.h"
 
@@ -15,7 +16,6 @@ class UIUserContextMenuScreen;
 class MainMenu;
 class PauseMenu;
 class OptionsMenu;
-class ModSelector;
 class SongBrowser;
 class SpectatorScreen;
 class BackgroundImageHandler;
@@ -274,7 +274,7 @@ class Osu : public App, public MouseListener {
     bool holding_slider = false;
 
     // mods
-    u32 previous_mod_flags = 0;   // mod flags before spectating/multiplaying/etc
+    ModSelection previous_mods;
     bool m_bModAutoTemp = false;  // when ctrl+clicking a map, the auto mod should disable itself after the map finishes
     bool m_bModAuto = false;
     bool m_bModAutopilot = false;

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

@@ -505,8 +505,7 @@ void RoomScreen::ragequit(bool play_sound) {
     osu->m_chat->removeChannel("#multiplayer");
     osu->m_chat->updateVisibility();
 
-    osu->m_modSelector->resetMods();
-    osu->m_modSelector->enableModsFromFlags(osu->previous_mod_flags);
+    osu->getModSelector()->restoreMods(osu->previous_mods);
 
     if(play_sound) {
         engine->getSound()->play(osu->getSkin()->m_menuBack);
@@ -592,7 +591,7 @@ void RoomScreen::on_room_joined(Room room) {
     osu->m_chat->addChannel("#multiplayer");
     osu->m_chat->updateVisibility();
 
-    osu->previous_mod_flags = osu->getScore()->getModsLegacy();
+    osu->previous_mods = osu->getModSelector()->getModSelection();
 
     osu->m_modSelector->resetMods();
     osu->m_modSelector->enableModsFromFlags(bancho.room.mods);

+ 1 - 1
src/App/Osu/SongBrowser/SongBrowser.cpp

@@ -904,7 +904,7 @@ bool SongBrowser::selectBeatmapset(i32 set_id) {
         osu->m_songBrowser2->updateSongButtonSorting();
         debugLog("Finished loading beatmapset %d.\n", set_id);
 
-        beatmapset = getDatabase()->getBeatmapSet(set_autodl);
+        beatmapset = getDatabase()->getBeatmapSet(set_id);
     }
 
     if(beatmapset == NULL) {

+ 1 - 1
src/Engine/Platform/WinEnvironment.cpp

@@ -315,7 +315,7 @@ std::vector<std::string> WinEnvironment::getFoldersInFolder(std::string folder)
 
         buffer = filename;
 
-        if(filename.length() > 0) {
+        if(filename.length() > 0 && filename.compare(L".") != 0 && filename.compare(L"..") != 0) {
             if((data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0) {
                 int size = WideCharToMultiByte(CP_UTF8, 0, filename.c_str(), filename.length(), NULL, 0, NULL, NULL);
                 std::string utf8filename(size, 0);