-
Notifications
You must be signed in to change notification settings - Fork 559
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add Discord Game SDK support #1217
base: master
Are you sure you want to change the base?
Conversation
Looking it over I'm surprised you can't SDL_LoadObject and then load DiscordCreate... seems like they do everything right, it's versioned properly and the rest of the API is a function table to avoid needing more exports. Do they mention any specific reason that dlopening doesn't work? Aside from that this looks okay; we might be able to avoid a lot of the build system goo if we can dynamically load like the other network backends. |
I'm a real newbie to C/C++ and honestly do not understand how to dynamically load in the way that you do with the function tables. Also, adding libdiscord_game_sdk.so to the linker options does not actually merge it into the VVVVVV executable, it just fufills the headerfiles needs for the function calls that the SDK uses. |
This is definitely worth checking out: https://wiki.libsdl.org/SDL2/SDL_LoadObject The idea is that instead of linking the SDK, we just use the headers to get the type declarations, and then store a pointer to the DiscordCreate function. We initialize the pointer by dynamically loading the SDK, then loading the function by its name. You can see this in the other network files as an example. |
Ahh that is interesting. So you are not talking about removing the headerfile completely, only keeping the structs. Nice, I can definitely do that. |
@flibitijibibo I've done your requests and the PR is almost ready! I just need to fix some potential crashes! |
Very strange finding...
|
Huh. Moving the sdl2 header up worked. Huh..... :/ |
Ready for review 👍 |
I'm wondering how this should work with localization. Ideally, every Discord user who sees the status messages sees them in their own chosen Discord language, not whatever language the player (the sender) happens to use. But unfortunately Discord does not support that at all - the game can only pass one string, and that string is shown worldwide. So I'm not sure that string should be in the player's language... For example, I may prefer to have my game and my Discord in Dutch, but pretty much all my online friends are from other countries and I talk to them in English. We've always made the localization features such that players should never have to feel forced to switch their game to English because of some kind of disadvantage, or accidentally reveal their in-game language to others when they wanted to keep it anonymous where they come from. So... I guess the lesser evil would be to force Rich Presence in English for now and call it a Discord L, and see if they add proper multi-language support later. Or we could maybe add a game option whether to translate Rich Presence status messages or not (we already have a lot of options, though...) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just did some light code quality scanning, no in-depth review yet.
Yes, I could do that very easily. |
Oops! Minor mistake, only happened because I had an old build of my pull request installed onto steam. It's totally fine. |
Oops (again) when running the build without discord, BOOM! A segfault. Patch incoming, lemme debug with GDB first. |
Well, I patched it. I think it is finally ready for a merge. Merge when you want to, for now feel free to review the code. I will play my version of VVVVVV and look for potential segfaults for now. Bye! |
…rd would see it in the player's language.
@Daaaav I have completely finished your requests. (I forgot to remove the localisation but now that's done) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Did a slightly more thorough review of the code - and of course we're still gonna need to test this.
desktop_version/src/DiscordNetwork.c
Outdated
discordCrashes = 0; | ||
} | ||
|
||
void DISCORD_update(const char *level, const char *name) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd probably rename level
and name
to something like area
and roomname
, to make them clearer. Also, code style thing: we put the *
with the type, not the variable name. (I see it's that way in the existing Steam code but we've been consistent in all new code)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Daaaav GOGNetwork does not have the type* naming convention for functions I didn't implement, so I added that too. Should I just keep to my Discord implementation? Or would this fix be acceptable as part of this PR?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd say it'd be acceptable to move spaces in the GOG/Steam code so that you don't have to add new code that either introduces type *
convention or is inconsistent with the existing code. For more unrelated parts (functions you didn't implement for Discord but which were in the same GOG/Steam files you were already making consistency fixes in... Eh. Might as well.
- remove more useless headerfiles - rename [level, name] to [area, roomname] - remove 10 repeats fallback - do not update_activity if it is the same value as last DISCORD_update - fix bug with DiscordCreate failure handling - rename (and invert) discordNotDetected to discordDetected
One of the nice things about this PR is that if anyone wants to implement another type of RPC (eg Steam RPC) they already got a baseplate set up for them :D |
Happy new year! To be clear, to my knowledge it's not planned for 2.5 to be released within the coming month. Unless you meant pushed to the repo and not pushed to store shelves, that one is realistic... |
Alright let's just push to the repo. I would have though something would happen with VVVVVV's 15th anniversary but if not, it's totally fine. |
@flibitijibibo @Daaaav Can we please get this pushed soon? I don’t want this PR to go stale like it has for the past 9 days. I just want at least some activity (playtesting, etc) |
I've been stuck on SDL3 for a while (RC1 coming soon!) so I've not been able to check this out - upstream doesn't move very fast so even if this takes a while to review it shouldn't have to get rebased or anything like that since I can't really merge other stuff either. |
Not to be rude, but you need to chill out... This is an entirely nonessential feature which has required a lot of intervention from maintainers and those more familiar with the codebase to fix bugs and and follow guidelines. 9 days is not a long time at all - being this impatient is really immature |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The new Network backend is pretty good, but how its features are integrated could be less invasive.
Separately we should implement Steam rich presence, which thankfully is a one-liner: https://partner.steamgames.com/doc/features/enhancedrichpresence
A good reason to do this is to prepare localized strings:
https://partner.steamgames.com/doc/api/ISteamFriends#richpresencelocalization
If this is too much to do in one patch then we could split this up into two parts, where one part is rich presence and the second part is Discord integration. (Discord could be done first FWIW, it just wouldn't be fancy integration at first.)
#define DISCORD_CLIENT_ID 1315544357532729447 | ||
|
||
// TO TERRY/FLIBIT: You can create your own Discord instance at the Discord Developer Portal. This ID belongs to me, so just be aware that if my account was to get hacked, VVVVVV RPC would too. Use your own! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We'll need to lock this in before we can merge, so whoever can find this number should patch this line ASAP
desktop_version/src/DiscordNetwork.c
Outdated
} | ||
if (!DISCORD_REQUIRE(app.core->run_callbacks(app.core))) | ||
{ | ||
// Something or other is wrong, but do we care? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Probably not, but Discord support might...? Not sure what their policy is on reporting internal errors
(By the way, we haven't playtested yet, so please also wait with merging until we've had the chance to do that.) (We have actually attempted to start playtesting but got stopped by some UB on Windows. So we're still working on it) |
@flibitijibibo I would be happy to expand this PR to include the Steam network RPC (you may have noticed my comment in the code lol), as the way you’ve got it set up makes it really easy. And also make it less invasive (I’m thinking run NETWORK_setRPC only when RPC is actually updated, running NETWORK_update each frame separately) However as of now I am on holidays and won’t get back to my computers for the next week or so. Feel free to suggest changes while I’m out, all of them will be greatly thanked and considered. |
I'm back and WHAT?? Undefined behavior? It's working for me... |
"About that Client ID I owe ya..." Ask Terry to do it or maybe you can do it yourself. I got a response but they said "there is a ID for VVVVVV, but we can only provide to people on the dev team". You have access to the Steamworks profile for VVVVVV, right (I saw you posting announcements) so maybe you can do it. Feel free to do it once you've finished the SDL3 pr, we can keep the placeholder for the time being |
@mothbeanie My past PR's to other very niche repos have been merged in less than a day without pinging people... so... ¯_(ツ)_/¯ |
Yes, something about incorrect calling convention that only affects Windows.
I have a feeling those past PRs might've been very small changes that were easy to instantly see they were correct? For this, we need to set aside parts of our free time to test thoroughly. And we have more things to do. This isn't critical. |
Thanks Flibit for the idea! :D
Co-authored-by: Ethan Lee <[email protected]>
Yep I understand. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's definitely getting better - here's another quick review.
#if NUM_BACKENDS > 0 | ||
int32_t i; | ||
for (i = 0; i < NUM_BACKENDS; i += 1) | ||
if (backends[i].IsInit) | ||
{ | ||
backends[i].Update(); | ||
if ( backends[i].Update() ) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We don't need to worry about Update status too much - as long as we do a good job with SetRPC this can stay as-is.
Co-authored-by: Ethan Lee <[email protected]>
Hmm something you commited made it not work... I'm looking through the code right now but it all looks good... debugging. Oh yeah and by "make it not work" I mean level changes dont quite register as they should |
OH YES I THINK I GOT IT! It's the POINTERS!!!!!!!!!!!!!!! oh shit fixing it is insane difficulty |
Fixed the pointers... but the fix SUCKS! It just makes it slower when your original changes were to make it faster. Or maybe it doesnt make it slower idk |
I've implemented Steam rich presence here: leo60228@418ff07 This expects localization strings added in Steamworks along these lines: "lang"
{
"english"
{
"tokens"
{
"#Default" "%area%"
"#NamedRoom" "%area%: %name%"
}
}
} Ideally, this would support localized room/area names, but this would significantly complicate both implementation and deployment. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This mostly looks good, though I found a number of minor nitpicks.
#define DISCORD_CLIENT_ID 1315544357532729447 | ||
|
||
// TO TERRY/FLIBIT: You can create your own Discord instance at the Discord Developer Portal. This ID belongs to me, so just be aware that if my account was to get hacked, VVVVVV RPC would too. Use your own! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The automatically assigned application ID is 491427544134975498
, but this doesn't currently work for rich presence. I'm not sure if the Discord Store release had a separate application ID.
|
||
int32_t DISCORD_init(void) | ||
{ | ||
#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__HAIKU__) || defined(__DragonFly__) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should probably be rewritten to check for OSes that Discord does support, rather than ones it doesn't.
|
||
app.activityMan->update_activity(app.activityMan, &activity, NULL, NULL); | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Newlines in this file seem generally inconsistent. This should probably be cleaned up.
} | ||
else | ||
{ | ||
char nextArea[RPC_SAFE_BUFFER] = "", nextRoom[RPC_SAFE_BUFFER] = ""; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This line is indented incorrectly.
// Dirty fix for custom levels getting the area from Dimension VVVVVV | ||
if (map.custommode) | ||
{ | ||
SDL_strlcpy(nextArea, game.customleveltitle.c_str(), RPC_SAFE_BUFFER-1); | ||
} | ||
else | ||
{ | ||
SDL_strlcpy(nextArea, map.currentarea(game.roomx, game.roomy), RPC_SAFE_BUFFER-1); | ||
} | ||
SDL_strlcpy(nextRoom, map.roomname, RPC_SAFE_BUFFER-1); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should only run in GAMEMODE.
// Update network per frame. | ||
NETWORK_update(); | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This line seems to have been added by accident.
//printf("room %s == %s, area %s == %s\n", rpcRoomname, nextRoom, rpcArea, nextArea); | ||
if ((SDL_strcmp(rpcArea, nextArea) != 0) || (SDL_strcmp(rpcRoomname, nextRoom) != 0)) | ||
{ | ||
// FIXME BEFORE PUSHING!!: These pointers aren't safe to use and result in RPC not updating when it needs to. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this still apply?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
no i fixed it, i just forgot to remove it
Changes:
Finished!
I would love to hear your thoughts on this change, and any improvements or suggestions are more than welcome.
Legal Stuff:
By submitting this pull request, I confirm that...
CONTRIBUTORS
file and the "GitHub Friends"section of the credits for all of said releases, but will NOT be compensated
for these changes unless there is a prior written agreement