From 1d8d9366022c064ef56d80d463c90a79721c6243 Mon Sep 17 00:00:00 2001 From: hgn Date: Mon, 30 Oct 2023 19:32:08 +0000 Subject: [PATCH] view weekly/all-time --- ent_route.c | 11 ++++- gameserver.c | 124 +++++++++++++++++++++++++---------------------- network.c | 62 +++++++++++------------- network.h | 7 ++- network_common.h | 5 ++ network_msg.h | 44 ----------------- world.c | 3 +- world.h | 11 +++++ world_load.c | 12 +++++ world_routes.c | 32 ++++++++++-- world_routes.h | 4 ++ world_sfd.c | 108 ++++++++++++++++++++++++++++++++++++----- world_sfd.h | 6 +++ 13 files changed, 269 insertions(+), 160 deletions(-) diff --git a/ent_route.c b/ent_route.c index a114640..1f0bbed 100644 --- a/ent_route.c +++ b/ent_route.c @@ -35,9 +35,18 @@ static void ent_route_preupdate( ent_route *route, int active ){ gui_helper_action( button_display_string( k_srbind_mleft ), "weekly" ); gui_helper_action( button_display_string( k_srbind_mright ), "all time" ); - gui_helper_action( button_display_string( k_srbind_mback ), "exit" ); + if( button_down( k_srbind_mleft ) ){ + world_sfd.view_weekly = 1; + world_sfd_compile_active_scores(); + } + + if( button_down( k_srbind_mright ) ){ + world_sfd.view_weekly = 0; + world_sfd_compile_active_scores(); + } + if( button_down( k_srbind_mback ) ){ world_entity_unfocus(); return; diff --git a/gameserver.c b/gameserver.c index 840f9d0..20f4e32 100644 --- a/gameserver.c +++ b/gameserver.c @@ -456,6 +456,62 @@ static u32 gameserver_get_current_week(void){ return time(NULL) / (7*24*60*60); } +static enum request_status gameserver_cat_table( + vg_msg *msg, + const char *mod, const char *route, u32 week, const char *alias ) +{ + char table_name[ DB_TABLE_UID_MAX ]; + if( !db_get_highscore_table_name( mod, route, week, table_name ) ) + return k_request_status_out_of_memory; + + char buf[512]; + vg_str q; + vg_strnull( &q, buf, 512 ); + vg_strcat( &q, "SELECT * FROM \"" ); + vg_strcat( &q, table_name ); + vg_strcat( &q, "\" ORDER BY time DESC LIMIT 10;" ); + if( !vg_strgood(&q) ) + return k_request_status_out_of_memory; + + sqlite3_stmt *stmt = db_stmt( q.buffer ); + if( !stmt ) + return k_request_status_database_error; + + vg_msg_frame( msg, alias ); + for( u32 i=0; i<10; i ++ ){ + int fc = sqlite3_step( stmt ); + + if( fc == SQLITE_ROW ){ + i32 time = sqlite3_column_int( stmt, 1 ); + i64 steamid_i64 = sqlite3_column_int64( stmt, 0 ); + u64 steamid = *((u64 *)&steamid_i64); + + if( steamid == k_connection_unauthorized ) + continue; + + vg_msg_frame( msg, "" ); + vg_msg_wkvu32( msg, "time", time ); + vg_msg_wkvu64( msg, "steamid", steamid ); + + char username[32]; + if( db_getuserinfo( steamid, username, sizeof(username), NULL ) ) + vg_msg_wkvstr( msg, "username", username ); + vg_msg_end_frame( msg ); + } + else if( fc == SQLITE_DONE ){ + break; + } + else { + log_sqlite3( fc ); + break; + } + } + + sqlite3_finalize( stmt ); + vg_msg_end_frame( msg ); + return k_request_status_ok; +} + static void gameserver_process_user_request( db_request *db_req ){ struct user_request_thread_data *inf = (void *)db_req->data; SteamNetworkingMessage_t *msg = inf->msg; @@ -490,67 +546,17 @@ static void gameserver_process_user_request( db_request *db_req ){ const char *route = vg_msg_getkvstr( &data, "route" ); u32 week = vg_msg_getkvu32( &data, "week", 0 ); - char table_name[ DB_TABLE_UID_MAX ]; - if( !db_get_highscore_table_name( mod, route, week, table_name ) ){ - gameserver_request_respond( k_request_status_out_of_memory, - res, NULL, msg ); - return; - } - - char buf[512]; - vg_str q; - vg_strnull( &q, buf, 512 ); - vg_strcat( &q, "SELECT * FROM \"" ); - vg_strcat( &q, table_name ); - vg_strcat( &q, "\" ORDER BY time DESC LIMIT 10;" ); - if( !vg_strgood(&q) ) { - gameserver_request_respond( k_request_status_out_of_memory, - res, NULL, msg ); - return; + if( week == NETWORK_LEADERBOARD_CURRENT_WEEK ){ + gameserver_cat_table( &body, mod, route, + gameserver_get_current_week(), "rows_weekly" ); } - - sqlite3_stmt *stmt = db_stmt( q.buffer ); - - if( !stmt ){ - gameserver_request_respond( k_request_status_database_error, - res, NULL, msg ); - return; - } - - vg_msg_frame( &body, "rows" ); - for( u32 i=0; i<10; i ++ ){ - int fc = sqlite3_step( stmt ); - - if( fc == SQLITE_ROW ){ - i32 time = sqlite3_column_int( stmt, 1 ); - i64 steamid_i64 = sqlite3_column_int64( stmt, 0 ); - u64 steamid = *((u64 *)&steamid_i64); - - if( steamid == k_connection_unauthorized ) - continue; - - vg_msg_frame( &body, "" ); - vg_msg_wkvu32( &body, "time", time ); - vg_msg_wkvu64( &body, "steamid", steamid ); - - char username[32]; - if( db_getuserinfo( steamid, username, sizeof(username), NULL ) ){ - vg_msg_wkvstr( &body, "username", username ); - } - - vg_msg_end_frame( &body ); - } - else if( fc == SQLITE_DONE ){ - break; - } - else { - log_sqlite3( fc ); - break; - } + else if( week == NETWORK_LEADERBOARD_ALLTIME_AND_CURRENT_WEEK ){ + gameserver_cat_table( &body, mod, route, 0, "rows" ); + gameserver_cat_table( &body, mod, route, + gameserver_get_current_week(), "rows_weekly" ); } - - sqlite3_finalize( stmt ); - vg_msg_end_frame( &body ); + else + gameserver_cat_table( &body, mod, route, week, "rows" ); if( body.error != k_vg_msg_error_OK ){ gameserver_request_respond( k_request_status_out_of_memory, diff --git a/network.c b/network.c index b0ae677..5d00d16 100644 --- a/network.c +++ b/network.c @@ -3,7 +3,9 @@ #include "network_msg.h" #include "network_common.h" #include "player_remote.h" +#include "world.h" #include "world_sfd.h" +#include "world_routes.h" static void scores_update(void); @@ -149,8 +151,10 @@ static void network_send_username(void){ } static void network_send_request( netmsg_request *req, vg_msg *body, - void (*callback)( netmsg_request *res, - vg_msg *body )){ + void (*callback)( + netmsg_request *res, vg_msg *body, + u64 userdata), + u64 userdata ){ u32 len = 0; if( body ){ len = body->cur.co; @@ -171,6 +175,7 @@ static void network_send_request( netmsg_request *req, vg_msg *body, vg_pool_item( &network_client.request_pool, req->id ); pn->callback = callback; pn->sendtime = vg.time_real; + pn->userdata = userdata; } else{ vg_error( "Unable to send request. Pool is full.\n" ); @@ -186,43 +191,29 @@ static void network_send_request( netmsg_request *req, vg_msg *body, k_nSteamNetworkingSend_Reliable, NULL ); } -static void network_scoreboard_callback( netmsg_request *res, vg_msg *body ){ - for( u32 i=0; i<13; i++ ) - sfd_encode( i, "" ); +static void network_scoreboard_callback( netmsg_request *res, vg_msg *body, + u64 userdata ){ + world_instance *world = world_current_instance(); - if( res->status != k_request_status_ok ){ - char buf[32]; - vg_str s; - vg_strnull( &s, buf, 32 ); - vg_strcat( &s, "Error: " ); - vg_strcati32( &s, res->status ); - - sfd_encode( 4, buf ); - return; - } + world_routes_recv_scoreboard( world, body, userdata, res->status ); + if( userdata == world_sfd.active_route_board ) + world_sfd_compile_active_scores(); +} - u32 l = 0; - if( vg_msg_seekframe( body, "rows" ) ){ - while( vg_msg_seekframe( body, NULL ) ){ - const char *username = vg_msg_getkvstr( body, "username" ); - if( username ) - sfd_encode( l ++, username ); - else - sfd_encode( l ++, "UNKNOWN USER" ); - - vg_msg_skip_frame( body ); - } - } -} /* mod_uid: world mod uid, * route_uid: run name (just a string) - * week: 0 for all-time, n for week # + * week: + * 0 ALL TIME + * 1 CURRENT WEEK + * 2 ALL TIME + CURRENT WEEK + * . + * 10+ specific week index */ static void network_request_scoreboard( const char *mod_uid, const char *route_uid, - u32 week ){ + u32 week, u64 userdata ){ if( !network_client.remote ) return; @@ -235,10 +226,11 @@ static void network_request_scoreboard( const char *mod_uid, vg_msg_wkvstr( &data, "mod", mod_uid ); vg_msg_wkvstr( &data, "route", route_uid ); vg_msg_wkvu32( &data, "week", week ); - network_send_request( req, &data, network_scoreboard_callback ); + network_send_request( req, &data, network_scoreboard_callback, userdata ); } -static void network_publish_callback( netmsg_request *res, vg_msg *body ){ +static void network_publish_callback( netmsg_request *res, vg_msg *body, + u64 userdata ){ if( res->status != k_request_status_ok ){ vg_error( "Publish laptime, server error #%d\n", (i32)res->status ); } @@ -260,7 +252,7 @@ static void network_publish_laptime( const char *mod_uid, vg_msg_wkvstr( &data, "mod", mod_uid ); vg_msg_wkvstr( &data, "route", route_uid ); vg_msg_wkvi32( &data, "time", time_centiseconds ); - network_send_request( req, &data, network_publish_callback ); + network_send_request( req, &data, network_publish_callback, 0 ); } static void network_request_rx_300_400( SteamNetworkingMessage_t *msg ){ @@ -288,7 +280,7 @@ static void network_request_rx_300_400( SteamNetworkingMessage_t *msg ){ if( res->id ){ struct network_request *pn = vg_pool_item( &network_client.request_pool, res->id ); - pn->callback( res, body ); + pn->callback( res, body, pn->userdata ); vg_pool_unwatch( &network_client.request_pool, res->id ); } } @@ -448,6 +440,7 @@ static void network_connect(void){ hSteamNetworkingSockets, &remoteAddr, 0, NULL ); } +#if 0 static void on_inet_scoreboard( SteamNetworkingMessage_t *msg ){ netmsg_scoreboard *sb = msg->m_pData; @@ -481,6 +474,7 @@ static void on_inet_scoreboard( SteamNetworkingMessage_t *msg ){ network_scores_updated = 1; } +#endif static void poll_remote_connection(void){ SteamNetworkingMessage_t *messages[32]; diff --git a/network.h b/network.h index 2916ad9..fc4829d 100644 --- a/network.h +++ b/network.h @@ -14,8 +14,6 @@ #define NETWORK_MAX_REQUESTS 8 -static int network_scores_updated = 0; - /* * Interface */ @@ -56,8 +54,9 @@ struct { struct network_request { vg_pool_node poolnode; - void (*callback)( netmsg_request *res, vg_msg *body ); + void (*callback)( netmsg_request *res, vg_msg *body, u64 userdata ); f64 sendtime; + u64 userdata; } *request_buffer; vg_pool request_pool; @@ -71,7 +70,7 @@ static int packet_minsize( SteamNetworkingMessage_t *msg, u32 size ); static void network_send_item( enum netmsg_playeritem_type type ); static void network_request_scoreboard( const char *mod_uid, const char *route_uid, - u32 week ); + u32 week, u64 userdata ); static void network_publish_laptime( const char *mod_uid, const char *route_uid, f64 lap_time ); diff --git a/network_common.h b/network_common.h index ad5fb56..82274ed 100644 --- a/network_common.h +++ b/network_common.h @@ -8,6 +8,11 @@ #define NETWORK_MAX_PLAYERS 20 #define NETWORK_FRAMERATE 0.1 #define NETWORK_BUFFERFRAMES 6 +#define NETWORK_LEADERBOARD_MAX_SIZE 1024 + +#define NETWORK_LEADERBOARD_ALLTIME 0 +#define NETWORK_LEADERBOARD_CURRENT_WEEK 1 +#define NETWORK_LEADERBOARD_ALLTIME_AND_CURRENT_WEEK 2 #include "addon_types.h" diff --git a/network_msg.h b/network_msg.h index 2e62521..d06494a 100644 --- a/network_msg.h +++ b/network_msg.h @@ -28,52 +28,8 @@ struct netmsg_auth }; enum{ k_inetmsg_auth = 1 }; -typedef struct netmsg_scores_request netmsg_scores_request; -struct netmsg_scores_request -{ - u16 inetmsg_id; -}; -enum{ k_inetmsg_scores_request = 2 }; - -typedef struct netmsg_set_score netmsg_set_score; -struct netmsg_set_score -{ - u16 inetmsg_id; - - u32 record_count; - struct netmsg_score_record - { - u32 trackid; - u64 playerid; - u16 points, time; - } - records[]; -}; -enum{ k_inetmsg_set_score = 6 }; -/* 31.05.23: k_inetmsg_set_score id changed from ID 3 to ID 6, - * 3 is now INVALID */ - -typedef struct netmsg_scoreboard netmsg_scoreboard; -enum{ k_inetmsg_scoreboard = 5 }; -struct netmsg_scoreboard{ - u16 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 */ - /* server control 100 */ - /* player updates 200 */ #define NETMSG_BOUNDARY_BIT 0x8000 diff --git a/world.c b/world.c index af9466c..40f3d75 100644 --- a/world.c +++ b/world.c @@ -58,8 +58,7 @@ static void skaterift_world_get_save_path( enum world_purpose which, #include "world_routes.c" #include "world_traffic.c" -static void world_update( world_instance *world, v3f pos ) -{ +static void world_update( world_instance *world, v3f pos ){ world_render.sky_time += world_render.sky_rate * vg.time_delta; world_render.sky_rate = vg_lerp( world_render.sky_rate, world_render.sky_target_rate, diff --git a/world.h b/world.h index 76d43d6..98b9df9 100644 --- a/world.h +++ b/world.h @@ -6,6 +6,7 @@ #define WORLD_H #include "render.h" +#include "network_msg.h" /* types */ @@ -22,6 +23,13 @@ enum world_purpose{ k_world_max }; +struct leaderboard_cache { + enum request_status status; + f64 cache_time; + u8 *data; + u32 data_len; +}; + typedef struct world_instance world_instance; static void skaterift_world_get_save_path( enum world_purpose which, @@ -194,6 +202,9 @@ struct world_instance { u32 cubemap_cooldown, cubemap_side; rb_object rb_geo; + + /* leaderboards */ + struct leaderboard_cache *leaderboard_cache; }; struct world_static { diff --git a/world_load.c b/world_load.c index 455d30d..fd75aa8 100644 --- a/world_load.c +++ b/world_load.c @@ -97,6 +97,18 @@ static void world_instance_load_mdl( u32 instance_id, const char *path ){ world_gen_compute_light_indices( world ); mdl_close( meta ); + /* allocate leaderboard buffers */ + u32 bs = mdl_arrcount(&world->ent_route)*sizeof(struct leaderboard_cache); + world->leaderboard_cache = vg_linear_alloc( heap, bs ); + + for( u32 i=0; ient_route ); i ++ ){ + struct leaderboard_cache *board = &world->leaderboard_cache[i]; + board->data = vg_linear_alloc( heap, NETWORK_LEADERBOARD_MAX_SIZE ); + board->status = k_request_status_client_error; + board->cache_time = 0.0; + board->data_len = 0; + } + vg_async_call( async_world_postprocess, world, 0 ); vg_async_stall(); } diff --git a/world_routes.c b/world_routes.c index 87b21c8..52c2c2a 100644 --- a/world_routes.c +++ b/world_routes.c @@ -17,6 +17,8 @@ #include "pointcloud.h" #include "gui.h" #include "steam.h" +#include "network_msg.h" +#include "network_common.h" #include "shaders/scene_route.h" #include "shaders/routeui.h" @@ -953,14 +955,37 @@ static void world_gen_routes_ent_init( world_instance *world ){ world_routes_clear( world ); } +static void world_routes_recv_scoreboard( world_instance *world, + vg_msg *body, u32 route_id, + enum request_status status ){ + if( route_id >= mdl_arrcount( &world->ent_route ) ){ + vg_error( "Scoreboard route_id out of range (%u)\n", route_id ); + return; + } + + struct leaderboard_cache *board = &world->leaderboard_cache[ route_id ]; + board->status = status; + + if( body == NULL ) + board->data_len = 0; + + if( body->max > NETWORK_LEADERBOARD_MAX_SIZE ){ + vg_error( "Scoreboard leaderboard too big (%u>%u)\n", body->max, + NETWORK_LEADERBOARD_MAX_SIZE ); + return; + } + + memcpy( board->data, body->buf, body->max ); + board->data_len = body->max; +} + /* * ----------------------------------------------------------------------------- * Events * ----------------------------------------------------------------------------- */ -static void world_routes_init(void) -{ +static void world_routes_init(void){ world_static.current_run_version = 200; world_static.time = 300.0; world_static.last_use = 0.0; @@ -969,8 +994,7 @@ static void world_routes_init(void) shader_routeui_register(); } -static void world_routes_update( world_instance *world ) -{ +static void world_routes_update( world_instance *world ){ world_static.time += vg.time_delta; for( u32 i=0; ient_route); i++ ){ diff --git a/world_routes.h b/world_routes.h index 13541ed..636793d 100644 --- a/world_routes.h +++ b/world_routes.h @@ -6,6 +6,7 @@ #define ROUTES_H #include "world.h" +#include "network_msg.h" static void world_routes_init(void); static void world_routes_fracture( world_instance *world, ent_gate *gate, @@ -21,5 +22,8 @@ static void world_routes_update_timer_texts( world_instance *world ); static void world_routes_update( world_instance *world ); static void world_routes_fixedupdate( world_instance *world ); static void world_routes_clear( world_instance *world ); +static void world_routes_recv_scoreboard( world_instance *world, + vg_msg *body, u32 route_id, + enum request_status status ); #endif /* ROUTES_H */ diff --git a/world_sfd.c b/world_sfd.c index 9310aee..ca6f774 100644 --- a/world_sfd.c +++ b/world_sfd.c @@ -6,6 +6,8 @@ #include "shaders/scene_vertex_blend.h" #include "network.h" #include "entity.h" +#include "network_common.h" +#include "world_routes.h" static f32 sfd_encode_glyph( char c ){ int value = 0; @@ -59,6 +61,77 @@ static void sfd_encode( u32 row, const char *str ){ } } +static void world_sfd_compile_scores( struct leaderboard_cache *board ){ + for( u32 i=0; i<13; i++ ) + sfd_encode( i, "" ); + + if( !board ){ + sfd_encode( 4, "Error out of range" ); + return; + } + + if( !network_client.remote ){ + sfd_encode( 4, "Offline" ); + return; + } + + if( board->status == k_request_status_not_found ){ + sfd_encode( 4, "No records" ); + return; + } + + if( board->status != k_request_status_ok ){ + char buf[32]; + vg_str s; + vg_strnull( &s, buf, 32 ); + vg_strcat( &s, "Error: " ); + vg_strcati32( &s, board->status ); + sfd_encode( 4, buf ); + return; + } + + vg_msg body; + vg_msg_init( &body, board->data, board->data_len ); + + const char *alias = "rows"; + + if( world_sfd.view_weekly ){ + alias = "rows_weekly"; + sfd_encode( 0, "Weekly" ); + } + else { + sfd_encode( 0, "All-Time" ); + } + + u32 l = 1; + if( vg_msg_seekframe( &body, alias ) ){ + while( vg_msg_seekframe( &body, NULL ) ){ + const char *username = vg_msg_getkvstr( &body, "username" ); + + if( username ) + sfd_encode( l ++, username ); + else + sfd_encode( l ++, "UNKNOWN USER" ); + + vg_msg_skip_frame( &body ); + } + } + else { + sfd_encode( 4, "No records" ); + } +} + +static void world_sfd_compile_active_scores(void){ + world_instance *world = world_current_instance(); + + struct leaderboard_cache *board = NULL; + + if( world_sfd.active_route_board < mdl_arrcount( &world->ent_route ) ) + board = &world->leaderboard_cache[ world_sfd.active_route_board ]; + + world_sfd_compile_scores( board ); +} + static void world_sfd_update( world_instance *world, v3f pos ){ if( mdl_arrcount( &world->ent_route ) ){ u32 closest = 0; @@ -74,22 +147,33 @@ static void world_sfd_update( world_instance *world, v3f pos ){ } } - if( (world_sfd.active_route_board != closest) || network_scores_updated ){ - network_scores_updated = 0; - world_sfd.active_route_board = closest; - ent_route *route = mdl_arritm( &world->ent_route, closest ); + struct leaderboard_cache *board = &world->leaderboard_cache[ closest ]; - addon_reg *world_reg = - world_static.instance_addons[ world_static.active_instance ]; + /* request new board if cache expires */ + if( network_client.remote ){ + f64 delta = vg.time_real - board->cache_time; + if( (delta > 45.0) || (board->cache_time == 0.0) ){ + board->cache_time = vg.time_real; + ent_route *route = mdl_arritm( &world->ent_route, closest ); + addon_reg *world_reg = + world_static.instance_addons[ world - world_static.instances ]; - char mod_uid[ ADDON_UID_MAX ]; - addon_alias_uid( &world_reg->alias, mod_uid ); + char mod_uid[ ADDON_UID_MAX ]; + addon_alias_uid( &world_reg->alias, mod_uid ); - network_request_scoreboard( - mod_uid, - mdl_pstr( &world->meta, route->pstr_name ), - 0 ); + network_request_scoreboard( + mod_uid, + mdl_pstr( &world->meta, route->pstr_name ), + NETWORK_LEADERBOARD_ALLTIME_AND_CURRENT_WEEK, closest ); + } } + + /* compile board text if we changed. */ + if( world_sfd.active_route_board != closest ){ + world_sfd_compile_active_scores(); + } + + world_sfd.active_route_board = closest; } for( int i=0; i