my fucking fingers
[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 VG_STATIC char steam_username_at_startup[128];
31
32 VG_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 VG_STATIC int steam_ready = 0,
41 steam_stats_ready = 0;
42
43 VG_STATIC void *hSteamNetworkingSockets,
44 *hSteamUser;
45
46 VG_STATIC ISteamUserStats *hSteamUserStats;
47 VG_STATIC HSteamPipe hSteamClientPipe;
48
49 VG_STATIC const char *steam_achievement_names[] =
50 {
51 "ALBERT", "MARC",
52 "ROUTE_MPY", "ROUTE_MPG", "ROUTE_MPB", "ROUTE_MPR",
53 "ROUTE_TO", "ROUTE_TC"
54 };
55
56 VG_STATIC void steam_store_achievements(void)
57 {
58 if( steam_ready && steam_stats_ready ){
59 SteamAPI_ISteamUserStats_StoreStats( hSteamUserStats );
60 }
61 }
62
63 VG_STATIC void steam_set_achievement( const char *name )
64 {
65 if( steam_ready && steam_stats_ready ){
66 if( SteamAPI_ISteamUserStats_SetAchievement( hSteamUserStats, name ) ){
67 vg_success( "Achievement set! '%s'\n", name );
68 }
69 else{
70 vg_warn( "Failed to set achievement: %s\n", name );
71 }
72 }
73 else{
74 vg_warn( "Failed to set achievement (steam not ready): %s\n", name );
75 }
76 }
77
78 VG_STATIC void steam_clear_achievement( const char *name )
79 {
80 if( steam_ready && steam_stats_ready ){
81 if( SteamAPI_ISteamUserStats_ClearAchievement( hSteamUserStats, name ) ){
82 vg_info( "Achievement cleared: '%s'\n", name );
83 }
84 else{
85 vg_warn( "Failed to clear achievement: %s\n", name );
86 }
87 }
88 else{
89 vg_warn( "Failed to clear achievement (steam not ready): %s\n", name );
90 }
91 }
92
93
94 VG_STATIC int steam_list_achievements( int argc, char const *argv[] )
95 {
96 vg_info( "Achievements: \n" );
97
98 if( steam_ready && steam_stats_ready ){
99 for( int i=0; i<vg_list_size(steam_achievement_names); i++ ){
100 int set = 0;
101 const char *name = steam_achievement_names[i];
102
103 if( SteamAPI_ISteamUserStats_GetAchievement(
104 hSteamUserStats, name, &set ) )
105 {
106 vg_info( " %s %s\n", (set? "[YES]": "[ ]"), name );
107 }
108 else{
109 vg_warn( " Error while fetching achievement status '%s'\n", name );
110 }
111 }
112 }
113 else{
114 vg_warn( " Steam is not initialized, no results\n" );
115 }
116
117 return 0;
118 }
119
120 VG_STATIC int steam_clear_all_achievements( int argc, char const *argv[] )
121 {
122 if( steam_ready && steam_stats_ready ){
123 for( int i=0; i<vg_list_size(steam_achievement_names); i++ ){
124 steam_clear_achievement( steam_achievement_names[i] );
125 }
126
127 steam_store_achievements();
128 }
129 else{
130 vg_warn( "steam is not initialized, cannot clear\n" );
131 }
132
133 return 0;
134 }
135
136 VG_STATIC int steam_set_achievemnt_test( int argc, char const *argv[] )
137 {
138 if( argc < 2 )
139 return 0;
140
141 if( strcmp( argv[0], "monkey_island" ) )
142 return 0;
143
144 steam_set_achievement( argv[1] );
145 steam_store_achievements();
146
147 return 0;
148 }
149
150 VG_STATIC void steam_on_recieve_current_stats( CallbackMsg_t *msg )
151 {
152 UserStatsReceived_t *rec = (UserStatsReceived_t *)msg->m_pubParam;
153
154 if( rec->m_eResult == k_EResultOK ){
155 vg_info( "Recieved stats for: %lu (user: %lu)\n", rec->m_nGameID,
156 rec->m_steamIDUser );
157 steam_stats_ready = 1;
158 }
159 else{
160 vg_error( "Error recieveing stats for user (%u)\n", rec->m_eResult );
161 }
162 }
163
164 VG_STATIC u32 utf8_byte0_byte_count( u8 char0 )
165 {
166 for( u32 k=2; k<4; k++ ){
167 if( !(char0 & (0x80 >> k)) )
168 return k;
169 }
170
171 return 0;
172 }
173
174 VG_STATIC void str_utf8_collapse( const char *str, char *buf, u32 length )
175 {
176 u8 *ustr = (u8 *)str;
177 u32 utf32_code = 0x00000000;
178 u32 i=0, j=0, utf32_byte_ct=0;
179
180 for(;i < length-1;){
181 if( ustr[i] == 0x00 )
182 break;
183
184 if( ustr[i] & 0x80 ){
185 if( utf32_byte_ct ){
186 utf32_byte_ct --;
187 utf32_code |= (ustr[i] & 0x3F) << (utf32_byte_ct*6);
188
189 if( !utf32_byte_ct ){
190 const char *match;
191 size_t chars = anyascii( utf32_code, &match );
192
193 for( u32 k=0; k<VG_MIN(chars, length-1-j); k++ ){
194 buf[ j++ ] = (u8)match[k];
195 }
196 }
197 }
198 else{
199 utf32_byte_ct = utf8_byte0_byte_count( ustr[i] )-1;
200 utf32_code = ustr[i] & (0x3F >> utf32_byte_ct);
201 utf32_code <<= utf32_byte_ct*6;
202 }
203 }
204 else{
205 utf32_byte_ct = 0x00;
206 buf[j ++] = str[i];
207 }
208
209 i++;
210 }
211
212 buf[j] = 0x00;
213 }
214
215 VG_STATIC int steam_init(void)
216 {
217 const char *username = NULL;
218
219 #ifdef SR_NETWORKED
220 vg_info( "Initializing steamworks\n" );
221
222 if( !SteamAPI_Init() ){
223 printf("\n");
224 vg_error( "Steamworks failed to initialize\n" );
225 return 1;
226 }
227
228 steam_ready = 1;
229
230 SteamAPI_ManualDispatch_Init();
231
232 /* Connect interfaces */
233 hSteamClientPipe = SteamAPI_GetHSteamPipe();
234 hSteamNetworkingSockets = SteamAPI_SteamNetworkingSockets_SteamAPI();
235 hSteamUser = SteamAPI_SteamUser();
236
237 ISteamUtils *utils = SteamAPI_SteamUtils();
238 SteamAPI_ISteamUtils_SetWarningMessageHook( utils, recv_steam_warning );
239
240 printf("\n");
241 vg_success( "\nSteamworks API running\n" );
242
243 ISteamFriends *hSteamFriends = SteamAPI_SteamFriends();
244 username = SteamAPI_ISteamFriends_GetPersonaName( hSteamFriends );
245
246 /*
247 * Request stats
248 * --------------------------------------------------------
249 */
250 hSteamUserStats = SteamAPI_SteamUserStats();
251 steam_register_callback( k_iUserStatsReceived,
252 steam_on_recieve_current_stats );
253
254 if( !SteamAPI_ISteamUserStats_RequestCurrentStats( hSteamUserStats ) )
255 vg_warn( "No Steam Logon: Cannot request stats\n" );
256
257
258 vg_console_reg_cmd( "ach_list", steam_list_achievements, NULL );
259 vg_console_reg_cmd( "ach_clear_all", steam_clear_all_achievements, NULL );
260 vg_console_reg_cmd( "ach_set", steam_set_achievemnt_test, NULL );
261
262 #endif
263
264 /* TODO: On username update callback */
265 str_utf8_collapse( username, steam_username_at_startup,
266 vg_list_size(steam_username_at_startup) );
267
268 return 1;
269 }
270
271 VG_STATIC void steam_update(void)
272 {
273 if( steam_ready ){
274 steamworks_event_loop( hSteamClientPipe );
275 }
276 }
277
278 VG_STATIC void steam_end(void)
279 {
280 if( steam_ready ){
281 vg_info( "Shutting down\n..." );
282 SteamAPI_Shutdown();
283 }
284 }
285
286 #endif /* STEAM_H */