소스 검색

Add instant replay

Clément Wolf 1 개월 전
부모
커밋
03e8b13d77

+ 31 - 0
src/App/Osu/Osu.cpp

@@ -1244,6 +1244,37 @@ void Osu::onKeyDown(KeyboardEvent &key) {
 
     // while playing (and not in options)
     if(isInPlayMode() && !m_optionsMenu->isVisible() && !m_chat->isVisible()) {
+        auto beatmap = getSelectedBeatmap();
+
+        // instant replay
+        if((beatmap->isPaused() || beatmap->hasFailed())) {
+            if(!key.isConsumed() && key == (KEYCODE)OsuKeyBindings::INSTANT_REPLAY.getInt()) {
+                if(!beatmap->m_bIsWatchingReplay) {
+                    Score score;
+                    score.replay = beatmap->live_replay;
+                    score.md5hash = beatmap->getSelectedDifficulty2()->getMD5Hash();
+                    score.modsLegacy = getScore()->getModsLegacy();
+
+                    // XXX: code reuse from saveAndSubmitScore, also incorrect when using Auto
+                    if(bancho.is_online()) {
+                        score.player_id = bancho.user_id;
+                        score.playerName = bancho.username.toUtf8();
+                    } else {
+                        auto local_name = convar->getConVarByName("name")->getString();
+                        score.player_id = 0;
+                        score.playerName = local_name.toUtf8();
+                    }
+
+                    double percentFinished = beatmap->getPercentFinished();
+                    double offsetPercent = 10000.f / beatmap->getLength();
+                    double seekPoint = fmax(0.f, percentFinished - offsetPercent);
+                    beatmap->cancelFailing();
+                    beatmap->watch(score, seekPoint);
+                    return;
+                }
+            }
+        }
+
         // while playing and not paused
         if(!getSelectedBeatmap()->isPaused()) {
             getSelectedBeatmap()->onKeyDown(key);

+ 24 - 16
src/App/Osu/OsuBeatmap.cpp

@@ -702,12 +702,23 @@ void OsuBeatmap::deselect() {
     unloadObjects();
 }
 
-bool OsuBeatmap::watch(Score score) {
+bool OsuBeatmap::watch(Score score, double start_percent) {
     // Replay is invalid
     if(score.replay.size() < 3) {
         return false;
     }
 
+    bancho.osu->replay_info.diff2_md5 = score.md5hash.hash;
+    bancho.osu->replay_info.mod_flags = score.modsLegacy;
+    bancho.osu->replay_info.username = UString(score.playerName.c_str());
+    bancho.osu->replay_info.player_id = score.player_id;
+
+    m_bIsPlaying = false;
+    m_bIsPaused = false;
+    m_bContinueScheduled = false;
+    stopStarCacheLoader();
+    unloadObjects();
+
     m_bIsWatchingReplay = true;
     m_osu->onBeforePlayStart();
 
@@ -723,7 +734,9 @@ bool OsuBeatmap::watch(Score score) {
 
     m_osu->m_songBrowser2->m_bHasSelectedAndIsPlaying = true;
     m_osu->m_songBrowser2->setVisible(false);
-    m_osu->onPlayStart();
+
+    m_bIsWaiting = true;  // ensure onPlayStart() will be called by seekPercent()
+    seekPercent(start_percent);
 
     return true;
 }
@@ -997,13 +1010,17 @@ void OsuBeatmap::stop(bool quit) {
 
     if(getSkin()->getFailsound()->isPlaying()) engine->getSound()->stop(getSkin()->getFailsound());
 
-    m_currentHitObject = NULL;
-
     m_bIsPlaying = false;
     m_bIsPaused = false;
     m_bContinueScheduled = false;
 
-    onBeforeStop(quit);
+    // kill any running star cache loader
+    stopStarCacheLoader();
+
+    saveAndSubmitScore(quit);
+
+    m_bIsWatchingReplay = false;
+    spectated_replay.clear();
 
     unloadObjects();
 
@@ -1628,6 +1645,7 @@ void OsuBeatmap::unloadMusic() {
 }
 
 void OsuBeatmap::unloadObjects() {
+    m_currentHitObject = nullptr;
     for(int i = 0; i < m_hitobjects.size(); i++) {
         delete m_hitobjects[i];
     }
@@ -3408,12 +3426,7 @@ void OsuBeatmap::onPlayStart() {
     onModUpdate(false, false);
 }
 
-void OsuBeatmap::onBeforeStop(bool quit) {
-    debugLog("OsuBeatmap::onBeforeStop()\n");
-
-    // kill any running star cache loader
-    stopStarCacheLoader();
-
+void OsuBeatmap::saveAndSubmitScore(bool quit) {
     // calculate stars
     double aim = 0.0;
     double aimSliderFactor = 0.0;
@@ -3549,11 +3562,6 @@ void OsuBeatmap::onBeforeStop(bool quit) {
     if(!isComplete) {
         m_osu->getScore()->setPPv2(0.0f);
     }
-
-    m_bIsWatchingReplay = false;
-    spectated_replay.clear();
-
-    debugLog("OsuBeatmap::onBeforeStop() done.\n");
 }
 
 void OsuBeatmap::onPaused(bool first) {

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

@@ -109,7 +109,7 @@ class OsuBeatmap {
                     // clicking on a beatmap)
     void selectDifficulty2(OsuDatabaseBeatmap *difficulty2);
     void deselect();  // stops + unloads the currently loaded music and deletes all hitobjects
-    bool watch(Score score);
+    bool watch(Score score, double start_percent);
     bool play();
     void restart(bool quick = false);
     void pause(bool quitIfWaiting = true);
@@ -408,7 +408,7 @@ class OsuBeatmap {
     }
 
     void onPlayStart();
-    void onBeforeStop(bool quit);
+    void saveAndSubmitScore(bool quit);
     void onPaused(bool first);
 
     void drawFollowPoints(Graphics *g);

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

@@ -31,6 +31,7 @@ ConVar OsuKeyBindings::SEEK_TIME_FORWARD("osu_key_seek_time_forward", (int)KEY_R
 ConVar OsuKeyBindings::QUICK_RETRY("osu_key_quick_retry", (int)KEY_BACKSPACE, FCVAR_NONE);
 ConVar OsuKeyBindings::QUICK_SAVE("osu_key_quick_save", (int)KEY_F6, FCVAR_NONE);
 ConVar OsuKeyBindings::QUICK_LOAD("osu_key_quick_load", (int)KEY_F7, FCVAR_NONE);
+ConVar OsuKeyBindings::INSTANT_REPLAY("osu_key_instant_replay", (int)KEY_F1, FCVAR_NONE);
 ConVar OsuKeyBindings::TOGGLE_CHAT("osu_key_toggle_chat", (int)KEY_F8, FCVAR_NONE);
 ConVar OsuKeyBindings::SAVE_SCREENSHOT("osu_key_save_screenshot", (int)KEY_F12, FCVAR_NONE);
 ConVar OsuKeyBindings::DISABLE_MOUSE_BUTTONS("osu_key_disable_mouse_buttons", (int)KEY_F10, FCVAR_NONE);
@@ -75,6 +76,7 @@ std::vector<ConVar*> OsuKeyBindings::ALL = {&OsuKeyBindings::LEFT_CLICK,
                                             &OsuKeyBindings::QUICK_RETRY,
                                             &OsuKeyBindings::QUICK_SAVE,
                                             &OsuKeyBindings::QUICK_LOAD,
+                                            &OsuKeyBindings::INSTANT_REPLAY,
                                             &OsuKeyBindings::TOGGLE_CHAT,
                                             &OsuKeyBindings::SAVE_SCREENSHOT,
                                             &OsuKeyBindings::DISABLE_MOUSE_BUTTONS,

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

@@ -37,6 +37,7 @@ class OsuKeyBindings {
     static ConVar QUICK_RETRY;
     static ConVar QUICK_SAVE;
     static ConVar QUICK_LOAD;
+    static ConVar INSTANT_REPLAY;
     static ConVar TOGGLE_CHAT;
     static ConVar SAVE_SCREENSHOT;
     static ConVar DISABLE_MOUSE_BUTTONS;

+ 1 - 0
src/App/Osu/OsuOptionsMenu.cpp

@@ -1025,6 +1025,7 @@ OsuOptionsMenu::OsuOptionsMenu(Osu *osu) : OsuScreenBackable(osu) {
     addKeyBindButton("Quick Retry (hold briefly)", &OsuKeyBindings::QUICK_RETRY);
     addKeyBindButton("Quick Save", &OsuKeyBindings::QUICK_SAVE);
     addKeyBindButton("Quick Load", &OsuKeyBindings::QUICK_LOAD);
+    addKeyBindButton("Instant Replay", &OsuKeyBindings::INSTANT_REPLAY);
     addSubSection("Keys - Universal", keyboardSectionTags);
     addKeyBindButton("Toggle chat", &OsuKeyBindings::TOGGLE_CHAT);
     addKeyBindButton("Save Screenshot", &OsuKeyBindings::SAVE_SCREENSHOT);

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

@@ -358,7 +358,7 @@ void OsuPauseMenu::onResolutionChange(Vector2 newResolution) {
 CBaseUIContainer *OsuPauseMenu::setVisible(bool visible) {
     m_bVisible = visible;
 
-    if(m_osu->isInPlayMode() && m_osu->getSelectedBeatmap() != NULL)
+    if(m_osu->isInPlayMode())
         setContinueEnabled(!m_osu->getSelectedBeatmap()->hasFailed());
     else
         setContinueEnabled(true);

+ 1 - 6
src/App/Osu/OsuReplay.cpp

@@ -266,17 +266,12 @@ void OsuReplay::load_and_watch(Score score) {
         return;
     }
 
-    bancho.osu->replay_info.diff2_md5 = score.md5hash.hash;
-    bancho.osu->replay_info.mod_flags = score.modsLegacy;
-    bancho.osu->replay_info.username = UString(score.playerName.c_str());
-    bancho.osu->replay_info.player_id = score.player_id;
-
     auto beatmap = bancho.osu->getSongBrowser()->getDatabase()->getBeatmapDifficulty(score.md5hash.hash);
     if(beatmap == nullptr) {
         // XXX: Auto-download beatmap
         bancho.osu->m_notificationOverlay->addNotification("Missing beatmap for this replay");
     } else {
         bancho.osu->getSongBrowser()->onDifficultySelected(beatmap, false);
-        bancho.osu->getSelectedBeatmap()->watch(score);
+        bancho.osu->getSelectedBeatmap()->watch(score, 0.f);
     }
 }