From 02e5027d274fc66fecca0572d0998e2c562da7a7 Mon Sep 17 00:00:00 2001 From: hgn Date: Tue, 9 May 2023 00:17:06 +0100 Subject: [PATCH] A complete workshop implementation, I guess --- ent_skateshop.c | 71 ++++++++++++++++++++++++++++++++--- ent_skateshop.h | 3 ++ model.h | 14 +++---- workshop.c | 99 ++++++++++++++++++++++++++++++++++++++++++++++--- workshop.h | 20 ++++++++++ 5 files changed, 186 insertions(+), 21 deletions(-) diff --git a/ent_skateshop.c b/ent_skateshop.c index 708e648..aeeaf70 100644 --- a/ent_skateshop.c +++ b/ent_skateshop.c @@ -1,6 +1,9 @@ #ifndef ENT_SKATESHOP_C #define ENT_SKATESHOP_C +#define VG_GAME +#include "vg/vg.h" +#include "vg/vg_steam_ugc.h" #include "ent_skateshop.h" #include "world.h" #include "player.h" @@ -250,9 +253,13 @@ VG_STATIC void workshop_scan_thread( void *_args ) reg->cache_ptr = NULL; vg_strncpy( file.name, reg->filename, 64, k_strncpy_always_add_null ); + vg_strncpy( file.name, reg->workshop.title, + 64, k_strncpy_always_add_null ); reg->filename_hash = hash; reg->workshop_id = 0; reg->state = k_registry_board_state_indexed; + reg->workshop.author = 0; + strcpy( reg->workshop.author_name, "custom" ); } next_file: tinydir_next( &dir ); @@ -303,6 +310,25 @@ next_file: tinydir_next( &dir ); reg->workshop_id = id; reg->state = k_registry_board_state_indexed; + workshop_file_info_clear( ®->workshop ); + strcpy( reg->workshop.title, "Workshop file" ); + + /* load the metadata off the disk */ + vg_async_item *call = + vg_async_alloc( sizeof(struct async_workshop_filepath_info) ); + + const char *meta_file = "/board.mdl.inf"; + char path[ 1024 ]; + struct async_workshop_filepath_info *info = call->payload; + info->buf = path; + info->id = reg->workshop_id; + info->len = vg_list_size(path) - strlen(meta_file)-1; + vg_async_dispatch( call, async_workshop_get_filepath ); + vg_async_stall(); /* too bad! */ + + strcat( path, meta_file ); + workshop_load_metadata( path, ®->workshop ); + next_file_workshop:; } @@ -348,6 +374,27 @@ VG_STATIC void unwatch_cache_board( struct cache_board *ptr ) ptr->ref_count --; } +/* + * Callback handler for persona state changes, + * it sets the author names on the registries + */ +VG_STATIC void callback_persona_statechange( CallbackMsg_t *msg ) +{ + PersonaStateChange_t *info = (PersonaStateChange_t *)msg->m_pubParam; + ISteamFriends *hSteamFriends = SteamAPI_SteamFriends(); + + if( info->m_nChangeFlags & k_EPersonaChangeName ){ + for( u32 i=0; iworkshop.author == info->m_ulSteamID ){ + const char *name = SteamAPI_ISteamFriends_GetFriendPersonaName( + hSteamFriends, info->m_ulSteamID ); + str_utf8_collapse( name, reg->workshop.author_name, 32 ); + } + } + } +} + /* * VG event init */ @@ -369,6 +416,11 @@ VG_STATIC void skateshop_init(void) board->last_use_time = -99999.9; board->ref_count = 0; } + + if( steam_ready ){ + steam_register_callback( k_iPersonaStateChange, + callback_persona_statechange ); + } } VG_STATIC struct cache_board *skateshop_selected_cache_if_loaded(void) @@ -460,8 +512,6 @@ VG_STATIC void global_skateshop_preupdate(void) } if( moved ){ - vg_info( "Select registry: %u\n", - global_skateshop.selected_registry_id ); global_skateshop.interaction_cooldown = 0.125f; return; } @@ -556,8 +606,10 @@ fade_out:; mdl_transform_m4x3( &mark_info->transform, mtext ); mdl_transform_m4x3( &mark_rack->transform, mrack ); +#if 0 const char *text_title = "Fish - Title"; const char *text_author = "by Shaniqua"; +#endif m4x3f mlocal, mmdl; m4x3_identity( mlocal ); @@ -596,24 +648,31 @@ fade_out:; struct cache_board *cache_ptr = skateshop_selected_cache_if_loaded(); if( !cache_ptr ) return; + struct registry_board *reg = + &global_skateshop.registry[cache_ptr->registry_id]; + struct workshop_file_info *info = ®->workshop; + /* Skin title * ----------------------------------------------------------------- */ + m3x3_zero( mlocal ); m3x3_setdiagonalv3( mlocal, (v3f){ scale, scale, thickness } ); - mlocal[3][0] = -font3d_string_width(&world_global.font,0,text_title); + mlocal[3][0] = -font3d_string_width( &world_global.font, 0, info->title ); mlocal[3][0] *= scale*0.5f; mlocal[3][1] = 0.1f; m4x3_mul( mtext, mlocal, mmdl ); - font3d_simple_draw( &world_global.font, 0, text_title, &main_camera, mmdl ); + font3d_simple_draw( &world_global.font, 0, info->title, &main_camera, mmdl ); /* Author name * ----------------------------------------------------------------- */ scale *= 0.4f; m3x3_setdiagonalv3( mlocal, (v3f){ scale, scale, thickness } ); - mlocal[3][0] = -font3d_string_width(&world_global.font,0,text_author); + mlocal[3][0] = -font3d_string_width( &world_global.font, 0, + info->author_name ); mlocal[3][0] *= scale*0.5f; mlocal[3][1] = 0.0f; m4x3_mul( mtext, mlocal, mmdl ); - font3d_simple_draw( &world_global.font, 0, text_author, &main_camera, mmdl ); + font3d_simple_draw( &world_global.font, 0, + info->author_name, &main_camera, mmdl ); } /* diff --git a/ent_skateshop.h b/ent_skateshop.h index e688168..4f84f7a 100644 --- a/ent_skateshop.h +++ b/ent_skateshop.h @@ -43,6 +43,9 @@ struct{ struct registry_board{ PublishedFileId_t workshop_id; + + /* only for steam workshop files */ + struct workshop_file_info workshop; struct cache_board *cache_ptr; char filename[64]; /* if workshop, string version of its published ID. */ diff --git a/model.h b/model.h index 811f3a1..664950f 100644 --- a/model.h +++ b/model.h @@ -274,8 +274,7 @@ VG_STATIC u32 mdl_query_array_size( mdl_array *arr ) u32 size = arr->item_size*arr->item_count; return vg_align8(size); } - else - return 0; + else return 0; } VG_STATIC const char *mdl_pstr( mdl_context *mdl, u32 pstr ); @@ -290,21 +289,18 @@ void mdl_fread_pack_file( mdl_context *mdl, mdl_file *info, void *dst ) fseek( mdl->file, mdl->pack_base_offset+info->pack_offset, SEEK_SET ); u64 l = fread( dst, info->pack_size, 1, mdl->file ); - if( l != 1 ) - mdl_load_fatal_corrupt( mdl ); + if( l != 1 ) mdl_load_fatal_corrupt( mdl ); } /* TODO: Rename these */ -VG_STATIC -void mdl_load_array_file_buffer( mdl_context *mdl, mdl_array *arr, - void *buffer ) +VG_STATIC void mdl_load_array_file_buffer( mdl_context *mdl, mdl_array *arr, + void *buffer ) { if( arr->item_count ){ fseek( mdl->file, arr->file_offset, SEEK_SET ); u64 l = fread( buffer, arr->item_size*arr->item_count, 1, mdl->file ); - if( l != 1 ) - mdl_load_fatal_corrupt( mdl ); + if( l != 1 ) mdl_load_fatal_corrupt( mdl ); } } diff --git a/workshop.c b/workshop.c index c82ca6e..30aaf7a 100644 --- a/workshop.c +++ b/workshop.c @@ -42,7 +42,6 @@ struct workshop_form{ */ char model_path[128]; - struct player_board board_model; /* what does the user want to do with the image preview? */ @@ -298,6 +297,9 @@ VG_STATIC void workshop_form_async_package_complete( void *data, u32 size ) */ struct workshop_package_thread_args{ PublishedFileId_t file_id; + + u64_steamid steamid; + char username[32]; }; VG_STATIC void _workshop_package_thread( void *_args ) { @@ -340,6 +342,40 @@ VG_STATIC void _workshop_package_thread( void *_args ) return; } + /* write the metadata file */ + struct workshop_file_info meta; + meta.author = args->steamid; + vg_strncpy( args->username, meta.author_name, vg_list_size(meta.author_name), + k_strncpy_always_add_null ); + vg_strncpy( workshop_form.submission.title, meta.title, + vg_list_size(meta.title), k_strncpy_always_add_null ); + + char _path[1024]; + vg_str path; + vg_strnull( &path, _path, vg_list_size( _path ) ); + vg_strcat( &path, info->abs_content_file ); + vg_strcat( &path, ".inf" ); + + if( vg_strgood( &path ) ){ + FILE *fp = fopen( _path, "wb" ); + + if( fp ){ + fwrite( &meta, sizeof(struct workshop_file_info), 1, fp ); + fclose( fp ); + } + else{ + info->success = 0; + info->failure_reason = "Cant write .inf file"; + vg_async_dispatch( call, workshop_form_async_package_complete ); + } + } + else{ + info->success = 0; + info->failure_reason = "Path too long"; + vg_async_dispatch( call, workshop_form_async_package_complete ); + return; + } + info->success = 1; vg_async_dispatch( call, workshop_form_async_package_complete ); } @@ -354,6 +390,16 @@ VG_STATIC void workshop_package_submission( PublishedFileId_t file_id ) vg_linear_alloc( vg_mem.scratch, sizeof(struct workshop_package_thread_args)); + ISteamFriends *hSteamFriends = SteamAPI_SteamFriends(); + ISteamUser *hSteamUser = SteamAPI_SteamUser(); + + args->steamid = SteamAPI_ISteamUser_GetSteamID( hSteamUser ); + + const char *username = SteamAPI_ISteamFriends_GetPersonaName(hSteamFriends); + str_utf8_collapse( username, args->username, vg_list_size( args->username )); + vg_info( "Steamid: "PRINTF_U64", Name: %s(%s)\n", + args->steamid, username, args->username ); + args->file_id = file_id; vg_loader_start( _workshop_package_thread, args ); } @@ -517,13 +563,29 @@ VG_STATIC void workshop_form_loadmodel_async_complete( void *payload, u32 size ) workshop_end_op(); } +/* + * Reciever for failure to load + */ +VG_STATIC void workshop_form_loadmodel_async_error( void *payload, u32 size ) +{ + workshop_end_op(); +} + /* * Thread which loads the model from the disk */ VG_STATIC void _workshop_form_load_thread( void *data ) { - player_board_load( &workshop_form.board_model, workshop_form.model_path ); - vg_async_call( workshop_form_loadmodel_async_complete, NULL, 0 ); + FILE *test = fopen( workshop_form.model_path, "rb" ); + if( test ){ + fclose( test ); + player_board_load( &workshop_form.board_model, workshop_form.model_path ); + vg_async_call( workshop_form_loadmodel_async_complete, NULL, 0 ); + } + else{ + vg_error( "workshop async load failed: file not found\n" ); + vg_async_call( workshop_form_loadmodel_async_error, NULL, 0 ); + } } /* @@ -1083,7 +1145,6 @@ VG_STATIC void workshop_form_gui_edit_page( ui_rect content ) .change = workshop_changed_description }; ui_rect desc_entry; - /* TODO: Tommora, new split_px_gap and split_px() */ ui_split( content, k_ui_axis_h, 8, 0, null, content ); ui_split( content, k_ui_axis_h, 28, 0, label, content ); ui_split( content, k_ui_axis_h, 28*4, 0, desc_entry, content ); @@ -1165,8 +1226,6 @@ VG_STATIC void workshop_form_gui_sidebar( ui_rect sidebar ) char buf[32]; strcpy( buf, "page " ); int i = 5; - - /* TODO: for what it is, this code is getting a bit.. special */ i += highscore_intl( buf+i, workshop_form.view_published_page_id+1, 4 ); buf[ i ++ ] = '/'; i += highscore_intl( buf+i, workshop_form.view_published_page_count, 4 ); @@ -1368,4 +1427,32 @@ VG_STATIC void async_workshop_get_installed_files( void *data, u32 len ) *info->len = j; } +VG_STATIC void vg_strsan_ascii( char *buf, u32 len ) +{ + for( u32 i=0; i 126 ){ + buf[i] = '?'; + } + } + buf[len-1] = '\0'; +} + +#define VG_STRSAN_ASCII( X ) vg_strsan_ascii( X, vg_list_size(X) ) + +VG_STATIC void workshop_load_metadata( const char *path, + struct workshop_file_info *info ) +{ + FILE *fp = fopen( path, "rb" ); + + if( fp ){ + if( fread( info, sizeof( struct workshop_file_info ), 1, fp ) ){ + VG_STRSAN_ASCII( info->author_name ); + VG_STRSAN_ASCII( info->title ); + } + fclose( fp ); + } +} + #endif /* WORKSHOP_C */ diff --git a/workshop.h b/workshop.h index a08bc4d..4a0f8b2 100644 --- a/workshop.h +++ b/workshop.h @@ -18,6 +18,12 @@ struct workshop{ } static workshop; +struct workshop_file_info{ + u64 author; + char author_name[32]; + char title[64]; +}; + struct async_workshop_filepath_info{ PublishedFileId_t id; char *buf; @@ -29,8 +35,22 @@ struct async_workshop_installed_files_info{ u32 *len; /* inout */ }; +struct async_workshop_metadata_info{ + struct workshop_file_info *info; + const char *path; +}; + +VG_STATIC void workshop_file_info_clear( struct workshop_file_info *info ) +{ + info->author = 0ul; + info->author_name[0] = '\0'; + info->title[0] = '\0'; +} + VG_STATIC void async_workshop_get_filepath( void *data, u32 len ); VG_STATIC void async_workshop_get_installed_files( void *data, u32 len ); +VG_STATIC void workshop_load_metadata( const char *path, + struct workshop_file_info *info ); /* * Start a new operation and crash if we are already running one. -- 2.25.1