2 * Copyright (C) 2021-2023 Mt.ZERO Software, Harry Godden - All Rights Reserved
5 #define _DEFAULT_SOURCE
10 volatile sig_atomic_t sig_stop
;
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"
19 #include "vg/vg_msg.h"
21 static void inthandler( int signum
) {
25 static const u64 k_connection_unauthorized
= 0xffffffffffffffff;
27 static u64_steamid
get_connection_authsteamid( SteamNetworkingMessage_t
*msg
){
28 i64 userdata
= SteamAPI_ISteamNetworkingSockets_GetConnectionUserData(
29 hSteamNetworkingSockets
, msg
->m_conn
);
31 return *((u64_steamid
*)&userdata
);
34 static void set_connection_authsteamid(HSteamNetConnection con
, u64_steamid id
){
35 i64 userdata
= *((i64
*)&id
);
37 SteamAPI_ISteamNetworkingSockets_SetConnectionUserData(
38 hSteamNetworkingSockets
, con
, userdata
);
41 static void gameserver_send_to_all( int ignore
,
42 const void *pData
, u32 cbData
,
44 for( int i
=0; i
<vg_list_size(gameserver
.clients
); i
++ ){
45 struct gameserver_client
*client
= &gameserver
.clients
[i
];
47 if( (i
==ignore
) || !client
->active
)
50 SteamAPI_ISteamNetworkingSockets_SendMessageToConnection(
51 hSteamNetworkingSockets
, client
->connection
,
52 pData
, cbData
, nSendFlags
, NULL
);
56 static void gameserver_player_join( int index
){
57 struct gameserver_client
*joiner
= &gameserver
.clients
[index
];
59 netmsg_playerjoin join
= { .inetmsg_id
= k_inetmsg_playerjoin
,
61 gameserver_send_to_all( index
, &join
, sizeof(join
),
62 k_nSteamNetworkingSend_Reliable
);
64 /* update the joining user about current connections */
66 netmsg_playerusername
*username
=
67 alloca( sizeof(netmsg_playerusername
) + NETWORK_USERNAME_MAX
);
68 username
->inetmsg_id
= k_inetmsg_playerusername
;
70 netmsg_playeritem
*item
=
71 alloca( sizeof(netmsg_playeritem
) + ADDON_UID_MAX
);
72 item
->inetmsg_id
= k_inetmsg_playeritem
;
74 for( int i
=0; i
<vg_list_size(gameserver
.clients
); i
++ ){
75 struct gameserver_client
*client
= &gameserver
.clients
[i
];
77 if( (i
==index
) || !client
->active
)
81 netmsg_playerjoin init
= { .inetmsg_id
= k_inetmsg_playerjoin
,
83 SteamAPI_ISteamNetworkingSockets_SendMessageToConnection(
84 hSteamNetworkingSockets
, joiner
->connection
,
85 &init
, sizeof(init
), k_nSteamNetworkingSend_Reliable
, NULL
);
89 u32 chs
= vg_strncpy( client
->username
, username
->name
,
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
);
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
;
103 size
= sizeof(netmsg_playeritem
) + chs
+ 1;
104 SteamAPI_ISteamNetworkingSockets_SendMessageToConnection(
105 hSteamNetworkingSockets
, joiner
->connection
,
106 item
, size
, k_nSteamNetworkingSend_Reliable
, NULL
);
111 static void gameserver_player_leave( int index
){
112 netmsg_playerjoin leave
;
113 leave
.inetmsg_id
= k_inetmsg_playerleave
;
116 vg_info( "Player leave (%d)\n", index
);
117 gameserver_send_to_all( index
, &leave
, sizeof(leave
),
118 k_nSteamNetworkingSend_Reliable
);
121 static void new_client_connecting( HSteamNetConnection client
){
125 for( int i
=0; i
<vg_list_size(gameserver
.clients
); i
++ ){
126 if( !gameserver
.clients
[i
].active
){
133 vg_error( "Server full\n" );
134 SteamAPI_ISteamNetworkingSockets_CloseConnection(
135 hSteamNetworkingSockets
, client
,
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
) );
147 gameserver
.clients
[index
].active
= 1;
148 gameserver
.clients
[index
].connection
= client
;
150 SteamAPI_ISteamNetworkingSockets_SetConnectionPollGroup(
151 hSteamNetworkingSockets
,
152 client
, gameserver
.client_group
);
154 /* Just to be sure */
155 set_connection_authsteamid( client
, -1 );
156 gameserver_player_join( index
);
159 vg_warn( "Error accepting client (id: %u)\n", client
);
160 SteamAPI_ISteamNetworkingSockets_CloseConnection(
161 hSteamNetworkingSockets
, client
,
162 k_ESteamNetConnectionEnd_Misc_InternalError
,
164 gameserver
.clients
[index
].active
= 0;
165 gameserver
.clients
[index
].connection
= 0;
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
);
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
];
180 if( client
->active
){
181 if( client
->connection
== hconn
){
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
);
193 vg_info( " %s -> %s\n",
194 string_ESteamNetworkingConnectionState(info
->m_eOldState
),
195 string_ESteamNetworkingConnectionState(info
->m_info
.m_eState
) );
197 if( info
->m_info
.m_eState
==k_ESteamNetworkingConnectionState_Connecting
){
198 new_client_connecting( info
->m_hConn
);
201 if( (info
->m_info
.m_eState
==
202 k_ESteamNetworkingConnectionState_ClosedByPeer
) ||
203 (info
->m_info
.m_eState
==
204 k_ESteamNetworkingConnectionState_ProblemDetectedLocally
) ){
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;
211 gameserver_player_leave(client_id
);
214 vg_info( "End reason: %d\n", info
->m_info
.m_eEndReason
);
215 SteamAPI_ISteamNetworkingSockets_CloseConnection(
216 hSteamNetworkingSockets
, info
->m_hConn
, 0, NULL
, 0 );
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
);
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
);
233 vg_low( "Attempting to verify user\n" );
235 if( msg
->m_cbSize
< sizeof(netmsg_auth
) ){
236 vg_error( "Malformed auth ticket, too small (%u)\n", msg
->m_conn
);
240 netmsg_auth
*auth
= msg
->m_pData
;
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
);
250 u32 ticket_len
= 1024;
252 int success
= SteamEncryptedAppTicket_BDecryptTicket(
253 auth
->ticket
, auth
->ticket_length
, decrypted
,
254 &ticket_len
, gameserver
.app_symmetric_key
,
255 k_nSteamEncryptedAppTicketSymmetricKeyLen
);
258 vg_error( "Failed to decrypt users ticket (client %u)\n", msg
->m_conn
);
259 vg_error( " ticket length: %u\n", auth
->ticket_length
);
261 SteamAPI_ISteamNetworkingSockets_CloseConnection(
262 hSteamNetworkingSockets
,
263 msg
->m_conn
, 0, NULL
, 1 );
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;
273 if( ctime
> expiretime
){
274 vg_error( "Ticket expired (client %u)\n", msg
->m_conn
);
276 /* TODO: Send expired information */
277 SteamAPI_ISteamNetworkingSockets_CloseConnection(
278 hSteamNetworkingSockets
,
279 msg
->m_conn
, 0, NULL
, 1 );
285 SteamEncryptedAppTicket_GetTicketSteamID( decrypted
, ticket_len
, &steamid
);
286 vg_success( "User is authenticated! steamid %lu (%u)\n",
287 steamid
.m_unAll64Bits
, msg
->m_conn
);
289 set_connection_authsteamid( msg
->m_conn
, steamid
.m_unAll64Bits
);
292 static int inet_require_auth( SteamNetworkingMessage_t
*msg
){
293 if( gameserver
.auth_mode
== eServerModeNoAuthentication
)
296 if( get_connection_authsteamid( msg
) == k_connection_unauthorized
){
297 vg_warn( "Unauthorized request! Disconnecting client: %u\n",
300 SteamAPI_ISteamNetworkingSockets_CloseConnection(
301 hSteamNetworkingSockets
,
302 msg
->m_conn
, 0, NULL
, 1 );
310 * Player updates sent to us
311 * -----------------------------------------------------------------------------
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
);
324 struct db_set_username_thread_data
{
326 char username
[ NETWORK_USERNAME_MAX
];
329 static void gameserver_update_db_username( db_request
*db_req
){
330 struct db_set_username_thread_data
*inf
= (void *)db_req
->data
;
332 if( inf
->steamid
== k_connection_unauthorized
)
336 if( inf
->steamid
== 76561198072130043 )
339 db_updateuser( inf
->steamid
, inf
->username
, admin
);
342 static void gameserver_rx_200_300( SteamNetworkingMessage_t
*msg
){
343 netmsg_blank
*tmp
= msg
->m_pData
;
345 int client_id
= gameserver_client_index( msg
->m_conn
);
346 if( client_id
== -1 ) return;
348 if( tmp
->inetmsg_id
== k_inetmsg_playerusername
){
349 if( !packet_minsize( msg
, sizeof(netmsg_playerusername
)+1 ))
352 struct gameserver_client
*client
= &gameserver
.clients
[ client_id
];
353 netmsg_playerusername
*src
= msg
->m_pData
;
355 u32 name_len
= network_msgstring( src
->name
, msg
->m_cbSize
,
356 sizeof(netmsg_playerusername
),
358 NETWORK_USERNAME_MAX
);
360 /* update other users about this change */
361 netmsg_playerusername
*prop
= alloca(sizeof(netmsg_playerusername
)+
362 NETWORK_USERNAME_MAX
);
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
);
369 vg_info( "client #%d changed name to: %s\n", client_id
, prop
->name
);
371 u32 propsize
= sizeof(netmsg_playerusername
) + chs
+ 1;
372 gameserver_send_to_all( client_id
, prop
, propsize
,
373 k_nSteamNetworkingSend_Reliable
);
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
);
385 else if( tmp
->inetmsg_id
== k_inetmsg_playerframe
){
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
);
393 else if( tmp
->inetmsg_id
== k_inetmsg_playeritem
){
394 netmsg_playeritem
*item
= msg
->m_pData
;
397 struct gameserver_client
*client
= &gameserver
.clients
[ client_id
];
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
);
405 char *dest
= client
->items
[ item
->type_index
];
407 network_msgstring( item
->uid
, msg
->m_cbSize
, sizeof(netmsg_playeritem
),
408 dest
, ADDON_UID_MAX
);
410 vg_info( "Client #%d equiped: [%s] %s\n",
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
);
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
);
426 vg_warn( "Unknown inetmsg_id recieved from client. (%u)\n",
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
);
438 vg_low( "[%d#%d] Response: %d\n", client_id
, (i32
)res
->id
, status
);
439 vg_msg_print( body
, len
);
442 res
->status
= status
;
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
);
451 struct user_request_thread_data
{
452 SteamNetworkingMessage_t
*msg
;
455 static u32
gameserver_get_current_week(void){
456 return time(NULL
) / (7*24*60*60);
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
;
463 int client_id
= gameserver_client_index( msg
->m_conn
);
464 if( client_id
== -1 ){
465 SteamAPI_SteamNetworkingMessage_t_Release( msg
);
469 netmsg_request
*req
= (netmsg_request
*)msg
->m_pData
;
471 vg_msg_init( &data
, req
->q
, msg
->m_cbSize
- sizeof(netmsg_request
) );
473 /* create response packet */
474 netmsg_request
*res
= alloca( sizeof(netmsg_request
) + 512 );
475 res
->inetmsg_id
= k_inetmsg_response
;
478 vg_msg_init( &body
, res
->q
, 512 );
480 const char *endpoint
= vg_msg_getkvstr( &data
, "endpoint" );
483 gameserver_request_respond( k_request_status_invalid_endpoint
,
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 );
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
,
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
,
512 sqlite3_stmt
*stmt
= db_stmt( q
.buffer
);
515 gameserver_request_respond( k_request_status_database_error
,
520 vg_msg_frame( &body
, "rows" );
521 for( u32 i
=0; i
<10; i
++ ){
522 int fc
= sqlite3_step( stmt
);
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
);
529 if( steamid
== k_connection_unauthorized
)
532 vg_msg_frame( &body
, "" );
533 vg_msg_wkvu32( &body
, "time", time
);
534 vg_msg_wkvu64( &body
, "steamid", steamid
);
537 if( db_getuserinfo( steamid
, username
, sizeof(username
), NULL
) ){
538 vg_msg_wkvstr( &body
, "username", username
);
541 vg_msg_end_frame( &body
);
543 else if( fc
== SQLITE_DONE
){
552 sqlite3_finalize( stmt
);
553 vg_msg_end_frame( &body
);
555 if( body
.error
!= k_vg_msg_error_OK
){
556 gameserver_request_respond( k_request_status_out_of_memory
,
561 gameserver_request_respond( k_request_status_ok
, res
, &body
, msg
);
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..?
568 u64 steamid
= get_connection_authsteamid( msg
);
569 if( steamid
== k_connection_unauthorized
){
570 gameserver_request_respond( k_request_status_unauthorized
,
575 const char *mod
= vg_msg_getkvstr( &data
, "mod" );
576 const char *route
= vg_msg_getkvstr( &data
, "route" );
578 char weekly_table
[ DB_TABLE_UID_MAX
],
579 alltime_table
[ DB_TABLE_UID_MAX
];
581 u32 week
= gameserver_get_current_week();
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
,
590 i32 centiseconds
= vg_msg_getkvi32( &data
, "time", -1 );
591 if( centiseconds
< 5*100 ){
592 gameserver_request_respond( k_request_status_client_error
,
597 db_writeusertime( alltime_table
, steamid
, centiseconds
, 1 );
598 db_writeusertime( weekly_table
, steamid
, centiseconds
, 1 );
600 gameserver_request_respond( k_request_status_ok
, res
, NULL
, msg
);
603 gameserver_request_respond( k_request_status_invalid_endpoint
,
608 static void gameserver_rx_300_400( SteamNetworkingMessage_t
*msg
){
609 netmsg_blank
*tmp
= msg
->m_pData
;
611 int client_id
= gameserver_client_index( msg
->m_conn
);
612 if( client_id
== -1 ){
613 SteamAPI_SteamNetworkingMessage_t_Release( msg
);
617 if( tmp
->inetmsg_id
== k_inetmsg_request
){
618 if( !packet_minsize( msg
, sizeof(netmsg_request
)+1 ))
621 db_request
*call
= db_alloc_request(
622 sizeof(struct user_request_thread_data
) );
623 struct user_request_thread_data
*inf
= (void *)call
->data
;
625 call
->handler
= gameserver_process_user_request
;
626 db_send_request( call
);
629 vg_warn( "Unknown inetmsg_id recieved from client. (%u)\n",
631 SteamAPI_SteamNetworkingMessage_t_Release( msg
);
635 static void poll_connections(void){
636 SteamNetworkingMessage_t
*messages
[32];
640 len
= SteamAPI_ISteamNetworkingSockets_ReceiveMessagesOnPollGroup(
641 hSteamNetworkingSockets
,
642 gameserver
.client_group
, messages
, vg_list_size(messages
) );
647 for( int i
=0; i
<len
; i
++ ){
648 SteamNetworkingMessage_t
*msg
= messages
[i
];
650 if( msg
->m_cbSize
< sizeof(netmsg_blank
) ){
651 vg_warn( "Discarding message (too small: %d)\n",
656 netmsg_blank
*tmp
= msg
->m_pData
;
658 if( (tmp
->inetmsg_id
>= 200) && (tmp
->inetmsg_id
< 300) ){
659 gameserver_rx_200_300( msg
);
660 SteamAPI_SteamNetworkingMessage_t_Release( msg
);
662 else if( (tmp
->inetmsg_id
>= 300) && (tmp
->inetmsg_id
< 400) ){
663 gameserver_rx_300_400( msg
);
666 if( tmp
->inetmsg_id
== k_inetmsg_auth
)
667 gameserver_rx_auth( msg
);
669 vg_warn( "Unknown inetmsg_id recieved from client. (%u)\n",
672 SteamAPI_SteamNetworkingMessage_t_Release( msg
);
678 static u64
seconds_to_server_ticks( double s
){
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
);
695 int main( int argc
, char *argv
[] ){
696 signal( SIGINT
, inthandler
);
697 signal( SIGQUIT
, inthandler
);
698 signal( SIGPIPE
, SIG_IGN
);
701 while( vg_argp( argc
, argv
) ){
702 if( vg_long_opt( "noauth" ) )
703 gameserver
.auth_mode
= eServerModeNoAuthentication
;
705 /* TODO: Options to override, ammend, remove etc */
708 vg_set_mem_quota( 80*1024*1024 );
712 db_request
*req
= db_alloc_request(0);
714 req
->handler
= test_runner
;
715 db_send_request(req
);
718 monitor_start_server(); /* UNIX socket monitor */
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
)){
730 vg_warn( "Running without user authentication.\n" );
733 if( !SteamGameServer_Init( 0, 27400, 27401,
734 gameserver
.auth_mode
, "1.0.0.0" ) ){
735 vg_error( "SteamGameServer_Init failed\n" );
739 void *hSteamGameServer
= SteamAPI_SteamGameServer();
740 SteamAPI_ISteamGameServer_LogOnAnonymous( hSteamGameServer
);
742 SteamAPI_ManualDispatch_Init();
743 HSteamPipe hsteampipe
= SteamGameServer_GetHSteamPipe();
744 hSteamNetworkingSockets
=
745 SteamAPI_SteamGameServerNetworkingSockets_SteamAPI();
747 steam_register_callback( k_iSteamNetAuthenticationStatus
, on_auth_status
);
748 steam_register_callback( k_iSteamNetConnectionStatusChangedCallBack
,
751 vg_success( "Steamworks API running\n" );
752 steamworks_event_loop( hsteampipe
);
757 HSteamListenSocket listener
;
758 SteamNetworkingIPAddr localAddr
;
759 SteamAPI_SteamNetworkingIPAddr_Clear( &localAddr
);
760 localAddr
.m_port
= 27402;
762 listener
= SteamAPI_ISteamNetworkingSockets_CreateListenSocketIP(
763 hSteamNetworkingSockets
, &localAddr
, 0, NULL
);
764 gameserver
.client_group
= SteamAPI_ISteamNetworkingSockets_CreatePollGroup(
765 hSteamNetworkingSockets
);
767 u64 server_ticks
= 8000,
768 last_record_save
= 8000,
769 last_scoreboard_gen
= 0,
770 last_monitor_heartbeat
= 0;
773 monitor_event_loop();
774 steamworks_event_loop( hsteampipe
);
781 (last_monitor_heartbeat
+ seconds_to_server_ticks(10.0))){
782 last_monitor_heartbeat
= server_ticks
;
790 SteamAPI_ISteamNetworkingSockets_DestroyPollGroup( hSteamNetworkingSockets
,
791 gameserver
.client_group
);
792 SteamAPI_ISteamNetworkingSockets_CloseListenSocket(
793 hSteamNetworkingSockets
, listener
);
795 vg_info( "Shutting down\n..." );
796 SteamGameServer_Shutdown();