Skip to content

Commit 26f0076

Browse files
authored
feat(discord): always show launcher in Discord (#113)
2 parents d77ac73 + 5b2b67a commit 26f0076

File tree

12 files changed

+186
-78
lines changed

12 files changed

+186
-78
lines changed

launcher/Application.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -742,6 +742,10 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv)
742742
m_settings->registerSetting("ShaderDownloadGeometry", "");
743743

744744
m_settings->registerSetting("EnableDiscordRichPresence", false);
745+
m_settings->registerSetting("AlwaysShowInDiscord", false);
746+
if (m_settings->get("AlwaysShowInDiscord").toBool()) {
747+
discord();
748+
}
745749

746750
// HACK: This code feels so stupid is there a less stupid way of doing this?
747751
{
@@ -1394,7 +1398,7 @@ std::shared_ptr<DiscordIntegration> Application::discord()
13941398
{
13951399
// lazy initialize
13961400
if (!m_discord) {
1397-
m_discord = std::make_shared<DiscordIntegration>();
1401+
m_discord = std::make_shared<DiscordIntegration>(m_settings->get("AlwaysShowInDiscord").toBool());
13981402
}
13991403
return m_discord;
14001404
}

launcher/discord/Activity.cpp

Lines changed: 22 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@
2626

2727
#include "Activity.h"
2828

29+
#include "BuildConfig.h"
30+
2931
namespace {
3032
enum class DiscordActivityType { Playing = 0, Streaming = 1, Listening = 2, Watching = 3, Custom = 4, Competing = 5 };
3133

@@ -34,57 +36,53 @@ QJsonValue makeNonce()
3436
return QUuid::createUuid().toString();
3537
}
3638

37-
QJsonValue makeActivityDetails(const InstancePtr& instance)
38-
{
39-
return "Minecraft " + instance->getVersionString();
40-
}
41-
42-
QJsonObject makeActivityTimestamps(const RunningInstance& instance)
39+
QJsonObject makeActivityTimestamps(const qint64 startTime)
4340
{
4441
QJsonObject timestamps;
4542

46-
timestamps["start"] = instance.startedAt.toSecsSinceEpoch();
43+
timestamps["start"] = startTime;
4744

4845
return timestamps;
4946
}
5047

51-
[[maybe_unused]] QJsonObject makeActivityAssets(const InstancePtr& instance)
52-
{
53-
QJsonObject assets;
54-
55-
assets["large_image"] = instance->iconKey();
56-
57-
return assets;
58-
}
59-
60-
QJsonObject makeActivity(const RunningInstance& instance)
48+
QJsonObject makeActivity(qint64 startTime, const QString& details)
6149
{
6250
QJsonObject activity;
6351

64-
activity["name"] = "Freesm Launcher";
52+
activity["name"] = BuildConfig.LAUNCHER_DISPLAYNAME;
6553
activity["type"] = static_cast<int>(DiscordActivityType::Playing);
66-
activity["details"] = makeActivityDetails(instance.ptr());
67-
activity["timestamps"] = makeActivityTimestamps(instance);
68-
// activity["assets"] = makeActivityAssets(instance);
54+
if (!details.isEmpty())
55+
activity["details"] = details;
56+
activity["timestamps"] = makeActivityTimestamps(startTime);
6957

7058
return activity;
7159
}
72-
} // namespace
7360

74-
QByteArray generateActivity(const RunningInstance& instance)
61+
QByteArray makeRequest(qint64 startTime, const QString& details)
7562
{
7663
QJsonObject request;
7764

7865
QJsonObject args;
7966
args["pid"] = APPLICATION->applicationPid();
80-
args["activity"] = makeActivity(instance);
67+
args["activity"] = makeActivity(startTime, details);
8168

8269
request["args"] = args;
8370
request["nonce"] = makeNonce();
8471
request["cmd"] = "SET_ACTIVITY";
8572

8673
return QJsonDocument(request).toJson();
8774
}
75+
} // namespace
76+
77+
QByteArray generateActivity(const RunningInstance& instance)
78+
{
79+
return makeRequest(instance.startedAt.toSecsSinceEpoch(), "Minecraft " + instance.ptr()->getVersionString());
80+
}
81+
82+
QByteArray generateBackgroundActivity(qint64 startTime)
83+
{
84+
return makeRequest(startTime, "");
85+
}
8886

