Implement SteamUserStatsLite

This commit is contained in:
Struma 2020-02-28 03:23:16 -05:00 committed by Roza
parent d722c70a07
commit bc7709fb53
8 changed files with 335 additions and 3 deletions

View file

@ -96,6 +96,10 @@ void MiniFFIBindingInit();
void DiscordBindingInit();
#endif
#ifdef HAVE_STEAMWORKS
void CUSLBindingInit();
#endif
RB_METHOD(mriPrint);
RB_METHOD(mriP);
RB_METHOD(mkxpDataDirectory);
@ -146,6 +150,10 @@ static void mriBindingInit() {
DiscordBindingInit();
#endif
#ifdef HAVE_STEAMWORKS
CUSLBindingInit();
#endif
if (rgssVer >= 3) {
_rb_define_module_function(rb_mKernel, "rgss_main", mriRgssMain);
_rb_define_module_function(rb_mKernel, "rgss_stop", mriRgssStop);

245
binding/cusl-binding.cpp Normal file
View file

@ -0,0 +1,245 @@
#include "binding-util.h"
#include <steam/isteamapps.h>
#include <steam/isteamuserstats.h>
// This is a simple implementation of Steam's user stats.
// Basically, a C++ version of this:
// https://github.com/GMMan/RGSS_SteamUserStatsLite
// May or may not be expanded in the future.
RB_METHOD(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)) {
ret =
SteamUserStats()->SetStat(RSTRING_PTR(name), (float)RFLOAT_VALUE(stat));
} else if (RB_TYPE_P(stat, RUBY_T_FIXNUM)) {
ret = SteamUserStats()->SetStat(RSTRING_PTR(name), (int)NUM2INT(stat));
} else {
rb_raise(rb_eTypeError,
"Statistic value must be either an integer or float.");
}
return rb_bool_new(ret);
}
RB_METHOD(CUSLGetStat) {
RB_UNUSED_PARAM;
VALUE name;
rb_scan_args(argc, argv, "1", &name);
SafeStringValue(name);
int resi;
float resf;
if (SteamUserStats()->GetStat(RSTRING_PTR(name), &resi)) {
return INT2NUM(resi);
} else if (SteamUserStats()->GetStat(RSTRING_PTR(name), &resf)) {
return rb_float_new(resf);
} else {
return Qnil;
}
}
RB_METHOD(CUSLUpdateAvgRateStat) {
RB_UNUSED_PARAM;
VALUE name, sessioncount, sessionlength;
rb_scan_args(argc, argv, "3", &name, &sessioncount, &sessionlength);
SafeStringValue(name);
Check_Type(sessioncount, RUBY_T_FLOAT);
Check_Type(sessionlength, RUBY_T_FLOAT);
bool ret = SteamUserStats()->UpdateAvgRateStat(
RSTRING_PTR(name), RFLOAT_VALUE(sessioncount), NUM2DBL(sessionlength));
return rb_bool_new(ret);
}
RB_METHOD(CUSLGetAchievement) {
RB_UNUSED_PARAM;
VALUE name;
rb_scan_args(argc, argv, "1", &name);
SafeStringValue(name);
bool ret;
bool valid = SteamUserStats()->GetAchievement(RSTRING_PTR(name), &ret);
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 = SteamUserStats()->SetAchievement(RSTRING_PTR(name));
return rb_bool_new(ret);
}
RB_METHOD(CUSLClearAchievement) {
RB_UNUSED_PARAM;
VALUE name;
rb_scan_args(argc, argv, "1", &name);
SafeStringValue(name);
bool ret = SteamUserStats()->ClearAchievement(RSTRING_PTR(name));
return rb_bool_new(ret);
}
RB_METHOD(CUSLGetAchievementAndUnlockTime) {
RB_UNUSED_PARAM;
VALUE name;
rb_scan_args(argc, argv, "1", &name);
SafeStringValue(name);
bool achieved;
uint time;
if (!SteamUserStats()->GetAchievementAndUnlockTime(RSTRING_PTR(name),
&achieved, &time))
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, UINT2NUM(time));
rb_ary_push(ret, t);
return ret;
}
RB_METHOD(CUSLGetAchievementDisplayAttribute) {
RB_UNUSED_PARAM;
VALUE name, key;
rb_scan_args(argc, argv, "2", &name, &key);
SafeStringValue(name);
SafeStringValue(key);
const char *ret = SteamUserStats()->GetAchievementDisplayAttribute(
RSTRING_PTR(name), RSTRING_PTR(key));
return rb_str_new_cstr(ret);
}
RB_METHOD(CUSLIndicateAchievementProgress) {
RB_UNUSED_PARAM;
VALUE name, progress, max;
rb_scan_args(argc, argv, "3", &name, &progress, &max);
SafeStringValue(name);
bool ret = SteamUserStats()->IndicateAchievementProgress(
RSTRING_PTR(name), NUM2UINT(progress), NUM2UINT(max));
if (ret)
return rb_bool_new(SteamUserStats()->StoreStats());
return rb_bool_new(ret);
}
RB_METHOD(CUSLGetNumAchievements) {
RB_UNUSED_PARAM;
rb_check_argc(argc, 0);
return UINT2NUM(SteamUserStats()->GetNumAchievements());
}
RB_METHOD(CUSLGetAchievementName) {
RB_UNUSED_PARAM;
VALUE index;
rb_scan_args(argc, argv, "1", &index);
return rb_str_new_cstr(SteamUserStats()->GetAchievementName(NUM2UINT(index)));
}
RB_METHOD(CUSLStoreStats) {
RB_UNUSED_PARAM;
rb_check_argc(argc, 0);
return rb_bool_new(SteamUserStats()->StoreStats());
}
RB_METHOD(CUSLResetAllStats) {
RB_UNUSED_PARAM;
bool achievementsToo;
rb_get_args(argc, argv, "b", &achievementsToo);
return rb_bool_new(SteamUserStats()->ResetAllStats(achievementsToo));
}
RB_METHOD(CUSLIsSubscribed) {
RB_UNUSED_PARAM;
rb_check_argc(argc, 0);
return rb_bool_new(SteamApps()->BIsSubscribed());
}
RB_METHOD(CUSLIsDlcInstalled) {
RB_UNUSED_PARAM;
VALUE appid;
rb_scan_args(argc, argv, "1", &appid);
return rb_bool_new(SteamApps()->BIsDlcInstalled(NUM2UINT(appid)));
}
void CUSLBindingInit() {
SteamUserStats()->RequestCurrentStats();
VALUE mSteamLite = rb_define_module("SteamLite");
_rb_define_module_function(mSteamLite, "subscribed?", CUSLIsSubscribed);
_rb_define_module_function(mSteamLite, "dlc_installed?", CUSLIsDlcInstalled);
_rb_define_module_function(mSteamLite, "get_stat", CUSLGetStat);
_rb_define_module_function(mSteamLite, "set_stat", CUSLSetStat);
_rb_define_module_function(mSteamLite, "update_avg_rate_stat",
CUSLUpdateAvgRateStat);
_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, "get_achievement_display_attribute",
CUSLGetAchievementDisplayAttribute);
_rb_define_module_function(mSteamLite, "indicate_achievement_progress",
CUSLIndicateAchievementProgress);
_rb_define_module_function(mSteamLite, "get_num_achievements",
CUSLGetNumAchievements);
_rb_define_module_function(mSteamLite, "get_achievement_name",
CUSLGetAchievementName);
_rb_define_module_function(mSteamLite, "reset_all_stats", CUSLResetAllStats);
}

