From: hgn Date: Thu, 8 Jun 2023 15:39:05 +0000 (+0100) Subject: enable workshop world submissions X-Git-Url: https://harrygodden.com/git/?a=commitdiff_plain;ds=inline;h=7b1e8a237acc3121c86fab9b5946da6a8d3bf6c4;p=carveJwlIkooP6JGAAIwe30JlM.git enable workshop world submissions --- diff --git a/addon.c b/addon.c index 29b24a0..504904f 100644 --- a/addon.c +++ b/addon.c @@ -4,6 +4,8 @@ #include "addon.h" #include "vg/vg_msg.h" #include "steam.h" +#include "workshop_types.h" +#include "workshop.h" static u32 addon_count( enum workshop_file_type type ){ return addon_system.registry_type_counts[ type ]; @@ -347,4 +349,35 @@ VG_STATIC void addon_mount_content_folder( enum workshop_file_type type, vg_dir_close(&dir); } +static int addon_get_content_folder( addon_reg *reg, vg_str *folder ){ + if( reg->workshop_id ){ + vg_async_item *call = + vg_async_alloc( sizeof(struct async_workshop_filepath_info) ); + struct async_workshop_filepath_info *info = call->payload; + info->buf = folder->buffer; + info->id = reg->workshop_id; + info->len = folder->len; + vg_async_dispatch( call, async_workshop_get_filepath ); + vg_async_stall(); /* too bad! */ + if( info->buf[0] == '\0' ){ + vg_error( "Failed SteamAPI_GetItemInstallInfo(" PRINTF_U64 ")\n", + reg->workshop_id ); + return 0; + } + folder->i = strlen( folder->buffer ); + return 1; + } + else{ + folder->i = 0; + if( reg->type == k_workshop_file_type_board ) + vg_strcat( folder, "boards/" ); + else if( reg->type == k_workshop_file_type_world ) + vg_strcat( folder, "maps/" ); + else return 0; + + vg_strcat( folder, reg->foldername ); + return 1; + } +} + #endif /* ADDON_C */ diff --git a/addon.h b/addon.h index 65e88e1..f1d466e 100644 --- a/addon.h +++ b/addon.h @@ -1,7 +1,8 @@ #ifndef ADDON_H #define ADDON_H -#include "workshop.h" +#include "common.h" +#include "vg/vg_steam_ugc.h" #include "workshop_types.h" #define ADDON_MOUNTED_MAX 128 #define ADDON_FOLDERNAME_MAX 64 @@ -38,6 +39,7 @@ static void addon_system_init( void ); static u32 addon_count( enum workshop_file_type type ); static addon_reg *get_addon_from_index(enum workshop_file_type type, u32 index); static u32 get_index_from_addon( enum workshop_file_type type, addon_reg *a ); +static int addon_get_content_folder( addon_reg *reg, vg_str *folder ); /* scanning routines */ VG_STATIC void addon_mount_content_folder( enum workshop_file_type type, diff --git a/ent_skateshop.c b/ent_skateshop.c index 08d32e8..7898f58 100644 --- a/ent_skateshop.c +++ b/ent_skateshop.c @@ -130,7 +130,6 @@ VG_STATIC void workshop_visibile_load_loop(void) { vg_info( "Running load loop\n" ); char path_buf[4096]; - vg_str folder; for( u32 i=0; ireg_ptr = get_addon_from_index( k_workshop_file_type_board, cache_ptr->reg_index ); - if( cache_ptr->reg_ptr->workshop_id ){ - vg_async_item *call = - vg_async_alloc( sizeof(struct async_workshop_filepath_info) ); - - struct async_workshop_filepath_info *info = call->payload; - info->buf = path_buf; - info->id = cache_ptr->reg_ptr->workshop_id; - info->len = vg_list_size(path_buf); - vg_async_dispatch( call, async_workshop_get_filepath ); - vg_async_stall(); /* too bad! */ - - if( path_buf[0] == '\0' ){ - vg_error( "Failed SteamAPI_GetItemInstallInfo(" PRINTF_U64 ")\n", - cache_ptr->reg_ptr->workshop_id ); - goto file_is_broken; - } + vg_str folder; + vg_strnull( &folder, path_buf, 4096 ); + if( !addon_get_content_folder( cache_ptr->reg_ptr, &folder ) ) + goto file_is_broken; - folder.buffer = path_buf; - folder.i = strlen(path_buf); - folder.len = 4096; - } - else{ - vg_strnull( &folder, path_buf, 4096 ); - vg_strcat( &folder, "boards/" ); - vg_strcat( &folder, cache_ptr->reg_ptr->foldername ); - } /* load content files * --------------------------------- */ @@ -336,45 +313,38 @@ VG_STATIC void pointcloud_clear_async(void *_, u32 __) VG_STATIC void skateshop_preview_loader_thread( void *_data ) { addon_reg *reg = _data; + + char path_buf[4096]; + vg_str path; + vg_strnull( &path, path_buf, 4096 ); + addon_get_content_folder( reg, &path ); + vg_strcat( &path, "/preview.bin" ); + + vg_linear_clear(vg_mem.scratch); + u32 size; - if( reg->workshop_id ){ - vg_error( "Workshop files unsupported\n" ); - vg_async_call( pointcloud_clear_async, NULL, 0 ); - } - else{ - char path_buf[4096]; - vg_str path; - vg_strnull( &path, path_buf, 4096 ); - vg_strcat( &path, "maps/" ); - vg_strcat( &path, reg->foldername ); - vg_strcat( &path, "/preview.bin" ); - - vg_linear_clear(vg_mem.scratch); - u32 size; - - void *data = vg_file_read( vg_mem.scratch, path_buf, &size ); - if( data ){ - if( size < sizeof(pointcloud_buffer) ){ - vg_async_call( pointcloud_clear_async, NULL, 0 ); - return; - } - - vg_async_item *call = vg_async_alloc(size); - pointcloud_buffer *pcbuf = call->payload; - memcpy( pcbuf, data, size ); - - u32 point_count = (size-sizeof(pointcloud_buffer)) / - sizeof(struct pointcloud_vert); - pcbuf->max = point_count; - pcbuf->count = point_count; - pcbuf->op = k_pointcloud_op_clear; - - vg_async_dispatch( call, async_pointcloud_sub ); - vg_async_call( pointcloud_async_end, NULL, 0 ); - } - else{ + void *data = vg_file_read( vg_mem.scratch, path_buf, &size ); + if( data ){ + if( size < sizeof(pointcloud_buffer) ){ vg_async_call( pointcloud_clear_async, NULL, 0 ); + return; } + + vg_async_item *call = vg_async_alloc(size); + pointcloud_buffer *pcbuf = call->payload; + memcpy( pcbuf, data, size ); + + u32 point_count = (size-sizeof(pointcloud_buffer)) / + sizeof(struct pointcloud_vert); + pcbuf->max = point_count; + pcbuf->count = point_count; + pcbuf->op = k_pointcloud_op_clear; + + vg_async_dispatch( call, async_pointcloud_sub ); + vg_async_call( pointcloud_async_end, NULL, 0 ); + } + else{ + vg_async_call( pointcloud_clear_async, NULL, 0 ); } } @@ -564,7 +534,9 @@ VG_STATIC void global_skateshop_preupdate(void) if( loadable && button_down( k_srbind_maccept ) ){ vg_info( "Select rift (%u)\n", global_skateshop.selected_world_id ); - skaterift_change_world( reg->foldername ); + world_loader.reg = reg; + world_loader.override_name[0] = '\0'; + skaterift_change_world_start(); return; } else{ @@ -711,6 +683,8 @@ fade_out:; } if( global_skateshop.render.reg_id != global_skateshop.selected_board_id ){ + global_skateshop.render.item_title = ""; + global_skateshop.render.item_desc = ""; addon_reg *reg = cache_ptr->reg_ptr; vg_msg root; vg_msg_init( &root, reg->metadata, reg->metadata_len ); @@ -771,6 +745,8 @@ VG_STATIC void skateshop_render_worldshop(void) mdl_entity_id_id(shop->boards.id_info)); if( global_skateshop.render.world_reg != global_skateshop.selected_world_id){ + global_skateshop.render.world_title = ""; + addon_reg *reg = get_addon_from_index( k_workshop_file_type_world, global_skateshop.selected_world_id ); vg_msg root; @@ -808,6 +784,12 @@ VG_STATIC void skateshop_render_worldshop(void) vg_strcat( &subtext, "Loading..." ); } else{ + addon_reg *reg = get_addon_from_index( k_workshop_file_type_world, + global_skateshop.selected_world_id ); + + if( reg->workshop_id ) + vg_strcat( &subtext, "(Workshop) " ); + vg_strcat( &subtext, global_skateshop.render.world_loc ); } } diff --git a/maps_src/template/addon.inf b/maps_src/template/addon.inf new file mode 100644 index 0000000..b71b466 Binary files /dev/null and b/maps_src/template/addon.inf differ diff --git a/maps_src/template/preview.jpg b/maps_src/template/preview.jpg new file mode 100644 index 0000000..63b72e4 Binary files /dev/null and b/maps_src/template/preview.jpg differ diff --git a/skaterift.c b/skaterift.c index 6cb3579..5400e76 100644 --- a/skaterift.c +++ b/skaterift.c @@ -156,10 +156,10 @@ VG_STATIC void vg_load(void) /* 'systems' are completely loaded now */ /* load home/permanent world manually */ - strcpy( world_loader.name, "mp_spawn" ); + world_loader.reg = NULL; + strcpy( world_loader.override_name, "mp_spawn" ); world_loader.generate_point_cloud = 1; world_loader.world_index = 0; - world_loader.location = k_world_load_type_local; world_load_mdl( "maps/mp_spawn/main.mdl" ); /* Completing addon registrations @@ -195,6 +195,7 @@ VG_STATIC void vg_load(void) vg_async_call( async_addon_reg_update, NULL, 0 ); vg_console_load_autos(); menu_link(); + temp_update_playermodel(); vg_async_call( async_skaterift_complete, NULL, 0 ); } diff --git a/skaterift.h b/skaterift.h index 8f9e3e7..a139476 100644 --- a/skaterift.h +++ b/skaterift.h @@ -3,6 +3,7 @@ #include "common.h" #include "world.h" +#include "addon.h" struct{ enum async_operation{ @@ -23,7 +24,7 @@ struct{ static skaterift = { .async_op = k_async_op_clientloading }; /* Skaterift api */ -static void skaterift_change_world( const char *world_path ); +static void skaterift_change_world_start( void ); static int skaterift_change_world_command( int argc, const char *argv[] ); /* diff --git a/workshop.c b/workshop.c index bcb8574..6f71579 100644 --- a/workshop.c +++ b/workshop.c @@ -534,7 +534,19 @@ VG_STATIC void _workshop_form_load_thread( void *data ) VG_STATIC void workshop_op_load_model(void) { if( workshop_form.submission.type == k_workshop_file_type_world ){ - vg_error( "Currently unsupported\n" ); + vg_warn( "WORLD LOAD INFO Currently unsupported\n" ); + return; + } + + workshop_form.view_world = world_current_instance(); + + if( mdl_arrcount( &workshop_form.view_world->ent_swspreview ) ){ + workshop_form.ptr_ent = + mdl_arritm( &workshop_form.view_world->ent_swspreview, 0 ); + } + else{ + vg_error( "There is no ent_swspreview in the level. " + "Cannot publish here\n" ); return; } @@ -683,7 +695,7 @@ VG_STATIC void workshop_op_download_and_view_submission( int result_index ) vg_msg root; vg_msg_init( &root, metadata_buf, len/2 ); - vg_msg workshop; + vg_msg workshop = root; if( vg_msg_seekframe( &workshop, "workshop", k_vg_msg_first )){ vg_msg_cmd kv_type = vg_msg_seekkv( &workshop, "type", k_vg_msg_first ); @@ -900,26 +912,24 @@ VG_STATIC void workshop_init(void) vg_console_reg_cmd( "workshop_submit", workshop_submit_command, NULL ); } -VG_STATIC void workshop_find_preview_entity(void) -{ - workshop_form.view_world = world_current_instance(); +VG_STATIC void workshop_render_world_preview(void){ + render_fb_bind( gpipeline.fb_workshop_preview, 0 ); - if( mdl_arrcount( &workshop_form.view_world->ent_swspreview ) ){ - workshop_form.ptr_ent = - mdl_arritm( &workshop_form.view_world->ent_swspreview, 0 ); - workshop_form.page = k_workshop_form_edit; - } - else{ - vg_error( "There is no ent_swspreview in the level. " - "Cannot publish here\n" ); - } + glClearColor( 0.0f, 0.0f, 0.3f, 1.0f ); + glClear( GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT ); + glEnable( GL_DEPTH_TEST ); + glDisable( GL_BLEND ); + + render_world( localplayer.viewable_world, &main_camera, 1 ); + + glBindFramebuffer( GL_FRAMEBUFFER, 0 ); + glViewport( 0,0, vg.window_x, vg.window_y ); } /* * Redraw the model file into the workshop framebuffer */ -VG_STATIC void workshop_render_preview(void) -{ +VG_STATIC void workshop_render_board_preview(void){ if( !workshop_form.ptr_ent ){ return; } @@ -1024,88 +1034,65 @@ VG_STATIC void workshop_changed_description( char *buf, u32 len ){ workshop_form.submission.submit_description = 1; } -VG_STATIC void workshop_form_gui_edit_page( ui_rect content ) -{ - if( workshop_form.submission.type == k_workshop_file_type_none ){ - ui_rect box; - rect_copy( content, box ); - box[3] = 128; - box[2] = (box[2]*2)/3; - ui_rect_center( content, box ); - - ui_rect row; - ui_split( box, k_ui_axis_h, 28, 0, row, box ); - ui_text( row, "Select the type of item\n", 1, k_ui_align_middle_center,0); - ui_split( box, k_ui_axis_h, 28, 0, row, box ); - ui_enum( row, "Type:", workshop_form_type_opts, - 3, &workshop_form.submission.submission_type_selection ); - ui_split( box, k_ui_axis_h, 8, 0, row, box ); - ui_split( box, k_ui_axis_h, 28, 0, row, box ); - - ui_rect button_l, button_r; - rect_copy( row, button_l ); - button_l[2] = 128*2; - ui_rect_center( row, button_l ); - ui_split_ratio( button_l, k_ui_axis_v, 0.5f, 2, button_l, button_r ); - - if( workshop_form.submission.submission_type_selection.value != - k_workshop_file_type_none ){ - if( ui_button_text( button_l, "OK", 1 ) ){ - workshop_form.submission.type = +VG_STATIC void workshop_form_gui_page_undecided( ui_rect content ){ + ui_rect box; + rect_copy( content, box ); + box[3] = 128; + box[2] = (box[2]*2)/3; + ui_rect_center( content, box ); + + ui_rect row; + ui_split( box, k_ui_axis_h, 28, 0, row, box ); + ui_text( row, "Select the type of item\n", 1, k_ui_align_middle_center,0); + ui_split( box, k_ui_axis_h, 28, 0, row, box ); + ui_enum( row, "Type:", workshop_form_type_opts, + 3, &workshop_form.submission.submission_type_selection ); + ui_split( box, k_ui_axis_h, 8, 0, row, box ); + ui_split( box, k_ui_axis_h, 28, 0, row, box ); + + ui_rect button_l, button_r; + rect_copy( row, button_l ); + button_l[2] = 128*2; + ui_rect_center( row, button_l ); + ui_split_ratio( button_l, k_ui_axis_v, 0.5f, 2, button_l, button_r ); + + if( workshop_form.submission.submission_type_selection.value != + k_workshop_file_type_none ){ + if( ui_button_text( button_l, "OK", 1 ) ){ + enum workshop_file_type type = workshop_form.submission.submission_type_selection.value; + workshop_form.submission.type = type; + + if( type == k_workshop_file_type_world ){ + workshop_form.view_changed = 1; + workshop_form.file_intent = k_workshop_form_file_intent_new; } } - else{ - ui_fill( button_l, ui_colour(k_ui_bg) ); - ui_text( button_l, "OK", 1, k_ui_align_middle_center, - ui_colour(k_ui_bg+4) ); - } - - if( ui_button_text( button_r, "Cancel", 1 ) ){ - workshop_form.page = k_workshop_form_open; - workshop_form.file_intent = k_workshop_form_file_intent_none; - } - return; } - - if( workshop_form.submission.type == k_workshop_file_type_world ){ - ui_rect box; - rect_copy( content, box ); - box[3] = 128; - box[2] = (box[2]*2)/3; - ui_rect_center( content, box ); - - ui_rect row; - ui_split( box, k_ui_axis_h, 28, 0, row, box ); - ui_text( row, "World submissions are currently not ready, sorry.", - 1, k_ui_align_middle_center,0); - ui_split( box, k_ui_axis_h, 8, 0, row, box ); - ui_split( box, k_ui_axis_h, 28, 0, row, box ); - - ui_rect button; - rect_copy( row, button ); - button[2] = 128; - ui_rect_center( row, button ); - if( ui_button_text( button, "OK", 1 ) ){ - workshop_form.page = k_workshop_form_open; - workshop_form.file_intent = k_workshop_form_file_intent_none; - } - - return; + else{ + ui_fill( button_l, ui_colour(k_ui_bg) ); + ui_text( button_l, "OK", 1, k_ui_align_middle_center, + ui_colour(k_ui_bg+4) ); } + + if( ui_button_text( button_r, "Cancel", 1 ) ){ + workshop_form.page = k_workshop_form_open; + workshop_form.file_intent = k_workshop_form_file_intent_none; + } +} - ui_rect image_plane; - ui_split( content, k_ui_axis_h, 300, 0, image_plane, content ); - ui_fill( image_plane, ui_colour( k_ui_bg+0 ) ); - - ui_rect img_box; - ui_fit_item( image_plane, (ui_px[2]){ 3, 2 }, img_box ); - +VG_STATIC void workshop_form_gui_draw_preview( ui_rect img_box ){ + enum workshop_file_type type = workshop_form.submission.type; if( workshop_form.file_intent == k_workshop_form_file_intent_keep_old ){ ui_image( img_box, gpipeline.fb_workshop_preview->attachments[0].id ); } else if( workshop_form.file_intent == k_workshop_form_file_intent_new ){ ui_image( img_box, gpipeline.fb_workshop_preview->attachments[0].id ); + + if( type == k_workshop_file_type_world ){ + return; + } + int hover = ui_inside_rect( img_box, vg_ui.mouse ), target = ui_inside_rect( img_box, vg_ui.mouse_click ); @@ -1159,12 +1146,28 @@ VG_STATIC void workshop_form_gui_edit_page( ui_rect content ) ui_text( img_box, "No image", 1, k_ui_align_middle_center, ui_colour( k_ui_orange ) ); } +} + +VG_STATIC void workshop_form_gui_edit_page( ui_rect content ){ + enum workshop_file_type type = workshop_form.submission.type; + + if( type == k_workshop_file_type_none ){ + workshop_form_gui_page_undecided( content ); + return; + } + + ui_rect image_plane; + ui_split( content, k_ui_axis_h, 300, 0, image_plane, content ); + ui_fill( image_plane, ui_colour( k_ui_bg+0 ) ); + + ui_rect img_box; + ui_fit_item( image_plane, (ui_px[2]){ 3, 2 }, img_box ); + workshop_form_gui_draw_preview( img_box ); /* file path */ ui_rect null, file_entry, file_button, file_label; ui_split( content, k_ui_axis_h, 8, 0, null, content ); ui_split( content, k_ui_axis_h, 28, 0, file_entry, content ); - ui_split( file_entry, k_ui_axis_v, -128, 0, file_entry, file_button ); if( workshop_form.submission.type == k_workshop_file_type_board ){ ui_label( file_entry, "Addon folder: skaterift/boards/", @@ -1175,27 +1178,36 @@ VG_STATIC void workshop_form_gui_edit_page( ui_rect content ) 1, 8, file_entry ); } - if( workshop_form.file_intent != k_workshop_form_file_intent_none ){ - ui_text( file_entry, workshop_form.addon_folder, 1, - k_ui_align_middle_left, ui_colour( k_ui_fg+4 ) ); - - if( ui_button_text( file_button, "Remove", 1 ) ){ - player_board_unload( &workshop_form.board_model ); - workshop_form.file_intent = k_workshop_form_file_intent_none; - workshop_form.addon_folder[0] = '\0'; - } - } - else{ + if( type == k_workshop_file_type_world ){ struct ui_textbox_callbacks callbacks = { .change = workshop_changed_model_path }; - ui_textbox( file_entry, workshop_form.addon_folder, vg_list_size(workshop_form.addon_folder), 0, &callbacks ); + } + else{ + ui_split( file_entry, k_ui_axis_v, -128, 0, file_entry, file_button ); + if( workshop_form.file_intent != k_workshop_form_file_intent_none ){ + ui_text( file_entry, workshop_form.addon_folder, 1, + k_ui_align_middle_left, ui_colour( k_ui_fg+4 ) ); + + if( ui_button_text( file_button, "Remove", 1 ) ){ + player_board_unload( &workshop_form.board_model ); + workshop_form.file_intent = k_workshop_form_file_intent_none; + workshop_form.addon_folder[0] = '\0'; + } + } + else{ + struct ui_textbox_callbacks callbacks = { + .change = workshop_changed_model_path + }; + + ui_textbox( file_entry, workshop_form.addon_folder, + vg_list_size(workshop_form.addon_folder), 0, &callbacks ); - if( ui_button_text( file_button, "Load", 1 ) ){ - workshop_find_preview_entity(); - workshop_op_load_model(); + if( ui_button_text( file_button, "Load", 1 ) ){ + workshop_op_load_model(); + } } } @@ -1369,7 +1381,6 @@ VG_STATIC void workshop_form_gui_sidebar( ui_rect sidebar ) workshop_form.submission.submit_description = 1; workshop_form.submission.submit_file_and_image = 1; workshop_form.page = k_workshop_form_edit; - workshop_find_preview_entity(); } for( int i=0; ifoldername, world_loader.reg->workshop_id ); + } + else{ + vg_info( "switching to %s(local)\n", world_loader.override_name ); + } if( world_static.active_world != 0 ){ vg_error( "Cannot change worlds while in non-root world\n" ); @@ -228,10 +234,7 @@ static void skaterift_change_world( const char *world_name ) else{ skaterift_begin_op( k_async_op_world_preloading ); - vg_linear_clear( vg_mem.scratch ); - vg_strncpy( world_name, world_loader.name, - vg_list_size(world_loader.name), k_strncpy_overflow_fatal ); - + vg_linear_clear( vg_mem.scratch ); /* ?? */ vg_info( "unloading old worlds\n" ); world_unlink_nonlocal( &world_static.worlds[0] ); @@ -249,8 +252,13 @@ static void skaterift_change_world( const char *world_name ) /* console command for the above function */ static int skaterift_change_world_command( int argc, const char *argv[] ) { - if( argc == 1 ) - skaterift_change_world( argv[0] ); + if( argc == 1 ){ + world_loader.reg = NULL; + vg_strncpy( argv[0], world_loader.override_name, + vg_list_size( world_loader.override_name ), + k_strncpy_always_add_null ); + skaterift_change_world_start(); + } return 0; } diff --git a/world_load.h b/world_load.h index 0b8a912..b37bae3 100644 --- a/world_load.h +++ b/world_load.h @@ -8,15 +8,21 @@ #include "world_routes.h" #include "world_entity.h" #include "world_volumes.h" +#include "addon.h" struct{ - char name[64]; + addon_reg *reg; +#if 0 enum world_load_type{ + k_world_load_type_none, k_world_load_type_local, k_world_load_type_workshop /* unimplemented */ } location; +#endif + + char override_name[64]; int generate_point_cloud; u32 world_index; } diff --git a/world_routes.c b/world_routes.c index 1ff33fe..56e6e4b 100644 --- a/world_routes.c +++ b/world_routes.c @@ -767,6 +767,33 @@ VG_STATIC void world_routes_surface_grid( world_instance *world, } } +VG_STATIC void world_write_preview( pointcloud_buffer *pcbuf ){ + char path_buf[4096]; + vg_str path; + vg_strnull( &path, path_buf, 4096 ); + + if( world_loader.reg ){ + /* Don't want to override the one we get from the workshop */ + if( world_loader.reg->workshop_id ) return; + + addon_get_content_folder( world_loader.reg, &path ); + } + else{ + vg_strcat( &path, "maps/" ); + vg_strcat( &path, world_loader.override_name ); + } + + vg_strcat( &path, "/preview.bin" ); + + if( !vg_strgood( &path ) ) vg_fatal_error( "Path too long\n" ); + FILE *fp = fopen( path_buf, "wb" ); + if( !fp ) vg_fatal_error( "Cannot open '%s' for writing\n", path_buf ); + + fwrite( pcbuf, sizeof(struct pointcloud_buffer) + + sizeof(struct pointcloud_vert)*pcbuf->count, 1, fp ); + fclose( fp ); +} + /* * Create the strips of colour that run through the world along course paths */ @@ -861,23 +888,7 @@ VG_STATIC void world_gen_routes_generate(void) vg_info( "Distrubuted %u points over %fkm^2!\n", pcbuf->count, area/1e6f ); - if( world_loader.location == k_world_load_type_local ){ - char path_buf[4096]; - vg_str path; - vg_strnull( &path, path_buf, 4096 ); - vg_strcat( &path, "maps/" ); - vg_strcat( &path, world_loader.name ); - vg_strcat( &path, "/preview.bin" ); - - if( !vg_strgood( &path ) ) vg_fatal_error( "Path too long\n" ); - FILE *fp = fopen( path_buf, "wb" ); - if( !fp ) vg_fatal_error( "Cannot open '%s' for writing\n", path_buf ); - - fwrite( pcbuf, sizeof(pcbuf) + - sizeof(struct pointcloud_vert)*pcbuf->count, 1, fp ); - fclose( fp ); - } - + world_write_preview( pcbuf ); vg_async_dispatch( call_pointcloud, async_pointcloud_sub ); }