8987
QByteArray generateEmptyActivity()
9088
{

launcher/discord/Activity.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,10 @@
1818

1919
#pragma once
2020

21+
#include <QByteArray>
22+
2123
struct RunningInstance;
2224

2325
QByteArray generateActivity(const RunningInstance& instance);
26+
QByteArray generateBackgroundActivity(qint64 startTime);
2427
QByteArray generateEmptyActivity();

launcher/discord/DiscordIntegration.cpp

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
* along with this program. If not, see <https://www.gnu.org/licenses/>.
1717
*/
1818

19+
#include <QDateTime>
1920
#include <QDir>
2021
#include <QJsonDocument>
2122
#include <QJsonObject>
@@ -28,7 +29,13 @@
2829

2930
#include "DiscordIntegration.h"
3031

31-
DiscordIntegration::DiscordIntegration() : m_socket(makeSocket()), m_queue(std::make_unique<DiscordQueue>())
32+
#include <QThread>
33+
34+
DiscordIntegration::DiscordIntegration(bool showAlways)
35+
: m_socket(makeSocket())
36+
, m_queue(std::make_unique<DiscordQueue>())
37+
, m_showAlways(showAlways)
38+
, m_startTime(QDateTime::currentSecsSinceEpoch())
3239
{
3340
connect(m_socket.get(), &DiscordSocket::connected, this, &DiscordIntegration::socketConnected);
3441
connect(m_socket.get(), &DiscordSocket::failed, this, &DiscordIntegration::socketFailed);
@@ -51,14 +58,23 @@ void DiscordIntegration::instanceStopped(const std::shared_ptr<BaseInstance>& in
5158
m_queue->instanceStopped(instance);
5259
}
5360

54-
bool DiscordIntegration::startActivity(const RunningInstance instance)
61+
void DiscordIntegration::showAlways(bool state)
62+
{
63+
m_showAlways = state;
64+
65+
if (!m_queue->isInstanceRunning()) {
66+
emit stopActivity();
67+
}
68+
}
69+
70+
void DiscordIntegration::startActivity(const RunningInstance instance)
5571
{
56-
return m_socket->send(generateActivity(instance));
72+
m_socket->enqueue(generateActivity(instance));
5773
}
5874

59-
bool DiscordIntegration::stopActivity()
75+
void DiscordIntegration::stopActivity()
6076
{
61-
return m_socket->send(generateEmptyActivity());
77+
m_socket->enqueue(m_showAlways ? generateBackgroundActivity(m_startTime) : generateEmptyActivity());
6278
}
6379

6480
void DiscordIntegration::socketConnected()

launcher/discord/DiscordIntegration.h

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,22 +29,27 @@ class DiscordIntegration : public QObject {
2929
Q_OBJECT
3030

3131
public:
32-
DiscordIntegration();
32+
explicit DiscordIntegration(bool showAlways);
3333
~DiscordIntegration() override;
3434

3535
public:
3636
void instanceStarted(const std::shared_ptr<BaseInstance>& instance);
3737
void instanceStopped(const std::shared_ptr<BaseInstance>& instance);
3838

39+
void showAlways(bool state);
40+
3941
private slots:
4042
void socketConnected();
4143
void socketFailed();
4244

43-
bool startActivity(RunningInstance instance);
44-
bool stopActivity();
45+
void startActivity(RunningInstance instance);
46+
void stopActivity();
4547

4648
private:
4749
std::unique_ptr<DiscordSocket> m_socket;
4850

4951
std::unique_ptr<DiscordQueue> m_queue;
52+
53+
bool m_showAlways;
54+
qint64 m_startTime;
5055
};

launcher/discord/DiscordQueue.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,11 @@ void DiscordQueue::instanceStopped(const std::shared_ptr<BaseInstance>& instance
4242
emit processQueue();
4343
}
4444

45+
bool DiscordQueue::isInstanceRunning()
46+
{
47+
return !m_runningInstance.expired();
48+
}
49+
4550
void DiscordQueue::socketReady()
4651
{
4752
m_socketReady = true;

launcher/discord/DiscordQueue.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ class DiscordQueue : public QObject {
3232
void instanceStarted(const std::shared_ptr<BaseInstance>& instance);
3333
void instanceStopped(const std::shared_ptr<BaseInstance>& instance);
3434

35+
bool isInstanceRunning();
36+
3537
public slots:
3638
void socketReady();
3739

launcher/discord/DiscordSocket.cpp

Lines changed: 59 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -52,27 +52,27 @@ void DiscordSocket::onConnected()
5252

5353
void DiscordSocket::handshake()
5454
{
55-
send(generateHandshake(), Opcode::Handshake);
55+
enqueue(generateHandshake(), Opcode::Handshake);
5656
}
5757

58-
void DiscordSocket::errorOccurred([[maybe_unused]] QLocalSocket::LocalSocketError socketError)
58+
void DiscordSocket::processReply()
5959
{
60-
emit failed();
61-
}
62-
63-
void DiscordSocket::read()
64-
{
65-
if (m_socket.bytesAvailable() != 0) {
66-
disconnect(&m_socket, &QLocalSocket::readyRead, this, &DiscordSocket::read);
60+
const auto reply = QJsonDocument::fromJson(m_msg);
61+
const auto obj = reply.object();
62+
if (obj["cmd"] == "DISPATCH" && obj["evt"] == "READY") {
6763
emit connected();
64+
return;
65+
}
66+
67+
if (!m_messagesToSend.isEmpty()) {
68+
emit send();
6869
}
6970
}
7071

71-
bool DiscordSocket::send(const QByteArray& data, Opcode opcode)
72+
void DiscordSocket::send()
7273
{
73-
if (m_socket.state() != QLocalSocket::ConnectedState) {
74-
qDebug() << "socket.state() != QLocalSocket::ConnectedState";
75-
}
74+
m_state = State::Sent;
75+
auto [data, opcode] = m_messagesToSend.dequeue();
7676

7777
QByteArray frame;
7878
QDataStream stream(&frame, QIODevice::WriteOnly);
@@ -87,10 +87,54 @@ bool DiscordSocket::send(const QByteArray& data, Opcode opcode)
8787
const auto sent = m_socket.write(frame);
8888
if (sent != frame.size()) {
8989
qDebug() << "send failed, sent " << sent << '/' << frame.size();
90-
return false;
90+
return;
9191
}
9292
m_socket.flush();
93-
return true;
93+
}
94+
95+
void DiscordSocket::errorOccurred([[maybe_unused]] QLocalSocket::LocalSocketError socketError)
96+
{
97+
emit failed();
98+
}
99+
100+
void DiscordSocket::read()
101+
{
102+
if (m_state != State::Reading) {
103+
if (m_socket.bytesAvailable() >= sizeof(quint32) * 2) {
104+
QDataStream in(&m_socket);
105+
in.setByteOrder(QDataStream::LittleEndian);
106+
107+
quint32 op;
108+
in >> op;
109+
110+
quint32 bytes;
111+
in >> bytes;
112+
m_pendingBytes = bytes;
113+
114+
m_state = State::Reading;
115+
m_msg = {};
116+
} else {
117+
return;
118+
}
119+
}
120+
121+
if (m_state == State::Reading) {
122+
auto toRead = std::min(m_socket.bytesAvailable(), m_pendingBytes);
123+
m_msg.append(m_socket.read(toRead));
124+
m_pendingBytes -= toRead;
125+
if (m_pendingBytes == 0) {
126+
m_state = State::Waiting;
127+
processReply();
128+
}
129+
}
130+
}
131+
132+
void DiscordSocket::enqueue(const QByteArray& data, Opcode opcode)
133+
{
134+
m_messagesToSend.enqueue({ data, opcode });
135+
if (m_state == State::Waiting) {
136+
emit send();
137+
}
94138
}
95139

96140
void UnixDiscordSocket::connectSocket()

launcher/discord/DiscordSocket.h

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,13 @@
1818

1919
#pragma once
2020

21+
#include <QByteArray>
2122
#include <QLocalSocket>
2223
#include <QObject>
24+
#include <QQueue>
2325

2426
class DiscordSocket : public QObject {
25-
enum class Opcode : uint32_t { Handshake = 0, Frame = 1, Close = 2, Ping = 3, Pong = 4 };
27+
enum class Opcode : quint32 { Handshake = 0, Frame = 1, Close = 2, Ping = 3, Pong = 4 };
2628

2729
Q_OBJECT
2830
public:
@@ -32,7 +34,7 @@ class DiscordSocket : public QObject {
3234

3335
virtual void connectSocket() = 0;
3436

35-
bool send(const QByteArray& data, Opcode opcode = Opcode::Frame);
37+
void enqueue(const QByteArray& data, Opcode opcode = Opcode::Frame);
3638

3739
QString errorString() const { return m_socket.errorString(); }
3840

@@ -45,15 +47,26 @@ class DiscordSocket : public QObject {
4547
protected:
4648
void handshake();
4749

50+
void processReply();
51+
4852
protected slots:
4953
void onConnected();
5054

5155
virtual void errorOccurred(QLocalSocket::LocalSocketError socketError);
5256

5357
void read();
5458

59+
void send();
60+
5561
protected:
5662
QLocalSocket m_socket;
63+
64+
private:
65+
enum class State { Waiting, Sent, Reading } m_state{ State::Waiting };
66+
qint64 m_pendingBytes{};
67+
QByteArray m_msg;
68+
69+
QQueue<std::pair<QByteArray, Opcode>> m_messagesToSend;
5770
};
5871

5972
class UnixDiscordSocket : public DiscordSocket {

0 commit comments

Comments
 (0)