From 89032d64e2867adb66e4598a0c66d3e853a22bb0 Mon Sep 17 00:00:00 2001 From: hgn Date: Thu, 18 Aug 2022 00:58:44 +0100 Subject: [PATCH] stuff --- blender_export.py | 12 +-- build.sh | 3 +- highscores.h | 206 +++++++++++++++++++++++++++++++------- network.h | 250 +++++++++++++++++++++++++++++----------------- network_msg.h | 24 ++++- server.c | 97 +++++++++--------- testaa.c | 13 ++- world_info.h | 35 +++++++ world_routes.h | 134 +++++++++++++++++++------ 9 files changed, 557 insertions(+), 217 deletions(-) create mode 100644 world_info.h diff --git a/blender_export.py b/blender_export.py index 6fadae2..c520e04 100644 --- a/blender_export.py +++ b/blender_export.py @@ -752,14 +752,10 @@ def cv_draw(): continue if loop_complete: - course_colours = [Vector((0,0.8,0.2,1.0)), \ - Vector((0,0.3,0.9,1.0)), \ - Vector((0.4,0.0,0.8,1.0)),\ - Vector((0.5,0.8,0.0,1.0)),\ - Vector((0.0,0.7,0.6,1.0)),\ - Vector((0.2,0.9,0.5,1.0)) ] - - cc = course_colours[ course_count % len(course_colours) ] + cc = Vector((obj.cv_data.colour[0],\ + obj.cv_data.colour[1],\ + obj.cv_data.colour[2],\ + 1.0)) for sj in range(si): sk = (sj+1)%si diff --git a/build.sh b/build.sh index ace67bf..9fb7886 100755 --- a/build.sh +++ b/build.sh @@ -144,10 +144,11 @@ vg_command(){ # Dependencies cp vg/dep/steam/steamclient.so bin/linux_server/ cp vg/dep/steam/libsteam_api.so bin/linux_server/ + cp vg/dep/steam/libsdkencryptedappticket.so bin/linux_server/ _compiler=$_linux_compiler _options=$_linux_options - _link="-lm $_linux_linksteam" + _link="-lm -lsdkencryptedappticket $_linux_linksteam" _src="server.c" _folder=$_linux_server_folder _dst="skaterift_server" diff --git a/highscores.h b/highscores.h index 84ab9a4..b1c9cc0 100644 --- a/highscores.h +++ b/highscores.h @@ -3,6 +3,7 @@ #include "vg/vg_store.h" #include "vg/vg_stdint.h" +#include "world_info.h" /* * Designed to be used across client and server, @@ -20,7 +21,7 @@ typedef struct highscore_playerinfo highscore_playerinfo; struct highscore_playerinfo { - char nickname[16]; + char nickname[10]; u64 playerid; union @@ -364,9 +365,14 @@ static aatree_ptr highscores_push_record( highscore_record *record ) return index; } -static aatree_ptr highscore_set_user_nickname( u64 steamid, char nick[16] ) +static aatree_ptr highscore_set_user_nickname( u64 steamid, char nick[10] ) { - vg_log( "Updating %lu's nickname\n", steamid ); + char name[11]; + for( int i=0; i<10; i++ ) + name[i] = nick[i]; + name[10] = '\0'; + + vg_log( "Updating %lu's nickname -> %s\n", steamid, name ); struct highscore_system *sys = &highscore_system; @@ -403,76 +409,206 @@ static aatree_ptr highscore_set_user_nickname( u64 steamid, char nick[16] ) record ); } - for( int i=0; i<16; i++ ) + for( int i=0; i<10; i++ ) info->nickname[i] = nick[i]; return AATREE_PTR_NIL; } -static void _highscore_showtime( void *data ) +/* Get the length of a string, bounded by '\0' or len, whichever is first */ +static int highscore_strlen( const char *str, int len ) +{ + int str_length; + for( str_length=0; str_length= width ) + return; + + buf[j] = str[i]; + } +} + +/* Print the string(max length:len) left aligned into buf */ +static void highscore_strl( char *buf, const char *str, int len ) { - highscore_record *record = data; - printf( "%hu", record->time ); + for( int i=0; i=len ) + return; + + buf[ len-1 - (i ++) ] = '0' + (value % 10); + value /= 10; + } + + for( ;i=len ) + break; - highscore_playerinfo *info = data; - for( int i=0; i<16; i++ ) - namebuf[i] = info->nickname[i]; + temp[ i ++ ] = '0' + (value % 10); + value /= 10; + } + + if( i>len ) + i = len; - printf( " %lu %s", info->playerid, namebuf ); + for( int j=0; jdbheader.tracks[ trackid ]; + highscore_track_table *table = &sys->dbheader.tracks[ id ]; aatree_ptr it = aatree_kth( &sys->aainfo_time, table->root_time, 0 ); - vg_info( "Highscores: top %u fastest records for track %u\n", count, trackid ); - vg_info( "================================================\n" ); - vg_info( "%3s| %16s | %5s | %5s | %s\n", "#", "Player", "Time", "Score", - "TrackID" ); - vg_info( "================================================\n" ); - int i=0; - while( it != AATREE_PTR_NIL && i < 10 ) + highscore_strc ( buf+w*0, inf->name, w,w ); + highscore_clear( buf+w*1, '-', w ); + highscore_strl ( buf+w*2, " #| Player | Time | Pts", 27 ); + + for( int i=0; iaainfo_time, it ); + char *line = buf+w*(3+i); + highscore_intr( line, i+1, 2, ' ' ); + line[2] = '|'; + if( it == AATREE_PTR_NIL ) + continue; + + highscore_record *record = aatree_get_data( &sys->aainfo_time, it ); highscore_playerinfo temp; temp.playerid = record->playerid; aatree_ptr info_ptr = aatree_find( &sys->aainfo_playerinfo_playerid, sys->dbheader.playerinfo_root, &temp ); - - char namebuf[17]; + + /* Player name */ if( info_ptr == AATREE_PTR_NIL ) - snprintf( namebuf, 16, "[%lu]", record->playerid ); + highscore_strl( line+3, "unknown", 10 ); else { highscore_playerinfo *inf = aatree_get_data( &sys->aainfo_playerinfo_playerid, info_ptr ); - for( int i=0; i<16; i++ ) - namebuf[i] = inf->nickname[i]; - namebuf[16] = '\0'; + highscore_strl( line+3, inf->nickname, 10 ); } - vg_info( "%3d| %16s %5hu %5hu %3hu\n", - i+1, namebuf, record->time, record->points, - record->trackid ); + u16 miliseconds = record->time, + seconds = miliseconds / 100, + minutes = seconds / 60; + + miliseconds %= 100; + seconds %= 60; + minutes %= 60; - i++; + if( minutes > 9 ) minutes = 9; + + /* Timer */ + highscore_intr( line+14, minutes, 1, '0' ); + line[15] = ':'; + highscore_intr( line+16, seconds, 2, '0' ); + line[18] = '.'; + highscore_intr( line+19, miliseconds, 2, '0' ); + + /* Score */ + highscore_intl( line+22, record->time, 5 ); it = aatree_next( &sys->aainfo_time, it ); } +} + +/* Print string out to file using newlines. Count is number of records + * ( this requires a buffer of (count+3)*27 size */ +static void highscores_board_printf( FILE *fp, const char *buf, u32 count ) +{ + int w=27; - vg_info( "================================================\n" ); + for( int i=0; iinetmsg_id = k_inetmsg_auth; + auth->ticket_length = steam_app_ticket_length; + for( int i=0; iticket[i] = steam_app_ticket[i]; + + SteamAPI_ISteamNetworkingSockets_SendMessageToConnection( + hSteamNetworkingSockets, cremote, auth, size, + k_nSteamNetworkingSend_Reliable, NULL ); +} + +static void send_score_request(void) +{ + vg_info( "Requesting scores\n" ); + netmsg_scores_request req; + req.inetmsg_id = k_inetmsg_scores_request; + + SteamAPI_ISteamNetworkingSockets_SendMessageToConnection( + hSteamNetworkingSockets, cremote, &req, sizeof(netmsg_scores_request), + k_nSteamNetworkingSend_Reliable, NULL ); +} + +static void send_score_update(void) +{ + vg_info( "Sending scores\n" ); + u32 size = sizeof(netmsg_set_score) + + 1 * sizeof(struct netmsg_score_record); + + netmsg_set_score *setscore = alloca( size ); + setscore->inetmsg_id = k_inetmsg_set_score; + setscore->record_count = 1; + setscore->records[0].trackid = 0; + setscore->records[0].playerid = 0; + setscore->records[0].points = 1386; + setscore->records[0].time = 19432; + + SteamAPI_ISteamNetworkingSockets_SendMessageToConnection( + hSteamNetworkingSockets, cremote, setscore, size, + k_nSteamNetworkingSend_Reliable, NULL ); +} + +static void send_nickname(void) +{ + netmsg_set_nickname nick; + nick.inetmsg_id = k_inetmsg_set_nickname; + + memset( nick.nickname, 0, 10 ); + strcpy( nick.nickname, "real H" ); + SteamAPI_ISteamNetworkingSockets_SendMessageToConnection( + hSteamNetworkingSockets, cremote, &nick, sizeof(netmsg_set_nickname), + k_nSteamNetworkingSend_Reliable, NULL ); + + network_name_update = 0; +} + +static void server_routine_update(void) +{ + send_auth_ticket(); + + if( network_name_update ) + send_nickname(); + + send_score_update(); + send_score_request(); +} + +static void on_server_connect_status( CallbackMsg_t *msg ) +{ + SteamNetConnectionStatusChangedCallback_t *info = (void *)msg->m_pubParam; + vg_info( " Connection status changed for %lu\n", info->m_hConn ); + vg_info( " %s -> %s\n", + string_ESteamNetworkingConnectionState(info->m_eOldState), + string_ESteamNetworkingConnectionState(info->m_info.m_eState) ); + + if( info->m_hConn == cremote ) + { + cremote_state = info->m_info.m_eState; + if( info->m_info.m_eState == + k_ESteamNetworkingConnectionState_Connected ) + { + vg_success(" Connected to remote server.. running updates\n"); + server_routine_update(); + } + } + else + { + vg_warn( " Recieved signal from unknown connection\n" ); + } +} + +static void network_connect_gc(void) +{ + /* Connect to server if not connected */ SteamNetworkingIPAddr remoteAddr; -#define USE_LOCALHOST -#ifdef USE_LOCALHOST +#ifdef SR_USE_LOCALHOST SteamAPI_SteamNetworkingIPAddr_SetIPv6LocalHost( &remoteAddr, 27402 ); #else const char *server_lon1 = "46.101.34.155:27402"; @@ -111,55 +207,38 @@ static void server_connect(void) hSteamNetworkingSockets, &remoteAddr, 0, NULL ); } -static void send_auth_ticket(void) +static void on_inet_scoreboard( SteamNetworkingMessage_t *msg ) { - u32 size = sizeof(netmsg_auth) + steam_app_ticket_length; - netmsg_auth *auth = malloc(size); - - auth.inetmsg_id = k_inetmsg_auth; - auth.ticket_length = steam_app_ticket_length; - for( int i=0; im_pData; -static void scores_update(void) -{ - vg_log( "scores_update()\n" ); + u32 base_size = sizeof(netmsg_scoreboard)- + sizeof(struct netmsg_board)*vg_list_size(track_infos), + expected = base_size+sizeof(struct netmsg_board)*sb->board_count; - if( cremote_state == k_ESteamNetworkingConnectionState_Connected ) + if( msg->m_cbSize != expected ) { - /* - * request updated scores, this does not require any authentication. - */ - netmsg_scores_request req; - req.inetmsg_id = k_inetmsg_scores_request; - - SteamAPI_ISteamNetworkingSockets_SendMessageToConnection( - hSteamNetworkingSockets, cremote, &req, - sizeof(netmsg_scores_request), - k_nSteamNetworkingSend_Reliable, NULL ); - - /* - * Send record update, it requires authentication - */ - if( steam_app_ticket_length ) - { - } + vg_error( "Server scoreboard was corrupted. Size: %u != %u\n", + msg->m_cbSize, expected ); } else { - /* - * if we are not connected, make a connection to the server and then in - * the future this function will be called again when it is connected - */ - server_connect(); + if( vg_list_size(track_infos) > sb->board_count ) + vg_warn( "Server is out of date, not enough boards recieved\n"); + else if( vg_list_size(track_infos) < sb->board_count ) + vg_warn( "Client out of date, server sent more boards than we have\n"); + else + vg_success( "Recieved new scoreboards from server\n" ); + + for( int i=0; i < vg_min(sb->board_count,vg_list_size(track_infos)); i++) + { + scoreboard_client_data.boards[i] = sb->boards[i]; + highscores_board_printf( stdout, sb->boards[i].data, 10 ); + } } + + /* We dont need to stay on the server currently */ + SteamAPI_ISteamNetworkingSockets_CloseConnection( + hSteamNetworkingSockets, cremote, 0, NULL, 1 ); } static void poll_connection(void) @@ -181,54 +260,52 @@ static void poll_connection(void) if( msg->m_cbSize < sizeof(netmsg_blank) ) { - vg_warn( "Discarding message (too small: %d)\n", - msg->m_cbSize ); + vg_warn( "Discarding message (too small: %d)\n", msg->m_cbSize ); continue; } netmsg_blank *tmp = msg->m_pData; - if( tmp->inetmsg_id == k_inetmsg_scores_info ) - { - netmsg_scores_info *info = msg->m_pData; - vg_log( "Recieved %u score records\n", info->record_count ); - SteamAPI_ISteamNetworkingSockets_CloseConnection( - hSteamNetworkingSockets, cremote, 0, NULL, 1 ); - cremote_state = k_ESteamNetworkingConnectionState_None; - } + if( tmp->inetmsg_id == k_inetmsg_scoreboard ) + on_inet_scoreboard( msg ); SteamAPI_SteamNetworkingMessage_t_Release( msg ); } } } -static u64 in_server_ticks( double seconds ) +/* + * Subroutine to be connected to main game loop, runs all routines on timers + */ +static void network_update(void) { - return (u64)(seconds / 0.1); -} + if( steam_ready ) + { + static double last_update = 0.0; + poll_connection(); + + if( vg_time > (last_update + 60.0) ) + { + last_update = vg_time; -static void on_server_connect_status( CallbackMsg_t *msg ) -{ - SteamNetConnectionStatusChangedCallback_t *info = (void *)msg->m_pubParam; - vg_info( " Connection status changed for %lu\n", info->m_hConn ); - vg_info( " %s -> %s\n", - string_ESteamNetworkingConnectionState(info->m_info.m_eState), - string_ESteamNetworkingConnectionState(info->m_eOldState) ); + if( steam_app_ticket_length ) + { + network_connect_gc(); + } + else + { + vg_log( "Not making remote connection; app ticket not gotten\n" ); + } + } - if( info->m_hConn == cremote ) - { - cremote_state = info->m_info.m_eState; - if( info->m_info.m_eState == - k_ESteamNetworkingConnectionState_Connected ) + if( vg_time > (last_update + 10.0) && + (cremote_state == k_ESteamNetworkingConnectionState_Connected )) { - vg_success(" Connected to remote server\n"); - scores_update(); + vg_warn( "Connected to server but no return... disconnecting\n" ); + SteamAPI_ISteamNetworkingSockets_CloseConnection( + hSteamNetworkingSockets, cremote, 0, NULL, 1 ); } } - else - { - vg_warn( " Recieved signal from unknown connection\n" ); - } } static void network_init(void) @@ -241,24 +318,15 @@ static void network_init(void) } } -static void network_update(void) -{ - if( steam_ready ) - { - static double last_update = -9000.0; - poll_connection(); - - if( vg_time > (last_update + 60.0) ) - { - last_update = vg_time; - scores_update(); - } - } -} - static void network_end(void) { /* TODO: Fire off any buffered highscores that need to be setn */ + if( cremote_state == k_ESteamNetworkingConnectionState_Connected || + cremote_state == k_ESteamNetworkingConnectionState_Connecting ) + { + SteamAPI_ISteamNetworkingSockets_CloseConnection( + hSteamNetworkingSockets, cremote, 0, NULL, 1 ); + } } #endif diff --git a/network_msg.h b/network_msg.h index 4ab0942..0a0d1f8 100644 --- a/network_msg.h +++ b/network_msg.h @@ -2,6 +2,8 @@ #define NETWORK_MSG_H #include "vg/vg_stdint.h" +#include "world_info.h" +#include "vg/vg_platform.h" #pragma pack(push,1) @@ -49,9 +51,29 @@ typedef struct netmsg_set_nickname netmsg_set_nickname; struct netmsg_set_nickname { u32 inetmsg_id; - char nickname[16]; + char nickname[10]; }; enum{ k_inetmsg_set_nickname = 4 }; + +typedef struct netmsg_scoreboard netmsg_scoreboard; +enum{ k_inetmsg_scoreboard = 5 }; +struct netmsg_scoreboard +{ + u32 inetmsg_id; + + u32 board_count; + struct netmsg_board + { + char data[27*13]; + } + boards[ vg_list_size(track_infos) ]; +} +static scoreboard_client_data = { + .inetmsg_id = k_inetmsg_scoreboard, + .board_count = vg_list_size(track_infos) +}; +/* probably about 10k */ + #pragma pack(pop) #endif /* NETWORK_MSG_H */ diff --git a/server.c b/server.c index 578c3f5..1f28633 100644 --- a/server.c +++ b/server.c @@ -26,11 +26,13 @@ void inthandler( int signum ) #include "network_msg.h" #include "highscores.h" -void *hSteamHTTP, - *hSteamNetworkingSockets; +static const u64 k_connection_unauthorized = 0xffffffffffffffff; -u8 steam_symetric_key[ k_nSteamEncryptedAppTicketSymmetricKeyLen ]; -HSteamNetPollGroup client_pollgroup; +static void *hSteamHTTP, + *hSteamNetworkingSockets; + +static u8 steam_symetric_key[ k_nSteamEncryptedAppTicketSymmetricKeyLen ]; +static HSteamNetPollGroup client_pollgroup; static void recieve_http( void *callresult, void *context ) { @@ -79,8 +81,9 @@ static void new_client_connecting( HSteamNetConnection client ) SteamAPI_ISteamNetworkingSockets_SetConnectionPollGroup( hSteamNetworkingSockets, client, client_pollgroup ); - - set_connection_authsteamid( client, 0 ); + + /* Just to be sure */ + set_connection_authsteamid( client, -1 ); } else { @@ -102,8 +105,8 @@ static void on_connect_status( CallbackMsg_t *msg ) vg_info( " Connection status changed for %lu\n", info->m_hConn ); vg_info( " %s -> %s\n", - string_ESteamNetworkingConnectionState(info->m_info.m_eState), - string_ESteamNetworkingConnectionState(info->m_eOldState) ); + string_ESteamNetworkingConnectionState(info->m_eOldState), + string_ESteamNetworkingConnectionState(info->m_info.m_eState) ); if( info->m_info.m_eState==k_ESteamNetworkingConnectionState_Connecting ) { @@ -113,7 +116,7 @@ static void on_connect_status( CallbackMsg_t *msg ) static void on_inet_auth( SteamNetworkingMessage_t *msg ) { - if( get_connection_authsteamid( msg ) ) + if( get_connection_authsteamid( msg ) != k_connection_unauthorized ) { vg_warn( "Already authorized this user but app ticket was sent" " again (%u)\n", msg->m_conn ); @@ -149,10 +152,11 @@ static void on_inet_auth( SteamNetworkingMessage_t *msg ) if( !success ) { vg_error( "Failed to decrypt users ticket (client %u)\n", msg->m_conn ); + vg_error( " ticket length: %u\n", auth->ticket_length ); SteamAPI_ISteamNetworkingSockets_CloseConnection( hSteamNetworkingSockets, - msg->m_conn, 0, NULL, 0 ); + msg->m_conn, 0, NULL, 1 ); return; } @@ -170,7 +174,7 @@ static void on_inet_auth( SteamNetworkingMessage_t *msg ) /* TODO: Send expired information */ SteamAPI_ISteamNetworkingSockets_CloseConnection( hSteamNetworkingSockets, - msg->m_conn, 0, NULL, 0 ); + msg->m_conn, 0, NULL, 1 ); return; } } @@ -185,14 +189,14 @@ static void on_inet_auth( SteamNetworkingMessage_t *msg ) static int inet_require_auth( SteamNetworkingMessage_t *msg ) { - if( !get_connection_authsteamid( msg ) ) + if( get_connection_authsteamid( msg ) == k_connection_unauthorized ) { vg_warn( "Unauthorized request! Disconnecting client: %u\n", msg->m_conn ); SteamAPI_ISteamNetworkingSockets_CloseConnection( hSteamNetworkingSockets, - msg->m_conn, 0, NULL, 0 ); + msg->m_conn, 0, NULL, 1 ); return 0; } @@ -201,35 +205,12 @@ static int inet_require_auth( SteamNetworkingMessage_t *msg ) static void on_inet_score_request( SteamNetworkingMessage_t *msg ) { -#if 0 - if( get_connection_authsteamid( msg ) ) - { - vg_log( "Recieved score request, sending records. (id: %u)\n", - msg->m_conn ); - - /* Send back current scores */ - u32 data_size = sizeof(netmsg_scores_info) + - 0*sizeof(struct netmsg_score_record); - netmsg_scores_info *return_info = malloc( data_size ); - - return_info->inetmsg_id = k_inetmsg_scores_info; - return_info->record_count = 0; - - SteamAPI_ISteamNetworkingSockets_SendMessageToConnection( - hSteamNetworkingSockets, msg->m_conn, - return_info, data_size, - k_nSteamNetworkingSend_Reliable, NULL ); - } - else - { - vg_warn( "Unauthorized request! Disconnecting client: %u\n", - msg->m_conn ); + if( !inet_require_auth(msg) ) return; - SteamAPI_ISteamNetworkingSockets_CloseConnection( - hSteamNetworkingSockets, - msg->m_conn, 0, NULL, 0 ); - } -#endif + SteamAPI_ISteamNetworkingSockets_SendMessageToConnection( + hSteamNetworkingSockets, msg->m_conn, + &scoreboard_client_data, sizeof(netmsg_scoreboard), + k_nSteamNetworkingSend_Reliable, NULL ); } static void on_inet_set_nickname( SteamNetworkingMessage_t *msg ) @@ -317,17 +298,34 @@ static void poll_connections(void) on_inet_score_request( msg ); else if( tmp->inetmsg_id == k_inetmsg_set_nickname ) on_inet_set_nickname( msg ); + else if( tmp->inetmsg_id == k_inetmsg_set_score ) + on_inet_set_score( msg ); SteamAPI_SteamNetworkingMessage_t_Release( msg ); } } } -u64 seconds_to_server_ticks( double s ) +static u64 seconds_to_server_ticks( double s ) { return s / 0.1; } +static void generate_boards(void) +{ + FILE *fp = fopen( "www/html/srhighscores.txt", "w" ); + + for( int i=0; idata, i, 10 ); + highscores_board_printf( fp, board->data, 10 ); + } + + fclose( fp ); +} + int main( int argc, char *argv[] ) { signal( SIGINT, inthandler ); @@ -393,7 +391,10 @@ int main( int argc, char *argv[] ) #endif u64 server_ticks = 8000, - last_record_save = 8000; + last_record_save = 8000, + last_scoreboard_gen = 0; + + generate_boards(); while( !sig_stop ) { @@ -403,13 +404,19 @@ int main( int argc, char *argv[] ) usleep(100000); server_ticks ++; - if(last_record_save+server_ticks > seconds_to_server_ticks( 10.0*60.0 )) + if(server_ticks > last_scoreboard_gen + seconds_to_server_ticks(1.0*60.0)) + { + last_scoreboard_gen = server_ticks; + generate_boards(); + } + + if(server_ticks > last_record_save + seconds_to_server_ticks( 10.0*60.0 )) { last_record_save = server_ticks; highscores_serialize_all(); } } - + highscores_serialize_all(); highscores_free(); diff --git a/testaa.c b/testaa.c index 5e2cd93..0f2bd3b 100644 --- a/testaa.c +++ b/testaa.c @@ -34,9 +34,9 @@ int main(int argc, const char *argv[]) highscores_push_record( &entry ); } - for( int i=0; i<80; i++ ) + for( int i=0; i<800; i++ ) { - char rando[16]; + char rando[10]; int l=2+rand()%8; for( int i=0; igates[id]; - struct route_node *pnode = &r->nodes[ig->node_id], - *pdest = &r->nodes[pnode->next[0]]; - - r->active_gate = id; - - for( int i=0; iroute_count; i++ ) - { - struct route *route = &r->routes[i]; - - route->active = 0; - for( int j=0; jref_count; j++ ) - { - if( pdest->route_ids[j] == i ) - { - route->active = 1; - break; - } - } - } -} - -static u32 world_routes_get_path( struct route *route, u32 stack[64] ) +static u32 world_routes_get_path( u32 starter, u32 stack[64] ) { struct subworld_routes *r = subworld_routes(); u32 stack_i[64]; - stack[0] = route->start; + stack[0] = starter; stack_i[0] = 0; u32 si = 1; @@ -166,6 +144,94 @@ static u32 world_routes_get_path( struct route *route, u32 stack[64] ) return 0; } +static void world_routes_verify_run( u32 route, double new_pass_time ) +{ + struct subworld_routes *r = subworld_routes(); + if( r->current_run_version == 0 ) return; + + u32 stack[64]; + u32 si = world_routes_get_path( r->routes[route].start, stack ); + + /* + * we only care about gates that ref gates, so shuffle down the array + */ + u32 sj = 0; + for( u32 i=0; inodes[stack[i]].is_gate && r->nodes[stack[(i+1)%si]].is_gate ) + stack[sj ++] = r->nodes[stack[i]].gate_id; + + /* + * run versions & times must always ASCEND apart from exactly once, where + * the tail connects to the head + */ + + vg_info("Verifying run (%u)\n", route); + + u32 descend_allowance = 1; + double lap_time = 0.0; + + for( u32 i=0; igates[stack[i]], + *pb = &r->gates[stack[(i+1) % sj]]; + + vg_info( " pa: %u, pb: %u\n", pa->passed_version, pb->passed_version ); + + int version_inorder = 0; + double diff = 0.0; + + if( pb->passed_version == pa->passed_version+1 ) + { + version_inorder = 1; + diff = pb->time_passed - pa->time_passed; + } + else if( pb->passed_version == pa->passed_version+1-sj && + pa->passed_version+1 == r->current_run_version ) + { + version_inorder = 1; + diff = new_pass_time - pa->time_passed; + } + + if( !version_inorder ) + return; + + lap_time += diff; + } + + /* We've now verified the run was completed correctly */ + vg_success( "Lap time set. route %u: %lf\n", route, lap_time ); +} + +static void world_routes_activate_gate( u32 id ) +{ + struct subworld_routes *r = subworld_routes(); + struct route_gate *ig = &r->gates[id]; + struct route_node *pnode = &r->nodes[ig->node_id], + *pdest = &r->nodes[pnode->next[0]]; + + r->active_gate = id; + + for( u32 i=0; iroute_count; i++ ) + { + struct route *route = &r->routes[i]; + + route->active = 0; + for( u32 j=0; jref_count; j++ ) + { + if( pdest->route_ids[j] == i ) + { + world_routes_verify_run( i, vg_time ); + route->active = 1; + break; + } + } + } + + ig->time_passed = vg_time; + ig->passed_version = r->current_run_version; + r->current_run_version ++; +} + static void world_routes_debug(void) { struct subworld_routes *r = subworld_routes(); @@ -181,7 +247,7 @@ static void world_routes_debug(void) struct route *route = &r->routes[i]; u32 stack[64]; - u32 si = world_routes_get_path( route, stack ); + u32 si = world_routes_get_path( route->start, stack ); u32 colours[] = { 0xfff58142, 0xff42cbf5, 0xff42f56c, 0xfff542b3, 0xff5442f5 }; @@ -239,7 +305,7 @@ static void world_routes_gen_meshes(void) struct route *route = &r->routes[i]; u32 stack[64]; - u32 si = world_routes_get_path( route, stack ); + u32 si = world_routes_get_path( route->start, stack ); u32 last_valid = 0; @@ -459,6 +525,8 @@ static void world_routes_loadfrom( mdl_header *mdl ) { struct route_gate *rg = &r->gates[r->gate_count]; rg->node_id = r->node_count; + rg->passed_version = 0; + rg->time_passed = 0.0; v3_copy( pnode->co, rg->gate.co[0] ); v3_copy( pother->co, rg->gate.co[1] ); @@ -527,7 +595,7 @@ static void world_routes_loadfrom( mdl_header *mdl ) struct route *route = &r->routes[i]; u32 stack[64]; - u32 si = world_routes_get_path( route, stack ); + u32 si = world_routes_get_path( route->start, stack ); for( int sj=0; sj