Browse Source

Handle lobby invite links

kiwec 2 months ago
parent
commit
00d68b74cc
5 changed files with 64 additions and 21 deletions
  1. 1 0
      src/App/Osu/Changelog.cpp
  2. 28 16
      src/App/Osu/Chat.cpp
  3. 20 1
      src/App/Osu/ChatLink.cpp
  4. 3 1
      src/App/Osu/Lobby.cpp
  5. 12 3
      src/App/Osu/RoomScreen.cpp

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

@@ -32,6 +32,7 @@ Changelog::Changelog() : ScreenBackable() {
     latest.changes.push_back("- Chat: added support for /me command");
     latest.changes.push_back("- Chat: added support for links");
     latest.changes.push_back("- Chat: added support for map links (auto-downloads)");
+    latest.changes.push_back("- Chat: added support for multiplayer invite links");
     changelogs.push_back(latest);
 
     CHANGELOG v35_05;

+ 28 - 16
src/App/Osu/Chat.cpp

@@ -94,23 +94,25 @@ void ChatChannel::add_message(ChatMessage msg) {
         }
     }
 
-    // regex101 format: (\[\[(.+?)\]\])|(\[(https?:\/\/\S+) (.+?)\])|(https?:\/\/\S+)
-    // example: link1 https://example.com link2 [https://regex101.com label] link3 [[FAQ]]
-    //
-    // Sadly, perl-style (?|(a)|(b)) capture groups are not supported in C++.
-    // So instead of having a nice regex that handles all cases, we have 6 capture groups.
+    // regex101 format: (\[\[(.+?)\]\])|(\[((\S+):\/\/\S+) (.+?)\])|(https?:\/\/\S+)
+    // This matches:
+    // - Raw URLs      https://example.com
+    // - Labeled URLs  [https://regex101.com useful website]
+    // - Lobby invites [osump://0/ join my lobby plz]
+    // - Wiki links    [[Chat Console]]
     //
     // Group 1) [[FAQ]]
     // Group 2) FAQ
     // Group 3) [https://regex101.com label]
     // Group 4) https://regex101.com
-    // Group 5) label
-    // Group 6) https://example.com
+    // Group 5) https
+    // Group 6) label
+    // Group 7) https://example.com
     //
     // Groups 1, 2 only exist for wiki links
-    // Groups 3, 4, 5 only exist for labeled links
-    // Group 6 only exists for raw links
-    std::wregex url_regex(L"(\\[\\[(.+?)\\]\\])|(\\[(https?://\\S+) (.+?)\\])|(https?://\\S+)");
+    // Groups 3, 4, 5, 6 only exist for labeled links
+    // Group 7 only exists for raw links
+    std::wregex url_regex(L"(\\[\\[(.+?)\\]\\])|(\\[((\\S+)://\\S+) (.+?)\\])|(https?://\\S+)");
 
     std::wstring msg_text = msg.text.wc_str();
     std::wsmatch match;
