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
# 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"
#include "vg/vg_store.h"
#include "vg/vg_stdint.h"
+#include "world_info.h"
/*
* Designed to be used across client and server,
struct highscore_playerinfo
{
- char nickname[16];
+ char nickname[10];
u64 playerid;
union
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;
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<len; str_length++ )
+ if( !str[str_length] )
+ return str_length;
+
+ return str_length;
+}
+
+/* Print the string(max length:len) centered into buf (has width:width) */
+static void highscore_strc( char *buf, const char *str, int len, int width )
+{
+ int str_length = highscore_strlen( str, len ),
+ offs = (width-str_length)/2;
+
+ for( int i=0; i<str_length; i++ )
+ {
+ int j=i+offs;
+
+ if( j >= 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; i++ )
+ {
+ if( !str[i] )
+ return;
+
+ buf[i] = str[i];
+ }
+}
+
+/* Print the string (max length:len) right aligned into buf (has width:width) */
+static void highscore_strr( char *buf, const char *str, int len, int width )
+{
+ int str_length = highscore_strlen( str, len );
+
+ for( int i=0; i<len; i++ )
+ {
+ if( !str[i] )
+ return;
+
+ buf[width-str_length+i] = str[i];
+ }
+}
+
+/* Print integer (padded with: alt), right aligned into buf(width: len) */
+static void highscore_intr( char *buf, int value, int len, char alt )
+{
+ int i=0;
+ while(value)
+ {
+ if( i>=len )
+ return;
+
+ buf[ len-1 - (i ++) ] = '0' + (value % 10);
+ value /= 10;
+ }
+
+ for( ;i<len; i ++ )
+ buf[ len-1 - i ] = alt;
}
-static void _highscore_showname( void *data )
+/* Print integer into buffer with max length len */
+static void highscore_intl( char *buf, int value, int len )
{
- char namebuf[17];
- namebuf[16] = '\0';
+ char temp[32];
+
+ int i=0;
+ while(value)
+ {
+ if( 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; j<i; j ++ )
+ {
+ buf[j] = temp[ i-1-j ];
+ }
+}
+
+/* Clear buffer with length using clr character */
+static void highscore_clear( char *buf, char clr, int length )
+{
+ for( int i=0; i<length; i++ )
+ buf[i] = clr;
}
-static void highscores_print_track( u32 trackid, u32 count )
+/*
+ Megapark Green
+--------------------------
+ #| Player | Time | Pts
+ 1|aaaabbbbcc 5:23.32 30000
+ 2| jef 0:20.34 10000
+ 3|aaabbbcccl 2:30.45 20000
+ 4|
+ 5|
+ 6|
+ 7|
+ 8|
+ 9|
+10|
+*/
+
+/* Generate a highscores board in text form, the width is always 27. Buffer
+ * must be (count+3)*27 in size. */
+static void highscores_board_generate( char *buf, u32 id, u32 count )
{
+ int w=27;
+ highscore_clear( buf, ' ', (count+3)*w );
+
+ struct track_info *inf = &track_infos[id];
struct highscore_system *sys = &highscore_system;
- highscore_track_table *table = &sys->dbheader.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; i<count; i++ )
{
- highscore_record *record = aatree_get_data( &sys->aainfo_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; i<count+3; i++ )
+ fprintf( fp, "%.27s\n", &buf[i*w] );
}
#endif /* HIGHSCORES_H */
#include "vg/vg_stdint.h"
#include "steam.h"
#include "network_msg.h"
+#include "highscores.h"
/*
* Interface
*/
+#define SR_USE_LOCALHOST
/* Call it at start; Connects us to the gameserver */
static void network_init(void);
*/
static u8 steam_app_ticket[ 1024 ];
static u32 steam_app_ticket_length;
+static int network_name_update = 1;
static HSteamNetConnection cremote;
static ESteamNetworkingConnectionState cremote_state =
NULL, 0 );
}
-static void server_connect(void)
+static void send_auth_ticket(void)
{
- /* Connect to server if not connected */
+ u32 size = sizeof(netmsg_auth) + steam_app_ticket_length;
+ netmsg_auth *auth = alloca(size);
+
+ auth->inetmsg_id = k_inetmsg_auth;
+ auth->ticket_length = steam_app_ticket_length;
+ for( int i=0; i<steam_app_ticket_length; i++ )
+ auth->ticket[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";
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; i<steam_app_ticket_length; i++ )
- auth.ticket[i] = steam_app_ticket[i];
-
- SteamAPI_ISteamNetworkingSockets_SendMessageToConnection(
- hSteamNetworkingSockets, cremote, auth, size,
- k_nSteamNetworkingSend_Reliable, NULL );
-
- free( auth );
-}
+ netmsg_scoreboard *sb = msg->m_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)
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)
}
}
-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
#define NETWORK_MSG_H
#include "vg/vg_stdint.h"
+#include "world_info.h"
+#include "vg/vg_platform.h"
#pragma pack(push,1)
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 */
#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 )
{
SteamAPI_ISteamNetworkingSockets_SetConnectionPollGroup(
hSteamNetworkingSockets,
client, client_pollgroup );
-
- set_connection_authsteamid( client, 0 );
+
+ /* Just to be sure */
+ set_connection_authsteamid( client, -1 );
}
else
{
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 )
{
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 );
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;
}
/* TODO: Send expired information */
SteamAPI_ISteamNetworkingSockets_CloseConnection(
hSteamNetworkingSockets,
- msg->m_conn, 0, NULL, 0 );
+ msg->m_conn, 0, NULL, 1 );
return;
}
}
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;
}
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 )
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; i<vg_list_size(track_infos); i++ )
+ {
+ struct netmsg_board *board = &scoreboard_client_data.boards[i];
+
+ highscores_board_generate( board->data, i, 10 );
+ highscores_board_printf( fp, board->data, 10 );
+ }
+
+ fclose( fp );
+}
+
int main( int argc, char *argv[] )
{
signal( SIGINT, inthandler );
#endif
u64 server_ticks = 8000,
- last_record_save = 8000;
+ last_record_save = 8000,
+ last_scoreboard_gen = 0;
+
+ generate_boards();
while( !sig_stop )
{
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();
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; i<l; i++ )
highscore_system.dbheader.playerinfo_root, 0,
&ln, &err, _highscore_showname, 1 );
#endif
+
+ char testy[27*(10+3)];
+
+ for( int i=0; i<vg_list_size(track_infos); i++ )
+ {
+ highscores_board_generate( testy, i, 10 );
+ highscores_board_printf( stdout, testy, 10 );
+ }
- highscores_print_track( 12, 10 );
highscores_serialize_all();
highscores_free();
return 0;
--- /dev/null
+#ifndef WORLD_INFO_H
+#define WORLD_INFO_H
+
+#include "vg/vg_stdint.h"
+
+/* Purely an information header, shares common strings across client and
+ * server programs. */
+
+static struct world_info
+{
+
+}
+world_info;
+
+static struct track_info
+{
+ const char *name;
+}
+track_infos[] =
+{
+ {
+ .name = "Megapark Green"
+ },
+ {
+ .name = "Megapark Blue"
+ },
+ {
+ .name = "Megapark Yellow"
+ },
+ {
+ .name = "Megapark Red"
+ }
+};
+
+#endif
{
teleport_gate gate;
- u32 route_count,
- node_id;
+ u32 node_id;
+
+ double time_passed; /* When did we last pass this gate? */
+ u32 passed_version; /* Incremented on every reset */
}
*gates;
u32 gate_count,
gate_cap;
- u32 active_gate;
+ u32 active_gate,
+ current_run_version;
scene scene_lines;
};
}
}
-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( int i=0; i<r->route_count; i++ )
- {
- struct route *route = &r->routes[i];
-
- route->active = 0;
- for( int j=0; j<pdest->ref_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;
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; i<si; i++ )
+ if( r->nodes[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; i<sj; i++ )
+ {
+ struct route_gate *pa = &r->gates[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; i<r->route_count; i++ )
+ {
+ struct route *route = &r->routes[i];
+
+ route->active = 0;
+ for( u32 j=0; j<pdest->ref_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();
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 };
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;
{
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] );
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<si; sj++ )
{