Skip to content

Add Discord support#1716

Merged
vadi2 merged 127 commits intoMudlet:developmentfrom
vadi2:add-basic-gamekit
Oct 5, 2018
Merged

Add Discord support#1716
vadi2 merged 127 commits intoMudlet:developmentfrom
vadi2:add-basic-gamekit

Conversation

@vadi2
Copy link
Copy Markdown
Member

@vadi2 vadi2 commented May 28, 2018

Brief overview of PR changes/additions

Add Discord integration to Mudlet.

Motivation for adding to Mudlet

Integrate with Discord like AAA games do, give MUDs another excellent, free channel for advertising, and, ultimately, make MUDs more modern and appealing.

Other info (issues closed, discussion etc)

Windows: https://ci.appveyor.com/api/buildjobs/3cxqfec12bka8il8/artifacts/src%2Fmudlet.zip
macOS: https://transfer.sh/jOII2/Mudlet-3.13.0-testing-PR1716-d02f94c.dmg
Linux: https://transfer.sh/7jGHI/Mudlet-3.13.0-testing-PR1716-d02f94c0-linux-x64.AppImage.tar

Current draft of the GMCP spec is: https://pastebin.com/Zt7Wbkwk. Documentation: https://wiki.mudlet.org/w/Manual:Scripting#Discord_Rich_Presence

Games supporting Discord out of the box: MidMUD, StickMUD, Achaea, Lusternia, Imperian, Aetolia

Currently available Lua API is documented here.

Sample previews:
peek 2018-06-08 05-33


peek 2018-06-09 17-06

@vadi2 vadi2 self-assigned this May 28, 2018
@vadi2 vadi2 requested a review from a team as a code owner May 28, 2018 12:08
@vadi2 vadi2 requested a review from a team May 28, 2018 12:08
@vadi2
Copy link
Copy Markdown
Member Author

vadi2 commented May 28, 2018

@keneanung could use your help in sorting out how it should build, as always. Right now I have to use LD_LIBRARY_PATH pointing to the Discord binary.

We also have the option of compiling it, it's open-source under MIT (so all OK @SlySven) but I'd rather compile less things, not more.

Copy link
Copy Markdown
Member

@SlySven SlySven left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You also need stuff for the CMake project files...


#define DISCORD_REPLY_NO 0
#define DISCORD_REPLY_YES 1
#define DISCORD_REPLY_IGNORE 2
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we have these at the top so they are obvious please...

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a third-party library's code


#define DISCORD_REPLY_NO 0
#define DISCORD_REPLY_YES 1
#define DISCORD_REPLY_IGNORE 2
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As above

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See above

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

^ that was a little terse, sorry was in a rush :)

src/mudlet.cpp Outdated
#include "edbee/models/textgrammar.h"
#include "edbee/texteditorwidget.h"
#include "edbee/views/texttheme.h"
#include "discord.h"
Copy link
Copy Markdown
Member

@SlySven SlySven May 28, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This has to be conditional, at least by platform - it won't work on FreeBSD because the Desktop application is not available for that platform. It may also not be wanted by some packagers - for instance since Discord is not packaged by Debian but provided by the Discord people themselves it is probable that @csmall will not want it included in Debian packages...

Based on my previous hackery, may I suggest an environmental variable WITH_DISCORD being set to NO to disable a #define INCLUDE_DISCORD on the supported platforms which is used to include/exclude the functionality.

Also you mentioned the code was MIT licenced - so it will need to be conditionally included in the "About dialog" - but it should be fairly straight-forward to conditionally add another licence to the listing there.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll fix the include.

I don't want yet another flag for this, we already have a lot of flags for trivial things and I don't see players wanting to use a what would be a less than functional Mudlet

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it possible to load the functionality at runtime, depending on if the libraries are available?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

http://doc.qt.io/qt-5/qlibrary.html#details looks like so! I will investigate this approach.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Conditional loading of the library dependent on availability will be a PITA for developers because they will have to arrange for the libraries concerned to both be available / not available to test both conditions won't they? I guess adding/removing some symlinks is one crude way to do it.

The Discord libraries - are they C or C++ code? I ask because that QLibrary seems to be aimed at dlopenìng (which I think is the name for run-time, explicit, loading of libraries on demand as opposed to the implicit, link stage of compilation, incorporation of library functions into an executable) C libraries only...

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All it takes is one LD_PRELOAD_PATH and only developers working with Discord code would need to do that - I prefer that option over more fobs in the build system.

It's C code, I think it'll be OK!

src/mudlet.pro Outdated
}

