5 #include "vg/vg_steam.h"
6 #include "vg/vg_steam_utils.h"
7 #include "vg/vg_steam_networking.h"
8 #include "vg/vg_steam_auth.h"
9 #include "vg/vg_steam_http.h"
10 #include "vg/vg_steam_friends.h"
11 #include "vg/vg_steam_user_stats.h"
12 #include "submodules/anyascii/impl/c/anyascii.c"
15 * We only want to use steamworks if building for the networked version,
16 * theres not much point otherwise. We mainly want steamworks for setting
17 * achievements etc.. so that includes our own server too.
19 * This file also wraps the functions and interfaces that we want to use to
20 * make them a bit easier to read, since they are the flat API they have very
21 * long names. in non-networked builds they will return default errors or do
25 static char steam_username_at_startup
[128] = "Unassigned";
27 static void recv_steam_warning( int severity
, const char *msg
)
30 vg_low( "%s\n", msg
);
32 vg_info( "%s\n", msg
);
35 static int steam_ready
= 0,
36 steam_stats_ready
= 0;
38 static void *hSteamNetworkingSockets
,
41 static ISteamUserStats
*hSteamUserStats
;
42 static HSteamPipe hSteamClientPipe
;
45 k_mc_achievement_master_engineer
,
46 k_mc_achievement_can_do_that
,
47 k_mc_achievement_bang
,
48 k_mc_achievement_good_enough
,
49 k_mc_achievement_tutorials
,
50 k_mc_achievement_mighty_consumer
,
51 k_mc_achievement_graduate
,
55 static const char *steam_achievement_names
[] = {
56 [k_mc_achievement_master_engineer
] = "MASTER_ENGINEER",
57 [k_mc_achievement_can_do_that
] = "CAN_DO_THAT",
58 [k_mc_achievement_bang
] = "BANG",
59 [k_mc_achievement_good_enough
] = "GOOD_ENOUGH",
60 [k_mc_achievement_tutorials
] = "TUTORIALS",
61 [k_mc_achievement_mighty_consumer
] = "MIGHTY_CONSUMER",
62 [k_mc_achievement_graduate
] = "GRADUATE"
65 static bool steam_achievement_set
[k_mc_achievement_max
];
67 static void steam_store_achievements(void){
68 if( steam_ready
&& steam_stats_ready
){
69 SteamAPI_ISteamUserStats_StoreStats( hSteamUserStats
);
73 static void steam_set_achievement( enum mc_achievement id
){
74 if( steam_achievement_set
[ id
] ) return;
75 const char *name
= steam_achievement_names
[ id
];
77 if( steam_ready
&& steam_stats_ready
){
78 if( SteamAPI_ISteamUserStats_SetAchievement( hSteamUserStats
, name
) ){
79 vg_success( "Achievement set! '%s'\n", name
);
83 vg_warn( "Failed to set achievement: %s\n", name
);
87 vg_warn( "Failed to set achievement (steam not ready): %s\n", name
);
90 steam_achievement_set
[ id
] = 1;
93 static void sw_set_achievement( const char *name
){
94 for( u32 i
=0; i
<k_mc_achievement_max
; i
++ ){
95 if( !strcmp( name
, steam_achievement_names
[i
] ) ){
96 steam_set_achievement( i
);
97 steam_store_achievements();
103 static void steam_clear_achievement( const char *name
){
104 if( steam_ready
&& steam_stats_ready
){
105 if( SteamAPI_ISteamUserStats_ClearAchievement( hSteamUserStats
, name
) ){
106 vg_info( "Achievement cleared: '%s'\n", name
);
109 vg_warn( "Failed to clear achievement: %s\n", name
);
113 vg_warn( "Failed to clear achievement (steam not ready): %s\n", name
);
118 static void steam_print_all_achievements(void){
119 vg_info( "Achievements: \n" );
121 if( steam_ready
&& steam_stats_ready
){
122 for( int i
=0; i
<vg_list_size(steam_achievement_names
); i
++ ){
123 steamapi_bool set
= 0;
124 const char *name
= steam_achievement_names
[i
];
126 if( SteamAPI_ISteamUserStats_GetAchievement(
127 hSteamUserStats
, name
, &set
) )
129 vg_info( " %s %s\n", (set
? "[YES]": "[ ]"), name
);
132 vg_warn( " Error while fetching achievement status '%s'\n", name
);
137 vg_warn( " Steam is not initialized, no results\n" );
141 static int steam_achievement_ccmd( int argc
, char const *argv
[] )
143 if( !(steam_ready
&& steam_stats_ready
) ){
144 vg_error( "steam_ready: %d, steam_stats_ready: %d\n",
145 steam_ready
, steam_stats_ready
);
150 if( !strcmp( argv
[0], "list" ) ){
151 steam_print_all_achievements();
154 else if( !strcmp( argv
[0], "clearall" )){
155 for( int i
=0; i
<vg_list_size(steam_achievement_names
); i
++ )
156 steam_clear_achievement( steam_achievement_names
[i
] );
158 steam_store_achievements();
163 if( !strcmp( argv
[0], "set" ) ){
164 sw_set_achievement( argv
[1] );
167 else if( strcmp( argv
[0], "clear" ) ){
168 steam_clear_achievement( argv
[1] );
169 steam_store_achievements();
177 static void steam_on_recieve_current_stats( CallbackMsg_t
*msg
)
179 UserStatsReceived_t
*rec
= (UserStatsReceived_t
*)msg
->m_pubParam
;
181 if( rec
->m_eResult
== k_EResultOK
){
182 vg_info( "Recieved stats for: %lu (user: %lu)\n", rec
->m_nGameID
,
183 rec
->m_steamIDUser
);
184 steam_stats_ready
= 1;
187 vg_error( "Error recieveing stats for user (%u)\n", rec
->m_eResult
);
191 static u32
utf8_byte0_byte_count( u8 char0
)
193 for( u32 k
=2; k
<4; k
++ ){
194 if( !(char0
& (0x80 >> k
)) )
201 static u32
str_utf8_collapse( const char *str
, char *buf
, u32 length
){
202 u8
*ustr
= (u8
*)str
;
203 u32 utf32_code
= 0x00000000;
204 u32 i
=0, j
=0, utf32_byte_ct
=0;
207 if( ustr
[i
] == 0x00 )
210 if( ustr
[i
] & 0x80 ){
213 utf32_code
|= (ustr
[i
] & 0x3F) << (utf32_byte_ct
*6);
215 if( !utf32_byte_ct
){
217 size_t chars
= anyascii( utf32_code
, &match
);
219 for( u32 k
=0; k
<VG_MIN(chars
, length
-1-j
); k
++ ){
220 buf
[ j
++ ] = (u8
)match
[k
];
225 utf32_byte_ct
= utf8_byte0_byte_count( ustr
[i
] )-1;
226 utf32_code
= ustr
[i
] & (0x3F >> utf32_byte_ct
);
227 utf32_code
<<= utf32_byte_ct
*6;
231 utf32_byte_ct
= 0x00;
242 static int steam_init(void){
243 const char *username
= "offline player";
245 vg_info( "Initializing steamworks\n" );
247 if( !SteamAPI_Init() ){
249 vg_error( "Steamworks failed to initialize\n" );
255 SteamAPI_ManualDispatch_Init();
257 /* Connect interfaces */
258 hSteamClientPipe
= SteamAPI_GetHSteamPipe();
259 hSteamNetworkingSockets
= SteamAPI_SteamNetworkingSockets_SteamAPI();
260 hSteamUser
= SteamAPI_SteamUser();
262 ISteamUtils
*utils
= SteamAPI_SteamUtils();
263 SteamAPI_ISteamUtils_SetWarningMessageHook( utils
, recv_steam_warning
);
266 vg_success( "\nSteamworks API running\n" );
268 ISteamFriends
*hSteamFriends
= SteamAPI_SteamFriends();
269 username
= SteamAPI_ISteamFriends_GetPersonaName( hSteamFriends
);
273 * --------------------------------------------------------
275 hSteamUserStats
= SteamAPI_SteamUserStats();
276 steam_register_callback( k_iUserStatsReceived
,
277 steam_on_recieve_current_stats
);
279 if( !SteamAPI_ISteamUserStats_RequestCurrentStats( hSteamUserStats
) )
280 vg_warn( "No Steam Logon: Cannot request stats\n" );
282 vg_console_reg_cmd( "ach", steam_achievement_ccmd
, NULL
);
284 /* TODO: On username update callback */
285 str_utf8_collapse( username
, steam_username_at_startup
,
286 vg_list_size(steam_username_at_startup
) );
291 static void steam_update(void)
294 steamworks_event_loop( hSteamClientPipe
);
298 static void steam_end(void)
301 vg_info( "Shutting down\n..." );