completed all glider stuff
[carveJwlIkooP6JGAAIwe30JlM.git] / steam.h
1 /*
2 * Copyright (C) 2021-2023 Mt.ZERO Software, Harry Godden - All Rights Reserved
3 * All trademarks are property of their respective owners
4 */
5
6 #ifndef STEAM_H
7 #define STEAM_H
8
9 #define VG_GAME
10 #include "vg/vg_steam.h"
11 #include "vg/vg_steam_utils.h"
12 #include "vg/vg_steam_networking.h"
13 #include "vg/vg_steam_auth.h"
14 #include "vg/vg_steam_http.h"
15 #include "vg/vg_steam_friends.h"
16 #include "vg/vg_steam_user_stats.h"
17 #include "submodules/anyascii/impl/c/anyascii.c"
18
19 /*
20 * We only want to use steamworks if building for the networked version,
21 * theres not much point otherwise. We mainly want steamworks for setting
22 * achievements etc.. so that includes our own server too.
23 *
24 * This file also wraps the functions and interfaces that we want to use to
25 * make them a bit easier to read, since they are the flat API they have very
26 * long names. in non-networked builds they will return default errors or do
27 * nothing.
28 */
29
30 static char steam_username_at_startup[128] = "Unassigned";
31
32 static void recv_steam_warning( int severity, const char *msg )
33 {
34 if( severity == 0 )
35 vg_low( "%s\n", msg );
36 else
37 vg_info( "%s\n", msg );
38 }
39
40 static int steam_ready = 0,
41 steam_stats_ready = 0;
42
43 static void *hSteamNetworkingSockets,
44 *hSteamUser;
45
46 static ISteamUserStats *hSteamUserStats;
47 static HSteamPipe hSteamClientPipe;
48
49 static const char *steam_achievement_names[] =
50 {
51 "ALBERT", "MARC", "JANET", "BERNADETTA",
52 "ROUTE_MPY", "ROUTE_MPG", "ROUTE_MPB", "ROUTE_MPR",
53 "ROUTE_TO", "ROUTE_TC", "CITY_COMPLETE", "MTZERO_SILVER", "MTZERO_GOLD",
54 "80FT"
55 };
56
57 static void steam_store_achievements(void)
58 {
59 if( steam_ready && steam_stats_ready ){
60 SteamAPI_ISteamUserStats_StoreStats( hSteamUserStats );
61 }
62 }
63
64 static void update_ach_models(void);
65 static void steam_set_achievement( const char *name ){
66 if( skaterift.demo_mode )
67 return;
68
69 /* hack lol */
70 if( !strcmp(name,"MARC") ) skaterift.achievements |= 0x1;
71 if( !strcmp(name,"ALBERT") ) skaterift.achievements |= 0x2;
72 if( !strcmp(name,"JANET") ) skaterift.achievements |= 0x4;
73 if( !strcmp(name,"BERNADETTA") ) skaterift.achievements |= 0x8;
74 update_ach_models();
75
76 if( steam_ready && steam_stats_ready ){
77 if( SteamAPI_ISteamUserStats_SetAchievement( hSteamUserStats, name ) ){
78 vg_success( "Achievement set! '%s'\n", name );
79
80 }
81 else{
82 vg_warn( "Failed to set achievement: %s\n", name );
83 }
84 }
85 else{
86 vg_warn( "Failed to set achievement (steam not ready): %s\n", name );
87 }
88 }
89
90 static void steam_clear_achievement( const char *name )
91 {
92 if( steam_ready && steam_stats_ready ){
93 if( SteamAPI_ISteamUserStats_ClearAchievement( hSteamUserStats, name ) ){
94 vg_info( "Achievement cleared: '%s'\n", name );
95 }
96 else{
97 vg_warn( "Failed to clear achievement: %s\n", name );
98 }
99 }
100 else{
101 vg_warn( "Failed to clear achievement (steam not ready): %s\n", name );
102 }
103 }
104
105
106 static void steam_print_all_achievements(void){
107 vg_info( "Achievements: \n" );
108
109 if( steam_ready && steam_stats_ready ){
110 for( int i=0; i<vg_list_size(steam_achievement_names); i++ ){
111 steamapi_bool set = 0;
112 const char *name = steam_achievement_names[i];
113
114 if( SteamAPI_ISteamUserStats_GetAchievement(
115 hSteamUserStats, name, &set ) )
116 {
117 vg_info( " %s %s\n", (set? "[YES]": "[ ]"), name );
118 }
119 else{
120 vg_warn( " Error while fetching achievement status '%s'\n", name );
121 }
122 }
123 }
124 else{
125 vg_warn( " Steam is not initialized, no results\n" );
126 }
127 }
128
129 static int steam_achievement_ccmd( int argc, char const *argv[] )
130 {
131 if( !(steam_ready && steam_stats_ready) ) return 1;
132
133 if( argc == 1 ){
134 if( !strcmp( argv[0], "list" ) ){
135 steam_print_all_achievements();
136 return 0;
137 }
138 else if( !strcmp( argv[0], "clearall" )){
139 for( int i=0; i<vg_list_size(steam_achievement_names); i++ )
140 steam_clear_achievement( steam_achievement_names[i] );
141
142 steam_store_achievements();
143 }
144 }
145
146 if( argc == 2 ){
147 if( !strcmp( argv[0], "set" ) ){
148 steam_set_achievement( argv[1] );
149 steam_store_achievements();
150 return 0;
151 }
152 else if( strcmp( argv[0], "clear" ) ){
153 steam_clear_achievement( argv[1] );
154 steam_store_achievements();
155 return 0;
156 }
157 }
158
159 return 1;
160 }
161
162 static void steam_on_recieve_current_stats( CallbackMsg_t *msg )
163 {
164 UserStatsReceived_t *rec = (UserStatsReceived_t *)msg->m_pubParam;
165
166 if( rec->m_eResult == k_EResultOK ){
167 vg_info( "Recieved stats for: %lu (user: %lu)\n", rec->m_nGameID,
168 rec->m_steamIDUser );
169 steam_stats_ready = 1;
170
171 steamapi_bool set = 0;
172 if( SteamAPI_ISteamUserStats_GetAchievement(
173 hSteamUserStats, "MARC", &set ) ){
174 if( set ) skaterift.achievements |= 0x1;
175 }
176 if( SteamAPI_ISteamUserStats_GetAchievement(
177 hSteamUserStats, "ALBERT", &set ) ){
178 if( set ) skaterift.achievements |= 0x2;
179 }
180 if( SteamAPI_ISteamUserStats_GetAchievement(
181 hSteamUserStats, "JANET", &set ) ){
182 if( set ) skaterift.achievements |= 0x4;
183 }
184 if( SteamAPI_ISteamUserStats_GetAchievement(
185 hSteamUserStats, "BERNADETTA", &set ) ){
186 if( set ) skaterift.achievements |= 0x8;
187 }
188 update_ach_models();
189 }
190 else{
191 vg_error( "Error recieveing stats for user (%u)\n", rec->m_eResult );
192 }
193 }
194
195 static u32 utf8_byte0_byte_count( u8 char0 )
196 {
197 for( u32 k=2; k<4; k++ ){
198 if( !(char0 & (0x80 >> k)) )
199 return k;
200 }
201
202 return 0;
203 }
204
205 static u32 str_utf8_collapse( const char *str, char *buf, u32 length ){
206 u8 *ustr = (u8 *)str;
207 u32 utf32_code = 0x00000000;
208 u32 i=0, j=0, utf32_byte_ct=0;
209
210 for(;j < length-1;){
211 if( ustr[i] == 0x00 )
212 break;
213
214 if( ustr[i] & 0x80 ){
215 if( utf32_byte_ct ){
216 utf32_byte_ct --;
217 utf32_code |= (ustr[i] & 0x3F) << (utf32_byte_ct*6);
218
219 if( !utf32_byte_ct ){
220 const char *match;
221 size_t chars = anyascii( utf32_code, &match );
222
223 for( u32 k=0; k<VG_MIN(chars, length-1-j); k++ ){
224 buf[ j++ ] = (u8)match[k];
225 }
226 }
227 }
228 else{
229 utf32_byte_ct = utf8_byte0_byte_count( ustr[i] )-1;
230 utf32_code = ustr[i] & (0x3F >> utf32_byte_ct);
231 utf32_code <<= utf32_byte_ct*6;
232 }
233 }
234 else{
235 utf32_byte_ct = 0x00;
236 buf[j ++] = str[i];
237 }
238
239 i++;
240 }
241
242 buf[j] = 0x00;
243 return j;
244 }
245
246 static int steam_init(void){
247 const char *username = "offline player";
248
249 #ifdef SR_NETWORKED
250 vg_info( "Initializing steamworks\n" );
251
252 if( !SteamAPI_Init() ){
253 printf("\n");
254 vg_error( "Steamworks failed to initialize\n" );
255 return 1;
256 }
257
258 steam_ready = 1;
259
260 SteamAPI_ManualDispatch_Init();
261
262 /* Connect interfaces */
263 hSteamClientPipe = SteamAPI_GetHSteamPipe();
264 hSteamNetworkingSockets = SteamAPI_SteamNetworkingSockets_SteamAPI();
265 hSteamUser = SteamAPI_SteamUser();
266
267 ISteamUtils *utils = SteamAPI_SteamUtils();
268 SteamAPI_ISteamUtils_SetWarningMessageHook( utils, recv_steam_warning );
269
270 printf("\n");
271 vg_success( "\nSteamworks API running\n" );
272
273 ISteamFriends *hSteamFriends = SteamAPI_SteamFriends();
274 username = SteamAPI_ISteamFriends_GetPersonaName( hSteamFriends );
275
276 /*
277 * Request stats
278 * --------------------------------------------------------
279 */
280 hSteamUserStats = SteamAPI_SteamUserStats();
281 steam_register_callback( k_iUserStatsReceived,
282 steam_on_recieve_current_stats );
283
284 if( !SteamAPI_ISteamUserStats_RequestCurrentStats( hSteamUserStats ) )
285 vg_warn( "No Steam Logon: Cannot request stats\n" );
286
287
288 vg_console_reg_cmd( "ach", steam_achievement_ccmd, NULL );
289
290 #endif
291
292 /* TODO: On username update callback */
293 str_utf8_collapse( username, steam_username_at_startup,
294 vg_list_size(steam_username_at_startup) );
295
296 return 1;
297 }
298
299 static void steam_update(void)
300 {
301 if( steam_ready ){
302 steamworks_event_loop( hSteamClientPipe );
303 }
304 }
305
306 static void steam_end(void)
307 {
308 if( steam_ready ){
309 vg_info( "Shutting down\n..." );
310 SteamAPI_Shutdown();
311 }
312 }
313
314 #endif /* STEAM_H */