linux {
HEADERS += ../3rdparty/discord/discord-rpc-linux/discord-rpc/linux-dynamic/include
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are the other two paths correct - they look different to this one in that they are missing a /discord element straight after the ../3rdparty directory:
../3rdparty/discord/discord-rpc-linux/discord-rpc/linux-dynamic/include
verses:
../3rdparty/discord-rpc-osx/discord-rpc/osx-dynamic/include
../3rdparty/discord-rpc-win/discord-rpc/win32-dynamic/include

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the catch :)

@keneanung
Copy link
Copy Markdown
Member

Do you plan to make it controllable via lua? We could also define custom GMCP/MSDP extensions instead of using triggers.

@vadi2
Copy link
Copy Markdown
Member Author

vadi2 commented May 29, 2018

Yes and yes.

Did you want to look at getting the GMCP/MSDP extensions communicated with other clients / community?

Copy link
Copy Markdown
Member

@SlySven SlySven left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do like what you are trying to achieve. 😀
I'm just sad that I won't be able to use it. 😭

Does the Discord API support opening up Discord in the channel of a specific MUD Game - I am sure some MUDs already have official ones but that may not always be the case and users on raiding parties or other activities may want per team or other sub-groupings and so may want to be able to suggest a channel to be opened in the Discord application depending on the situation - and they may want to automate that into a Mudlet script/package/module...

src/discord.cpp Outdated
#include "pre_guard.h"
#include <functional>
#include "../3rdparty/discord/discord-rpc-linux/discord-rpc/linux-dynamic/include/discord_register.h"
#include "../3rdparty/discord/discord-rpc-linux/discord-rpc/linux-dynamic/include/discord_rpc.h"
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This and the preceding header are redundant as you've already #included them in the discord.h file! {Ironic considering you just have or are remove such duplicates from the existing Mudlet source files. 🤣 }

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed, thanks for spotting this.

src/discord.cpp Outdated
#include "../3rdparty/discord/discord-rpc-linux/discord-rpc/linux-dynamic/include/discord_rpc.h"
#include "post_guard.h"

static const char* APPLICATION_ID = "450571881909583884";
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this a GUID for Mudlet on Discord? We might want to note that in a comment so we know what this magic number is...

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Documented.

src/discord.cpp Outdated
}

char buffer[256];
sprintf(buffer, "Playing %s", name.toUtf8().constData());
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🌏 I18n: Discord is aiming to cover more than English IIRC so we may need to tr(...) the string; so, will this work:

sprintf(buffer, tr("Playing %1").arg(name).toUtf8().constData());

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, right! Thanks.

I also went with:

sprintf(buffer, "%s", tr("Playing %1").arg(name).toUtf8().constData());

That is more secure.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ehh... I am not sure this is a good idea. If it shows for an italian user "giocando a clessindra", nobody elsewhere will know what are they doing.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider the Spanish players, previously using MudletRL, are they going to want to see:

Jugando: Reinos de leyenda

or:

Playing: Reinos de leyenda

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Spanish Discord users want to see the former while the English want to see the latter and the German Discord users want Spielt: Reinos de leyenda. Optimally, Discord should translate this depending on the side viewing the status.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was looking to see how well developed Discord was for non-Americanish languages to see whether it is likely they'd look at this but was not able to find anything out. Also, it is not something that this bot is going to solve - and since they dropped their free service on 2018/05/17 it is not one that we can afford to invite to our channel... 🙁

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Discord does this just fine. Using Discord with German client, I would see "Spielt Mudlet" and not "Playing Mudlet". Here is a screenshot for future reference:
image

src/discord.cpp Outdated
char buffer[256];
sprintf(buffer, "Playing %s", name.toUtf8().constData());
mDiscordPresence.details = buffer;
mDiscordPresence.largeImageKey = name.toLower().toUtf8().constData();
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is toLower() appropriate here?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, Discord lowercases the asset names

src/discord.cpp Outdated
void Discord::timerEvent(QTimerEvent *event)
void Discord::timerEvent(QTimerEvent* event)
{
if (!mLoaded) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is, aborting on fail always the way to go with short methods like this, would not:

if (mLoaded) {
    Discord_RunCallbacks();
}

be just as functional but even briefer?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah :)

src/discord.cpp Outdated
mDiscordPresence.partySize = 5;
mDiscordPresence.partyMax = 6;
mDiscordPresence.matchSecret = "zdgfghrfsyheqrwqgshbfxdq35 4 5";
mDiscordPresence.joinSecret = "ASFDFSHR512345 RASGSADWr";
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we have an explanation somewhere about what these magic numbers mean/are for - or even the whole mDiscordPresence?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

