JnCrMx / discord-game-sdk4j

Java bindings for Discord's Game SDK
MIT License
121 stars 23 forks source link

Discord is forcibly started and the application is terminated #53

Open BullyWiiPlaza opened 2 years ago

BullyWiiPlaza commented 2 years ago

This is a weird problem because it seems to behave in an inconsistent way but a user reported with video proof that my application which uses discord-game-sdk4j will cause Discord to be started and on CMD the following is printed out:

Discord 1.0.9006
Starting app.
Starting updater.
Module ./ElectronTestRpc was not included.
WEIGHT \\?\C:\Users\<my user name>\AppData\Local\Discord\app-1.0.9006\modules\discord_krisp-1\discord_krisp\NC_small_8k.thw
WEIGHT \\?\C:\Users\<my user name>\AppData\Local\Discord\app-1.0.9006\modules\discord_krisp-1\discord_krisp\NC_small_16k.thw
WEIGHT \\?\C:\Users\<my user name>\AppData\Local\Discord\app-1.0.9006\modules\discord_krisp-1\discord_krisp\c6.s.f.27f1a3.thw
WEIGHT \\?\C:\Users\<my user name>\AppData\Local\Discord\app-1.0.9006\modules\discord_krisp-1\discord_krisp\VAD_weight.thw

image

Also when this happens the main GUI/application is terminated in an instant. I assume that might have caused a Java VM crash but there is no respective crash log. If that user replaces the downloaded discord_game_sdk.dll with a corrupted one, Core.init() will fail with an UnsatisfiedLinkError and therefore the "weird" behavior explained above stops occurring and everything is back to "normal" besides the fact that the Discord SDK isn't working obviously.

If the above does not occur, if I start my application while Discord is closed and then terminate the application, I get the following exception upon closing the SDK:

[ERROR] Failed to configure networking: ResponseError { code: TransactionAborted, message: "Transaction was aborted" }
Exception in thread "Thread-11" de.jcm.discordgamesdk.GameSDKException: Game SDK operation failed: TRANSACTION_ABORTED
        at de.jcm.discordgamesdk.Core.lambda$static$0(Core.java:386)
        at de.jcm.discordgamesdk.Core.destroy(Native Method)
        at de.jcm.discordgamesdk.Core.close(Core.java:628)

Also, the activity state updates do not start working when I start Discord manually after the application has initialized the Discord SDK already. I basically need to have Discord already running for this to work properly.

Any ideas or fixes? I would prefer if the library does not ever start Discord on its own, does not crash the application or the JVM and just provides the Discord RPC functionality when Discord is open, similar to this project which is now deprecated. Besides on Mac OS X I didn't observe any issue using it (https://github.com/discord/discord-rpc/issues/170).

JnCrMx commented 2 years ago

It is the default behaviour of the Discord Game SDK to try to launch the current application via Discord (and thereby also launch Discord) if Discord is not opened, but installed. I also dislike this behaviour and would much prefer there to be an error code or exception I could work with, however the library calls ``exit``` (the C function) directly and intercepting that is possible, but extremly dirty.

However, there is a simple way around that: Specificying the NoRequireDiscord in the CreateParams of the Core. Please refer to the official documentation for more details on it: https://discord.com/developers/docs/game-sdk/discord#data-models-createflags-enum. If you create the Core with this flag, it will work even if Discord is not open or installed. However, of course no functionality will be available and trying to use any will result in exception (which you can catch and handle).

For an example, look at one of my projects using this library: https://github.com/JnCrMx/MinecraftDiscordLobbies/blob/1.16.4/src/main/java/com/github/JnCrMx/discordlobbies/DiscordLobbiesMod.java#L185 It calls runCallbacks once to see if Discord is present. If runCallbacks fails (i.e. throws an exception), it stores that Discord is not present and will disable functionality accordingly.

BullyWiiPlaza commented 2 years ago

Hi, thanks a lot, using NoRequireDiscord helped significantly. Actually, the statement new Core(parameters) throws a GameSDKException and does not even get to core.runCallbacks().

Another issue I see is when Discord is closed and restarted. The SDK would have to be re-initialized somehow because it just stops working in that case. I tried to keep creating a Core object and if it failed I would close() my main discordAPI class instance (activity.close(); core.close();). However, this breaks updating the activity state in general so I had to remove the following else branch again:

while (...)
{
    if (discordAPI == null)
    {
        discordAPI = getDiscordAPI();
        discordAPI.runCallbacksAsync();
        LOGGER.info("Discord game SDK successfully initialized...");
    } else
    {
        try
        {
            DiscordGameAPI temporaryDiscordAPI = getDiscordAPI();
            temporaryDiscordAPI.close();
        } catch (final GameSDKException exception)
        {
            LOGGER.info("Closing Discord API since Discord is closed...");
            discordAPI.close();

            // Discord is not running
            discordAPI = null;
        }
    }

    Thread.sleep(...);
}

Is there any elegant way to solve this?

JnCrMx commented 2 years ago

There is no elegant way to solve this, but maybe a slightly better one: Do a userManager().getUser request for a well-known user ID and check if the callback is called in time (like give it a second max or so). If not, Discord is most likely closed.

I know that the solution is not good at all, but for now it is the best I can think of. I am currently working at implementing the SDK in pure Java without using Discord's natives at all, and this implementation will hopefully have a better solution for this issue.

Another, but platform-specific way might be to just check if the socket (either Unix Socket or probably a port or something under Windows) is still open.