@@ -122,18 +124,28 @@ void ChatChannel::add_message(ChatMessage msg) {
         int match_len;
         UString link_url;
         UString link_label;
-        if(match[6].matched) {
+        if(match[7].matched) {
             // Raw link
-            match_pos = match.position(6);
-            match_len = match.length(6);
-            link_url = match.str(6).c_str();
-            link_label = match.str(6).c_str();
+            match_pos = match.position(7);
+            match_len = match.length(7);
+            link_url = match.str(7).c_str();
+            link_label = match.str(7).c_str();
         } else if(match[3].matched) {
             // Labeled link
             match_pos = match.position(3);
             match_len = match.length(3);
             link_url = match.str(4).c_str();
-            link_label = match.str(5).c_str();
+            link_label = match.str(6).c_str();
+
+            // Normalize invite links to osump://
+            UString link_protocol = match.str(5).c_str();
+            if(link_protocol == UString("osu")) {
+                // osu:// -> osump://
+                link_url.insert(2, "mp");
+            } else if(link_protocol == UString("http://osump")) {
+                // http://osump:// -> osump://
+                link_url.erase(0, 7);
+            }
         } else {
             // Wiki link
             match_pos = match.position(1);

+ 20 - 1
src/App/Osu/ChatLink.cpp

@@ -4,8 +4,11 @@
 #include <regex>
 
 #include "Bancho.h"
+#include "Lobby.h"
 #include "MainMenu.h"
+#include "NotificationOverlay.h"
 #include "Osu.h"
+#include "RoomScreen.h"
 #include "SongBrowser/SongBrowser.h"
 #include "TooltipOverlay.h"
 
@@ -32,7 +35,23 @@ void ChatLink::mouse_update(bool *propagate_clicks) {
 }
 
 void ChatLink::onMouseUpInside() {
-    // TODO: Handle lobby invite links, on click join the lobby (even if passworded)
+    if(m_link.startsWith("osump://")) {
+        if(osu->m_room->isVisible()) {
+            osu->getNotificationOverlay()->addNotification("You are already in a multiplayer room.");
+            return;
+        }
+
+        // If the password has a space in it, parsing will break, but there's no way around it...
+        // osu!stable also considers anything after a space to be part of the lobby title :(
+        std::regex password_regex("osump://(\\d+)/(\\S*)");
+        std::string invite_str = m_link.toUtf8();
+        std::smatch match;
+        std::regex_search(invite_str, match, password_regex);
+        u32 invite_id = strtoul(match.str(1).c_str(), NULL, 10);
+        UString password = match.str(2).c_str();
+        osu->m_lobby->joinRoom(invite_id, password);
+        return;
+    }
 
     // This lazy escaping is only good for endpoint URLs, not anything more serious
     UString escaped_endpoint;

+ 3 - 1
src/App/Osu/Lobby.cpp

@@ -204,12 +204,14 @@ void Lobby::joinRoom(u32 id, UString password) {
     send_packet(packet);
 
     for(CBaseUIElement* elm : m_list->getContainer()->getElements()) {
-        auto room = (RoomUIElement*)elm;
+        RoomUIElement* room = dynamic_cast<RoomUIElement*>(elm);
+        if(room == NULL) continue;
         if(room->room_id != id) continue;
         room->join_btn->is_loading = true;
         break;
     }
 
+    debugLog("Joining room #%d with password '%s'\n", id, password.toUtf8());
     osu->getNotificationOverlay()->addNotification("Joining room...");
 }
 

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

@@ -11,6 +11,7 @@
 #include "CBaseUIContainer.h"
 #include "CBaseUILabel.h"
 #include "CBaseUITextbox.h"
+#include "Changelog.h"
 #include "Chat.h"
 #include "Database.h"
 #include "Downloader.h"
@@ -32,6 +33,7 @@
 #include "SongBrowser/SongBrowser.h"
 #include "SongBrowser/SongButton.h"
 #include "SoundEngine.h"
+#include "SpectatorScreen.h"
 #include "UIAvatar.h"
 #include "UIButton.h"
 #include "UICheckbox.h"
@@ -561,10 +563,17 @@ void RoomScreen::on_room_joined(Room room) {
 
     on_map_change();
 
-    // Currently we can only join rooms from the lobby.
-    // If we add ability to join from links, you would need to hide all other
-    // screens, kick the player out of the song they're currently playing, etc.
+    // Close all screens and stop any activity the player is in
+    stop_spectating();
+    if(osu->getSelectedBeatmap()->isPlaying()) {
+        osu->getSelectedBeatmap()->stop(true);
+    }
+    osu->m_rankingScreen->setVisible(false);
+    osu->m_songBrowser2->setVisible(false);
+    osu->m_changelog->setVisible(false);
+    osu->m_mainMenu->setVisible(false);
     osu->m_lobby->setVisible(false);
+
     updateLayout(osu->getScreenSize());
     m_bVisible = true;