+/*
+ * Copyright (C) 2021-2022 Mt.ZERO Software, Harry Godden - All Rights Reserved
+ */
+
#ifndef HIGHSCORES_H
#define HIGHSCORES_H
#include "vg/vg_store.h"
#include "vg/vg_stdint.h"
+#include "world_info.h"
/*
* Designed to be used across client and server,
aainfo_playerinfo_playerid,
aainfo_playerinfo;
- void *data, *playerinfo_data;
-}
-highscore_system;
-
-static int highscore_cmp_points( void *a, void *b )
-{
- highscore_record *pa = a, *pb = b;
- return (int)pa->points - (int)pb->points;
-}
-
-static int highscore_cmp_datetime( void *a, void *b )
-{
- highscore_record *pa = a, *pb = b;
-
- if( pa->datetime == pb->datetime ) return 0;
- return pa->datetime < pb->datetime? 1: -1;
-}
-
-static int highscore_cmp_time( void *a, void *b )
-{
- highscore_record *pa = a, *pb = b;
- return (int)pb->time - (int)pa->time;
-}
-
-static int highscore_cmp_playerid( void *a, void *b )
-{
- highscore_record *pa = a, *pb = b;
- if( pa->playerid == pb->playerid ) return 0;
- return pa->playerid < pb->playerid? -1: 1;
-}
-
-static int highscore_cmp_playerinfo_playerid( void *a, void *b )
-{
- highscore_playerinfo *pa = a, *pb = b;
- if( pa->playerid == pb->playerid ) return 0;
- return pa->playerid < pb->playerid? -1: 1;
-}
-
-static void *highscore_malloc( u32 count, u32 size )
-{
- size_t requested_mem = size * count;
- void *data = malloc( requested_mem );
-
- requested_mem /= 1024;
- requested_mem /= 1024;
-
- if( !data )
- {
- vg_error( "Could not allocated %dmb of memory\n", requested_mem );
- return NULL;
- }
- else
- vg_success( "Allocated %dmb for %u records\n", requested_mem, count );
-
- return data;
-}
-
-static void highscores_free(void)
-{
- free( highscore_system.data );
- free( highscore_system.playerinfo_data );
-}
-
-static int highscores_init( u32 pool_size, u32 playerinfo_pool_size )
-{
- struct highscore_system *sys = &highscore_system;
-
- sys->data = highscore_malloc( pool_size, sizeof(highscore_record) );
- if( !sys->data ) return 0;
-
- sys->playerinfo_data =
- highscore_malloc( playerinfo_pool_size, sizeof(highscore_playerinfo));
- if( !sys->playerinfo_data )
- {
- free( sys->data );
- return 0;
- }
-
- /* This is ugly.. too bad! */
- sys->aainfo.base = highscore_system.data;
- sys->aainfo.stride = sizeof(highscore_record);
- sys->aainfo.offset = offsetof(highscore_record,pool);
- sys->aainfo.p_cmp = NULL;
-
- sys->aainfo_datetime.base = highscore_system.data;
- sys->aainfo_datetime.stride = sizeof(highscore_record);
- sys->aainfo_datetime.offset = offsetof(highscore_record,aa.datetime);
- sys->aainfo_datetime.p_cmp = highscore_cmp_datetime;
-
- sys->aainfo_points.base = highscore_system.data;
- sys->aainfo_points.stride = sizeof(highscore_record);
- sys->aainfo_points.offset = offsetof(highscore_record,aa.points);
- sys->aainfo_points.p_cmp = highscore_cmp_points;
-
- sys->aainfo_time.base = highscore_system.data;
- sys->aainfo_time.stride = sizeof(highscore_record);
- sys->aainfo_time.offset = offsetof(highscore_record,aa.time);
- sys->aainfo_time.p_cmp = highscore_cmp_time;
-
- sys->aainfo_playerid.base = highscore_system.data;
- sys->aainfo_playerid.stride = sizeof(highscore_record);
- sys->aainfo_playerid.offset = offsetof(highscore_record,aa.playerid);
- sys->aainfo_playerid.p_cmp = highscore_cmp_playerid;
-
- sys->aainfo_playerinfo_playerid.base = highscore_system.playerinfo_data;
- sys->aainfo_playerinfo_playerid.stride = sizeof(highscore_playerinfo);
- sys->aainfo_playerinfo_playerid.offset =
- offsetof(highscore_playerinfo,aa_playerid);
- sys->aainfo_playerinfo_playerid.p_cmp = highscore_cmp_playerinfo_playerid;
-
- sys->aainfo_playerinfo.base = highscore_system.playerinfo_data;
- sys->aainfo_playerinfo.stride = sizeof(highscore_playerinfo);
- sys->aainfo_playerinfo.offset = offsetof(highscore_playerinfo,aapn);
- sys->aainfo_playerinfo.p_cmp = NULL;
-
- FILE *fp = fopen( ".aadb", "rb" );
- if( fp )
- {
- vg_info( "Loading existing database\n" );
-
- u64 count = fread( &sys->dbheader, sizeof(highscore_database), 1, fp );
-
- if( count != 1 )
- {
- vg_error( "Unexpected EOF reading database header\n" );
-
- highscores_free();
- return 0;
- }
-
- count = fread( sys->data, sizeof(highscore_record), pool_size, fp );
- if( count != pool_size )
- {
- vg_error( "Unexpected EOF reading database contents;"
- " %lu records of %u were read\n", count, pool_size );
-
- highscores_free();
- return 0;
- }
-
- count = fread( sys->playerinfo_data, sizeof(highscore_playerinfo),
- playerinfo_pool_size, fp );
- if( count != playerinfo_pool_size )
- {
- vg_error( "Unexpected EOF reading playerinfo contents;"
- " %lu records of %u were read\n", count,
- playerinfo_pool_size );
-
- highscores_free();
- return 0;
- }
-
- fclose( fp );
- }
- else
- {
- vg_log( "No existing database found (.aadb)\n" );
- vg_info( "Initializing database nodes\n" );
- memset( &sys->dbheader, 0, sizeof(highscore_database) );
-
- sys->dbheader.pool_head = aatree_init_pool( &sys->aainfo, pool_size );
- sys->dbheader.entry_capacity = pool_size;
-
- for( int i=0; i<vg_list_size(sys->dbheader.tracks); i++ )
- {
- highscore_track_table *table = &sys->dbheader.tracks[i];
- table->root_points = AATREE_PTR_NIL;
- table->root_playerid = AATREE_PTR_NIL;
- table->root_time = AATREE_PTR_NIL;
- table->root_datetime = AATREE_PTR_NIL;
- }
-
- /* Initialize secondary db */
- sys->dbheader.playerinfo_head = aatree_init_pool(
- &sys->aainfo_playerinfo,
- playerinfo_pool_size );
- sys->dbheader.playerinfo_capacity = playerinfo_pool_size;
- sys->dbheader.playerinfo_root = AATREE_PTR_NIL;
- }
-
- return 1;
-}
-
-static int highscores_serialize_all(void)
-{
- struct highscore_system *sys = &highscore_system;
- vg_info( "Serializing database\n" );
-
- FILE *fp = fopen( ".aadb", "wb" );
-
- if( !fp )
- {
- vg_error( "Could not open .aadb\n" );
- return 0;
- }
+ void *data,
+ *playerinfo_data;
- fwrite( &sys->dbheader, sizeof(highscore_database), 1, fp );
- fwrite( sys->data, sizeof(highscore_record),
- sys->dbheader.entry_capacity, fp );
- fwrite( sys->playerinfo_data, sizeof(highscore_playerinfo),
- sys->dbheader.playerinfo_capacity, fp );
-
- fclose( fp );
- return 1;
+ u32 pool_size, playerinfo_pool_size;
}
+highscore_system;
-static aatree_ptr highscores_push_record( highscore_record *record )
-{
- struct highscore_system *sys = &highscore_system;
-
- /* TODO: Verify steam ID */
- vg_log( "Inserting record into database for track %hu\n",record->trackid );
-
- if( record->trackid >= vg_list_size(sys->dbheader.tracks) )
- {
- vg_error( "TrackID out of range (%hu>=%d)\n", record->trackid,
- vg_list_size(sys->dbheader.tracks) );
-
- return AATREE_PTR_NIL;
- }
-
- /* Search for existing record on this track */
- highscore_track_table *table = &sys->dbheader.tracks[record->trackid];
- aatree_ptr existing = aatree_find( &sys->aainfo_playerid,
- table->root_playerid,
- record );
-
- if( existing != AATREE_PTR_NIL )
- {
- highscore_record *crecord = aatree_get_data( &sys->aainfo_playerid,
- existing );
-
- if( crecord->time < record->time ||
- (crecord->time == record->time && crecord->points > record->points))
- {
- vg_log( "Not overwriting better score\n" );
- return existing;
- }
-
- vg_log( "Freeing existing record for player %lu\n", record->playerid );
- table->root_playerid = aatree_del( &sys->aainfo_playerid, existing );
- table->root_datetime = aatree_del( &sys->aainfo_datetime, existing );
- table->root_points = aatree_del( &sys->aainfo_points, existing );
- table->root_time = aatree_del( &sys->aainfo_time, existing );
-
- aatree_pool_free( &sys->aainfo, existing, &sys->dbheader.pool_head );
- }
-
- aatree_ptr index =
- aatree_pool_alloc( &sys->aainfo, &sys->dbheader.pool_head );
-
- if( index == AATREE_PTR_NIL )
- {
- vg_error( "Database records are over capacity!\n" );
- return index;
- }
-
- highscore_record *dst = aatree_get_data( &sys->aainfo, index );
- memset( dst, 0, sizeof(highscore_record) );
-
- dst->trackid = record->trackid;
- dst->datetime = record->datetime;
- dst->playerid = record->playerid;
- dst->points = record->points;
- dst->time = record->time;
-
- table->root_time =
- aatree_insert( &sys->aainfo_time, table->root_time, index );
- table->root_datetime =
- aatree_insert( &sys->aainfo_datetime, table->root_datetime, index );
- table->root_playerid =
- aatree_insert( &sys->aainfo_playerid, table->root_playerid, index );
- table->root_points =
- aatree_insert( &sys->aainfo_points, table->root_points, index );
-
- return index;
-}
-
-static aatree_ptr highscore_set_user_nickname( u64 steamid, char nick[16] )
-{
- vg_log( "Updating %lu's nickname\n", steamid );
-
- struct highscore_system *sys = &highscore_system;
-
- highscore_playerinfo temp;
- temp.playerid = steamid;
-
- aatree_ptr record = aatree_find( &sys->aainfo_playerinfo_playerid,
- sys->dbheader.playerinfo_root,
- &temp );
- highscore_playerinfo *info;
-
- if( record != AATREE_PTR_NIL )
- {
- info = aatree_get_data( &sys->aainfo_playerinfo, record );
- }
- else
- {
- record = aatree_pool_alloc( &sys->aainfo_playerinfo,
- &sys->dbheader.playerinfo_head );
-
- if( record == AATREE_PTR_NIL )
- {
- vg_error( "Player info database is over capacity!\n" );
- return AATREE_PTR_NIL;
- }
-
- info = aatree_get_data( &sys->aainfo_playerinfo, record );
- memset( info, 0, sizeof(highscore_playerinfo) );
-
- info->playerid = steamid;
- sys->dbheader.playerinfo_root = aatree_insert(
- &sys->aainfo_playerinfo_playerid,
- sys->dbheader.playerinfo_root,
- record );
- }
-
- for( int i=0; i<16; i++ )
- info->nickname[i] = nick[i];
-
- return AATREE_PTR_NIL;
-}
-
-static void _highscore_showtime( void *data )
-{
- highscore_record *record = data;
- printf( "%hu", record->time );
-}
-
-static void _highscore_showname( void *data )
-{
- char namebuf[17];
- namebuf[16] = '\0';
-
- highscore_playerinfo *info = data;
- for( int i=0; i<16; i++ )
- namebuf[i] = info->nickname[i];
-
- printf( " %lu %s", info->playerid, namebuf );
-}
-
-static void highscores_print_track( u32 trackid, u32 count )
-{
- struct highscore_system *sys = &highscore_system;
-
- highscore_track_table *table = &sys->dbheader.tracks[ trackid ];
- 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_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];
- if( info_ptr == AATREE_PTR_NIL )
- snprintf( namebuf, 16, "[%lu]", record->playerid );
- 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';
- }
-
- vg_info( "%3d| %16s %5hu %5hu %3hu\n",
- i+1, namebuf, record->time, record->points,
- record->trackid );
-
- i++;
- it = aatree_next( &sys->aainfo_time, it );
- }
-
- vg_info( "================================================\n" );
-}
+static int highscore_intr( char *buf, int value, int len, char alt );
+static int highscore_intl( char *buf, int value, int len );
+static void highscores_board_printf( FILE *fp, const char *buf, u32 count );
+static aatree_ptr highscore_set_user_nickname( u64 steamid, char nick[16] );
+static aatree_ptr highscores_push_record( highscore_record *record );
+static void highscores_board_generate( char *buf, u32 id, u32 count );
+static void highscores_init( u32 pool_size, u32 playerinfo_pool_size );
+static int highscores_read( const char *path );
+static void highscores_create_db(void);
+static int highscores_serialize_all(void);
#endif /* HIGHSCORES_H */