View file

@ -41,6 +41,10 @@ if discord == true
binding_source += files('discord-binding.cpp')
endif
if steamworks == true
binding_source += files('cusl-binding.cpp')
endif
if miniffi == true
binding_source += files('miniffi-binding.cpp')
endif

View file

@ -269,7 +269,10 @@ RB_METHOD(MiniFFI_call) {
(unsigned long)ApiFunction(params[0], params[1], params[2], params[3],
params[4], params[5], params[6], params[7]);
// Setting stdcall doesn't work anymore, I HATE WINDOWS
// Telling the compiler that the called function uses stdcall
// apparently doesn't work anymore, so assembly is used instead.
// Technically also allows for an unlimited number of arguments,
// but the above code does not
#else
unsigned long ret = 0;
asm volatile(".intel_syntax noprefix\n"

View file

@ -18,6 +18,10 @@ global_include_dirs = []
global_args = []
global_link_args = []
sizeof = {'void*': compilers['cpp'].sizeof('void*'),
'long': compilers['cpp'].sizeof('long')
}
win64 = (sizeof['void*'] != sizeof['long'])
# ====================
# Ext libs
# ====================
@ -37,6 +41,46 @@ if discord_libpath != ''
endif
endif
# STEAMWORKS
steamworks = false
steamworks_path = get_option('steamworks_path')
if steamworks_path != ''
libname = 'steam_api'
if host_system == 'linux'
if sizeof['void*'] == 4
bindir = 'linux32'
else
bindir = 'linux64'
endif
elif host_system == 'windows'
if win64 == true
bindir = 'win64'
libname += '64'
else
bindir = ''
endif
else
bindir = 'osx'
endif
steam_libpath = steamworks_path + '/redistributable_bin/' + bindir
steamlib = compilers['cpp'].find_library(libname, required: false, dirs: [steam_libpath])
if steamlib.found() == true
if get_option('steam_appid') != ''
global_include_dirs += include_directories(steamworks_path + '/public')
global_args += ['-I@0@/public'.format(steamworks_path),
'-DHAVE_STEAMWORKS',
'-DSTEAM_APPID=' + get_option('steam_appid')]
global_dependencies += steamlib
steamworks = true
else
error('Steamworks SDK was found, but steam_appid isn\'t set!')
endif
endif
endif
# BOOST UNORDERED
global_include_dirs += include_directories('boost-unordered')
@ -53,7 +97,7 @@ endif
# Decide whether or not to use MiniFFI
miniffi = get_option('use_miniffi')
if miniffi == true
if compilers['cpp'].sizeof('void*') == compilers['cpp'].sizeof('long')
if win64 != true
miniffi = true
global_args += '-DUSE_MINIFFI'
else

View file

@ -18,4 +18,6 @@ option('workdir_current', type: 'boolean', value: false, description: 'Keep curr
option('independent_appimage', type: 'boolean', value: true, description: 'Set current directory to the original location of the AppImage when contained within one')
option('discord_sdk_path', type: 'string', value: '', description: 'Path to Discord GameSDK')
option('steamworks_path', type: 'string', value: '', description: 'Path to Steamworks SDK')
option('steam_appid', type: 'string', value: '', description: 'Steam application ID.')
option('appimagekit_path', type: 'string', value: '', description: 'Path to AppImageKit, used for building AppImages')

View file

@ -48,6 +48,10 @@
#include "discordstate.h"
#endif
#ifdef HAVE_STEAMWORKS
#include "steam/steam_api.h"
#endif
#include <algorithm>
#include <errno.h>
#include <sys/time.h>
@ -590,6 +594,11 @@ void Graphics::update() {
shState->discord().update();
#endif
#ifdef HAVE_STEAMWORKS
if (SteamAPI_IsSteamRunning())
SteamAPI_RunCallbacks();
#endif
if (p->frozen)
return;

View file

@ -46,7 +46,9 @@
#endif
#import <ObjFW/ObjFW.h>
#ifdef HAVE_STEAMWORKS
#import <steam/steam_api.h>
#endif
#import "icon.png.xxd"
#ifndef THREADED_GLINIT
@ -157,6 +159,17 @@ static void setupWindowIcon(const Config &conf, SDL_Window *win) {
int main(int argc, char *argv[]) {
@autoreleasepool {
#ifdef HAVE_STEAMWORKS
if (SteamAPI_RestartAppIfNecessary(STEAM_APPID)) {
Debug() << "Restarting with Steam...";
return 0;
}
if (!SteamAPI_Init()) {
showInitError("Steamworks failed to initialize.");
return 0;
}
#endif
SDL_SetHint(SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS, "0");
SDL_SetHint(SDL_HINT_ACCELEROMETER_AS_JOYSTICK, "0");
@ -390,6 +403,10 @@ int main(int argc, char *argv[]) {
if (wsadata.wVersion)
WSACleanup();
#endif
#ifdef HAVE_STEAMWORKS
SteamAPI_Shutdown();
#endif
Sound_Quit();
TTF_Quit();
IMG_Quit();