mirror of
https://github.com/mkxp-z/mkxp-z.git
synced 2025-04-21 21:52:04 +02:00

rb_raise calls longjmp, which bypasses C++ destructors, and also keeps the error for catch blocks from being unallocated if passed by reference, which we do for exceptions. Some of the calls I left can still jump out of try blocks, which you're not supposed to do, but there shouldn't be any objects with destructors initialized at those points so it's probably fine.
222 lines
6 KiB
C++
222 lines
6 KiB
C++
#ifdef MKXPZ_STEAM
|
|
#include "binding-util.h"
|
|
#include "steamshim_child.h"
|
|
|
|
#define STEAMSHIM_GETV(t, v, d) \
|
|
while (STEAMSHIM_alive()) { \
|
|
const STEAMSHIM_Event *e = STEAMSHIM_pump(); \
|
|
if (e && e->type == t) { \
|
|
d = e->v; \
|
|
break; \
|
|
} \
|
|
}
|
|
|
|
#define STEAMSHIM_GETV_EXP(t, exp) \
|
|
while (STEAMSHIM_alive()) { \
|
|
const STEAMSHIM_Event *e = STEAMSHIM_pump(); \
|
|
if (e && e->type == t) { \
|
|
exp; \
|
|
break; \
|
|
} \
|
|
}
|
|
|
|
#define STEAMSHIM_GET_OK(t, d) STEAMSHIM_GETV(t, okay, d)
|
|
|
|
#define STEAMSHIM_GETV_AND_OK(t, v, dst, ok) \
|
|
while (STEAMSHIM_alive()) { \
|
|
const STEAMSHIM_Event *e = STEAMSHIM_pump(); \
|
|
if (e && e->type == t) { \
|
|
dst = e->v; \
|
|
ok = e->okay; \
|
|
break; \
|
|
} \
|
|
}
|
|
|
|
RB_METHOD_GUARD(CUSLSetStat) {
|
|
RB_UNUSED_PARAM;
|
|
|
|
VALUE name, stat;
|
|
rb_scan_args(argc, argv, "2", &name, &stat);
|
|
SafeStringValue(name);
|
|
|
|
bool ret;
|
|
if (RB_TYPE_P(stat, RUBY_T_FLOAT)) {
|
|
STEAMSHIM_setStatF(RSTRING_PTR(name), (float)RFLOAT_VALUE(stat));
|
|
STEAMSHIM_GET_OK(SHIMEVENT_SETSTATF, ret);
|
|
} else if (RB_TYPE_P(stat, RUBY_T_FIXNUM)) {
|
|
STEAMSHIM_setStatI(RSTRING_PTR(name), (int)NUM2INT(stat));
|
|
STEAMSHIM_GET_OK(SHIMEVENT_SETSTATI, ret);
|
|
} else {
|
|
throw Exception(Exception::TypeError,
|
|
"Statistic value must be either an integer or float.");
|
|
}
|
|
return rb_bool_new(ret);
|
|
}
|
|
RB_METHOD_GUARD_END
|
|
|
|
RB_METHOD(CUSLGetStatI) {
|
|
RB_UNUSED_PARAM;
|
|
|
|
VALUE name;
|
|
rb_scan_args(argc, argv, "1", &name);
|
|
SafeStringValue(name);
|
|
|
|
int resi;
|
|
bool valid;
|
|
|
|
STEAMSHIM_getStatI(RSTRING_PTR(name));
|
|
STEAMSHIM_GETV_AND_OK(SHIMEVENT_GETSTATI, ivalue, resi, valid);
|
|
|
|
if (!valid)
|
|
return Qnil;
|
|
|
|
return INT2NUM(resi);
|
|
}
|
|
|
|
RB_METHOD(CUSLGetStatF) {
|
|
RB_UNUSED_PARAM;
|
|
|
|
VALUE name;
|
|
rb_scan_args(argc, argv, "1", &name);
|
|
SafeStringValue(name);
|
|
|
|
float resf;
|
|
bool valid;
|
|
|
|
STEAMSHIM_getStatI(RSTRING_PTR(name));
|
|
STEAMSHIM_GETV_AND_OK(SHIMEVENT_GETSTATI, fvalue, resf, valid);
|
|
|
|
if (!valid)
|
|
return Qnil;
|
|
|
|
return rb_float_new(resf);
|
|
}
|
|
|
|
RB_METHOD(CUSLGetAchievement) {
|
|
RB_UNUSED_PARAM;
|
|
|
|
VALUE name;
|
|
rb_scan_args(argc, argv, "1", &name);
|
|
SafeStringValue(name);
|
|
|
|
bool ret;
|
|
bool valid;
|
|
|
|
STEAMSHIM_getAchievement(RSTRING_PTR(name));
|
|
STEAMSHIM_GETV_AND_OK(SHIMEVENT_GETACHIEVEMENT, ivalue, ret, valid);
|
|
|
|
if (!valid)
|
|
return Qnil;
|
|
|
|
return rb_bool_new(ret);
|
|
}
|
|
|
|
RB_METHOD(CUSLSetAchievement) {
|
|
RB_UNUSED_PARAM;
|
|
|
|
VALUE name;
|
|
rb_scan_args(argc, argv, "1", &name);
|
|
SafeStringValue(name);
|
|
|
|
bool ret;
|
|
STEAMSHIM_setAchievement(RSTRING_PTR(name), true);
|
|
STEAMSHIM_GET_OK(SHIMEVENT_SETACHIEVEMENT, ret);
|
|
return rb_bool_new(ret);
|
|
}
|
|
|
|
RB_METHOD(CUSLClearAchievement) {
|
|
RB_UNUSED_PARAM;
|
|
|
|
VALUE name;
|
|
|
|
rb_scan_args(argc, argv, "1", &name);
|
|
SafeStringValue(name);
|
|
|
|
bool ret;
|
|
STEAMSHIM_setAchievement(RSTRING_PTR(name), false);
|
|
STEAMSHIM_GET_OK(SHIMEVENT_SETACHIEVEMENT, ret);
|
|
return rb_bool_new(ret);
|
|
}
|
|
|
|
RB_METHOD(CUSLGetAchievementAndUnlockTime) {
|
|
RB_UNUSED_PARAM;
|
|
|
|
VALUE name;
|
|
|
|
rb_scan_args(argc, argv, "1", &name);
|
|
SafeStringValue(name);
|
|
|
|
bool achieved;
|
|
unsigned long long time;
|
|
bool valid;
|
|
|
|
STEAMSHIM_getAchievement(RSTRING_PTR(name));
|
|
STEAMSHIM_GETV_EXP(SHIMEVENT_GETACHIEVEMENT, {
|
|
valid = e->okay;
|
|
achieved = e->ivalue;
|
|
time = e->epochsecs;
|
|
});
|
|
|
|
if (!valid)
|
|
return Qnil;
|
|
|
|
VALUE ret = rb_ary_new();
|
|
rb_ary_push(ret, rb_bool_new(achieved));
|
|
|
|
if (!time) {
|
|
rb_ary_push(ret, Qnil);
|
|
return ret;
|
|
}
|
|
|
|
VALUE t = rb_funcall(rb_cTime, rb_intern("at"), 1, ULL2NUM(time));
|
|
rb_ary_push(ret, t);
|
|
return ret;
|
|
}
|
|
|
|
RB_METHOD(CUSLStoreStats) {
|
|
RB_UNUSED_PARAM;
|
|
|
|
rb_check_argc(argc, 0);
|
|
bool ok;
|
|
|
|
STEAMSHIM_storeStats();
|
|
STEAMSHIM_GET_OK(SHIMEVENT_STATSSTORED, ok);
|
|
return rb_bool_new(ok);
|
|
}
|
|
|
|
RB_METHOD(CUSLResetAllStats) {
|
|
RB_UNUSED_PARAM;
|
|
|
|
bool achievementsToo;
|
|
|
|
rb_get_args(argc, argv, "b", &achievementsToo);
|
|
|
|
STEAMSHIM_resetStats(achievementsToo);
|
|
STEAMSHIM_GET_OK(SHIMEVENT_RESETSTATS, achievementsToo);
|
|
return rb_bool_new(achievementsToo);
|
|
}
|
|
|
|
void CUSLBindingInit() {
|
|
|
|
STEAMSHIM_requestStats();
|
|
bool ok;
|
|
STEAMSHIM_GET_OK(SHIMEVENT_STATSRECEIVED, ok);
|
|
|
|
VALUE mSteamLite = rb_define_module("SteamLite");
|
|
|
|
_rb_define_module_function(mSteamLite, "get_stat_i", CUSLGetStatI);
|
|
_rb_define_module_function(mSteamLite, "get_stat_f", CUSLGetStatF);
|
|
_rb_define_module_function(mSteamLite, "set_stat", CUSLSetStat);
|
|
|
|
_rb_define_module_function(mSteamLite, "store_stats", CUSLStoreStats);
|
|
|
|
_rb_define_module_function(mSteamLite, "get_achievement", CUSLGetAchievement);
|
|
_rb_define_module_function(mSteamLite, "set_achievement", CUSLSetAchievement);
|
|
_rb_define_module_function(mSteamLite, "clear_achievement",
|
|
CUSLClearAchievement);
|
|
_rb_define_module_function(mSteamLite, "get_achievement_and_unlock_time",
|
|
CUSLGetAchievementAndUnlockTime);
|
|
|
|
_rb_define_module_function(mSteamLite, "reset_all_stats", CUSLResetAllStats);
|
|
}
|
|
#endif
|