Use a default internal Discord Activity on startup

This commit is contained in:
Inori 2019-09-04 17:25:35 -04:00 committed by Inori
parent c9135f1b74
commit 866692b43a
6 changed files with 78 additions and 25 deletions

View file

@ -84,6 +84,10 @@ In the RMXP version of RGSS, fonts are loaded directly from system specific sear
If a requested font is not found, no error is generated. Instead, a built-in font is used. By default, this font is Liberation Sans. WenQuanYi MicroHei is used as the built-in font if the `cjk_fallback_font` option is used.
## Discord Support
mkxp-z can optionally be built with support for the Discord GameSDK. Currently only basic Activity (rich presence) functionality is implemented.
## Win32API
Win32API exists in mkxp-z as both `Win32API.new` and `MiniFFI.new` (This class is available under macOS, linux and Windows and "Win32API" as a name makes no sense on the former two platforms). It functions nearly the same as Ruby 1.8's Win32API, for better or worse. The third and fourth arguments are now optional (if you just want a function that takes no arguments and returns nothing, for instance), and `new` will yield to blocks. Being simple as it is, it remains mostly as the lazy option/last resort to add C functions from shared libraries if you can't/don't want to build mkxp-z yourself.

View file

@ -44,19 +44,6 @@ RB_METHOD(DiscordGetUserId)
return LL2NUM(shState->discord().userId());
}
RB_METHOD(DiscordActivityInitialize)
{
RB_UNUSED_PARAM;
DiscordActivity *activity = ALLOC(DiscordActivity);
setPrivateData(self, activity);
memset(activity, 0, sizeof(DiscordActivity));
activity->type = DiscordActivityType_Playing;
return self;
}
RB_METHOD(DiscordActivitySend)
{
RB_UNUSED_PARAM;
@ -69,6 +56,25 @@ RB_METHOD(DiscordActivitySend)
return Qnil;
}
RB_METHOD(DiscordActivityInitialize)
{
RB_UNUSED_PARAM;
DiscordActivity *activity = ALLOC(DiscordActivity);
setPrivateData(self, activity);
memset(activity, 0, sizeof(DiscordActivity));
activity->type = DiscordActivityType_Playing;
if (rb_block_given_p())
{
rb_yield(self);
return DiscordActivitySend(0, 0, self);
};
return self;
}
RB_METHOD(DiscordActivityClear)
{
RB_UNUSED_PARAM;
@ -78,6 +84,26 @@ RB_METHOD(DiscordActivityClear)
return Qnil;
}
#define DEF_DCPROP_ACTPARTYSZ(n) \
RB_METHOD(DiscordActivityGetParty##n) \
{ \
RB_UNUSED_PARAM; \
DiscordActivity *p = getPrivateData<DiscordActivity>(self); \
return INT2NUM(p->party.size.n); \
} \
RB_METHOD(DiscordActivitySetParty##n) \
{ \
RB_UNUSED_PARAM; \
int num; \
rb_get_args(argc, argv, "i", &num); \
DiscordActivity *p = getPrivateData<DiscordActivity>(self); \
p->party.size.n = num; \
return INT2NUM(num); \
}
DEF_DCPROP_ACTPARTYSZ(current_size);
DEF_DCPROP_ACTPARTYSZ(max_size);
#define DEF_DCPROP_S(basename, propname, maxsz) \
RB_METHOD(Discord##basename##Get##propname) \
{ \
@ -182,7 +208,6 @@ p->subname.propname = b; \
return rb_bool_new(b); \
}
DEF_DCPROP_S(Activity, name, 128);
DEF_DCPROP_S(Activity, state, 128);
DEF_DCPROP_S(Activity, details, 128);
DEF_DCPROP_S_SUB(Activity, assets, large_image, 128);
@ -192,9 +217,9 @@ DEF_DCPROP_S_SUB(Activity, assets, small_text, 128);
DEF_DCPROP_S_SUB(Activity, secrets, match, 128);
DEF_DCPROP_S_SUB(Activity, secrets, join, 128);
DEF_DCPROP_S_SUB(Activity, secrets, spectate, 128);
DEF_DCPROP_S_SUB(Activity, party, id, 128);
DEF_DCPROP_I(Activity, type, INT, EDiscordActivityType);
DEF_DCPROP_I(Activity, application_id, LL, int64_t);
DEF_DCPROP_I_SUB(Activity, timestamps, start, LL, DiscordTimestamp);
DEF_DCPROP_I_SUB(Activity, timestamps, end, LL, DiscordTimestamp);
DEF_DCPROP_B(Activity, instance);
@ -225,7 +250,6 @@ void DiscordBindingInit()
_rb_define_method(activityClass, "send", DiscordActivitySend);
BIND_DCPROP(Activity, "name", name);
BIND_DCPROP(Activity, "state", state);
BIND_DCPROP(Activity, "details", details);
BIND_DCPROP(Activity, "large_image", assets_large_image);
@ -235,9 +259,11 @@ void DiscordBindingInit()
BIND_DCPROP(Activity, "match_secret", secrets_match);
BIND_DCPROP(Activity, "join_secret", secrets_join);
BIND_DCPROP(Activity, "spectate_secret", secrets_spectate);
BIND_DCPROP(Activity, "party_id", party_id);
BIND_DCPROP(Activity, "party_currentsize", Partycurrent_size);
BIND_DCPROP(Activity, "party_maxsize", Partymax_size);
BIND_DCPROP(Activity, "type", type);
BIND_DCPROP(Activity, "application_id", application_id);
BIND_DCPROP(Activity, "start_time", timestamps_start);
BIND_DCPROP(Activity, "end_time", timestamps_end);
BIND_DCPROP(Activity, "instance", instance);

View file

@ -305,3 +305,11 @@
# (default: none)
#
# titleLanguage=japanese
# The Discord Client ID for your application. If left undefined,
# mkxp-z's Client ID is used by default.
# Only has an effect if mkxp-z is built with Discord support.
#
# discordClientId=1234567890

View file

@ -1,11 +1,17 @@
#include <discord_game_sdk.h>
#include <time.h>
#include "sharedstate.h"
#include "eventthread.h"
#include "discordstate.h"
#include "exception.h"
#include "debugwriter.h"
#include "bitmap.h"
#include "config.h"
void defaultActivityCb(void *callback_data, enum EDiscordResult result)
{
}
struct Application {
struct IDiscordCore* core;
@ -20,6 +26,8 @@ struct Application {
struct DiscordStatePrivate
{
RGSSThreadData *threadData;
DiscordClientId clientId;
IDiscordCore *core;
@ -29,6 +37,7 @@ struct DiscordStatePrivate
IDiscordUserEvents userEvents;
DiscordUser currentUser;
DiscordActivity defaultActivity;
bool discordInstalled;
bool connected;
@ -105,23 +114,29 @@ int discordTryConnect(DiscordStatePrivate *p)
if (rc != DiscordResult_Ok)
return rc;
p->core->set_log_hook(p->core, DiscordLogLevel_Debug, (void*)p, discordLogHook);
p->core->set_log_hook(p->core, DiscordLogLevel_Error, (void*)p, discordLogHook);
p->app.activities = p->core->get_activity_manager(p->core);
p->app.users = p->core->get_user_manager(p->core);
p->connected = true;
strncpy((char*)&p->defaultActivity.details, p->threadData->config.game.title.c_str(), 128);
p->defaultActivity.timestamps.start = time(0);
p->app.activities->update_activity(p->app.activities, &p->defaultActivity, 0, defaultActivityCb);
return rc;
}
DiscordState::DiscordState(DiscordClientId clientId, int *result)
DiscordState::DiscordState(RGSSThreadData *rtData)
{
p = new DiscordStatePrivate();
p->threadData = rtData;
memset(&p->app, 0, sizeof(Application));
p->clientId = clientId;
int rc = discordTryConnect(p);
if (result) *result = rc;
p->clientId = rtData->config.discordClientId;
discordTryConnect(p);
}
DiscordState::~DiscordState()

View file

@ -12,7 +12,7 @@ struct DiscordStatePrivate;
class DiscordState
{
public:
DiscordState(DiscordClientId clientId, int *result);
DiscordState(RGSSThreadData *rtData);
~DiscordState();
IDiscordActivityManager *activityManager();

View file

@ -115,7 +115,7 @@ struct SharedStatePrivate
config(threadData->config),
midiState(threadData->config),
#ifdef HAVE_DISCORDSDK
discord(threadData->config.discordClientId, 0),
discord(threadData),
#endif
graphics(threadData),
input(*threadData),