Permalink
Browse files

Merge pull request #7249 from yourWaifu/discord-rpc-join

Add Discord Join Net Play functionally
  • Loading branch information...
delroth committed Aug 19, 2018
2 parents 0ed0e51 + 158c0d5 commit 0fdb6f4267dd34fc15d49d1aeaffd6734851936d
@@ -29,6 +29,7 @@ class HttpRequest::Impl final
bool IsValid() const;
void SetCookies(const std::string& cookies);
void UseIPv4();
Response Fetch(const std::string& url, Method method, const Headers& headers, const u8* payload,
size_t size);
@@ -62,6 +63,11 @@ void HttpRequest::SetCookies(const std::string& cookies)
m_impl->SetCookies(cookies);
}
void HttpRequest::UseIPv4()
{
m_impl->UseIPv4();
}
HttpRequest::Response HttpRequest::Get(const std::string& url, const Headers& headers)
{
return m_impl->Fetch(url, Impl::Method::GET, headers, nullptr, 0);
@@ -136,6 +142,11 @@ void HttpRequest::Impl::SetCookies(const std::string& cookies)
curl_easy_setopt(m_curl.get(), CURLOPT_COOKIE, cookies.c_str());
}
void HttpRequest::Impl::UseIPv4()
{
curl_easy_setopt(m_curl.get(), CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
}
static size_t CurlWriteCallback(char* data, size_t size, size_t nmemb, void* userdata)
{
auto* buffer = static_cast<std::vector<u8>*>(userdata);
@@ -32,6 +32,7 @@ class HttpRequest final
using Headers = std::map<std::string, std::optional<std::string>>;
void SetCookies(const std::string& cookies);
void UseIPv4();
Response Get(const std::string& url, const Headers& headers = {});
Response Post(const std::string& url, const std::vector<u8>& payload,
const Headers& headers = {});
@@ -1330,6 +1330,7 @@ void NetPlayClient::OnTraversalStateChanged()
Disconnect();
m_dialog->OnTraversalError(m_traversal_client->GetFailureReason());
}
m_dialog->OnTraversalStateChanged(state);
}
// called from ---NETPLAY--- thread
@@ -47,6 +47,7 @@ class NetPlayUI
virtual void OnConnectionLost() = 0;
virtual void OnConnectionError(const std::string& message) = 0;
virtual void OnTraversalError(TraversalClient::FailureReason error) = 0;
virtual void OnTraversalStateChanged(TraversalClient::State state) = 0;
virtual void OnSaveDataSyncFailure() = 0;
virtual bool IsRecording() = 0;
@@ -807,8 +807,15 @@ unsigned int NetPlayServer::OnData(sf::Packet& packet, Client& player)
void NetPlayServer::OnTraversalStateChanged()
{
if (m_dialog && m_traversal_client->GetState() == TraversalClient::Failure)
if (!m_dialog)
return;
const TraversalClient::State state = m_traversal_client->GetState();
if (state == TraversalClient::Failure)
m_dialog->OnTraversalError(m_traversal_client->GetFailureReason());
m_dialog->OnTraversalStateChanged(state);
}
// called from ---GUI--- thread
@@ -8,6 +8,8 @@ set(CMAKE_AUTOMOC ON)
add_executable(dolphin-emu
AboutDialog.cpp
CheatsManager.cpp
DiscordHandler.cpp
DiscordJoinRequestDialog.cpp
FIFO/FIFOPlayerWindow.cpp
FIFO/FIFOAnalyzer.cpp
HotkeyScheduler.cpp
@@ -0,0 +1,98 @@
// Copyright 2018 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#ifdef USE_DISCORD_PRESENCE
#include "DolphinQt/DiscordHandler.h"
#include <iterator>
#include <QApplication>
#include "Common/Thread.h"
#include "UICommon/DiscordPresence.h"
#include "DolphinQt/DiscordJoinRequestDialog.h"
#include "DolphinQt/QtUtils/RunOnObject.h"
DiscordHandler::DiscordHandler(QWidget* parent) : QObject{parent}, m_parent{parent}
{
connect(this, &DiscordHandler::JoinRequest, this, &DiscordHandler::ShowNewJoinRequest);
}
DiscordHandler::~DiscordHandler()
{
Stop();
}
void DiscordHandler::Start()
{
m_stop_requested.Set(false);
m_thread = std::thread(&DiscordHandler::Run, this);
}
void DiscordHandler::Stop()
{
m_stop_requested.Set(true);
if (m_thread.joinable())
m_thread.join();
}
void DiscordHandler::DiscordJoinRequest(const char* id, const std::string& discord_tag,
const char* avatar)
{
emit DiscordHandler::JoinRequest(id, discord_tag, avatar);
}
void DiscordHandler::DiscordJoin()
{
emit DiscordHandler::Join();
}
void DiscordHandler::ShowNewJoinRequest(const std::string& id, const std::string& discord_tag,
const std::string& avatar)
{
std::lock_guard<std::mutex> lock(m_request_dialogs_mutex);
m_request_dialogs.emplace_front(m_parent, id, discord_tag, avatar);
DiscordJoinRequestDialog& request_dialog = m_request_dialogs.front();
request_dialog.show();
request_dialog.raise();
request_dialog.activateWindow();
QApplication::alert(nullptr, DiscordJoinRequestDialog::s_max_lifetime_seconds * 1000);
}
void DiscordHandler::Run()
{
while (!m_stop_requested.IsSet())
{
if (m_thread.joinable())
Discord::CallPendingCallbacks();
// close and remove dead requests
{
std::lock_guard<std::mutex> lock(m_request_dialogs_mutex);
for (auto request_dialog = m_request_dialogs.begin();
request_dialog != m_request_dialogs.end();)
{
if (std::time(nullptr) < request_dialog->GetCloseTimestamp())
{
++request_dialog;
continue;
}
RunOnObject(m_parent, [this, &request_dialog] {
request_dialog->close();
request_dialog = m_request_dialogs.erase(request_dialog);
return nullptr;
});
}
}
Common::SleepCurrentThread(1000 * 2);
}
}
#endif
@@ -0,0 +1,49 @@
// Copyright 2018 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#pragma once
#include <list>
#include <mutex>
#include <thread>
#include <QObject>
#include "Common/Flag.h"
#include "UICommon/DiscordPresence.h"
class DiscordJoinRequestDialog;
class DiscordHandler : public QObject, public Discord::Handler
{
Q_OBJECT
#ifdef USE_DISCORD_PRESENCE
public:
explicit DiscordHandler(QWidget* parent);
~DiscordHandler();
void Start();
void Stop();
void DiscordJoin() override;
void DiscordJoinRequest(const char* id, const std::string& discord_tag,
const char* avatar) override;
void ShowNewJoinRequest(const std::string& id, const std::string& discord_tag,
const std::string& avatar);
#endif
signals:
void Join();
void JoinRequest(const std::string id, const std::string discord_tag, const std::string avatar);
#ifdef USE_DISCORD_PRESENCE
private:
void Run();
QWidget* m_parent;
Common::Flag m_stop_requested;
std::thread m_thread;
std::list<DiscordJoinRequestDialog> m_request_dialogs;
std::mutex m_request_dialogs_mutex;
#endif
};
@@ -0,0 +1,91 @@
// Copyright 2018 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#ifdef USE_DISCORD_PRESENCE
#include "DolphinQt/DiscordJoinRequestDialog.h"
#include <QGridLayout>
#include <QLabel>
#include <QPixmap>
#include <QPushButton>
#include <discord-rpc/include/discord_rpc.h>
#include "Common/HttpRequest.h"
#include "Common/StringUtil.h"
DiscordJoinRequestDialog::DiscordJoinRequestDialog(QWidget* parent, const std::string& id,
const std::string& discord_tag,
const std::string& avatar)
: QDialog(parent), m_user_id(id), m_close_timestamp(std::time(nullptr) + s_max_lifetime_seconds)
{
setWindowTitle(tr("Request to Join Your Party"));
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
QPixmap avatar_pixmap;
if (!avatar.empty())
{
const std::string avatar_endpoint = StringFromFormat(
"https://cdn.discordapp.com/avatars/%s/%s.png", id.c_str(), avatar.c_str());
Common::HttpRequest request;
Common::HttpRequest::Response response = request.Get(avatar_endpoint);
if (response.has_value())
avatar_pixmap.loadFromData(response->data(), static_cast<uint>(response->size()), "png");
}
CreateLayout(discord_tag, avatar_pixmap);
ConnectWidgets();
}
std::time_t DiscordJoinRequestDialog::GetCloseTimestamp() const
{
return m_close_timestamp;
}
void DiscordJoinRequestDialog::CreateLayout(const std::string& discord_tag, const QPixmap& avatar)
{
m_main_layout = new QGridLayout;
m_invite_button = new QPushButton(tr("\u2714 Invite"));
m_decline_button = new QPushButton(tr("\u2716 Decline"));
m_ignore_button = new QPushButton(tr("Ignore"));
QLabel* text =
new QLabel(tr("%1\nwants to join your party.").arg(QString::fromStdString(discord_tag)));
text->setAlignment(Qt::AlignCenter);
if (!avatar.isNull())
{
QLabel* picture = new QLabel();
picture->setPixmap(avatar);
m_main_layout->addWidget(picture, 1, 0, 1, 3, Qt::AlignHCenter);
}
m_main_layout->addWidget(text, 2, 0, 3, 3, Qt::AlignHCenter);
m_main_layout->addWidget(m_invite_button, 8, 0);
m_main_layout->addWidget(m_decline_button, 8, 1);
m_main_layout->addWidget(m_ignore_button, 8, 2);
setLayout(m_main_layout);
}
void DiscordJoinRequestDialog::ConnectWidgets()
{
connect(m_invite_button, &QPushButton::pressed, [this] { Reply(DISCORD_REPLY_YES); });
connect(m_decline_button, &QPushButton::pressed, [this] { Reply(DISCORD_REPLY_NO); });
connect(m_ignore_button, &QPushButton::pressed, [this] { Reply(DISCORD_REPLY_IGNORE); });
connect(this, &QDialog::rejected, this, [this] { Reply(DISCORD_REPLY_IGNORE); });
}
void DiscordJoinRequestDialog::Reply(int reply)
{
Discord_Respond(m_user_id.c_str(), reply);
close();
}
#endif
@@ -0,0 +1,35 @@
// Copyright 2018 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#pragma once
#include <QDialog>
#include <ctime>
class QGridLayout;
class QPixmap;
class DiscordJoinRequestDialog : public QDialog
{
Q_OBJECT
public:
explicit DiscordJoinRequestDialog(QWidget* parent, const std::string& id,
const std::string& discord_tag, const std::string& avatar);
std::time_t GetCloseTimestamp() const;
static constexpr std::time_t s_max_lifetime_seconds = 30;
private:
void CreateLayout(const std::string& discord_tag, const QPixmap& avatar);
void ConnectWidgets();
void Reply(int reply);
QGridLayout* m_main_layout;
QPushButton* m_invite_button;
QPushButton* m_decline_button;
QPushButton* m_ignore_button;
const std::string m_user_id;
const std::time_t m_close_timestamp;
};
@@ -107,6 +107,8 @@
<QtMoc Include="Config\PatchesWidget.h" />
<QtMoc Include="Config\PropertiesDialog.h" />
<QtMoc Include="Config\SettingsWindow.h" />
<QtMoc Include="DiscordHandler.h" />
<QtMoc Include="DiscordJoinRequestDialog.h" />
<QtMoc Include="FIFO\FIFOAnalyzer.h" />
<QtMoc Include="FIFO\FIFOPlayerWindow.h" />
<QtMoc Include="TAS\GCTASInputWindow.h" />
@@ -175,6 +177,8 @@
<ClCompile Include="$(QtMocOutPrefix)CodeViewWidget.cpp" />
<ClCompile Include="$(QtMocOutPrefix)CodeWidget.cpp" />
<ClCompile Include="$(QtMocOutPrefix)ControllersWindow.cpp" />
<ClCompile Include="$(QtMocOutPrefix)DiscordHandler.cpp" />
<ClCompile Include="$(QtMocOutPrefix)DiscordJoinRequestDialog.cpp" />
<ClCompile Include="$(QtMocOutPrefix)DoubleClickEventFilter.cpp" />
<ClCompile Include="$(QtMocOutPrefix)ElidedButton.cpp" />
<ClCompile Include="$(QtMocOutPrefix)FlowLayout.cpp" />
@@ -320,6 +324,8 @@
<ClCompile Include="Debugger\JITWidget.cpp" />
<ClCompile Include="Debugger\MemoryWidget.cpp" />
<ClCompile Include="Debugger\MemoryViewWidget.cpp" />
<ClCompile Include="DiscordHandler.cpp" />
<ClCompile Include="DiscordJoinRequestDialog.cpp" />
<ClCompile Include="FIFO\FIFOAnalyzer.cpp" />
<ClCompile Include="FIFO\FIFOPlayerWindow.cpp" />
<ClCompile Include="QtUtils\WinIconHelper.cpp" />
Oops, something went wrong.

0 comments on commit 0fdb6f4

Please sign in to comment.