src/discord.h Outdated
#include <QTimerEvent>
#include <QLibrary>
#include "../3rdparty/discord/discord-rpc-linux/discord-rpc/linux-dynamic/include/discord_register.h"
#include "../3rdparty/discord/discord-rpc-linux/discord-rpc/linux-dynamic/include/discord_rpc.h"
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are these platform specific - so need #if defined(Q_OS_LINUX) etc. wrappings?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah.

@vadi2
Copy link
Copy Markdown
Member Author

vadi2 commented May 30, 2018

Does the Discord API support opening up Discord in the channel of a specific MUD Game

I'm not sure, but I like what you're thinking! We'll get to this in time...

@vadi2
Copy link
Copy Markdown
Member Author

vadi2 commented May 30, 2018

Problem: 1 profile open, easy - discord should say you're playing X game.

2 profiles open, different games - which should be reported? :(

Perhaps the currently focused tab, that would work in multiview too. This is also where @SlySven's idea of not reporting to Discord comes in - a person may want to have some characters they keep secret, while some characters are public... so yes should have a per-profile option for this. Opt in or opt out is the question - opt-in and people won't notice to enable it, opt-out and their secret characters might get leaked.

I think opt-in with a way to notify the user that they can enable it would be the way to go.

src/discord.cpp Outdated
char buffer[128];
auto status = mStatus.toUtf8();
strncpy(buffer, status.constData(), status.length());
discordPresence.state = status.constData();
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@SlySven could use your help in making this nicer... it has a few warnings.

@vadi2
Copy link
Copy Markdown
Member Author

vadi2 commented Sep 26, 2018

Updated.

auto detail = mudlet->mDiscord.getDetailText(mpHost);
if (!detail.isEmpty()) {
detail = QStringLiteral("(\"%1\")").arg(detail);
detail = QStringLiteral("<br/>(\"%1\")").arg(detail);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please note <br/> IS NOT VALID HTML! That is actually an XHTML tag - the one I think you should be using is <br> - as shown in https://doc.qt.io/qt-5/richtext-html-subset.html - Qt actually states in that link: "Qt's text widgets are able to display rich text, specified using a subset of HTML 4 markup."

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This tag works fine as intended in Qt

<img src=":/icons/discord-rich-presence-large-icon.png"/>
<p style="color: #989A9F;" id="large-icon">%2</p>
</td>
<td class="tg-jn9l"><p class="detail" id="detail">%3 %4</p></td>
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Needs one more space to be indented properly I think.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, fixed

@Kebap
Copy link
Copy Markdown
Contributor

Kebap commented Sep 30, 2018

Setting a custom discord application ID worked as expected and usingMudletDiscordID changed from true to false as well

@Kebap
Copy link
Copy Markdown
Contributor

Kebap commented Oct 2, 2018

For some reason now, in my test profile, I am allowed to check the "Discord" box upon connection, even though this is no "known" game at all. Is that intended behavior?

@Kebap
Copy link
Copy Markdown
Contributor

Kebap commented Oct 2, 2018

For some reason, now my tests won't work anymore. Not sure if it was setting that checkbox, or some foul play with setting and removing the custom application ID somehow, now all my set-commands will yield "true" but not display in Discord anymore. Will have to investigate further.

It seems the profile remembers, if I set a custom ID and then will activate the checkbox in connection dialogue, right?

@vadi2
Copy link
Copy Markdown
Member Author

vadi2 commented Oct 2, 2018

I'm not too certain, I'll look at that code. Discord box should only be enabled for "known" games and afaik there's no functionality to "remember" a game.

I'd like to build one in so games using GMCP don't have to wait for a Mudlet update in order to enable the box for them, but that's in the future.

@vadi2
Copy link
Copy Markdown
Member Author

vadi2 commented Oct 2, 2018

Yes, there's a feature that if a custom Discord ID was known, that game is remembered to have Discord support (thanks @SlySven!).

But that shouldn't break the set-commands, I'll have a look.

@vadi2
Copy link
Copy Markdown
Member Author

vadi2 commented Oct 2, 2018

Turning things on and off seems to work as expected here.

Copy link
Copy Markdown
Member

@keneanung keneanung left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I haven't tested it, but the lua part looks good.

The infrastructure part is something I'd like to see improved at some point (ew checking in binaries), but it's good enough for now.

@vadi2 vadi2 merged commit 4de6f97 into Mudlet:development Oct 5, 2018
@vadi2 vadi2 deleted the add-basic-gamekit branch October 5, 2018 04:26
@Kebap Kebap mentioned this pull request Jul 2, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants