remove sub-world concept
[carveJwlIkooP6JGAAIwe30JlM.git] / gameserver.c
1 /*
2 * Copyright (C) 2021-2023 Mt.ZERO Software, Harry Godden - All Rights Reserved
3 */
4
5 #define _DEFAULT_SOURCE
6 #include <signal.h>
7 #include <unistd.h>
8 #include <time.h>
9
10 volatile sig_atomic_t sig_stop;
11
12 #include "gameserver.h"
13 #include "highscores.c"
14 #include "servermonitor_server.c"
15 #include "vg/vg_opt.h"
16 #include "network_common.h"
17 #include "gameserver_db.h"
18 #include "vg/vg_m.h"
19 #include "vg/vg_msg.h"
20
21 static void inthandler( int signum ) {
22 sig_stop = 1;
23 }
24
25 static const u64 k_connection_unauthorized = 0xffffffffffffffff;
26
27 static u64_steamid get_connection_authsteamid( SteamNetworkingMessage_t *msg ){
28 i64 userdata = SteamAPI_ISteamNetworkingSockets_GetConnectionUserData(
29 hSteamNetworkingSockets, msg->m_conn );
30
31 return *((u64_steamid *)&userdata);
32 }
33
34 static void set_connection_authsteamid(HSteamNetConnection con, u64_steamid id){
35 i64 userdata = *((i64 *)&id);
36
37 SteamAPI_ISteamNetworkingSockets_SetConnectionUserData(
38 hSteamNetworkingSockets, con, userdata );
39 }
40
41 static void gameserver_send_to_all( int ignore,
42 const void *pData, u32 cbData,
43 int nSendFlags ){
44 for( int i=0; i<vg_list_size(gameserver.clients); i++ ){
45 struct gameserver_client *client = &gameserver.clients[i];
46
47 if( (i==ignore) || !client->active )
48 continue;
49
50 SteamAPI_ISteamNetworkingSockets_SendMessageToConnection(
51 hSteamNetworkingSockets, client->connection,
52 pData, cbData, nSendFlags, NULL );
53 }
54 }
55
56 static void gameserver_player_join( int index ){
57 struct gameserver_client *joiner = &gameserver.clients[index];
58
59 netmsg_playerjoin join = { .inetmsg_id = k_inetmsg_playerjoin,
60 .index = index };
61 gameserver_send_to_all( index, &join, sizeof(join),
62 k_nSteamNetworkingSend_Reliable );
63
64 /* update the joining user about current connections */
65
66 netmsg_playerusername *username =
67 alloca( sizeof(netmsg_playerusername) + NETWORK_USERNAME_MAX );
68 username->inetmsg_id = k_inetmsg_playerusername;
69
70 netmsg_playeritem *item =
71 alloca( sizeof(netmsg_playeritem) + ADDON_UID_MAX );
72 item->inetmsg_id = k_inetmsg_playeritem;
73
74 for( int i=0; i<vg_list_size(gameserver.clients); i++ ){
75 struct gameserver_client *client = &gameserver.clients[i];
76
77 if( (i==index) || !client->active )
78 continue;
79
80 /* join */
81 netmsg_playerjoin init = { .inetmsg_id = k_inetmsg_playerjoin,
82 .index = i };
83 SteamAPI_ISteamNetworkingSockets_SendMessageToConnection(
84 hSteamNetworkingSockets, joiner->connection,
85 &init, sizeof(init), k_nSteamNetworkingSend_Reliable, NULL );
86
87 /* username */
88 username->index = i;
89 u32 chs = vg_strncpy( client->username, username->name,
90 NETWORK_USERNAME_MAX,
91 k_strncpy_always_add_null );
92 u32 size = sizeof(netmsg_playerusername) + chs + 1;
93 SteamAPI_ISteamNetworkingSockets_SendMessageToConnection(
94 hSteamNetworkingSockets, joiner->connection,
95 username, size, k_nSteamNetworkingSend_Reliable, NULL );
96
97 /* items */
98 for( int j=0; j<k_netmsg_playeritem_max; j++ ){
99 chs = vg_strncpy( client->items[j], item->uid, ADDON_UID_MAX,
100 k_strncpy_always_add_null );
101 item->type_index = j;
102 item->client = i;
103 size = sizeof(netmsg_playeritem) + chs + 1;
104 SteamAPI_ISteamNetworkingSockets_SendMessageToConnection(
105 hSteamNetworkingSockets, joiner->connection,
106 item, size, k_nSteamNetworkingSend_Reliable, NULL );
107 }
108 }
109 }
110
111 static void gameserver_player_leave( int index ){
112 netmsg_playerjoin leave;
113 leave.inetmsg_id = k_inetmsg_playerleave;
114 leave.index = index;
115
116 vg_info( "Player leave (%d)\n", index );
117 gameserver_send_to_all( index, &leave, sizeof(leave),
118 k_nSteamNetworkingSend_Reliable );
119 }
120
121 static void new_client_connecting( HSteamNetConnection client ){
122 int index = -1;
123
124 /* TODO: LRU */
125 for( int i=0; i<vg_list_size(gameserver.clients); i++ ){
126 if( !gameserver.clients[i].active ){
127 index = i;
128 break;
129 }
130 }
131
132 if( index == -1 ){
133 vg_error( "Server full\n" );
134 SteamAPI_ISteamNetworkingSockets_CloseConnection(
135 hSteamNetworkingSockets, client,
136 4500,
137 NULL, 1 );
138 return;
139 }
140
141 EResult accept_status = SteamAPI_ISteamNetworkingSockets_AcceptConnection(
142 hSteamNetworkingSockets, client );
143 if( accept_status == k_EResultOK ){
144 vg_success( "Accepted client (id: %u, index: %d)\n", client, index );
145 memset( &gameserver.clients[index], 0, sizeof(struct gameserver_client) );
146
147 gameserver.clients[index].active = 1;
148 gameserver.clients[index].connection = client;
149
150 SteamAPI_ISteamNetworkingSockets_SetConnectionPollGroup(
151 hSteamNetworkingSockets,
152 client, gameserver.client_group );
153
154 /* Just to be sure */
155 set_connection_authsteamid( client, -1 );
156 gameserver_player_join( index );
157 }
158 else{
159 vg_warn( "Error accepting client (id: %u)\n", client );
160 SteamAPI_ISteamNetworkingSockets_CloseConnection(
161 hSteamNetworkingSockets, client,
162 k_ESteamNetConnectionEnd_Misc_InternalError,
163 NULL, 1 );
164 gameserver.clients[index].active = 0;
165 gameserver.clients[index].connection = 0;
166 }
167 }
168
169 static void on_auth_status( CallbackMsg_t *msg ){
170 SteamNetAuthenticationStatus_t *info = (void *)msg->m_pubParam;
171 vg_info( " Authentication availibility: %s\n",
172 string_ESteamNetworkingAvailability(info->m_eAvail) );
173 vg_info( " %s\n", info->m_debugMsg );
174 }
175
176 static int gameserver_client_index( HSteamNetConnection hconn ){
177 for( int i=0; i<vg_list_size(gameserver.clients); i++ ){
178 struct gameserver_client *client = &gameserver.clients[i];
179
180 if( client->active ){
181 if( client->connection == hconn ){
182 return i;
183 }
184 }
185 }
186 return -1;
187 }
188
189 static void on_connect_status( CallbackMsg_t *msg ){
190 SteamNetConnectionStatusChangedCallback_t *info = (void *)msg->m_pubParam;
191 vg_info( " Connection status changed for %lu\n", info->m_hConn );
192
193 vg_info( " %s -> %s\n",
194 string_ESteamNetworkingConnectionState(info->m_eOldState),
195 string_ESteamNetworkingConnectionState(info->m_info.m_eState) );
196
197 if( info->m_info.m_eState==k_ESteamNetworkingConnectionState_Connecting ){
198 new_client_connecting( info->m_hConn );
199 }
200
201 if( (info->m_info.m_eState ==
202 k_ESteamNetworkingConnectionState_ClosedByPeer ) ||
203 (info->m_info.m_eState ==
204 k_ESteamNetworkingConnectionState_ProblemDetectedLocally ) ){
205
206 int client_id = gameserver_client_index( info->m_hConn );
207 if( client_id != -1 ){
208 struct gameserver_client *client = &gameserver.clients[client_id];
209 client->connection = 0;
210 client->active = 0;
211 gameserver_player_leave(client_id);
212 }
213
214 vg_info( "End reason: %d\n", info->m_info.m_eEndReason );
215 SteamAPI_ISteamNetworkingSockets_CloseConnection(
216 hSteamNetworkingSockets, info->m_hConn, 0, NULL, 0 );
217 }
218 }
219
220 static void gameserver_rx_auth( SteamNetworkingMessage_t *msg ){
221 if( gameserver.auth_mode != eServerModeAuthentication ){
222 vg_error( "Running server without authentication. "
223 "Connection %u tried to authenticate.\n", msg->m_conn );
224 return;
225 }
226
227 if( get_connection_authsteamid( msg ) != k_connection_unauthorized ){
228 vg_warn( "Already authorized this user but app ticket was sent"
229 " again (%u)\n", msg->m_conn );
230 return;
231 }
232
233 vg_low( "Attempting to verify user\n" );
234
235 if( msg->m_cbSize < sizeof(netmsg_auth) ){
236 vg_error( "Malformed auth ticket, too small (%u)\n", msg->m_conn );
237 return;
238 }
239
240 netmsg_auth *auth = msg->m_pData;
241
242 if( msg->m_cbSize < sizeof(netmsg_auth)+auth->ticket_length ||
243 auth->ticket_length > 1024 ){
244 vg_error( "Malformed auth ticket, ticket_length incorrect (%u)\n",
245 auth->ticket_length );
246 return;
247 }
248
249 u8 decrypted[1024];
250 u32 ticket_len = 1024;
251
252 int success = SteamEncryptedAppTicket_BDecryptTicket(
253 auth->ticket, auth->ticket_length, decrypted,
254 &ticket_len, gameserver.app_symmetric_key,
255 k_nSteamEncryptedAppTicketSymmetricKeyLen );
256
257 if( !success ){
258 vg_error( "Failed to decrypt users ticket (client %u)\n", msg->m_conn );
259 vg_error( " ticket length: %u\n", auth->ticket_length );
260
261 SteamAPI_ISteamNetworkingSockets_CloseConnection(
262 hSteamNetworkingSockets,
263 msg->m_conn, 0, NULL, 1 );
264 return;
265 }
266
267 if( SteamEncryptedAppTicket_GetTicketIssueTime( decrypted, ticket_len )){
268 RTime32 ctime = time(NULL),
269 tickettime = SteamEncryptedAppTicket_GetTicketIssueTime(
270 decrypted, ticket_len ),
271 expiretime = tickettime + 24*3*60*60;
272
273 if( ctime > expiretime ){
274 vg_error( "Ticket expired (client %u)\n", msg->m_conn );
275
276 /* TODO: Send expired information */
277 SteamAPI_ISteamNetworkingSockets_CloseConnection(
278 hSteamNetworkingSockets,
279 msg->m_conn, 0, NULL, 1 );
280 return;
281 }
282 }
283
284 CSteamID steamid;
285 SteamEncryptedAppTicket_GetTicketSteamID( decrypted, ticket_len, &steamid );
286 vg_success( "User is authenticated! steamid %lu (%u)\n",
287 steamid.m_unAll64Bits, msg->m_conn );
288
289 set_connection_authsteamid( msg->m_conn, steamid.m_unAll64Bits );
290 }
291
292 static int inet_require_auth( SteamNetworkingMessage_t *msg ){
293 if( gameserver.auth_mode == eServerModeNoAuthentication )
294 return 1;
295
296 if( get_connection_authsteamid( msg ) == k_connection_unauthorized ){
297 vg_warn( "Unauthorized request! Disconnecting client: %u\n",
298 msg->m_conn );
299
300 SteamAPI_ISteamNetworkingSockets_CloseConnection(
301 hSteamNetworkingSockets,
302 msg->m_conn, 0, NULL, 1 );
303
304 return 0;
305 }
306 else return 1;
307 }
308
309 /*
310 * Player updates sent to us
311 * -----------------------------------------------------------------------------
312 */
313
314 static int packet_minsize( SteamNetworkingMessage_t *msg, u32 size ){
315 if( msg->m_cbSize < size ) {
316 vg_error( "Invalid packet size (must be at least %u)\n", size );
317 return 0;
318 }
319 else{
320 return 1;
321 }
322 }
323
324 struct db_set_username_thread_data {
325 u64 steamid;
326 char username[ NETWORK_USERNAME_MAX ];
327 };
328
329 static void gameserver_update_db_username( db_request *db_req ){
330 struct db_set_username_thread_data *inf = (void *)db_req->data;
331
332 if( inf->steamid == k_connection_unauthorized )
333 return;
334
335 int admin = 0;
336 if( inf->steamid == 76561198072130043 )
337 admin = 2;
338
339 db_updateuser( inf->steamid, inf->username, admin );
340 }
341
342 static void gameserver_rx_200_300( SteamNetworkingMessage_t *msg ){
343 netmsg_blank *tmp = msg->m_pData;
344
345 int client_id = gameserver_client_index( msg->m_conn );
346 if( client_id == -1 ) return;
347
348 if( tmp->inetmsg_id == k_inetmsg_playerusername ){
349 if( !packet_minsize( msg, sizeof(netmsg_playerusername)+1 ))
350 return;
351
352 struct gameserver_client *client = &gameserver.clients[ client_id ];
353 netmsg_playerusername *src = msg->m_pData;
354
355 u32 name_len = network_msgstring( src->name, msg->m_cbSize,
356 sizeof(netmsg_playerusername),
357 client->username,
358 NETWORK_USERNAME_MAX );
359
360 /* update other users about this change */
361 netmsg_playerusername *prop = alloca(sizeof(netmsg_playerusername)+
362 NETWORK_USERNAME_MAX );
363
364 prop->inetmsg_id = k_inetmsg_playerusername;
365 prop->index = client_id;
366 u32 chs = vg_strncpy( client->username, prop->name, NETWORK_USERNAME_MAX,
367 k_strncpy_always_add_null );
368
369 vg_info( "client #%d changed name to: %s\n", client_id, prop->name );
370
371 u32 propsize = sizeof(netmsg_playerusername) + chs + 1;
372 gameserver_send_to_all( client_id, prop, propsize,
373 k_nSteamNetworkingSend_Reliable );
374
375 /* update database about this */
376 db_request *call = db_alloc_request(
377 sizeof(struct db_set_username_thread_data) );
378 struct db_set_username_thread_data *inf = (void *)call->data;
379 inf->steamid = get_connection_authsteamid( msg );
380 vg_strncpy( client->username, inf->username,
381 sizeof(inf->username), k_strncpy_always_add_null );
382 call->handler = gameserver_update_db_username;
383 db_send_request( call );
384 }
385 else if( tmp->inetmsg_id == k_inetmsg_playerframe ){
386 /* propogate */
387 netmsg_playerframe *frame = alloca(msg->m_cbSize);
388 memcpy( frame, msg->m_pData, msg->m_cbSize );
389 frame->client = client_id;
390 gameserver_send_to_all( client_id, frame, msg->m_cbSize,
391 k_nSteamNetworkingSend_Unreliable );
392 }
393 else if( tmp->inetmsg_id == k_inetmsg_playeritem ){
394 netmsg_playeritem *item = msg->m_pData;
395
396 /* record */
397 struct gameserver_client *client = &gameserver.clients[ client_id ];
398
399 if( item->type_index >= k_netmsg_playeritem_max ){
400 vg_warn( "Client #%d invalid equip type %u\n",
401 client_id, (u32)item->type_index );
402 return;
403 }
404
405 char *dest = client->items[ item->type_index ];
406
407 network_msgstring( item->uid, msg->m_cbSize, sizeof(netmsg_playeritem),
408 dest, ADDON_UID_MAX );
409
410 vg_info( "Client #%d equiped: [%s] %s\n",
411 client_id,
412 (const char *[]){[k_netmsg_playeritem_board]="board",
413 [k_netmsg_playeritem_player]="player",
414 [k_netmsg_playeritem_world0]="world0",
415 [k_netmsg_playeritem_world1]="world1"
416 }[item->type_index], item->uid );
417
418 /* propogate */
419 netmsg_playeritem *prop = alloca(msg->m_cbSize);
420 memcpy( prop, msg->m_pData, msg->m_cbSize );
421 prop->client = client_id;
422 gameserver_send_to_all( client_id, prop, msg->m_cbSize,
423 k_nSteamNetworkingSend_Reliable );
424 }
425 else {
426 vg_warn( "Unknown inetmsg_id recieved from client. (%u)\n",
427 tmp->inetmsg_id );
428 }
429 }
430
431 static void gameserver_request_respond( enum request_status status,
432 netmsg_request *res, vg_msg *body,
433 SteamNetworkingMessage_t *msg ){
434 int client_id = gameserver_client_index( msg->m_conn );
435 u32 len = 0;
436 if( body ){
437 len = body->cur.co;
438 vg_low( "[%d#%d] Response: %d\n", client_id, (i32)res->id, status );
439 vg_msg_print( body, len );
440 }
441
442 res->status = status;
443
444 SteamAPI_ISteamNetworkingSockets_SendMessageToConnection(
445 hSteamNetworkingSockets, msg->m_conn,
446 res, sizeof(netmsg_request) + len,
447 k_nSteamNetworkingSend_Reliable, NULL );
448 SteamAPI_SteamNetworkingMessage_t_Release( msg );
449 }
450
451 struct user_request_thread_data {
452 SteamNetworkingMessage_t *msg;
453 };
454
455 static u32 gameserver_get_current_week(void){
456 return time(NULL) / (7*24*60*60);
457 }
458
459 static void gameserver_process_user_request( db_request *db_req ){
460 struct user_request_thread_data *inf = (void *)db_req->data;
461 SteamNetworkingMessage_t *msg = inf->msg;
462
463 int client_id = gameserver_client_index( msg->m_conn );
464 if( client_id == -1 ){
465 SteamAPI_SteamNetworkingMessage_t_Release( msg );
466 return;
467 }
468
469 netmsg_request *req = (netmsg_request *)msg->m_pData;
470 vg_msg data;
471 vg_msg_init( &data, req->q, msg->m_cbSize - sizeof(netmsg_request) );
472
473 /* create response packet */
474 netmsg_request *res = alloca( sizeof(netmsg_request) + 512 );
475 res->inetmsg_id = k_inetmsg_response;
476 res->id = req->id;
477 vg_msg body;
478 vg_msg_init( &body, res->q, 512 );
479
480 const char *endpoint = vg_msg_getkvstr( &data, "endpoint" );
481
482 if( !endpoint ){
483 gameserver_request_respond( k_request_status_invalid_endpoint,
484 res, NULL, msg );
485 return;
486 }
487
488 if( !strcmp( endpoint, "scoreboard" ) ){
489 const char *mod = vg_msg_getkvstr( &data, "mod" );
490 const char *route = vg_msg_getkvstr( &data, "route" );
491 u32 week = vg_msg_getkvu32( &data, "week", 0 );
492
493 char table_name[ DB_TABLE_UID_MAX ];
494 if( !db_get_highscore_table_name( mod, route, week, table_name ) ){
495 gameserver_request_respond( k_request_status_out_of_memory,
496 res, NULL, msg );
497 return;
498 }
499
500 char buf[512];
501 vg_str q;
502 vg_strnull( &q, buf, 512 );
503 vg_strcat( &q, "SELECT * FROM \"" );
504 vg_strcat( &q, table_name );
505 vg_strcat( &q, "\" ORDER BY time DESC LIMIT 10;" );
506 if( !vg_strgood(&q) ) {
507 gameserver_request_respond( k_request_status_out_of_memory,
508 res, NULL, msg );
509 return;
510 }
511
512 sqlite3_stmt *stmt = db_stmt( q.buffer );
513
514 if( !stmt ){
515 gameserver_request_respond( k_request_status_database_error,
516 res, NULL, msg );
517 return;
518 }
519
520 vg_msg_frame( &body, "rows" );
521 for( u32 i=0; i<10; i ++ ){
522 int fc = sqlite3_step( stmt );
523
524 if( fc == SQLITE_ROW ){
525 i32 time = sqlite3_column_int( stmt, 1 );
526 i64 steamid_i64 = sqlite3_column_int64( stmt, 0 );
527 u64 steamid = *((u64 *)&steamid_i64);
528
529 if( steamid == k_connection_unauthorized )
530 continue;
531
532 vg_msg_frame( &body, "" );
533 vg_msg_wkvu32( &body, "time", time );
534 vg_msg_wkvu64( &body, "steamid", steamid );
535
536 char username[32];
537 if( db_getuserinfo( steamid, username, sizeof(username), NULL ) ){
538 vg_msg_wkvstr( &body, "username", username );
539 }
540
541 vg_msg_end_frame( &body );
542 }
543 else if( fc == SQLITE_DONE ){
544 break;
545 }
546 else {
547 log_sqlite3( fc );
548 break;
549 }
550 }
551
552 sqlite3_finalize( stmt );
553 vg_msg_end_frame( &body );
554
555 if( body.error != k_vg_msg_error_OK ){
556 gameserver_request_respond( k_request_status_out_of_memory,
557 res, NULL, msg );
558 return;
559 }
560
561 gameserver_request_respond( k_request_status_ok, res, &body, msg );
562 }
563 else if( !strcmp( endpoint, "setlap" ) ){
564 /* TODO: we can change userdata to be the client ID and store that in
565 * the client structure. it also would save us scanning the
566 * client array over and over..?
567 */
568 u64 steamid = get_connection_authsteamid( msg );
569 if( steamid == k_connection_unauthorized ){
570 gameserver_request_respond( k_request_status_unauthorized,
571 res, NULL, msg );
572 return;
573 }
574
575 const char *mod = vg_msg_getkvstr( &data, "mod" );
576 const char *route = vg_msg_getkvstr( &data, "route" );
577
578 char weekly_table[ DB_TABLE_UID_MAX ],
579 alltime_table[ DB_TABLE_UID_MAX ];
580
581 u32 week = gameserver_get_current_week();
582
583 if( !db_get_highscore_table_name( mod, route, 0, alltime_table ) ||
584 !db_get_highscore_table_name( mod, route, week, weekly_table ) ){
585 gameserver_request_respond( k_request_status_out_of_memory,
586 res, NULL, msg );
587 return;
588 }
589
590 i32 centiseconds = vg_msg_getkvi32( &data, "time", -1 );
591 if( centiseconds < 5*100 ){
592 gameserver_request_respond( k_request_status_client_error,
593 res, NULL, msg );
594 return;
595 }
596
597 db_writeusertime( alltime_table, steamid, centiseconds, 1 );
598 db_writeusertime( weekly_table, steamid, centiseconds, 1 );
599
600 gameserver_request_respond( k_request_status_ok, res, NULL, msg );
601 }
602 else{
603 gameserver_request_respond( k_request_status_invalid_endpoint,
604 res, NULL, msg );
605 }
606 }
607
608 static void gameserver_rx_300_400( SteamNetworkingMessage_t *msg ){
609 netmsg_blank *tmp = msg->m_pData;
610
611 int client_id = gameserver_client_index( msg->m_conn );
612 if( client_id == -1 ){
613 SteamAPI_SteamNetworkingMessage_t_Release( msg );
614 return;
615 }
616
617 if( tmp->inetmsg_id == k_inetmsg_request ){
618 if( !packet_minsize( msg, sizeof(netmsg_request)+1 ))
619 return;
620
621 db_request *call = db_alloc_request(
622 sizeof(struct user_request_thread_data) );
623 struct user_request_thread_data *inf = (void *)call->data;
624 inf->msg = msg;
625 call->handler = gameserver_process_user_request;
626 db_send_request( call );
627 }
628 else {
629 vg_warn( "Unknown inetmsg_id recieved from client. (%u)\n",
630 tmp->inetmsg_id );
631 SteamAPI_SteamNetworkingMessage_t_Release( msg );
632 }
633 }
634
635 static void poll_connections(void){
636 SteamNetworkingMessage_t *messages[32];
637 int len;
638
639 while(1){
640 len = SteamAPI_ISteamNetworkingSockets_ReceiveMessagesOnPollGroup(
641 hSteamNetworkingSockets,
642 gameserver.client_group, messages, vg_list_size(messages) );
643
644 if( len <= 0 )
645 return;
646
647 for( int i=0; i<len; i++ ){
648 SteamNetworkingMessage_t *msg = messages[i];
649
650 if( msg->m_cbSize < sizeof(netmsg_blank) ){
651 vg_warn( "Discarding message (too small: %d)\n",
652 msg->m_cbSize );
653 continue;
654 }
655
656 netmsg_blank *tmp = msg->m_pData;
657
658 if( (tmp->inetmsg_id >= 200) && (tmp->inetmsg_id < 300) ){
659 gameserver_rx_200_300( msg );
660 SteamAPI_SteamNetworkingMessage_t_Release( msg );
661 }
662 else if( (tmp->inetmsg_id >= 300) && (tmp->inetmsg_id < 400) ){
663 gameserver_rx_300_400( msg );
664 }
665 else{
666 if( tmp->inetmsg_id == k_inetmsg_auth )
667 gameserver_rx_auth( msg );
668 else {
669 vg_warn( "Unknown inetmsg_id recieved from client. (%u)\n",
670 tmp->inetmsg_id );
671 }
672 SteamAPI_SteamNetworkingMessage_t_Release( msg );
673 }
674 }
675 }
676 }
677
678 static u64 seconds_to_server_ticks( double s ){
679 return s / 0.01;
680 }
681
682 static void test_runner( db_request *req ){
683 vg_warn( "RUNNER\n" );
684 char table[DB_TABLE_UID_MAX];
685 if( db_get_highscore_table_name( "sr002-local-mp_mtzero",
686 "Coastal Run", 0, table ) ){
687 if( db_writeusertime( table, 76561198072130043, 232, 1 ) ){
688 vg_success( "Written time\n" );
689 i32 v = db_readusertime( table, 76561198072130043 );
690 vg_success( "Returned time: %u\n", v );
691 }
692 }
693 }
694
695 int main( int argc, char *argv[] ){
696 signal( SIGINT, inthandler );
697 signal( SIGQUIT, inthandler );
698 signal( SIGPIPE, SIG_IGN );
699
700 char *arg;
701 while( vg_argp( argc, argv ) ){
702 if( vg_long_opt( "noauth" ) )
703 gameserver.auth_mode = eServerModeNoAuthentication;
704
705 /* TODO: Options to override, ammend, remove etc */
706 }
707
708 vg_set_mem_quota( 80*1024*1024 );
709 vg_alloc_quota();
710
711 db_init();
712 db_request *req = db_alloc_request(0);
713 if( req ){
714 req->handler = test_runner;
715 db_send_request(req);
716 }
717
718 monitor_start_server(); /* UNIX socket monitor */
719
720 /* steamworks init
721 * --------------------------------------------------------------- */
722 steamworks_ensure_txt( "2103940" );
723 if( gameserver.auth_mode == eServerModeAuthentication ){
724 if( !vg_load_steam_symetric_key( "application_key",
725 gameserver.app_symmetric_key )){
726 return 0;
727 }
728 }
729 else{
730 vg_warn( "Running without user authentication.\n" );
731 }
732
733 if( !SteamGameServer_Init( 0, 27400, 27401,
734 gameserver.auth_mode, "1.0.0.0" ) ){
735 vg_error( "SteamGameServer_Init failed\n" );
736 return 0;
737 }
738
739 void *hSteamGameServer = SteamAPI_SteamGameServer();
740 SteamAPI_ISteamGameServer_LogOnAnonymous( hSteamGameServer );
741
742 SteamAPI_ManualDispatch_Init();
743 HSteamPipe hsteampipe = SteamGameServer_GetHSteamPipe();
744 hSteamNetworkingSockets =
745 SteamAPI_SteamGameServerNetworkingSockets_SteamAPI();
746
747 steam_register_callback( k_iSteamNetAuthenticationStatus, on_auth_status );
748 steam_register_callback( k_iSteamNetConnectionStatusChangedCallBack,
749 on_connect_status );
750
751 vg_success( "Steamworks API running\n" );
752 steamworks_event_loop( hsteampipe );
753
754 /*
755 * Create a listener
756 */
757 HSteamListenSocket listener;
758 SteamNetworkingIPAddr localAddr;
759 SteamAPI_SteamNetworkingIPAddr_Clear( &localAddr );
760 localAddr.m_port = 27402;
761
762 listener = SteamAPI_ISteamNetworkingSockets_CreateListenSocketIP(
763 hSteamNetworkingSockets, &localAddr, 0, NULL );
764 gameserver.client_group = SteamAPI_ISteamNetworkingSockets_CreatePollGroup(
765 hSteamNetworkingSockets );
766
767 u64 server_ticks = 8000,
768 last_record_save = 8000,
769 last_scoreboard_gen = 0,
770 last_monitor_heartbeat = 0;
771
772 while( !sig_stop ){
773 monitor_event_loop();
774 steamworks_event_loop( hsteampipe );
775 poll_connections();
776
777 usleep(10000);
778 server_ticks ++;
779
780 if( server_ticks >
781 (last_monitor_heartbeat + seconds_to_server_ticks(10.0))){
782 last_monitor_heartbeat = server_ticks;
783 monitor_heartbeat();
784 }
785
786 if( db_killed() )
787 break;
788 }
789
790 SteamAPI_ISteamNetworkingSockets_DestroyPollGroup( hSteamNetworkingSockets,
791 gameserver.client_group );
792 SteamAPI_ISteamNetworkingSockets_CloseListenSocket(
793 hSteamNetworkingSockets, listener );
794
795 vg_info( "Shutting down\n..." );
796 SteamGameServer_Shutdown();
797 db_kill();
798 db_free();
799
800 return 0;
801 }