u32 propsize = sizeof(netmsg_playerusername) + chs + 1;
gameserver_send_to_all( client_id, prop, propsize, k_nSteamNetworkingSend_Reliable );
- db_action_set_username( client->steamid, client->username );
+
+ struct profile_edits edits = {0};
+ edits.steamid = client->steamid;
+ edits.set_name = 1;
+ vg_strncpy( client->username, edits.name, sizeof(edits.name), k_strncpy_always_add_null );
+ db_action_edit_profile( &edits );
}
else if( tmp->inetmsg_id == k_inetmsg_playerframe )
{
return 0;
}
+static int _rcon_edit_user( int argc, const char *argv[] )
+{
+ if( argc >= 1 )
+ {
+ u64 steamid = 0;
+ bool hex = 0;
+
+ if( argv[0][0] == '0' )
+ if( argv[0][1] == 'x' )
+ hex = 1;
+
+ if( hex ) steamid = strtoull( argv[0]+2, NULL, 16 );
+ else steamid = strtoull( argv[0], NULL, 10 );
+
+ if( steamid )
+ {
+ if( argc == 1 )
+ {
+ vg_info( "User details for %lx: not-implemented\n", steamid );
+ return 1;
+ }
+
+ struct profile_edits edits = {0};
+ edits.steamid = steamid;
+
+ int j = 1;
+ while( j < argc )
+ {
+ if( !strcmp( argv[j], "name" ) )
+ {
+ j ++;
+ if( j == argc )
+ {
+ vg_error( "Need string for name <x>\n" );
+ return 0;
+ }
+
+ edits.set_name = 1;
+ vg_strncpy( argv[j], edits.name, sizeof(edits.name), k_strncpy_always_add_null );
+ j ++;
+ }
+ else if( !strcmp( argv[j], "cc" ) )
+ {
+ j ++;
+ if( j == argc )
+ {
+ vg_error( "Need string for cc <x>\n" );
+ return 0;
+ }
+
+ edits.set_cc = 1;
+ vg_strncpy( argv[j], edits.cc, 4, k_strncpy_always_add_null );
+ j ++;
+ }
+ else if( argv[j][0] == '+' || argv[j][0] == '-' )
+ {
+ bool set = argv[j][0] == '+';
+ u32 flag = 0x00;
+ if( !strcmp( argv[j]+1, "LEGEND" ) ) flag = 0x2;
+ else if( !strcmp( argv[j]+1, "EARLY" ) ) flag = 0x1;
+ else if( !strcmp( argv[j]+1, "ADMIN" ) ) flag = 0x8000;
+ else
+ {
+ vg_error( "Unknown flag '%s'\n", argv[j]+1 );
+ return 0;
+ }
+
+ if( set ) edits.set_flags |= flag;
+ else edits.clear_flags |= flag;
+ j ++;
+ }
+ else
+ {
+ vg_error( "Unknown option '%s'\n", argv[j] );
+ return 0;
+ }
+ }
+
+ db_action_edit_profile( &edits );
+ }
+ else
+ {
+ vg_error( "Invalid steam id format '%s'\n", argv[0] );
+ return 0;
+ }
+ }
+ else
+ {
+ vg_info( "Usage: edit_profile\n"
+ " Options:\n"
+ " +FLAG (LEGEND,EARLY,ADMIN)\n"
+ " -FLAG\n"
+ " cc <cc>\n",
+ " name <username>\n" );
+ }
+
+ return 0;
+}
+
+static int _rcon_dumpdb( int argc, const char *argv[] )
+{
+ if( argc == 1 )
+ {
+ db_action_dump( argv[0] );
+ return 1;
+ }
+ else
+ {
+ vg_error( "Usage: dumpdb <output_filepath>\n" );
+ return 0;
+ }
+}
+
int main( int argc, const char *argv[] )
{
_gameserver.thread = pthread_self();
vg_log_init();
vg_console_init();
vg_console_reg_cmd( "spoofid", _rcon_spoofid, NULL );
+ vg_console_reg_cmd( "dumpdb", _rcon_dumpdb, NULL );
+ vg_console_reg_cmd( "edit_user", _rcon_edit_user, NULL );
signal( SIGINT, inthandler );
signal( SIGQUIT, inthandler );
_gs_db.users_tree = db->userdata_address + offsetof(struct skaterift_database, users_tree);
_gs_db.leaderboards_table = db->userdata_address + offsetof(struct skaterift_database, leaderboards_table);
vg_db_tree_init( db, _gs_db.users_tree );
- vg_db_dumb_table_init( db, _gs_db.leaderboards_table, sizeof(struct skaterift_leaderboard), 0xffff );
+ vg_db_table_init( db, _gs_db.leaderboards_table, sizeof(struct skaterift_leaderboard), 0xffff );
vg_db_skipper_init( db, db->userdata_address + offsetof(struct skaterift_database,leaderboards_skipper), 0xffff );
while( vg_async_process_next_task( &_gs_db.tasks ) ) {}
static i32 leaderboard_uid_compare( vg_skipper_context *ctx, void *comparand, u16 item_index )
{
- u64 item_addr = vg_db_dumb_table_get( &_gs_db.db, ctx->table_address, item_index );
+ u64 item_addr = vg_db_table_get( &_gs_db.db, ctx->table_address, item_index );
struct leaderboard_comparand *lc = comparand;
u32 hash;
u16 table_id;
if( vg_db_skipper_find( &_gs_db.db, &uid_ctx, &table_id, &lc ) )
- return vg_db_dumb_table_get( &_gs_db.db, _gs_db.leaderboards_table, table_id );
+ return vg_db_table_get( &_gs_db.db, _gs_db.leaderboards_table, table_id );
struct skaterift_leaderboard leaderboard;
/* create */
- u64 new_address = vg_db_dumb_table_append( &_gs_db.db, _gs_db.leaderboards_table );
+ u64 new_address = vg_db_table_append( &_gs_db.db, _gs_db.leaderboards_table );
if( new_address )
{
vg_info( "Creating new leaderboard for uid: '%s'\n", uid );
vg_db_write( &_gs_db.db, new_address, &leaderboard, sizeof(leaderboard) );
u16 max = 0xffff;
- vg_db_dumb_table_init( &_gs_db.db, new_address+offsetof(struct skaterift_leaderboard,entries),
+ vg_db_table_init( &_gs_db.db, new_address+offsetof(struct skaterift_leaderboard,entries),
sizeof(struct skaterift_entry), max );
vg_db_skipper_init( &_gs_db.db, new_address+offsetof(struct skaterift_leaderboard,steamid_skipper), max );
vg_db_skipper_init( &_gs_db.db, new_address+offsetof(struct skaterift_leaderboard,time_skipper), max );
- u16 table_id = vg_db_dumb_table_count( &_gs_db.db, index_table_address ) -1;
+ u16 table_id = vg_db_table_count( &_gs_db.db, index_table_address ) -1;
vg_db_skipper_placement( &_gs_db.db, &uid_ctx, table_id, &lc );
vg_db_checkpoint( &_gs_db.db );
return new_address;
static i32 leaderboard_steamid_compare( vg_skipper_context *ctx, void *comparand, u16 item_index )
{
- u64 item_addr = vg_db_dumb_table_get( &_gs_db.db, ctx->table_address, item_index );
+ u64 item_addr = vg_db_table_get( &_gs_db.db, ctx->table_address, item_index );
u64 steamid;
vg_db_read( &_gs_db.db, item_addr + offsetof(struct skaterift_entry,steamid), &steamid, sizeof(steamid) );
u64 compid = *((u64 *)comparand);
}
static i32 leaderboard_time_compare( vg_skipper_context *ctx, void *comparand, u16 item_index )
{
- u64 item_addr = vg_db_dumb_table_get( &_gs_db.db, ctx->table_address, item_index );
+ u64 item_addr = vg_db_table_get( &_gs_db.db, ctx->table_address, item_index );
u32 time;
vg_db_read( &_gs_db.db, item_addr + offsetof(struct skaterift_entry,centiseconds), &time, sizeof(time) );
u32 comptime = *((u32 *)comparand);
u16 entry_id;
if( vg_db_skipper_find( &_gs_db.db, &steamid_ctx, &entry_id, &steamid ) )
{
- entry_address = vg_db_dumb_table_get( &_gs_db.db, table, entry_id );
+ entry_address = vg_db_table_get( &_gs_db.db, table, entry_id );
vg_db_read( &_gs_db.db, entry_address, &entry, sizeof(entry) );
if( (centiseconds > entry.centiseconds) && (entry.centiseconds > 200) && only_if_faster )
}
else
{
- entry_address = vg_db_dumb_table_append( &_gs_db.db, table );
- entry_id = vg_db_dumb_table_count( &_gs_db.db, table ) -1;
+ entry_address = vg_db_table_append( &_gs_db.db, table );
+ entry_id = vg_db_table_count( &_gs_db.db, table ) -1;
vg_db_skipper_placement( &_gs_db.db, &steamid_ctx, entry_id, &steamid );
}
return 0;
}
-struct task_set_username
-{
- u64 steamid;
- char name[NETWORK_USERNAME_MAX];
-};
-static void task_set_username( vg_async_task *task )
+void _db_edit_profile( struct profile_edits *info )
{
THREAD_1;
- struct task_set_username *info = (void *)task->data;
if( info->steamid == k_steamid_max )
return;
struct skaterift_profile profile = {0};
u64 user_address = vg_db_translate( &_gs_db.db, _gs_db.users_tree, info->steamid );
if( user_address )
- {
vg_db_read( &_gs_db.db, user_address, &profile, sizeof(profile) );
- }
else
{
user_address = vg_db_virtual_allocate( &_gs_db.db, 32*1024 );
vg_db_tree_map( &_gs_db.db, _gs_db.users_tree, info->steamid, user_address );
}
- memset( profile.name, 0, sizeof(profile.name) );
- vg_strncpy( info->name, profile.name, sizeof(profile.name), k_strncpy_always_add_null );
+ if( info->set_name )
+ {
+ memset( profile.name, 0, sizeof(profile.name) );
+ vg_strncpy( info->name, profile.name, sizeof(profile.name), k_strncpy_always_add_null );
+ }
+
+ if( info->set_cc )
+ {
+ memset( profile.cc, 0, sizeof(profile.cc) );
+ vg_strncpy( info->cc, profile.cc, sizeof(profile.cc), k_strncpy_always_add_null );
+ }
+
+ if( info->set_flags )
+ profile.flags |= info->set_flags;
+
+ if( info->clear_flags )
+ profile.flags &= ~info->clear_flags;
+
vg_db_write( &_gs_db.db, user_address, &profile, sizeof(profile) );
vg_db_checkpoint( &_gs_db.db );
}
-void db_action_set_username( u64 steamid, const char *username )
+static void task_edit_profile( vg_async_task *task )
{
- THREAD_0;
+ THREAD_1;
+ _db_edit_profile( (void *)task->data );
+}
- vg_async_task *task = vg_allocate_async_task( &_gs_db.tasks, sizeof(struct task_set_username), 1 );
- struct task_set_username *info = (void *)task->data;
- info->steamid = steamid;
- vg_strncpy( username, info->name, sizeof(info->name), k_strncpy_always_add_null );
- vg_async_task_dispatch( task, task_set_username );
+void db_action_edit_profile( struct profile_edits *edits )
+{
+ THREAD_0;
+ vg_async_task *task = vg_allocate_async_task( &_gs_db.tasks, sizeof(struct profile_edits), 1 );
+ memcpy( (void *)task->data, edits, sizeof(struct profile_edits) );
+ vg_async_task_dispatch( task, task_edit_profile );
}
enum request_status gameserver_read_highscore_table( vg_msg *msg, char uid[ DB_TABLE_UID_MAX ] )
{
+ THREAD_1;
+
u64 leaderboard_address = db_leaderboard_address( uid );
u64 table_address = leaderboard_address + offsetof(struct skaterift_leaderboard,entries);
u16 item_index;
while( vg_db_skipper_iter( &_gs_db.db, &time_ctx, &item_index ) )
{
- u64 entry_address = vg_db_dumb_table_get( &_gs_db.db, table_address, item_index );
+ u64 entry_address = vg_db_table_get( &_gs_db.db, table_address, item_index );
struct skaterift_entry entry;
vg_db_read( &_gs_db.db, entry_address, &entry, sizeof(entry) );
enum request_status _gs_db_get_profile( vg_msg *msg, u64 steamid )
{
+ THREAD_1;
+
u16 top3_count = 0,
top10_count = 0;
u16 item_index;
while( vg_db_skipper_iter( &_gs_db.db, &time_ctx, &item_index ) )
{
- u64 entry_address = vg_db_dumb_table_get( &_gs_db.db, table_address, item_index );
+ u64 entry_address = vg_db_table_get( &_gs_db.db, table_address, item_index );
struct skaterift_entry entry;
vg_db_read( &_gs_db.db, entry_address, &entry, sizeof(entry) );
return k_request_status_ok;
}
+
+struct task_db_dump
+{
+ u32 none;
+ char output_path[];
+};
+
+void _gs_db_dump_task( vg_async_task *task )
+{
+ THREAD_1;
+ struct task_db_dump *info = (void *)task->data;
+
+ FILE *fp = fopen( info->output_path, "w" );
+ if( !fp )
+ {
+ vg_error( "Cannot open '%s'\n", fp );
+ return;
+ }
+
+ vg_db *db = &_gs_db.db;
+ u64 master_table_addr = db->userdata_address + offsetof(struct skaterift_database, leaderboards_table),
+ user_tree_addr = db->userdata_address + offsetof(struct skaterift_database, users_tree);
+
+ fprintf( fp, "profiles\n"
+ "{\n" );
+ vg_tree_iter iter;
+ vg_db_tree_iter_init( db, &iter, user_tree_addr );
+
+ while( vg_db_tree_iter( db, &iter ) )
+ {
+ u64 steamid = iter.key,
+ profile_addr = iter.value;
+
+ struct skaterift_profile profile;
+ vg_db_read( db, profile_addr, &profile, sizeof(profile) );
+ fprintf( fp, " 0x%lx\n"
+ " {\n"
+ " name %s\n"
+ " cc %s\n"
+ " flags 0x%x\n"
+ " }\n", steamid, profile.name, profile.cc, profile.flags );
+ }
+
+ fprintf( fp, "}\n" );
+
+ fprintf( fp, "leaderboards\n"
+ "{\n" );
+ u16 table_count = vg_db_table_count( db, master_table_addr );
+ for( u16 i=0; i<table_count; i ++ )
+ {
+ u64 leaderboard_addr = vg_db_table_get( db, master_table_addr, i );
+
+ char uid[ DB_TABLE_UID_MAX ];
+ vg_db_read( db, leaderboard_addr + offsetof(struct skaterift_leaderboard,uid), uid, sizeof(uid) );
+ fprintf( fp, " %s\n"
+ " {\n", uid );
+
+ u64 entries_addr = leaderboard_addr + offsetof(struct skaterift_leaderboard, entries);
+ u16 entries_count = vg_db_table_count( db, entries_addr );
+
+ for( u16 j=0; j<entries_count; j ++ )
+ {
+ struct skaterift_entry entry;
+ u64 entry_addr = vg_db_table_get( db, entries_addr, j );
+ vg_db_read( db, entry_addr, &entry, sizeof(entry) );
+ fprintf( fp, " 0x%lx\n"
+ " {\n"
+ " last_second %lu\n"
+ " centiseconds %u\n"
+ " }\n", entry.steamid, entry.last_second, entry.centiseconds );
+ }
+
+ fprintf( fp, " }\n" );
+ }
+ fprintf( fp, "}\n" );
+
+ fclose( fp );
+}
+
+void db_action_dump( const char *path )
+{
+ THREAD_0;
+ vg_async_task *task = vg_allocate_async_task( &_gs_db.tasks, sizeof(struct task_db_dump) + strlen(path)+1, 1 );
+ struct task_db_dump *info = (void *)task->data;
+ info->none = 0;
+ strcpy( info->output_path, path );
+ vg_async_task_dispatch( task, _gs_db_dump_task );
+}