numerous
[carveJwlIkooP6JGAAIwe30JlM.git] / network.h
1 #ifndef NETWORK_H
2 #define NETWORK_H
3
4 #include "vg/vg_stdint.h"
5 #include "steam.h"
6 #include "network_msg.h"
7 #include "highscores.h"
8
9 /*
10 * Interface
11 */
12 #define SR_USE_LOCALHOST
13
14 /* Call it at start; Connects us to the gameserver */
15 static void network_init(void);
16
17 /* Run this from main loop */
18 static void network_update(void);
19
20 /* Call it at shutdown */
21 static void network_end(void);
22
23 /*
24 * Can buffer up a bunch of these by calling many times, they will be
25 * sent at the next connection
26 */
27 static void network_submit_highscore( u32 trackid, u16 points, u16 time );
28
29 /*
30 * Game endpoints are provided with the same names to allow running without a
31 * network connection.
32 */
33 #ifdef SR_NETWORKED
34
35 /*
36 * Runtime connection stuff
37 */
38 static u8 steam_app_ticket[ 1024 ];
39 static u32 steam_app_ticket_length;
40 static int network_name_update = 1;
41 static int network_scores_updated = 0;
42
43 static HSteamNetConnection cremote;
44 static ESteamNetworkingConnectionState cremote_state =
45 k_ESteamNetworkingConnectionState_None;
46
47 /*
48 * Implementation
49 */
50
51 static void scores_update(void);
52
53 static void on_auth_ticket_recieved( void *result, void *context )
54 {
55 EncryptedAppTicketResponse_t *response = result;
56
57 if( response->m_eResult == k_EResultOK )
58 {
59 vg_info( " New app ticket ready\n" );
60 }
61 else
62 {
63 vg_warn( " Could not request new encrypted app ticket (%u)\n",
64 response->m_eResult );
65 }
66
67 if( SteamAPI_ISteamUser_GetEncryptedAppTicket( hSteamUser,
68 steam_app_ticket,
69 vg_list_size(steam_app_ticket),
70 &steam_app_ticket_length ))
71 {
72 vg_success( " Loaded app ticket (%u bytes)\n", steam_app_ticket_length );
73 }
74 else
75 {
76 vg_error( " No ticket availible\n" );
77 steam_app_ticket_length = 0;
78 }
79 }
80
81 static void request_auth_ticket(void)
82 {
83 /*
84 * TODO Check for one thats cached on the disk and load it.
85 * This might be OK though because steam seems to cache the result
86 */
87
88 vg_info( "Requesting new authorization ticket\n" );
89 steam_async *call = steam_new_async();
90 call->data = NULL;
91 call->p_handler = on_auth_ticket_recieved;
92 call->id = SteamAPI_ISteamUser_RequestEncryptedAppTicket( hSteamUser,
93 NULL, 0 );
94 }
95
96 static void send_auth_ticket(void)
97 {
98 u32 size = sizeof(netmsg_auth) + steam_app_ticket_length;
99 netmsg_auth *auth = alloca(size);
100
101 auth->inetmsg_id = k_inetmsg_auth;
102 auth->ticket_length = steam_app_ticket_length;
103 for( int i=0; i<steam_app_ticket_length; i++ )
104 auth->ticket[i] = steam_app_ticket[i];
105
106 SteamAPI_ISteamNetworkingSockets_SendMessageToConnection(
107 hSteamNetworkingSockets, cremote, auth, size,
108 k_nSteamNetworkingSend_Reliable, NULL );
109 }
110
111 static void send_score_request(void)
112 {
113 vg_info( "Requesting scores\n" );
114 netmsg_scores_request req;
115 req.inetmsg_id = k_inetmsg_scores_request;
116
117 SteamAPI_ISteamNetworkingSockets_SendMessageToConnection(
118 hSteamNetworkingSockets, cremote, &req, sizeof(netmsg_scores_request),
119 k_nSteamNetworkingSend_Reliable, NULL );
120 }
121
122 static void send_score_update(void)
123 {
124 vg_info( "Sending scores\n" );
125 u32 size = sizeof(netmsg_set_score) +
126 vg_list_size(track_infos)*sizeof(struct netmsg_score_record);
127 netmsg_set_score *setscore = alloca( size );
128 setscore->inetmsg_id = k_inetmsg_set_score;
129
130 int count = 0;
131 for( u32 i=0; i<vg_list_size(track_infos); i++ )
132 {
133 if( track_infos[i].push )
134 {
135 track_infos[i].push = 0;
136 highscore_record *user_record = highscore_find_user_record( 0, i );
137
138 if( !user_record )
139 {
140 vg_error( "No score set but tried to upload for track %u\n", i );
141 continue;
142 }
143
144 setscore->records[count].trackid = i;
145 setscore->records[count].playerid = 0;
146 setscore->records[count].points = user_record->points;
147 setscore->records[count].time = user_record->time;
148
149 count ++;
150 }
151 }
152
153 if( count == 0 )
154 return;
155
156 u32 send_size = sizeof(netmsg_set_score) +
157 count*sizeof(struct netmsg_score_record);
158 setscore->record_count = count;
159
160 SteamAPI_ISteamNetworkingSockets_SendMessageToConnection(
161 hSteamNetworkingSockets, cremote, setscore, send_size,
162 k_nSteamNetworkingSend_Reliable, NULL );
163 }
164
165 static void send_nickname(void)
166 {
167 netmsg_set_nickname nick;
168 nick.inetmsg_id = k_inetmsg_set_nickname;
169
170 memset( nick.nickname, 0, 10 );
171 strcpy( nick.nickname, "Harry" );
172
173 SteamAPI_ISteamNetworkingSockets_SendMessageToConnection(
174 hSteamNetworkingSockets, cremote, &nick, sizeof(netmsg_set_nickname),
175 k_nSteamNetworkingSend_Reliable, NULL );
176
177 network_name_update = 0;
178 }
179
180 static void server_routine_update(void)
181 {
182 send_auth_ticket();
183
184 if( network_name_update )
185 send_nickname();
186
187 send_score_update();
188 send_score_request();
189 }
190
191 static void on_server_connect_status( CallbackMsg_t *msg )
192 {
193 SteamNetConnectionStatusChangedCallback_t *info = (void *)msg->m_pubParam;
194 vg_info( " Connection status changed for %lu\n", info->m_hConn );
195 vg_info( " %s -> %s\n",
196 string_ESteamNetworkingConnectionState(info->m_eOldState),
197 string_ESteamNetworkingConnectionState(info->m_info.m_eState) );
198
199 if( info->m_hConn == cremote )
200 {
201 cremote_state = info->m_info.m_eState;
202 if( info->m_info.m_eState ==
203 k_ESteamNetworkingConnectionState_Connected )
204 {
205 vg_success(" Connected to remote server.. running updates\n");
206 server_routine_update();
207 }
208 }
209 else
210 {
211 vg_warn( " Recieved signal from unknown connection\n" );
212 }
213 }
214
215 static void network_connect_gc(void)
216 {
217 /* Connect to server if not connected */
218 SteamNetworkingIPAddr remoteAddr;
219
220 #ifdef SR_USE_LOCALHOST
221 SteamAPI_SteamNetworkingIPAddr_SetIPv6LocalHost( &remoteAddr, 27402 );
222 #else
223 const char *server_lon1 = "46.101.34.155:27402";
224 SteamAPI_SteamNetworkingIPAddr_ParseString( &remoteAddr, server_lon1 );
225 #endif
226
227 char buf[256];
228 SteamAPI_SteamNetworkingIPAddr_ToString( &remoteAddr, buf, 256, 1 );
229 vg_info( "connect to: %s\n", buf );
230
231 cremote = SteamAPI_ISteamNetworkingSockets_ConnectByIPAddress(
232 hSteamNetworkingSockets, &remoteAddr, 0, NULL );
233 }
234
235 static void on_inet_scoreboard( SteamNetworkingMessage_t *msg )
236 {
237 netmsg_scoreboard *sb = msg->m_pData;
238
239 u32 base_size = sizeof(netmsg_scoreboard)-
240 sizeof(struct netmsg_board)*vg_list_size(track_infos),
241 expected = base_size+sizeof(struct netmsg_board)*sb->board_count;
242
243 if( msg->m_cbSize != expected )
244 {
245 vg_error( "Server scoreboard was corrupted. Size: %u != %u\n",
246 msg->m_cbSize, expected );
247 }
248 else
249 {
250 if( vg_list_size(track_infos) > sb->board_count )
251 vg_warn( "Server is out of date, not enough boards recieved\n");
252 else if( vg_list_size(track_infos) < sb->board_count )
253 vg_warn( "Client out of date, server sent more boards than we have\n");
254 else
255 vg_success( "Recieved new scoreboards from server\n" );
256
257 for( int i=0; i < vg_min(sb->board_count,vg_list_size(track_infos)); i++)
258 {
259 scoreboard_client_data.boards[i] = sb->boards[i];
260 highscores_board_printf( stdout, sb->boards[i].data, 10 );
261 }
262 }
263
264 /* We dont need to stay on the server currently */
265 SteamAPI_ISteamNetworkingSockets_CloseConnection(
266 hSteamNetworkingSockets, cremote, 0, NULL, 1 );
267
268 network_scores_updated = 1;
269 }
270
271 static void poll_connection(void)
272 {
273 SteamNetworkingMessage_t *messages[32];
274 int len;
275
276 while(1)
277 {
278 len = SteamAPI_ISteamNetworkingSockets_ReceiveMessagesOnConnection(
279 hSteamNetworkingSockets, cremote, messages, vg_list_size(messages));
280
281 if( len <= 0 )
282 return;
283
284 for( int i=0; i<len; i++ )
285 {
286 SteamNetworkingMessage_t *msg = messages[i];
287
288 if( msg->m_cbSize < sizeof(netmsg_blank) )
289 {
290 vg_warn( "Discarding message (too small: %d)\n", msg->m_cbSize );
291 continue;
292 }
293
294 netmsg_blank *tmp = msg->m_pData;
295
296 if( tmp->inetmsg_id == k_inetmsg_scoreboard )
297 on_inet_scoreboard( msg );
298
299 SteamAPI_SteamNetworkingMessage_t_Release( msg );
300 }
301 }
302 }
303
304 /*
305 * Subroutine to be connected to main game loop, runs all routines on timers
306 */
307 static void network_update(void)
308 {
309 if( steam_ready )
310 {
311 static double last_update = 0.0;
312 poll_connection();
313
314 if( vg_time > (last_update + 60.0) )
315 {
316 last_update = vg_time;
317
318 if( steam_app_ticket_length )
319 {
320 network_connect_gc();
321 }
322 else
323 {
324 vg_log( "Not making remote connection; app ticket not gotten\n" );
325 }
326 }
327
328 if( vg_time > (last_update + 10.0) &&
329 (cremote_state == k_ESteamNetworkingConnectionState_Connected ))
330 {
331 vg_warn( "Connected to server but no return... disconnecting\n" );
332 SteamAPI_ISteamNetworkingSockets_CloseConnection(
333 hSteamNetworkingSockets, cremote, 0, NULL, 1 );
334 }
335 }
336 }
337
338 static void network_init(void)
339 {
340 if( steam_ready )
341 {
342 steam_register_callback( k_iSteamNetConnectionStatusChangedCallBack,
343 on_server_connect_status );
344 request_auth_ticket();
345 }
346 }
347
348 static void network_end(void)
349 {
350 /* TODO: Fire off any buffered highscores that need to be setn */
351 if( cremote_state == k_ESteamNetworkingConnectionState_Connected ||
352 cremote_state == k_ESteamNetworkingConnectionState_Connecting )
353 {
354 SteamAPI_ISteamNetworkingSockets_CloseConnection(
355 hSteamNetworkingSockets, cremote, 0, NULL, 1 );
356 }
357 }
358
359 #else /* SR_NETWORKED */
360
361 static void network_init(void){}
362 static void network_update(void){}
363 static void network_end(void){}
364
365 #endif /* SR_NETWORKED */
366 #endif /* NETWORK_H */