From 00291aeca81d2d0fface12ce5890f4e6d7f7c982 Mon Sep 17 00:00:00 2001 From: hgn Date: Mon, 21 Apr 2025 05:44:38 +0100 Subject: [PATCH] replay almst done --- src/ent_route.c | 24 +- src/freecam.c | 22 +- src/gameserver.c | 7 +- src/menu.c | 14 +- src/network_requests.c | 36 +- src/player.c | 35 +- src/player.h | 1 - src/player_common.c | 85 ++- src/player_remote.c | 72 ++- src/player_remote.h | 6 +- src/player_render.c | 5 + src/player_render.h | 2 - src/player_replay.c | 1165 ---------------------------------------- src/player_replay.h | 123 ----- src/player_skate.c | 7 +- src/replay2.c | 663 +++++++++++++++++++---- src/replay2.h | 78 ++- src/skaterift.c | 47 +- src/world_load.c | 4 +- 19 files changed, 763 insertions(+), 1633 deletions(-) delete mode 100644 src/player_replay.c delete mode 100644 src/player_replay.h diff --git a/src/ent_route.c b/src/ent_route.c index 7dd48d0..48f4bd7 100644 --- a/src/ent_route.c +++ b/src/ent_route.c @@ -118,7 +118,7 @@ void ent_route_preupdate(void) // TODO: put this in a header u32 minutes_span = (centiseconds+(200*60)) / (100*60); - vg_queue_clear( &_remote_replay.replay.buffer ); + vg_queue_clear( &_remote_replay.buffer ); _remote_replay.min_frame_t = 0.0; _remote_replay.total_chunks = minutes_span; _remote_replay.chunks_downloaded = 0; @@ -134,7 +134,10 @@ void ent_route_preupdate(void) } // TODO: UI overlay for downlaoding - sfd_encode( (v2i){0,6}, "Downloading ...", k_world_sfd_center ); + world_clear_event( k_world_event_route_leaderboard ); + srinput.state = k_input_state_resume; + gui_helper_reset( k_gui_helper_mode_clear ); + _replay2_open_player( k_replay_type_network, 0 ); break; } else @@ -146,24 +149,7 @@ void ent_route_preupdate(void) } } -#if 0 -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(); - } - _ent_route.helper_alltime->greyed = !world_sfd.view_weekly; - _ent_route.helper_weekly->greyed = world_sfd.view_weekly; -#endif - E0: - if( button_down( k_srbind_mback ) ) { if( world_clear_event( k_world_event_route_leaderboard ) ) diff --git a/src/freecam.c b/src/freecam.c index d961ed6..c0a0f57 100644 --- a/src/freecam.c +++ b/src/freecam.c @@ -1,12 +1,12 @@ #include "skaterift.h" #include "player.h" #include "player_render.h" -#include "player_replay.h" +#include "replay2.h" #include "input.h" void freecam_preupdate(void) { - vg_camera *cam = &player_replay.replay_freecam; + vg_camera *cam = &_replay2.replay_freecam; v3f angles; v3_copy( cam->angles, angles ); player_look( angles, 1.0f ); @@ -15,10 +15,9 @@ void freecam_preupdate(void) v3f d; v3_sub( angles, cam->angles, d ); - v3_muladds( player_replay.freecam_w, d, 20.0f, player_replay.freecam_w ); - v3_muls( player_replay.freecam_w, decay, player_replay.freecam_w ); - v3_muladds( cam->angles, player_replay.freecam_w, vg.time_frame_delta, - cam->angles ); + v3_muladds( _replay2.freecam_w, d, 20.0f, _replay2.freecam_w ); + v3_muls( _replay2.freecam_w, decay, _replay2.freecam_w ); + v3_muladds( cam->angles, _replay2.freecam_w, vg.time_frame_delta, cam->angles ); cam->angles[1] = vg_clampf( cam->angles[1], -VG_PIf*0.5f,VG_PIf*0.5f); vg_camera_update_transform( cam ); @@ -33,12 +32,9 @@ void freecam_preupdate(void) joystick_state( k_srjoystick_steer, input ); v2_muls( input, vg.time_frame_delta*6.0f*20.0f, input ); - v3_muladds( player_replay.freecam_v, lookdir, -input[1], - player_replay.freecam_v ); - v3_muladds( player_replay.freecam_v, sidedir, input[0], - player_replay.freecam_v ); + v3_muladds( _replay2.freecam_v, lookdir, -input[1], _replay2.freecam_v ); + v3_muladds( _replay2.freecam_v, sidedir, input[0], _replay2.freecam_v ); - v3_muls( player_replay.freecam_v, decay, player_replay.freecam_v ); - v3_muladds( cam->pos, - player_replay.freecam_v, vg.time_frame_delta, cam->pos ); + v3_muls( _replay2.freecam_v, decay, _replay2.freecam_v ); + v3_muladds( cam->pos,_replay2.freecam_v, vg.time_frame_delta, cam->pos ); } diff --git a/src/gameserver.c b/src/gameserver.c index 7a9909b..051d8fe 100644 --- a/src/gameserver.c +++ b/src/gameserver.c @@ -745,14 +745,17 @@ int main( int argc, char *argv[] ) signal( SIGQUIT, inthandler ); signal( SIGPIPE, SIG_IGN ); - char *arg; - while( vg_argp( argc, argv ) ) { + _vg_opt_init( argc, argv ); + const char *arg; if( vg_long_opt( "noauth", "Disable server authentication" ) ) _gameserver.auth_mode = eServerModeNoAuthentication; if( vg_long_opt( "replay-info", "Print replay info periodically" ) ) _gs_replay.print_info = 1; + + if( !_vg_opt_check() ) + return 0; } if( !vg_init_async_queue( &_gameserver.tasks ) ) diff --git a/src/menu.c b/src/menu.c index d36cca8..1296bdd 100644 --- a/src/menu.c +++ b/src/menu.c @@ -93,6 +93,14 @@ void menu_open( enum menu_page page ) { menu.page = page; } + + if( menu.page == k_menu_page_main ) + { + if( menu.main_index == k_menu_main_map ) + { + world_map_initialize_view(); + } + } } static void menu_close(void) @@ -939,8 +947,7 @@ void menu_gui( ui_context *ctx ) if( menu_button( ctx, list, R == 2, 1, "Replay" ) ) { - //menu.page = k_menu_page_credits; - skaterift_open_replay(); + _replay2_open_player( k_replay_type_local, 1 ); } ui_rect end = { list[0], list[1]+list[3]-64, list[2], 72 }; @@ -1016,8 +1023,7 @@ void menu_gui( ui_context *ctx ) ui_rect title; ui_split( inf, k_ui_axis_h, 28*2, 0, title, inf ); ctx->font = &vgf_default_title; - ui_text( ctx, - title, "Where to go", 1, k_ui_align_middle_center, 0 ); + ui_text( ctx, title, "Where to go", 1, k_ui_align_middle_center, 0 ); ui_split( inf, k_ui_axis_h, 28, 0, title, inf ); ctx->font = &vgf_default_large; diff --git a/src/network_requests.c b/src/network_requests.c index 5f76a88..3413c5b 100644 --- a/src/network_requests.c +++ b/src/network_requests.c @@ -166,32 +166,6 @@ void network_publish_laptime( const char *mod_uid, const char *route_uid, f64 la network_send_request( packet, &data, NULL, 0 ); } -#if 0 -static void replay_download_callback( void *data, u32 data_size, u64 userdata, enum request_status status ) -{ - if( status == k_request_status_ok ) - vg_info( "%u bytes downloaded OK\n", data_size ); - else - vg_warn( "Womp womp\n" ); -} - -void network_download_replay( u64 steamid, u32 minute ) -{ - if( !network_connected() ) - return; - - netmsg_request *packet = alloca( sizeof(netmsg_request) + 512 ); - packet->inetmsg_id = k_inetmsg_request; - - vg_msg data; - vg_msg_init( &data, packet->buffer, 512 ); - vg_msg_wkvstr( &data, "endpoint", "replay" ); - vg_msg_wkvnum( &data, "minute", k_vg_msg_u32, 1, &minute ); - vg_msg_wkvnum( &data, "steamid", k_vg_msg_u64, 1, &steamid ); - network_send_request( packet, &data, replay_download_callback, 0 ); -} -#endif - static void _delete_request( net_request *request ) { vg_pool_unwatch( &_net_requests.request_pool, vg_pool_id( &_net_requests.request_pool, request ) ); @@ -240,6 +214,8 @@ void _net_handle_response_message( SteamNetworkingMessage_t *msg ) if( old_id ) { net_request *old_request = vg_pool_item( &_net_requests.request_pool, old_id ); + if( old_request->callback ) + old_request->callback( NULL, 0, old_request->userdata, k_request_status_server_error ); old_request->state = k_request_state_error; log_request_status( old_request, "Interrupted by new header" ); _delete_request( old_request ); @@ -249,6 +225,8 @@ void _net_handle_response_message( SteamNetworkingMessage_t *msg ) struct netmsg_transfer_header *header = (void *)response->buffer; if( header->data_size > 1024*1024*4 ) { + if( request->callback ) + request->callback( NULL, 0, request->userdata, k_request_status_out_of_memory ); request->state = k_request_state_error; log_request_status( request, "Header specified size too large (>4mb)" ); _delete_request( request ); @@ -268,6 +246,10 @@ void _net_handle_response_message( SteamNetworkingMessage_t *msg ) if( current_id != response->id ) { net_request *current = vg_pool_item( &_net_requests.request_pool, current_id ); + if( request->callback ) + request->callback( NULL, 0, request->userdata, k_request_status_server_error ); + if( current->callback ) + current->callback( NULL, 0, current->userdata, k_request_status_server_error ); current->state = k_request_state_error; request->state = k_request_state_error; log_request_status( current, "Transfer protocol fault" ); @@ -305,6 +287,8 @@ void _net_handle_response_message( SteamNetworkingMessage_t *msg ) } else { + if( request->callback ) + request->callback( NULL, 0, request->userdata, k_request_status_server_error ); request->state = k_request_state_error; log_request_status( request, request_status_string(response->status) ); _delete_request( request ); diff --git a/src/player.c b/src/player.c index bc63268..a02d571 100644 --- a/src/player.c +++ b/src/player.c @@ -4,7 +4,6 @@ #include "input.h" #include "world.h" #include "audio.h" -#include "player_replay.h" #include "network.h" #include "network_common.h" #include "world_routes.h" @@ -227,8 +226,6 @@ void player__pass_gate( u32 id ) { player__transport( gate->transport ); - skaterift_record_frame( &player_replay.local, 1 ); - /* I genuinely have no idea why this code was like it was, I don't think it's right. Maybe an artifact of editing * this area some time ago. Keeping it but zero'd out in case I remember in the distant futre. */ #if 0 @@ -242,8 +239,6 @@ void player__pass_gate( u32 id ) #endif localplayer.gate_waiting = gate; - localplayer.deferred_frame_record = 1; - world_routes_fracture( world, gate, localplayer.rb.co, localplayer.rb.v ); world_routes_activate_entry_gate( world, gate ); } @@ -316,7 +311,8 @@ void player__im_gui( ui_context *ctx ) if( player_subsystems[ localplayer.subsystem ]->im_gui ) player_subsystems[ localplayer.subsystem ]->im_gui( ctx ); - skaterift_replay_debug_info( ctx ); + // FIXME + //skaterift_replay_debug_info( ctx ); } void player__setpos( v3f pos ) @@ -328,7 +324,8 @@ void player__setpos( v3f pos ) void player__clean_refs(void) { - replay_clear( &player_replay.local ); + // FIXME + //replay_clear( &player_replay.local ); gui_helper_reset( k_gui_helper_mode_clear ); _world.challenge_target = NULL; @@ -410,34 +407,36 @@ void net_sfx_play( struct net_sfx *sfx ) } }; -static struct net_sfx *find_lower_priority_sfx( struct net_sfx *buffer, u32 len, - u32 *count, u8 priority ){ +struct net_sfx *net_sfx_buffer_allocate( struct net_sfx *buffer, u32 len, u32 *count, u8 priority ) +{ struct net_sfx *p_sfx = NULL; - if( *count < len ){ + if( *count < len ) + { p_sfx = &buffer[ *count ]; *count = *count+1; } - else { - for( u32 i=0; ipriority < priority ){ + if( a->priority < priority ) + { p_sfx = a; break; } } } - return p_sfx; } -void player__networked_sfx( u8 system, u8 priority, u8 id, - v3f pos, f32 volume ) +void player__networked_sfx( u8 system, u8 priority, u8 id, v3f pos, f32 volume ) { struct net_sfx sfx, - *p_net = find_lower_priority_sfx( + *p_net = net_sfx_buffer_allocate( localplayer.sfx_buffer, 4, &localplayer.sfx_buffer_count, priority ), - *p_replay = find_lower_priority_sfx( + *p_replay = net_sfx_buffer_allocate( localplayer.local_sfx_buffer, 2, &localplayer.local_sfx_buffer_count, priority ); diff --git a/src/player.h b/src/player.h index 5311e7e..7ec7183 100644 --- a/src/player.h +++ b/src/player.h @@ -86,7 +86,6 @@ struct localplayer v3f cam_land_punch, cam_land_punch_v; ent_gate *gate_waiting; - int deferred_frame_record; int immobile; bool immunity; diff --git a/src/player_common.c b/src/player_common.c index 1ecbae9..f8ebdbf 100644 --- a/src/player_common.c +++ b/src/player_common.c @@ -13,19 +13,17 @@ float player_get_heading_yaw(void) static void player_camera_portal_correction(void) { - if( localplayer.gate_waiting ){ + if( localplayer.gate_waiting ) + { /* construct plane equation for reciever gate */ v4f plane; q_mulv( localplayer.gate_waiting->q[1], (v3f){0.0f,0.0f,1.0f}, plane ); plane[3] = v3_dot( plane, localplayer.gate_waiting->co[1] ); f32 pol = v3_dot( localplayer.cam.pos, plane ) - plane[3]; - - int cleared = (pol < 0.0f) || (pol > 5.0f); - - if( cleared ){ + bool cleared = (pol < 0.0f) || (pol > 5.0f); + if( cleared ) vg_success( "Plane cleared\n" ); - } m4x3f inverse; m4x3_invert_affine( localplayer.gate_waiting->transport, inverse ); @@ -37,21 +35,13 @@ static void player_camera_portal_correction(void) m3x3_mulv( inverse, v0, v0 ); v3_angles( v0, localplayer.cam.angles ); - skeleton_apply_transform( &localplayer.skeleton, inverse, - localplayer.final_mtx ); + skeleton_apply_transform( &localplayer.skeleton, inverse, localplayer.final_mtx ); /* record and re-put things again */ if( cleared ) { - skaterift_record_frame( &player_replay.local, 1 ); - localplayer.deferred_frame_record = 1; - - skeleton_apply_transform( &localplayer.skeleton, - localplayer.gate_waiting->transport, - localplayer.final_mtx ); - - m4x3_mulv( localplayer.gate_waiting->transport, - localplayer.cam.pos, localplayer.cam.pos ); + skeleton_apply_transform( &localplayer.skeleton, localplayer.gate_waiting->transport, localplayer.final_mtx ); + m4x3_mulv( localplayer.gate_waiting->transport, localplayer.cam.pos, localplayer.cam.pos ); v3_angles_vector( localplayer.cam.angles, v0 ); m3x3_mulv( localplayer.gate_waiting->transport, v0, v0 ); v3_angles( v0, localplayer.cam.angles ); @@ -61,22 +51,23 @@ static void player_camera_portal_correction(void) } } -void player__cam_iterate(void) +void compute_cam_controller_offsets( enum player_subsystem system, struct player_cam_controller *cc ) { - struct player_cam_controller *cc = &localplayer.cam_control; - - if( localplayer.subsystem == k_player_subsystem_walk ){ + if( system == k_player_subsystem_walk ) + { v3_copy( (v3f){-0.1f,1.8f,0.0f}, cc->fpv_viewpoint ); v3_copy( (v3f){0.0f,0.0f,0.0f}, cc->fpv_offset ); v3_copy( (v3f){0.0f,1.8f,0.0f}, cc->tpv_offset ); } - else if( localplayer.subsystem == k_player_subsystem_glide ){ + else if( system == k_player_subsystem_glide ) + { v3_copy( (v3f){-0.15f,1.75f,0.0f}, cc->fpv_viewpoint ); v3_copy( (v3f){0.0f,0.0f,0.0f}, cc->fpv_offset ); v3_copy( (v3f){0.0f,-1.0f,0.0f}, cc->tpv_offset ); v3_add( cc->tpv_offset_extra, cc->tpv_offset, cc->tpv_offset ); } - else{ + else + { v3_copy( (v3f){-0.15f,1.75f,0.0f}, cc->fpv_viewpoint ); v3_copy( (v3f){0.0f,0.0f,0.0f}, cc->fpv_offset ); @@ -84,16 +75,22 @@ void player__cam_iterate(void) v3_copy( (v3f){0.0f,h,0.0f}, cc->tpv_offset ); v3_add( cc->tpv_offset_extra, cc->tpv_offset, cc->tpv_offset ); } +} + +void player__cam_iterate(void) +{ + struct player_cam_controller *cc = &localplayer.cam_control; + compute_cam_controller_offsets( localplayer.subsystem, cc ); localplayer.cam_velocity_constant = 0.25f; localplayer.cam_velocity_coefficient = 0.7f; /* lerping */ - if( localplayer.cam_dist_smooth == 0.0f ){ + if( localplayer.cam_dist_smooth == 0.0f ) localplayer.cam_dist_smooth = localplayer.cam_dist; - } - else { + else + { localplayer.cam_dist_smooth = vg_lerpf( localplayer.cam_dist_smooth, localplayer.cam_dist, @@ -146,28 +143,20 @@ void player__cam_iterate(void) /* position */ v3f fpv_pos, fpv_offset; - m4x3_mulv( localplayer.final_mtx[ localplayer.id_head-1 ], - cc->fpv_viewpoint_smooth, fpv_pos ); + m4x3_mulv( localplayer.final_mtx[ localplayer.id_head-1 ], cc->fpv_viewpoint_smooth, fpv_pos ); m3x3_mulv( localplayer.rb.to_world, cc->fpv_offset_smooth, fpv_offset ); v3_add( fpv_offset, fpv_pos, fpv_pos ); /* angles */ v3f velocity_angles; - v3_lerp( cc->cam_velocity_smooth, localplayer.rb.v, 4.0f*vg.time_frame_delta, - cc->cam_velocity_smooth ); - + v3_lerp( cc->cam_velocity_smooth, localplayer.rb.v, 4.0f*vg.time_frame_delta, cc->cam_velocity_smooth ); v3_angles( cc->cam_velocity_smooth, velocity_angles ); velocity_angles[1] *= localplayer.cam_velocity_coefficient_smooth; velocity_angles[1] += localplayer.cam_velocity_constant_smooth; - float inf_fpv = localplayer.cam_velocity_influence_smooth * - cc->camera_type_blend, - inf_tpv = localplayer.cam_velocity_influence_smooth * - (1.0f-cc->camera_type_blend); - - vg_camera_lerp_angles( localplayer.angles, velocity_angles, - inf_fpv, - localplayer.angles ); + float inf_fpv = localplayer.cam_velocity_influence_smooth * cc->camera_type_blend, + inf_tpv = localplayer.cam_velocity_influence_smooth * (1.0f-cc->camera_type_blend); + vg_camera_lerp_angles( localplayer.angles, velocity_angles, inf_fpv, localplayer.angles ); /* * Third person camera @@ -197,15 +186,12 @@ void player__cam_iterate(void) float ya = atan2f( -cc->cam_velocity_smooth[1], 30.0f ); follow_angles[1] = 0.3f + ya; - vg_camera_lerp_angles( localplayer.angles, follow_angles, - inf_tpv, - localplayer.angles ); + vg_camera_lerp_angles( localplayer.angles, follow_angles, inf_tpv, localplayer.angles ); v3f pco; v4f pq; rb_extrapolate( &localplayer.rb, pco, pq ); - v3_muladds( pco, localplayer.holdout_pose.root_co, - localplayer.holdout_time, pco ); + v3_muladds( pco, localplayer.holdout_pose.root_co, localplayer.holdout_time, pco ); v3_lerp( cc->tpv_lpf, pco, 20.0f*vg.time_frame_delta, cc->tpv_lpf ); /* now move into world */ @@ -225,7 +211,7 @@ void player__cam_iterate(void) v3_add( tpv_origin, tpv_offset, tpv_pos ); #if 0 - if( localplayer.subsystem == k_player_subsystem_walk ) + if( localplayer.subsystem == k_player_susystem_walk ) { v3f fwd, right; v3_angles_vector( localplayer.angles, fwd ); @@ -245,8 +231,7 @@ void player__cam_iterate(void) /* Camera shake */ f32 speed = v3_length(localplayer.rb.v), strength = k_cam_shake_strength * speed; - localplayer.cam_trackshake += - speed*k_cam_shake_trackspeed*vg.time_frame_delta; + localplayer.cam_trackshake += speed*k_cam_shake_trackspeed*vg.time_frame_delta; v2f rnd = {vg_perlin_fract_1d( localplayer.cam_trackshake, 1.0f, 4, 20 ), vg_perlin_fract_1d( localplayer.cam_trackshake, 1.0f, 4, 63 ) }; @@ -258,10 +243,8 @@ void player__cam_iterate(void) v3_muladds( localplayer.cam_land_punch, localplayer.cam_land_punch_v, vg.time_frame_delta, localplayer.cam_land_punch ); v3_add( Fd, Fs, F ); - v3_muladds( localplayer.cam_land_punch_v, F, vg.time_frame_delta, - localplayer.cam_land_punch_v ); - v3_add( localplayer.cam_land_punch, localplayer.cam.pos, - localplayer.cam.pos ); + v3_muladds( localplayer.cam_land_punch_v, F, vg.time_frame_delta, localplayer.cam_land_punch_v ); + v3_add( localplayer.cam_land_punch, localplayer.cam.pos, localplayer.cam.pos ); /* portal transitions */ player_camera_portal_correction(); diff --git a/src/player_remote.c b/src/player_remote.c index 74a0cda..7c54d85 100644 --- a/src/player_remote.c +++ b/src/player_remote.c @@ -56,13 +56,12 @@ void relink_all_remote_player_worlds(void) void player_remote_update_friendflags( struct network_player *remote ) { ISteamFriends *hSteamFriends = SteamAPI_SteamFriends(); - remote->isfriend = SteamAPI_ISteamFriends_HasFriend( hSteamFriends, - remote->steamid, k_EFriendFlagImmediate ); - remote->isblocked = SteamAPI_ISteamFriends_HasFriend( hSteamFriends, - remote->steamid, k_EFriendFlagBlocked ); + remote->isfriend = SteamAPI_ISteamFriends_HasFriend( hSteamFriends, remote->steamid, k_EFriendFlagImmediate ); + remote->isblocked = SteamAPI_ISteamFriends_HasFriend( hSteamFriends, remote->steamid, k_EFriendFlagBlocked ); } -void decode_playerframe( netmsg_playerframe *frame, u32 data_length, struct interp_frame *dest ) +void decode_playerframe( netmsg_playerframe *frame, u32 data_length, struct interp_frame *dest, v2f out_angles, + struct net_sfx *sfx_buffer, u32 *inout_sfx_buffer_len ) { dest->active = 1; dest->subsystem = frame->subsystem; @@ -77,8 +76,10 @@ void decode_playerframe( netmsg_playerframe *frame, u32 data_length, struct inte }; /* camera */ - v2f _null_v2f = {0,0}; - bitpack_qv2f( &ctx, 8, 0.0f, VG_TAUf, _null_v2f ); + v2f angles = {0,0}; + bitpack_qv2f( &ctx, 8, 0.0f, 1.0f, angles ); + if( out_angles ) + v2_muls( angles, VG_TAUf, out_angles ); /* animation * -------------------------------------------------------------*/ @@ -96,39 +97,28 @@ void decode_playerframe( netmsg_playerframe *frame, u32 data_length, struct inte /* sfx * -------------------------------------------------------------*/ + u32 max_sfx_out = 0, sfx_out = 0; + + if( sfx_buffer ) + max_sfx_out = *inout_sfx_buffer_len; + for( u32 i=0; isound_effects; i ++ ) { - struct net_sfx sfx; - net_sfx_exchange( &ctx, &sfx ); + struct net_sfx sfx, *sfx_dst = &sfx; -#if 0 - f64 t = (frame->timestamp - NETWORK_FRAMERATE) + (sfx.subframe*NETWORK_FRAMERATE); - f32 remaining = t - ib->t; - - if( remaining <= 0.0f ) - net_sfx_play( &sfx ); - else + // TODO: Priority? + if( isystem == k_player_subsystem_invalid ) - { - dst = sj; - break; - } - - if( sj->priority < sfx.priority ) - dst = sj; - } - - *dst = sfx; - dst->subframe = remaining; + sfx_out ++; + sfx_dst = &sfx_buffer[i]; } -#endif + + net_sfx_exchange( &ctx, sfx_dst ); } + if( sfx_buffer ) + *inout_sfx_buffer_len = sfx_out; + /* glider * -------------------------------------------------------------*/ @@ -259,7 +249,7 @@ void player_remote_rx_200_300( SteamNetworkingMessage_t *msg ) /* camera */ v2f _null_v2f = {0,0}; - bitpack_qv2f( &ctx, 8, 0.0f, VG_TAUf, _null_v2f ); + bitpack_qv2f( &ctx, 8, 0.0f, 1.0f, _null_v2f ); /* animation * -------------------------------------------------------------*/ @@ -430,7 +420,10 @@ void remote_player_send_playerframe(void) /* camera * -------------------------------- */ - bitpack_qv2f( &ctx, 8, 0.0f, VG_TAUf, (v2f){ fmod( localplayer.angles[0], VG_TAUf ), localplayer.angles[1] } ); + + f32 y = vg_fractf(localplayer.angles[0]/VG_TAUf), + p = localplayer.angles[1]/VG_TAUf; + bitpack_qv2f( &ctx, 8, 0.0f, 1.0f, (v2f){ y, p } ); /* animation * -----------------------------------------------*/ @@ -749,12 +742,15 @@ static int remote_players_randomize( int argc, const char *argv[] ){ void remote_sfx_pre_update(void) { - for( u32 i=0; isystem != k_player_subsystem_invalid ){ + if( si->system != k_player_subsystem_invalid ) + { si->subframe -= vg.time_frame_delta; - if( si->subframe <= 0.0f ){ + if( si->subframe <= 0.0f ) + { net_sfx_play( si ); si->system = k_player_subsystem_invalid; } diff --git a/src/player_remote.h b/src/player_remote.h index a6bd72c..ecbc033 100644 --- a/src/player_remote.h +++ b/src/player_remote.h @@ -99,8 +99,7 @@ void relink_all_remote_player_worlds(void); void player_remote_update_friendflags( struct network_player *remote ); void remote_players_init(void); void remote_sfx_pre_update(void); -void remote_players_imgui_world( ui_context *ctx, world_instance *world, - m4x4f pv, f32 max_dist, int geo_cull ); +void remote_players_imgui_world( ui_context *ctx, world_instance *world, m4x4f pv, f32 max_dist, int geo_cull ); void remote_players_imgui_lobby( ui_context *ctx ); void remote_players_chat_imgui( ui_context *ctx ); void pose_remote_player( f64 pose_time, struct interp_frame *f0, struct interp_frame *f1, struct player_board *board, @@ -109,3 +108,6 @@ void pose_remote_player( f64 pose_time, struct interp_frame *f0, struct interp_f struct player_board_pose *out_board_pose, struct player_effects_data *out_effects, bool *out_render_glider ); + +void decode_playerframe( netmsg_playerframe *frame, u32 data_length, struct interp_frame *dest, v2f out_angles, + struct net_sfx *sfx_buffer, u32 *inout_sfx_buffer_len ); diff --git a/src/player_render.c b/src/player_render.c index 0f5b6c7..ebcd8bd 100644 --- a/src/player_render.c +++ b/src/player_render.c @@ -285,6 +285,7 @@ void player__animate(void) player__cam_iterate(); } +#if 0 static void player_copy_frame_animator( replay_frame *frame ) { struct player_subsystem_interface *sys = player_subsystems[localplayer.subsystem]; @@ -295,6 +296,7 @@ static void player_copy_frame_animator( replay_frame *frame ) memcpy( sys->animator_data, src, sys->animator_size ); } } +#endif void lerp_player_pose( player_pose *pose0, player_pose *pose1, f32 t, player_pose *posed ) { @@ -326,8 +328,10 @@ void player__observe_system( enum player_subsystem id ) } } +#if 0 void player__animate_from_replay( replay_buffer *replay ) { + VG_ASSERT(0); replay_frame *frame = replay->cursor_frame, *next = NULL; if( frame ) @@ -404,6 +408,7 @@ void player__animate_from_replay( replay_buffer *replay ) apply_full_skeleton_pose( &localplayer.skeleton, &localplayer.pose, localplayer.final_mtx ); } +#endif void player__pre_render(void) { diff --git a/src/player_render.h b/src/player_render.h index 0c89154..b2491a7 100644 --- a/src/player_render.h +++ b/src/player_render.h @@ -5,7 +5,6 @@ #include "world.h" #include "player_render.h" #include "player_api.h" -#include "player_replay.h" enum eboard_truck{ k_board_truck_back = 0, @@ -70,6 +69,5 @@ void player__observe_system( enum player_subsystem id ); void player_load_animations( const char *path ); void player_load_animation_reference( const char *path ); void player__render( vg_camera *cam ); -void player__animate_from_replay( replay_buffer *replay ); void player__animate(void); void player__pre_render(void); diff --git a/src/player_replay.c b/src/player_replay.c deleted file mode 100644 index c8666be..0000000 --- a/src/player_replay.c +++ /dev/null @@ -1,1165 +0,0 @@ -#include "skaterift.h" -#include "player.h" -#include "player_replay.h" -#include "input.h" -#include "gui.h" -#include "freecam.h" - -#include "player_walk.h" -#include "player_skate.h" -#include "player_dead.h" -#include "player_glide.h" - -struct replay_globals player_replay = -{ - .active_keyframe = -1, -}; - -void replay_clear( replay_buffer *replay ) -{ - replay->head = NULL; - replay->tail = NULL; - replay->cursor_frame = NULL; - replay->statehead = NULL; - replay->cursor = -99999.9; -} - -void *replay_frame_data( replay_frame *frame, enum replay_framedata type ) -{ - if( frame->data_table[type][1] == 0 ) - return NULL; - - void *baseptr = frame; - return baseptr + frame->data_table[type][0]; -} - -static u16 replay_frame_calculate_data_offsets( - u16 data_table[k_replay_framedata_rows][2] ){ - - u32 total = vg_align8( sizeof(replay_frame) ); - for( u32 i=0; i 0xffff ) - vg_fatal_error( "Exceeded frame storage capacity\n" ); - } - return total; -} - -static void replay_tailpop( replay_buffer *replay ){ - if( replay->cursor_frame == replay->tail ) - replay->cursor_frame = NULL; - if( replay->statehead == replay->tail ) - replay->statehead = NULL; - - replay->tail = replay->tail->r; - - if( replay->tail ) - replay->tail->l = NULL; - else - replay->head = NULL; -} - -static replay_frame *replay_newframe( replay_buffer *replay, u16 animator_size, u16 gamestate_size, u16 sfx_count, - bool save_glider ) -{ - u16 data_table[ k_replay_framedata_rows ][2]; - data_table[ k_replay_framedata_animator ][1] = animator_size; - data_table[ k_replay_framedata_gamestate ][1] = gamestate_size; - data_table[ k_replay_framedata_sfx ][1] = sfx_count*sizeof(struct net_sfx); - data_table[ k_replay_framedata_internal_gamestate ][1] = 0; - if( gamestate_size ) - { - data_table[ k_replay_framedata_internal_gamestate ][1] = - sizeof( replay_gamestate ); - } - - data_table[ k_replay_framedata_glider ][1] = 0; - if( save_glider ) - { - data_table[ k_replay_framedata_glider ][1] = - sizeof(struct replay_glider_data); - } - - u32 nextsize = replay_frame_calculate_data_offsets( data_table ); - - replay_frame *frame = NULL; - if( replay->head ) - { - u32 headsize = replay->head->total_size, - nextpos = ((void *)replay->head - replay->data) + headsize; - - if( nextpos + nextsize > replay->size ) - { - nextpos = 0; - - /* maintain contiguity */ - while( replay->tail ) - { - if( (void *)replay->tail - replay->data ) - replay_tailpop( replay ); - else break; - } - } - -check_again:; - u32 tailpos = (void *)replay->tail - replay->data; - - if( tailpos >= nextpos ) - { - if( nextpos + nextsize > tailpos ) - { - replay_tailpop( replay ); - - if( replay->tail ) - goto check_again; - } - } - - frame = replay->data + nextpos; - - if( replay->head ) - replay->head->r = frame; - } - else - frame = replay->data; - - for( u32 i=0; idata_table[i][0] = data_table[i][0]; - frame->data_table[i][1] = data_table[i][1]; - } - - frame->total_size = nextsize; - frame->l = replay->head; - frame->r = NULL; - replay->head = frame; - if( !replay->tail ) replay->tail = frame; - if( gamestate_size ) replay->statehead = frame; - - return frame; -} - -static void replay_emit_frame_sounds( replay_frame *frame ) -{ - void *baseptr = frame; - u16 *inf = frame->data_table[k_replay_framedata_sfx]; - struct net_sfx *buffer = baseptr + inf[0]; - u32 count = inf[1] / sizeof(struct net_sfx); - - for( u32 i=0; ihead ) return 0; - - if( t < replay->tail->time ) t = replay->tail->time; - if( t > replay->head->time ) t = replay->head->time; - - if( !replay->cursor_frame ) { - replay->cursor = replay->head->time; - replay->cursor_frame = replay->head; - - if( fabs(replay->head->time-t) > fabs(replay->tail->time-t) ){ - replay->cursor = replay->tail->time; - replay->cursor_frame = replay->tail; - } - } - - f64 dir = t - replay->cursor; - if( dir == 0.0 ) return 0; - dir = vg_signf( dir ); - - - u32 i=4096; - while( i --> 0 ){ - if( dir < 0.0 ){ - if( t > replay->cursor_frame->time ) { - replay->cursor = t; - return 1; - } - } - - replay_frame *next; - if( dir > 0.0 ) next = replay->cursor_frame->r; - else next = replay->cursor_frame->l; - - if( !next ) break; - - if( dir > 0.0 ){ - if( t < next->time ){ - replay->cursor = t; - return 1; - } - } - - replay_emit_frame_sounds( next ); - - replay->cursor_frame = next; - replay->cursor = next->time; - - if( !i ) return 1; - } - - replay->cursor = t; - return 0; -} - -replay_frame *replay_find_recent_stateframe( replay_buffer *replay ) -{ - replay_frame *frame = replay->cursor_frame; - u32 i=4096; - while( i --> 0 ){ - if( !frame ) return frame; - if( frame->data_table[ k_replay_framedata_gamestate ][1] ) return frame; - frame = frame->l; - } - - return NULL; -} - -f32 replay_subframe_time( replay_buffer *replay ) -{ - replay_frame *frame = replay->cursor_frame; - if( !frame ) return 0.0f; - replay_frame *next = frame->r; - if( next ) - { - f64 l = next->time - frame->time, - t = (l <= (1.0/128.0))? 0.0: (replay->cursor - frame->time) / l; - return vg_clampf( t, 0.0f, 1.0f ); - } - else - return 0.0f; -} - -void replay_get_frame_camera( replay_frame *frame, vg_camera *cam ) -{ - cam->fov = frame->cam.fov; - v3_copy( frame->cam.pos, cam->pos ); - v3_copy( frame->cam.angles, cam->angles ); -} - -void replay_get_camera( replay_buffer *replay, vg_camera *cam ) -{ - cam->nearz = 0.1f; - cam->farz = 100.0f; - if( replay->cursor_frame ) - { - replay_frame *next = replay->cursor_frame->r; - - if( next ) - { - vg_camera temp; - - replay_get_frame_camera( replay->cursor_frame, cam ); - replay_get_frame_camera( next, &temp ); - vg_camera_lerp( cam, &temp, replay_subframe_time( replay ), cam ); - } - else - { - replay_get_frame_camera( replay->cursor_frame, cam ); - } - } - else - { - v3_zero( cam->pos ); - v3_zero( cam->angles ); - cam->fov = 90.0f; - } -} - -void skaterift_get_replay_cam( vg_camera *cam ) -{ - replay_buffer *replay = &player_replay.local; - - if( player_replay.active_keyframe != -1 ) - { - replay_keyframe *kf = - &player_replay.keyframes[player_replay.active_keyframe]; - - v3_copy( kf->cam.pos, cam->pos ); - v3_copy( kf->cam.angles, cam->angles ); - cam->fov = kf->cam.fov; - return; - } - - if( player_replay.keyframe_count >= 2 ) - { - for( u32 i=0; icursor) && (kf[1].time>replay->cursor) ) - { - f64 l = kf[1].time - kf[0].time, - t = (l <= (1.0/128.0))? 0.0: (replay->cursor-kf[0].time) / l; - - if( player_replay.keyframe_count >= 3 ) - { - f32 m_start = 0.5f, m_end = 0.5f; - - if( i > 0 ) - { - if( (t < 0.5f) || (i==player_replay.keyframe_count-2) ) - { - kf --; - } - } - - u32 last = player_replay.keyframe_count-1; - if( kf+0 == player_replay.keyframes ) m_start = 1.0f; - if( kf+2 == player_replay.keyframes+last ) m_end = 1.0f; - - f32 ts = vg_lerpf( kf[0].time, kf[1].time, 1.0f-m_start ), - te = vg_lerpf( kf[1].time, kf[2].time, m_end ); - - l = te-ts; - t = (replay->cursor-ts)/l; - - /* - * Adjust t, so that its derivative matches at the endpoints. - * Since t needs to go from 0 to 1, it will naturally change at - * different rates between keyframes. So this smooths it out. - * - * Newton method, going through standard direct quadratic eq has - * precision / other problems. Also we only care about 0>t>1. - */ - f32 b = (kf[1].time-ts)/l, - x0 = 1.0-t; - for( u32 i=0; i<4; i ++ ) - { - f32 ix0 = 1.0f-x0, - fx_x0 = 2.0f*b*x0*ix0 + ix0*ix0 - t, - fxd_x0 = 2.0f*(-2.0f*b*x0 + b + x0 - 1.0f); - x0 = x0 - (fx_x0/fxd_x0); - } - t = 1.0-x0; - - f32 t0 = t*m_start+(1.0f-m_start), - t1 = t*m_end; - - v3f ps, pe, as, ae; - f32 fs, fe; - - /* first order */ - v3_lerp( kf[0].cam.pos, kf[1].cam.pos, t0, ps ); - vg_camera_lerp_angles( kf[0].cam.angles, kf[1].cam.angles, - t0, as ); - fs = vg_lerpf( kf[0].cam.fov, kf[1].cam.fov, t0 ); - - v3_lerp( kf[1].cam.pos, kf[2].cam.pos, t1, pe ); - vg_camera_lerp_angles( kf[1].cam.angles, kf[2].cam.angles, - t1, ae ); - fe = vg_lerpf( kf[1].cam.fov, kf[2].cam.fov, t1 ); - - /* second order */ - v3_lerp( ps, pe, t, cam->pos ); - vg_camera_lerp_angles( as, ae, t, cam->angles ); - cam->fov = vg_lerpf( fs, fe, t ); - } - else - { - v3_lerp( kf[0].cam.pos, kf[1].cam.pos, t, cam->pos ); - vg_camera_lerp_angles( kf[0].cam.angles, kf[1].cam.angles, - t, cam->angles ); - cam->fov = vg_lerpf( kf[0].cam.fov, kf[1].cam.fov, t ); - } - return; - } - } - } - - replay_get_camera( replay, cam ); -} - -struct replay_rb -{ - v3f co, v, w; - v4f q; -}; - -void skaterift_record_frame( replay_buffer *replay, int force_gamestate ) -{ - f64 delta = 9999999.9, - statedelta = 9999999.9; - - if( replay->head ) - delta = vg.time - replay->head->time; - - if( replay->statehead ) - statedelta = vg.time - replay->statehead->time; - - const f64 k_replay_rate = 1.0/30.0, - k_gamestate_rate = 0.5; - - int save_frame = 0, - save_state = 0, - save_glider = 0; - - if( force_gamestate ) save_state = 1; - if( statedelta > k_gamestate_rate ) save_state = 1; - if( delta > k_replay_rate ) save_frame = 1; - if( save_state ) save_frame = 1; - - if( localplayer.have_glider || localplayer.glider_orphan || localplayer.subsystem == k_player_subsystem_glide ) - save_glider = 1; - - if( !save_frame ) return; - - u16 gamestate_size = 0; - if( save_state ) - { - /* TODO: have as part of system struct */ - gamestate_size = (u32 []){ - [k_player_subsystem_walk ] = sizeof(struct player_walk_state), - [k_player_subsystem_drive] = 0, - [k_player_subsystem_skate] = sizeof(struct player_skate_state), - [k_player_subsystem_dead ] = localplayer.ragdoll.part_count * sizeof(struct replay_rb), - [k_player_subsystem_glide] = sizeof(struct replay_rb), - }[ localplayer.subsystem ]; - } - - u16 animator_size = player_subsystems[localplayer.subsystem]->animator_size; - - replay_frame *frame = replay_newframe( replay, animator_size, gamestate_size, - localplayer.local_sfx_buffer_count, - save_glider ); - frame->system = localplayer.subsystem; - - if( save_state ) - { - replay_gamestate *gs = replay_frame_data( frame, k_replay_framedata_internal_gamestate ); - - gs->current_run_version = _world.current_run_version; - gs->drowned = localplayer.drowned; - - /* permanent block */ - memcpy( &gs->rb, &localplayer.rb, sizeof(rigidbody) ); - memcpy( &gs->glider_rb, &player_glide.rb, sizeof(rigidbody) ); - memcpy( &gs->cam_control, &localplayer.cam_control, - sizeof(struct player_cam_controller) ); - v3_copy( localplayer.angles, gs->angles ); - - void *dst = replay_frame_data( frame, k_replay_framedata_gamestate ); - - /* subsytem/dynamic block */ - if( localplayer.subsystem == k_player_subsystem_walk ) - memcpy( dst, &player_walk.state, gamestate_size ); - else if( localplayer.subsystem == k_player_subsystem_skate ) - memcpy( dst, &player_skate.state, gamestate_size ); - else if( localplayer.subsystem == k_player_subsystem_dead ){ - struct replay_rb *arr = dst; - for( u32 i=0; ico, arr[i].co ); - v3_copy( rb->w, arr[i].w ); - v3_copy( rb->v, arr[i].v ); - v4_copy( rb->q, arr[i].q ); - } - } - else if( localplayer.subsystem == k_player_subsystem_glide ){ - struct replay_rb *arr = dst; - rigidbody *rb = &player_glide.rb; - v3_copy( rb->co, arr[0].co ); - v3_copy( rb->w, arr[0].w ); - v3_copy( rb->v, arr[0].v ); - v4_copy( rb->q, arr[0].q ); - } - } - - if( save_glider ) - { - struct replay_glider_data *inf = replay_frame_data( frame, k_replay_framedata_glider ); - inf->have_glider = localplayer.have_glider; - inf->glider_orphan = localplayer.glider_orphan; - inf->t = player_glide.t; - v3_copy( player_glide.rb.co, inf->co ); - v4_copy( player_glide.rb.q, inf->q ); - } - - replay->cursor = vg.time; - replay->cursor_frame = frame; - frame->time = vg.time; - - /* camera */ - v3_copy( localplayer.cam.pos, frame->cam.pos ); - if( localplayer.gate_waiting ){ - m4x3_mulv( localplayer.gate_waiting->transport, - frame->cam.pos, frame->cam.pos ); - - v3f v0; - v3_angles_vector( localplayer.cam.angles, v0 ); - m3x3_mulv( localplayer.gate_waiting->transport, v0, v0 ); - v3_angles( v0, frame->cam.angles ); - } - else - v3_copy( localplayer.cam.angles, frame->cam.angles ); - - frame->cam.fov = localplayer.cam.fov; - - /* animator */ - void *dst = replay_frame_data( frame, k_replay_framedata_animator ), - *src = player_subsystems[localplayer.subsystem]->animator_data; - memcpy( dst, src, animator_size ); - - /* sound effects */ - memcpy( replay_frame_data( frame, k_replay_framedata_sfx ), - localplayer.local_sfx_buffer, - sizeof(struct net_sfx)*localplayer.local_sfx_buffer_count ); - - localplayer.local_sfx_buffer_count = 0; -} - -static void skaterift_restore_frame( replay_frame *frame ) -{ - replay_gamestate *gs = - replay_frame_data( frame, k_replay_framedata_internal_gamestate ); - void *src = replay_frame_data( frame, k_replay_framedata_gamestate ); - u16 src_size = frame->data_table[ k_replay_framedata_gamestate ][1]; - _world.current_run_version = gs->current_run_version; - localplayer.drowned = gs->drowned; - - if(frame->system == k_player_subsystem_walk ){ - memcpy( &player_walk.state, src, src_size ); - } - else if( frame->system == k_player_subsystem_skate ){ - memcpy( &player_skate.state, src, src_size ); - } - else if( frame->system == k_player_subsystem_dead ){ - player__dead_transition(0); - struct replay_rb *arr = src; - - for( u32 i=0; irb; - - v3_copy( arr[i].co, rb->co ); - v3_copy( arr[i].w, rb->w ); - v3_copy( arr[i].v, rb->v ); - v4_copy( arr[i].q, rb->q ); - - v3_copy( arr[i].co, part->prev_co ); - v4_copy( arr[i].q, part->prev_q ); - rb_update_matrices( rb ); - } - } - else if( frame->system == k_player_subsystem_glide ){ - struct replay_rb *arr = src; - rigidbody *rb = &player_glide.rb; - v3_copy( arr[0].co, rb->co ); - v3_copy( arr[0].w, rb->w ); - v3_copy( arr[0].v, rb->v ); - v4_copy( arr[0].q, rb->q ); - rb_update_matrices( rb ); - } - - localplayer.subsystem = frame->system; - - /* restore the seperated glider data if we have it */ - if( frame->data_table[ k_replay_framedata_glider ][1] ){ - struct replay_glider_data *inf = - replay_frame_data( frame, k_replay_framedata_glider ); - - localplayer.have_glider = inf->have_glider; - localplayer.glider_orphan = inf->glider_orphan; - player_glide.t = inf->t; - } - else { - localplayer.have_glider = 0; - localplayer.glider_orphan = 0; - player_glide.t = 0.0f; - } - - memcpy( &localplayer.rb, &gs->rb, sizeof(rigidbody) ); - memcpy( &player_glide.rb, &gs->glider_rb, sizeof(rigidbody) ); - v3_copy( gs->angles, localplayer.angles ); - - v3_copy( frame->cam.pos, localplayer.cam.pos ); - v3_copy( frame->cam.angles, localplayer.cam.angles ); - localplayer.cam.fov = frame->cam.fov; - - memcpy( &localplayer.cam_control, &gs->cam_control, - sizeof(struct player_cam_controller) ); - - /* chop end off replay */ - frame->r = NULL; - player_replay.local.statehead = frame; - player_replay.local.head = frame; - player_replay.local.cursor_frame = frame; - player_replay.local.cursor = frame->time; - player_replay.replay_control = k_replay_control_scrub; - skaterift.activity = k_skaterift_default; - vg.time = frame->time; -} - -static void skaterift_replay_resume(void) -{ - replay_frame *prev = replay_find_recent_stateframe(&player_replay.local); - - if( prev ) - { - player_replay.replay_control = k_replay_control_resume; - player_replay.resume_target = prev; - player_replay.resume_begin = player_replay.local.cursor; - player_replay.resume_transition = 0.0f; - } -} - -static void _remote_replay_pre_update(void); -void skaterift_replay_pre_update(void) -{ - if( skaterift.activity != k_skaterift_replay ) - return; - - bool input = 1; - - if( player_replay.replay_control == k_replay_control_resume ) - { - if( player_replay.local.cursor_frame == player_replay.resume_target || - player_replay.local.cursor_frame == NULL ) - { - skaterift_restore_frame( player_replay.resume_target ); - } - else - { - vg_slewf( &player_replay.resume_transition, 1.0f, vg.time_frame_delta * (1.0f/1.0f) ); - - if( player_replay.resume_transition >= 1.0f ) - skaterift_restore_frame( player_replay.resume_target ); - else { - f64 target = vg_lerp( player_replay.resume_begin, - player_replay.resume_target->time, - vg_smoothstepf( player_replay.resume_transition ) ); - if( replay_seek( &player_replay.local, target ) ) - player_replay.track_velocity = 1.0f; - else - player_replay.track_velocity = 0.0f; - } - } - } - else - { - if( button_down( k_srbind_replay_play ) ) - player_replay.replay_control ^= k_replay_control_play; - - if( button_down( k_srbind_replay_freecam ) ) - { - player_replay.use_freecam ^= 0x1; - - if( player_replay.use_freecam ) - { - replay_get_camera( &player_replay.local, &player_replay.replay_freecam ); - } - } - - if( button_down( k_srbind_replay_hide_ui ) ) - player_replay.hide_ui = 1; - - f32 target_speed = axis_state( k_sraxis_replay_h ) * 5.0; - - if( fabsf(target_speed) > 0.01f ) - player_replay.replay_control = k_replay_control_scrub; - - if( player_replay.replay_control == k_replay_control_play ) - target_speed = 1.0; - - vg_slewf( &player_replay.track_velocity, target_speed, 18.0f*vg.time_frame_delta ); - - if( fabsf( player_replay.track_velocity ) > 0.0001f ) - { - f64 target = player_replay.local.cursor; - target += player_replay.track_velocity * vg.time_frame_delta; - - if( !replay_seek( &player_replay.local, target ) ) - player_replay.track_velocity = 0.0f; - } - - if( button_down( k_srbind_mback ) ) - { - if( player_replay.hide_ui ) - { - player_replay.hide_ui = 0; - } - else - { - if( player_replay.local.statehead ) - skaterift_restore_frame( player_replay.local.statehead ); - else - skaterift.activity = k_skaterift_default; - } - srinput.state = k_input_state_resume; - } - - if( player_replay.use_freecam ) - { - freecam_preupdate(); - } - else - { - if( skaterift.allow_replay_resume ) - { - if( button_down( k_srbind_replay_resume ) ) - { - skaterift_replay_resume(); - } - } - } - } -} - -void skaterift_open_replay(void) -{ - vg_error( "stub!!!\n" ); - return; - - skaterift.activity = k_skaterift_replay; - skaterift_record_frame( &player_replay.local, 1 ); - if( player_replay.local.head ) - { - player_replay.local.cursor = player_replay.local.head->time; - player_replay.local.cursor_frame = player_replay.local.head; - } - player_replay.replay_control = k_replay_control_scrub; - player_replay.hide_ui = 0; - gui_helper_reset( k_gui_helper_mode_clear ); -} - -void skaterift_replay_init(void) -{ - u32 MB = 1024*1024; - player_replay.local.data = vg_linear_alloc( vg_mem.rtmemory, 6*MB ); - player_replay.local.size = 6*MB; - replay_clear( &player_replay.local ); -} - -void skaterift_replay_debug_info( ui_context *ctx ) -{ - player__debugtext( ctx, 2, "replay info" ); - replay_buffer *replay = &player_replay.local; - - u32 head = 0, - tail = 0; - if( replay->tail ) tail = (void *)replay->tail - replay->data; - if( replay->head ) head = (void *)replay->head - replay->data; - - player__debugtext( ctx, 1, "head @%u | tail @%u\n", head, tail ); - - if( replay->statehead ) - { - for( u32 i=0; istatehead->data_table[i][0], - replay->statehead->data_table[i][1] ); - } - u32 state = (void *)replay->statehead - replay->data; - player__debugtext( ctx, 1, "gs @%u\n", state ); - player__debugtext( ctx, 1, "gamestate_size: %hu\n", - replay->statehead->data_table[k_replay_framedata_gamestate][1] ); - } - else - player__debugtext( ctx, 1, "gs @NULL\n" ); - - f64 start = replay->cursor, - end = replay->cursor; - if( replay->tail ) start = replay->tail->time; - if( replay->head ) end = replay->head->time; - - f64 cur = replay->cursor - start, - len = end - start; - - player__debugtext( ctx, 1, "cursor: %.2fs / %.2fs\n", cur, len ); -} - -static int _keyframe_cmp( const void *p1, const void *p2 ) -{ - const replay_keyframe *kf1 = p1, *kf2 = p2; - return kf1->time > kf2->time; -} - -static void replay_keyframe_sort(void) -{ - qsort( player_replay.keyframes, player_replay.keyframe_count, - sizeof(replay_keyframe), _keyframe_cmp ); -} - -static void replay_fly_edit_keyframe( ui_context *ctx, replay_keyframe *kf ) -{ - if( ui_click_down( ctx, UI_MOUSE_LEFT ) ) - { - /* init freecam */ - v3_copy( kf->cam.pos, player_replay.replay_freecam.pos ); - v3_copy( kf->cam.angles, player_replay.replay_freecam.angles ); - v3_zero( player_replay.freecam_v ); - v3_zero( player_replay.freecam_w ); - player_replay.replay_freecam.fov = kf->cam.fov; - } - - /* move freecam */ - ui_capture_mouse( ctx, 0 ); - freecam_preupdate(); - - if( vg_getkey(SDLK_q) ) - player_replay.freecam_v[1] -= vg.time_frame_delta*6.0f*20.0f; - if( vg_getkey(SDLK_e) ) - player_replay.freecam_v[1] += vg.time_frame_delta*6.0f*20.0f; - - v3_copy( player_replay.replay_freecam.pos, g_render.cam.pos ); - v3_copy( player_replay.replay_freecam.angles, g_render.cam.angles); - g_render.cam.fov = player_replay.replay_freecam.fov; - - v3_copy( g_render.cam.pos, kf->cam.pos ); - v3_copy( g_render.cam.angles, kf->cam.angles ); - kf->cam.fov = g_render.cam.fov; -} - -void skaterift_replay_imgui( ui_context *ctx ) -{ - if( skaterift.activity != k_skaterift_replay ) - return; - - if( player_replay.hide_ui ) - return; - - if( vg_input.display_input_method != k_input_method_controller ) - { - ui_capture_mouse( ctx, 1 ); - } - - replay_buffer *replay = &player_replay.local; - f64 start = replay->cursor, - end = replay->cursor; - if( replay->tail ) start = replay->tail->time; - if( replay->head ) end = replay->head->time; - f64 len = end - start, - cur = (replay->cursor - start) / len; - - char buffer[ 128 ]; - - /* mainbar */ - ui_rect timeline = { 8, vg.window_y-(32+8), vg.window_x-16, 32 }; - ui_rect start_box; - ui_split( timeline, k_ui_axis_v, 32, 8, start_box, timeline ); - - const char *start_text = (player_replay.replay_control == k_replay_control_play)? "||": ">"; - if( menu_button_rect( ctx, start_box, 0, 1, start_text ) ) - { - player_replay.replay_control ^= k_replay_control_play; - } - - ui_fill( ctx, timeline, ui_colour( ctx, k_ui_bg ) ); - - /* cursor frame block */ - if( replay->cursor_frame ) - { - if( replay->cursor_frame->r ) - { - f64 l = (replay->cursor_frame->r->time-replay->cursor_frame->time)/len, - s = (replay->cursor_frame->time - start) / len; - ui_rect box = { timeline[0] + s*(f64)timeline[2], timeline[1], - VG_MAX(4,(ui_px)(l*timeline[2])), timeline[3]+2 }; - ui_fill( ctx, box, ui_colour( ctx, k_ui_bg+4 ) ); - } - } - - /* cursor */ - ui_rect cusor = { timeline[0] + cur*(f64)timeline[2] - 1, timeline[1], - 2, timeline[3] }; - ui_fill( ctx, cusor, ui_colour( ctx, k_ui_bg+7 ) ); - - /* latest state marker */ - if( skaterift.allow_replay_resume ) - { - if( replay->statehead ) - { - f64 t = (replay->statehead->time - start) / len; - ui_rect tag = { timeline[0] + t*(f64)timeline[2], timeline[1], - 2, timeline[3]+8 }; - ui_fill( ctx, tag, ui_colour( ctx, k_ui_green+k_ui_brighter ) ); - } - - /* previous state marker */ - replay_frame *prev = replay_find_recent_stateframe( replay ); - if( prev ) - { - f64 t = (prev->time - start) / len; - ui_rect tag = { timeline[0] + t*(f64)timeline[2], timeline[1], - 2, timeline[3]+8 }; - ui_fill( ctx, tag, ui_colour( ctx, k_ui_yellow+k_ui_brighter ) ); - } - } - - snprintf( buffer, 128, "-%.2fs", (end-replay->cursor) ); - ui_text( ctx, timeline, buffer, 1, k_ui_align_middle_left, 0 ); - ui_text( ctx, timeline, "0s", 1, k_ui_align_middle_right, 0 ); - - - /* helpers */ - ctx->font = &vgf_default_large; - - ui_rect helper_list_l = { 10, timeline[1] - (ctx->font->sy+8), vg.window_x/2, ctx->font->sy }; - char buf[256]; - vg_str str; - vg_strnull( &str, buf, sizeof(buf) ); - vg_input_string( &str, input_axis_list[k_sraxis_replay_h], 1 ); - vg_strcat( &str, "\x07 Scrub" ); - ui_text( ctx, helper_list_l, buf, 1, k_ui_align_left, 0 ); - helper_list_l[1] -= helper_list_l[3]+2; - - vg_strnull( &str, buf, sizeof(buf) ); - vg_input_string( &str, input_button_list[k_srbind_replay_play], 1 ); - vg_strcat( &str, (player_replay.replay_control == k_replay_control_play)? "\x07 Pause": "\x07 Play" ); - ui_text( ctx, helper_list_l, buf, 1, k_ui_align_left, 0 ); - helper_list_l[1] -= helper_list_l[3]+2; - - vg_strnull( &str, buf, sizeof(buf) ); - vg_input_string( &str, input_button_list[k_srbind_replay_freecam], 1 ); - vg_strcat( &str, "\x07 Freecam" ); - ui_text( ctx, helper_list_l, buf, 1, k_ui_align_left, 0 ); - helper_list_l[1] -= helper_list_l[3]+2; - - vg_strnull( &str, buf, sizeof(buf) ); - vg_input_string( &str, input_button_list[k_srbind_replay_hide_ui], 1 ); - vg_strcat( &str, "\x07 Hide UI" ); - ui_text( ctx, helper_list_l, buf, 1, k_ui_align_left, 0 ); - helper_list_l[1] -= helper_list_l[3]+2; - - ui_rect helper_list_r = { vg.window_x/2, timeline[1] - (ctx->font->sy+8), vg.window_x/2-10, ctx->font->sy }; - vg_strnull( &str, buf, sizeof(buf) ); - vg_input_string( &str, input_button_list[k_srbind_mback], 1 ); - vg_strcat( &str, "\x07 Exit Replay" ); - ui_text( ctx, helper_list_r, buf, 1, k_ui_align_right, 0 ); - helper_list_l[1] -= helper_list_r[3]+2; - - if( player_replay.use_freecam ) - { - ui_rect box = { vg.window_x/2 - 200, 40, 400, ctx->font->sy }; - ui_text( ctx, box, KYEL "\x06\x02--- Freecam Enabled ---", 1, k_ui_align_center, 0 ); - } - - ctx->font = &vgf_default_small; - - /* timeline scrub */ - bool start_in_timeline = - ui_clicking(ctx, UI_MOUSE_LEFT) && - ui_inside_rect(timeline, ctx->mouse_click); - - if( (ui_inside_rect( timeline, ctx->mouse )) || start_in_timeline ) - { - ui_rect cursor = { ctx->mouse[0], timeline[1], 4, timeline[3] }; - ui_fill( ctx, cursor, ui_colour( ctx, k_ui_fg ) ); - ctx->cursor = k_ui_cursor_ibeam; - - if( ui_clicking( ctx, UI_MOUSE_LEFT ) && start_in_timeline ) - { - f64 mouse_t = start + ((f64)(ctx->mouse[0]-timeline[0]) / (f64)timeline[2])*len; - replay_seek( &player_replay.local, mouse_t ); - player_replay.active_keyframe = -1; - } - } - - - /* This contains the UI for the old removed keyframe editor --------------------------------------- */ -#if 0 - /* script bar */ - ui_rect script = { timeline[0], timeline[1]+timeline[3] + 2, timeline[2], 16 }; - ui_fill( ctx, script, ui_colour( ctx, k_ui_bg ) ); - - /* keyframe draw and select */ - bool absorb_by_keyframe = 0; - ui_px lx = 0; - for( u32 i=0; itime-start)/len; - - ui_px x = timeline[0] + t*(f64)timeline[2]-8; - - /* draw connections between keyframes */ - if( i ) - { - ui_rect con = { lx, script[1]+7, x-lx, 1 }; - ui_fill( ctx, con, ui_colour( ctx, k_ui_blue ) ); - vg_line( kf->cam.pos, player_replay.keyframes[i-1].cam.pos, VG__BLUE ); - } - - /* keyframe selection */ - ui_rect tag = { x, script[1], 16, 16 }; - - if( ui_inside_rect( tag, ctx->mouse ) ) - { - absorb_by_keyframe = 1; - - if( ui_click_down( ctx, UI_MOUSE_LEFT ) ) - { - if( player_replay.active_keyframe != i ) - { - player_replay.active_keyframe = i; - replay_seek( &player_replay.local, kf->time ); - } - } - else - { - ui_outline( ctx, tag, 1, ui_colour(ctx, k_ui_fg), 0 ); - } - } - - /* edit controls */ - u32 drag_colour = ui_opacity( ui_colour(ctx, k_ui_bg+2), 0.5f ); - if( i == player_replay.active_keyframe ) - { - ui_outline( ctx, tag, 2, ui_colour(ctx, k_ui_fg), 0 ); - - ui_rect tray = { tag[0]+8-32, tag[1]+16+2, 64, 16 }; - ui_rect dragbar = { tray[0]+16, tray[1], 32, 16 }; - - bool pos_correct = 0; - - if( ui_inside_rect( dragbar, ctx->mouse_click ) ) - { - if( ui_clicking( ctx, UI_MOUSE_LEFT ) ) - { - drag_colour = ui_opacity( ui_colour(ctx,k_ui_fg), 0.5f ); - pos_correct = 1; - replay_seek( &player_replay.local, mouse_t ); - } - else if( ui_click_up( ctx, UI_MOUSE_LEFT ) ) - { - pos_correct = 1; - kf->time = mouse_t; - replay_keyframe_sort(); - - for( u32 j=0; jmouse[0]-8; - tray[0] = tag[0]+8-32; - dragbar[0] = tray[0]+16; - } - } - - if( ui_inside_rect( dragbar, ctx->mouse ) ) - { - ctx->cursor = k_ui_cursor_hand; - } - - if( !pos_correct ) - { - ui_fill( ctx, tray, - ui_opacity( ui_colour( ctx, k_ui_bg+2 ), 0.5f ) ); - } - - ui_fill( ctx, dragbar, drag_colour ); - ui_text( ctx, dragbar, ":::", 1, k_ui_align_middle_center, 0 ); - - if( !pos_correct ) - { - ui_rect btn = { tray[0], tray[1], 16, 16 }; - if( ui_button_text( ctx, btn, "X", 1 ) == k_ui_button_click ) - { - for( u32 j=i; jmouse ) ) - { - ctx->cursor = k_ui_cursor_hand; - - ui_rect cursor = { ctx->mouse[0], script[1], 4, 16 }; - ui_fill( ctx, cursor, ui_colour( ctx, k_ui_fg ) ); - - if( !absorb_by_keyframe && ui_click_down( ctx, UI_MOUSE_LEFT ) ) - { - u32 max = VG_ARRAY_LEN( player_replay.keyframes ); - if( player_replay.keyframe_count == max ) - { - ui_start_modal( ctx, "Maximum keyframes reached", UI_MODAL_BAD ); - } - else - { - replay_keyframe *kf = - &player_replay.keyframes[player_replay.keyframe_count++]; - - kf->time = mouse_t; - v3_copy( g_render.cam.pos, kf->cam.pos ); - v3_copy( g_render.cam.angles, kf->cam.angles ); - kf->cam.fov = g_render.cam.fov; - - replay_keyframe_sort(); - } - } - } -#endif - -#if 0 - if( ui_button( ctx, panel, "Clear keyframes" ) == k_ui_button_click ) - { - player_replay.keyframe_count = 0; - } - - if( (ui_button( ctx, panel, "Hide UI (F2)" ) == k_ui_button_click) ) - { - player_replay.hide_ui = 1; - } - - if( player_replay.active_keyframe != -1 ) - { - replay_keyframe *kf = - &player_replay.keyframes[ player_replay.active_keyframe ]; - - enum ui_button_state mask_using = - k_ui_button_holding_inside | - k_ui_button_holding_outside | - k_ui_button_click; - - if( ui_button( ctx, panel, "Edit cam" ) & mask_using ) - { - replay_fly_edit_keyframe( ctx, kf ); - } - } - - ui_info( ctx, panel, "World settings" ); - f32 new_time = _world.main.time; - if( ui_slider( ctx, panel, "Time of day", 0, 1, &new_time ) ) - _world.main.time = new_time; - - ui_info( ctx, panel, "" ); -#endif -} diff --git a/src/player_replay.h b/src/player_replay.h deleted file mode 100644 index d1f190d..0000000 --- a/src/player_replay.h +++ /dev/null @@ -1,123 +0,0 @@ -#pragma once -#include "player_render.h" -#include "vg/vg_rigidbody.h" - -typedef struct replay_buffer replay_buffer; -typedef struct replay_frame replay_frame; -typedef struct replay_keyframe replay_keyframe; - -typedef struct replay_gamestate replay_gamestate; -typedef struct replay_sfx replay_sfx; - -struct replay_buffer { - void *data; - u32 size; /* bytes */ - - replay_frame *head, *tail, *cursor_frame, - *statehead; - f64 cursor; -}; - -enum replay_framedata{ - k_replay_framedata_animator, - k_replay_framedata_gamestate, - k_replay_framedata_internal_gamestate, - k_replay_framedata_sfx, - k_replay_framedata_glider, - k_replay_framedata_rows -}; - -struct replay_cam -{ - v3f pos, angles; - f32 fov; -}; - -struct replay_frame -{ - struct replay_cam cam; - f64 time; - - replay_frame *l, *r; - - enum player_subsystem system; - u16 total_size; - u16 data_table[k_replay_framedata_rows][2]; -}; - -/* player-defined replay frames */ -struct replay_keyframe -{ - struct replay_cam cam; - f64 time; -}; - -struct replay_gamestate -{ - rigidbody rb, glider_rb; /* TODO: these don't need to be saved with their - full matrices */ - v3f angles; - struct player_cam_controller cam_control; - u32 current_run_version; - bool drowned; -}; - -/* we save this per-anim-frame. if there glider is existing in any state */ -struct replay_glider_data -{ - bool have_glider, glider_orphan; - f32 t; - v3f co; - v4f q; -}; - -struct replay_sfx { - u32 none; -}; - -struct replay_globals -{ - replay_buffer local; - - replay_frame *resume_target; - f64 resume_begin; - f32 resume_transition; - - enum replay_control { - k_replay_control_scrub = 0x00, - k_replay_control_play = 0x01, - k_replay_control_resume= 0x02 - } - replay_control; - f32 track_velocity; - struct gui_helper *helper_resume, *helper_freecam; - - vg_camera replay_freecam; - bool use_freecam; - bool hide_ui; - v3f freecam_v, freecam_w; - - i32 editor_mode; - replay_keyframe keyframes[32]; - u32 keyframe_count; - i32 active_keyframe; -} -extern player_replay; - -int replay_seek( replay_buffer *replay, f64 t ); - -replay_frame *replay_find_recent_stateframe( replay_buffer *replay ); -void replay_get_camera( replay_buffer *replay, vg_camera *cam ); -void replay_get_frame_camera( replay_frame *frame, vg_camera *cam ); -f32 replay_subframe_time( replay_buffer *replay ); -void replay_clear( replay_buffer *replay ); -void *replay_frame_data( replay_frame *frame, enum replay_framedata type ); - -void skaterift_replay_pre_update(void); -void skaterift_replay_imgui( ui_context *ctx ); -void skaterift_replay_debug_info( ui_context *ctx ); -void skaterift_record_frame( replay_buffer *replay, int force_gamestate ); -void skaterift_replay_post_render(void); -void skaterift_replay_init(void); -void skaterift_get_replay_cam( vg_camera *cam ); -void skaterift_open_replay(void); diff --git a/src/player_skate.c b/src/player_skate.c index 9c20d73..569ef94 100644 --- a/src/player_skate.c +++ b/src/player_skate.c @@ -1342,10 +1342,8 @@ void player__skate_comp_audio( void *_animator ) slide = 0.0f; f32 gate = skaterift.time_rate; - - if( skaterift.activity == k_skaterift_replay ){ - gate = vg_minf( 1.0f, fabsf(player_replay.track_velocity) ); - } + if( skaterift.activity == k_skaterift_replay ) + gate = vg_minf( 1.0f, fabsf(_replay2.track_velocity) ); f32 vol_main = sqrtf( (1.0f-air)*attn*(1.0f-slide) * 0.4f ) * gate, vol_air = sqrtf( air *attn * 0.5f ) * gate, @@ -2807,7 +2805,6 @@ begin_collision:; player__pass_gate( id ); } - /* FIXME: Rate limit */ static int stick_frames = 0; if( state->activity >= k_skate_activity_ground ) diff --git a/src/replay2.c b/src/replay2.c index ce01904..04bcc05 100644 --- a/src/replay2.c +++ b/src/replay2.c @@ -1,52 +1,74 @@ #include "replay2.h" struct _remote_replay _remote_replay; -struct _replay_player _replay_player; +struct _replay2 _replay2; void _replay2_init(void) { u32 MB = 1024*1024, size = 4*MB; - _remote_replay.replay.buffer.buffer = vg_linear_alloc( vg_mem.rtmemory, size ); - _remote_replay.replay.buffer.size = size; + _remote_replay.buffer.buffer = vg_linear_alloc( vg_mem.rtmemory, size ); + _remote_replay.buffer.size = size; + + _replay2.buffer.buffer = vg_linear_alloc( vg_mem.rtmemory, size*2 ); + _replay2.buffer.size = size*2; struct skeleton *sk = &localplayer.skeleton; u32 mtx_size = sizeof(m4x3f)*sk->bone_count; - _replay_player.final_mtx = vg_linear_alloc( vg_mem.rtmemory, mtx_size ); + _replay2.final_mtx = vg_linear_alloc( vg_mem.rtmemory, mtx_size ); } -void _replay2_open_player( replay2 *replay, bool end ) +static vg_queue *_replay2_player_buffer(void) { - if( replay == NULL ) - { - vg_error( "Cannot open a NULL replay\n" ); - return; - } - if( replay->buffer.allocation_count < 2 ) - { - vg_error( "Not enough frames in that replay\n" ); - return; - } + return _replay2.type == k_replay_type_local? &_replay2.buffer: &_remote_replay.buffer; +} +void _replay2_open_player( enum replay_type type, bool end ) +{ skaterift.activity = k_skaterift_replay; - _replay_player.replay = replay; + _replay2.type = type; + _replay2.animation_dirty = 1; + + vg_queue *buffer = _replay2_player_buffer(); + if( buffer->allocation_count >= 2 ) + { + if( end ) _replay2.cursor_frame_offset = buffer->head_offset; + else _replay2.cursor_frame_offset = buffer->tail_offset; - if( end ) - _replay_player.cursor_frame_offset = replay->buffer.head_offset; + replay2_frame *frame = vg_queue_data( buffer, _replay2.cursor_frame_offset ); + _replay2.cursor = frame->time; + + if( type == k_replay_type_local ) + { + replay2_frame *frame_start = vg_queue_data( buffer, buffer->tail_offset ), + *frame_end = vg_queue_data( buffer, buffer->head_offset ); + + _replay2.start_t = frame_start->time; + _replay2.end_t = frame_end->time; + } + } else - _replay_player.cursor_frame_offset = replay->buffer.tail_offset; + _replay2.cursor_frame_offset = 0; - replay2_frame *frame = vg_queue_data( &replay->buffer, _replay_player.cursor_frame_offset ); - _replay_player.cursor = frame->time; + if( type == k_replay_type_local ) + { + _replay2.highlight = 0; + _replay2.playermodel_cache_id = localplayer.playermodel_view_slot; + _replay2.board_cache_id = localplayer.board_view_slot; + addon_cache_watch( k_addon_type_player, _replay2.playermodel_cache_id ); + addon_cache_watch( k_addon_type_board, _replay2.board_cache_id ); + } } void replay2_close_player(void) { - addon_cache_unwatch( k_addon_type_player, _replay_player.playermodel_cache_id ); - addon_cache_unwatch( k_addon_type_board, _replay_player.board_cache_id ); - _replay_player.playermodel_cache_id = 0; - _replay_player.board_cache_id = 0; + addon_cache_unwatch( k_addon_type_player, _replay2.playermodel_cache_id ); + addon_cache_unwatch( k_addon_type_board, _replay2.board_cache_id ); + _replay2.playermodel_cache_id = 0; + _replay2.board_cache_id = 0; + _remote_replay.state = k_remote_replay_state_none; + localplayer.immobile = 0; } /* remote replay downloader @@ -57,7 +79,13 @@ static void replay_download_callback( void *data, u32 data_size, u64 userdata, e THREAD_0; bool is_from_network = userdata; - replay2 *replay = &_remote_replay.replay; + + if( (_remote_replay.state != k_remote_replay_state_downloading) && + (_remote_replay.state != k_remote_replay_state_getinfo) ) + { + vg_warn( "Ignoring chunk download callback: State is not downloading\n" ); + return; + } struct remote_replay_chunk *chunk = &_remote_replay.chunks[ _remote_replay.chunks_downloaded ]; if( status == k_request_status_ok ) @@ -109,14 +137,14 @@ static void replay_download_callback( void *data, u32 data_size, u64 userdata, e if( playermodel_str ) { - addon_cache_unwatch( k_addon_type_player, _replay_player.playermodel_cache_id ); - _replay_player.playermodel_cache_id = addon_cache_create_viewer_from_uid( k_addon_type_player, playermodel_str ); + addon_cache_unwatch( k_addon_type_player, _replay2.playermodel_cache_id ); + _replay2.playermodel_cache_id = addon_cache_create_viewer_from_uid( k_addon_type_player, playermodel_str ); } if( board_str ) { - addon_cache_unwatch( k_addon_type_board, _replay_player.board_cache_id ); - _replay_player.board_cache_id = addon_cache_create_viewer_from_uid( k_addon_type_board, board_str ); + addon_cache_unwatch( k_addon_type_board, _replay2.board_cache_id ); + _replay2.board_cache_id = addon_cache_create_viewer_from_uid( k_addon_type_board, board_str ); } } @@ -125,6 +153,7 @@ static void replay_download_callback( void *data, u32 data_size, u64 userdata, e } vg_info( "Processing %u bytes of network frames\n", data_size ); + vg_queue *buffer = &_remote_replay.buffer; u32 offset = 0; while(1) @@ -154,15 +183,15 @@ static void replay_download_callback( void *data, u32 data_size, u64 userdata, e } _remote_replay.min_frame_t = playerframe->timestamp; - replay2_frame *dst_frame = vg_queue_alloc( &replay->buffer, sizeof(replay2_frame) + snm->msg_size, NULL ); + replay2_frame *dst_frame = vg_queue_alloc( buffer, sizeof(replay2_frame) + snm->msg_size, NULL ); if( !dst_frame ) { vg_error( "Out of mem adding frame!\n" ); goto E0; } - dst_frame->net_frame_size = snm->msg_size; + dst_frame->net.frame_size = snm->msg_size; dst_frame->time = playerframe->timestamp; - memcpy( &dst_frame->net_frame, playerframe, snm->msg_size ); + memcpy( &dst_frame->net.frame, playerframe, snm->msg_size ); } S0: offset += sizeof(serialized_netmsg) + snm->msg_size; @@ -176,14 +205,14 @@ S0: offset += sizeof(serialized_netmsg) + snm->msg_size; if( _remote_replay.chunks_downloaded == _remote_replay.total_chunks ) { _remote_replay.state = k_remote_replay_state_ready; - vg_success( "Winner! (%u total frames)\n", replay->buffer.allocation_count ); + vg_success( "Replay got! (%u total frames)\n", buffer->allocation_count ); - replay2_frame *frame_start = vg_queue_data( &replay->buffer, replay->buffer.tail_offset ), - *frame_end = vg_queue_data( &replay->buffer, replay->buffer.head_offset ); + replay2_frame *frame_start = vg_queue_data( buffer, buffer->tail_offset ), + *frame_end = vg_queue_data( buffer, buffer->head_offset ); - if( 1 /* remote replay specific */ ) + if( 1 ) { - _replay2_open_player( replay, 0 ); + _replay2_open_player( k_replay_type_network, 0 ); f64 highlight_start = (frame_end->time - _remote_replay.start_offset), highlight_end = (frame_end->time - _remote_replay.end_offset), @@ -195,19 +224,22 @@ S0: offset += sizeof(serialized_netmsg) + snm->msg_size; if( end > frame_end->time ) end = frame_end->time; - _replay_player.start_t = start; - _replay_player.end_t = end; - _replay_player.highlight_start = highlight_start - start; - _replay_player.highlight_length = highlight_end - highlight_start; - _replay_player.highlight = 1; + _replay2.start_t = start; + _replay2.end_t = end; + _replay2.highlight_start = highlight_start - start; + _replay2.highlight_length = highlight_end - highlight_start; + _replay2.highlight = 1; _replay2_seek( start, 0 ); } else { + /* for generic local replay / rewind */ +#if 0 _replay2_open_player( replay, 1 ); - _replay_player.start_t = frame_start->time; - _replay_player.end_t = frame_end->time; + _replay2.start_t = frame_start->time; + _replay2.end_t = frame_end->time; _replay2_seek( frame_end->time, 0 ); +#endif } } else @@ -332,6 +364,19 @@ static void _remote_replay_pre_update(void) } } +void _replay2_get_camera( vg_camera *cam ) +{ + if( _replay2.animation_dirty ) + vg_camera_copy( &localplayer.cam, cam ); + else + { + if( _replay2.use_freecam ) + vg_camera_copy( &_replay2.replay_freecam, cam ); + else + vg_camera_copy( &_replay2.playback_cam, cam ); + } +} + void _replay2_pre_update(void) { _remote_replay_pre_update(); @@ -339,45 +384,231 @@ void _replay2_pre_update(void) if( skaterift.activity != k_skaterift_replay ) return; - if( _replay_player.animation_dirty ) + if( button_down( k_srbind_mback ) ) { - _replay_player.animation_dirty = 0; + if( _replay2.hide_ui ) + _replay2.hide_ui = 0; + else + { + replay2_close_player(); + skaterift.activity = k_skaterift_default; + } + + srinput.state = k_input_state_resume; + } + + vg_queue *buffer = _replay2_player_buffer(); + if( buffer->allocation_count < 2 ) + return; + + if( button_down( k_srbind_replay_play ) ) + _replay2.replay_control ^= k_replay_control_play; - replay2 *replay = _replay_player.replay; - replay2_frame *current_frame = vg_queue_data( &replay->buffer, _replay_player.cursor_frame_offset ), - *next_frame = NULL; + if( button_down( k_srbind_replay_freecam ) ) + { + if( !_replay2.use_freecam ) + _replay2_get_camera( &_replay2.replay_freecam ); + + _replay2.use_freecam ^= 0x1; + } - u32 next_frame_offset; - if( vg_queue_next( &replay->buffer, _replay_player.cursor_frame_offset, &next_frame_offset ) ) + if( button_down( k_srbind_replay_hide_ui ) ) + _replay2.hide_ui = 1; + + f32 target_speed = axis_state( k_sraxis_replay_h ) * 5.0; + if( fabsf(target_speed) > 0.01f ) + _replay2.replay_control = k_replay_control_scrub; + if( _replay2.replay_control == k_replay_control_play ) + target_speed = 1.0; + vg_slewf( &_replay2.track_velocity, target_speed, 18.0f*vg.time_frame_delta ); + + if( fabsf( _replay2.track_velocity ) > 0.0001f ) + { + f64 target = _replay2.cursor; + target += _replay2.track_velocity * vg.time_frame_delta; + bool stop = 0; + if( target > _replay2.end_t ) { - next_frame = vg_queue_data( &replay->buffer, next_frame_offset ); + target = _replay2.end_t; + stop = 1; + } + if( target < _replay2.start_t ) + { + target = _replay2.start_t; + stop = 1; + } + if( stop ) + { + _replay2.track_velocity = 0.0; + _replay2.replay_control = k_replay_control_scrub; } - /* decode frames */ - struct interp_frame interp_frame0, interp_frame1; - u32 s0 = current_frame->net_frame_size - sizeof(netmsg_playerframe); - decode_playerframe( ¤t_frame->net_frame, s0, &interp_frame0 ); + _replay2_seek( target, 1 ); + } - m4x3f *final_mtx = _replay_player.final_mtx; - v3f *glider_mtx = _replay_player.glider_mtx; - struct player_board_pose *board_pose = &_replay_player.board_pose; - struct player_board *board = addon_cache_item_data( k_addon_type_board, _replay_player.board_cache_id, 1 ); - struct player_effects_data *effects = &_replay_player.effect_data; - bool *glider_flag = &_replay_player.render_glider; - f64 frame_time = _replay_player.cursor; + if( _replay2.use_freecam ) + freecam_preupdate(); - if( next_frame ) + if( _replay2.animation_dirty ) + { + _replay2.animation_dirty = 0; + + m4x3f *final_mtx = _replay2.final_mtx; + v3f *glider_mtx = _replay2.glider_mtx; + struct player_board_pose *board_pose = &_replay2.board_pose; + struct player_board *board = addon_cache_item_data( k_addon_type_board, _replay2.board_cache_id, 1 ); + struct player_effects_data *effects = &_replay2.effect_data; + bool *glider_flag = &_replay2.render_glider; + f64 frame_time = _replay2.cursor; + + if( !_replay2.cursor_decoded ) + _replay2_decode(); + + if( _replay2.type == k_replay_type_network ) { - u32 s1 = next_frame->net_frame_size - sizeof(netmsg_playerframe); - decode_playerframe( &next_frame->net_frame, s1, &interp_frame1 ); - pose_remote_player( frame_time, &interp_frame0, &interp_frame1, board, final_mtx, glider_mtx, - board_pose, effects, glider_flag ); + struct interp_frame *i0 = &_remote_replay.interp0, + *i1 = &_remote_replay.interp1; + struct player_cam_controller cc = { .camera_mode = k_cam_thirdperson, .camera_type_blend = 0 }; + compute_cam_controller_offsets( i0->subsystem, &cc ); + pose_remote_player( frame_time, i0, i1, board, final_mtx, glider_mtx, board_pose, effects, glider_flag ); + + f32 t = (frame_time - i0->timestamp) / (i1->timestamp - i0->timestamp); + t = vg_clampf( t, 0.0f, 1.0f ); + u16 bounds = i0->boundary_hash^i1->boundary_hash; + if( bounds & NETMSG_BOUNDARY_BIT ) + t = 1.0f; + if( bounds & NETMSG_GATE_BOUNDARY_BIT ) + t = 1.0f; + + v2f angles; + v2_lerp( _remote_replay.cam0, _remote_replay.cam1, t, angles ); + + /* position */ + v3f fpv_pos, fpv_offset; + m4x3_mulv( _replay2.final_mtx[ localplayer.id_head-1 ], cc.fpv_viewpoint, fpv_pos ); + m3x3_mulv( _replay2.final_mtx[0], cc.fpv_offset, fpv_offset ); // NOTE: [0] could be wrong (was rb.to_world) + v3_add( fpv_offset, fpv_pos, fpv_pos ); + + /* origin */ + v3f tpv_origin, tpv_offset, tpv_pos; + m4x3_mulv( _replay2.final_mtx[0], cc.tpv_offset, tpv_origin ); + + /* offset */ + v3f camera_follow_dir = + { -sinf( angles[0] ) * cosf( angles[1] ), + sinf( angles[1] ), + cosf( angles[0] ) * cosf( angles[1] ) }; + v3_muls( camera_follow_dir, 1.8f, tpv_offset ); + //v3_muladds( tpv_offset, cc.cam_velocity_smooth, -0.025f, tpv_offset ); + + v3_add( tpv_origin, tpv_offset, tpv_pos ); + v3_lerp( tpv_pos, fpv_pos, cc.camera_type_blend, _replay2.playback_cam.pos ); + v2_copy( angles, _replay2.playback_cam.angles ); + f32 fov_skate = vg_lerpf( 97.0f, 135.0f, k_fov ), + fov_walk = vg_lerpf( 90.0f, 110.0f, k_fov ); + _replay2.playback_cam.fov = vg_lerpf( fov_walk, fov_skate, cc.camera_type_blend ); } else { - pose_remote_player( frame_time, &interp_frame0, NULL, board, final_mtx, glider_mtx, board_pose, - effects, glider_flag ); + replay2_frame *current_frame = vg_queue_data( buffer, _replay2.cursor_frame_offset ), + *next_frame = NULL; + void *animator0 = (void *)current_frame->local.data, + *animator1 = NULL; + struct replay_glider_data *glider0 = (void *)current_frame->local.data + current_frame->local.animator_size, + *glider1 = NULL; + struct player_subsystem_interface *sys0 = player_subsystems[current_frame->local.subsystem], + *sys1 = NULL; + + u32 next_offset; + if( vg_queue_next( buffer, _replay2.cursor_frame_offset, &next_offset ) ) + { + next_frame = vg_queue_data( buffer, next_offset ); + animator1 = (void *)next_frame->local.data; + glider1 = (void *)next_frame->local.data + next_frame->local.animator_size; + sys1 = player_subsystems[next_frame->local.subsystem]; + } + + player_pose pose; + + f32 t = 0.0f; + if( next_frame ) + { + t = (f32)((_replay2.cursor - current_frame->time) / (next_frame->time - current_frame->time)); + + u16 bounds = current_frame->local.boundary^next_frame->local.boundary; + if( bounds & NETMSG_BOUNDARY_BIT ) + t = 1.0f; + if( bounds & NETMSG_GATE_BOUNDARY_BIT ) + t = 1.0f; + + player_pose pose0, pose1; + sys0->pose( animator0, &pose0 ); + sys1->pose( animator1, &pose1 ); + lerp_player_pose( &pose0, &pose1, t, &pose ); + vg_camera_lerp( ¤t_frame->local.camera, &next_frame->local.camera, t, &_replay2.playback_cam ); + } + else + { + sys0->pose( animator0, &pose ); + vg_camera_copy( ¤t_frame->local.camera, &_replay2.playback_cam ); + } + + player__observe_system( current_frame->local.subsystem ); + if( sys0->sfx_comp ) + sys0->sfx_comp( animator0 ); + +#if 0 + if( g0 ) + { + if( g0->glider_orphan ) + { + if( g1 ) + { + v3_lerp( g0->co, g1->co, t, player_glide.rb.co ); + q_nlerp( g0->q, g1->q, t, player_glide.rb.q ); + } + else + { + v3_copy( g0->co, player_glide.rb.co ); + v4_copy( g0->q, player_glide.rb.q ); + } + + rb_update_matrices( &player_glide.rb ); + } + + if( g1 ) + player_glide.t = vg_lerpf( g0->t, g1->t, t ); + else + player_glide.t = g0->t; + + localplayer.have_glider = g0->have_glider; + localplayer.glider_orphan = g0->glider_orphan; + } + else /* no glider data in g1, or edge case we dont care about */ + { + localplayer.have_glider = 0; + localplayer.glider_orphan = 0; + player_glide.t = 0.0f; + } +#endif + + apply_full_skeleton_pose( &localplayer.skeleton, &pose, final_mtx ); + } + } + + if( _replay2.replay_control == k_replay_control_play ) + { + u32 j=0; + for( u32 i=0; i<_replay2.sfx_queue_length; i ++ ) + { + struct net_sfx *sfx = &_replay2.sfx_queue[i]; + f64 t = (_replay2.sfx_basetime - NETWORK_FRAMERATE) + (sfx->subframe*NETWORK_FRAMERATE); + if( _replay2.cursor >= t ) + net_sfx_play( sfx ); + else + _replay2.sfx_queue[ j ++ ] = _replay2.sfx_queue[i]; } + _replay2.sfx_queue_length = j; } } @@ -386,13 +617,13 @@ void _replay2_render_player( world_instance *world, vg_camera *cam ) if( skaterift.activity != k_skaterift_replay ) return; - struct player_model *model = addon_cache_item_data( k_addon_type_player, _replay_player.playermodel_cache_id, 1 ); + struct player_model *model = addon_cache_item_data( k_addon_type_player, _replay2.playermodel_cache_id, 1 ); struct skeleton *sk = &localplayer.skeleton; - render_playermodel( cam, world, 0, model, sk, _replay_player.final_mtx ); + render_playermodel( cam, world, 0, model, sk, _replay2.final_mtx ); - struct player_board *board = addon_cache_item_data( k_addon_type_board, _replay_player.board_cache_id, 1 ); - render_board( cam, world, board, _replay_player.final_mtx[localplayer.id_board], - &_replay_player.board_pose, k_board_shader_player ); + struct player_board *board = addon_cache_item_data( k_addon_type_board, _replay2.board_cache_id, 1 ); + render_board( cam, world, board, _replay2.final_mtx[localplayer.id_board], + &_replay2.board_pose, k_board_shader_player ); #if 0 if( !gliders ) @@ -421,24 +652,79 @@ void _replay2_render_player( world_instance *world, vg_camera *cam ) #endif } +void _replay2_decode(void) +{ + vg_queue *buffer = _replay2_player_buffer(); + replay2_frame *current_frame = vg_queue_data( buffer, _replay2.cursor_frame_offset ), + *next_frame = NULL; + u32 next_offset; + if( vg_queue_next( buffer, _replay2.cursor_frame_offset, &next_offset ) ) + next_frame = vg_queue_data( buffer, next_offset ); + else + _replay2.sfx_queue_length = 0; /* sfx's are expresed relative to the next frame, if no next, no sound. */ + + if( _replay2.type == k_replay_type_network ) + { + u32 s0 = current_frame->net.frame_size - sizeof(netmsg_playerframe); + decode_playerframe( ¤t_frame->net.frame, s0, &_remote_replay.interp0, _remote_replay.cam0, NULL, NULL ); + + if( next_frame ) + { + u32 len = VG_ARRAY_LEN( _replay2.sfx_queue ); + replay2_frame *next_frame = vg_queue_data( buffer, next_offset ); + u32 s1 = next_frame->net.frame_size - sizeof(netmsg_playerframe); + decode_playerframe( &next_frame->net.frame, s1, &_remote_replay.interp1, _remote_replay.cam1, + _replay2.sfx_queue, &len ); + _replay2.sfx_queue_length = len; + } + else + { + memcpy( &_remote_replay.interp1, &_remote_replay.interp0, sizeof(struct interp_frame) ); + _remote_replay.interp1.timestamp += 1.0; + } + + _replay2.sfx_basetime = _remote_replay.interp1.timestamp; + } + else + { + if( next_frame ) + { + u32 sfx_offset = next_frame->local.animator_size + next_frame->local.glider_size; + struct net_sfx *sfx_src = (void *)next_frame->local.data + sfx_offset; + + _replay2.sfx_queue_length = 0; + u32 max_sfx = VG_ARRAY_LEN( _replay2.sfx_queue ); + for( u32 i=0; (ilocal.sfx_count) && (_replay2.sfx_queue_lengthtime; + } + else + _replay2.sfx_basetime = current_frame->time + 1.0; + } + + _replay2.cursor_decoded = 1; +} + void _replay2_seek( f64 t, bool play_sounds ) { - replay2 *replay = _replay_player.replay; - VG_ASSERT( replay ); + vg_queue *buffer = _replay2_player_buffer(); - replay2_frame *frame_start = vg_queue_data( &replay->buffer, replay->buffer.tail_offset ), - *frame_end = vg_queue_data( &replay->buffer, replay->buffer.head_offset ); + replay2_frame *frame_start = vg_queue_data( buffer, buffer->tail_offset ), + *frame_end = vg_queue_data( buffer, buffer->head_offset ); if( t < frame_start->time ) t = frame_start->time; if( t > frame_end->time ) t = frame_end->time; - f64 dir = t - _replay_player.cursor; + f64 dir = t - _replay2.cursor; if( dir == 0.0 ) return; dir = vg_signf( dir ); - u32 current_offset = _replay_player.cursor_frame_offset; - replay2_frame *current_frame = vg_queue_data( &replay->buffer, current_offset ); + replay2_frame *current_frame = vg_queue_data( buffer, _replay2.cursor_frame_offset ); for( u32 i=0; i<4096; i ++ ) { if( dir < 0.0 ) @@ -451,12 +737,12 @@ void _replay2_seek( f64 t, bool play_sounds ) bool next = 0; u32 next_offset; - if( dir > 0.0 ) next = vg_queue_next( &replay->buffer, current_offset, &next_offset ); - else next = vg_queue_previous( &replay->buffer, current_offset, &next_offset ); + if( dir > 0.0 ) next = vg_queue_next( buffer, _replay2.cursor_frame_offset, &next_offset ); + else next = vg_queue_previous( buffer, _replay2.cursor_frame_offset, &next_offset ); if( !next ) break; - replay2_frame *next_frame = vg_queue_data( &replay->buffer, next_offset ); + replay2_frame *next_frame = vg_queue_data( buffer, next_offset ); if( dir > 0.0 ) { if( next_frame->time > t ) @@ -465,18 +751,21 @@ void _replay2_seek( f64 t, bool play_sounds ) } } - current_offset = next_offset; + _replay2.cursor_frame_offset = next_offset; + _replay2.cursor_decoded = 0; current_frame = next_frame; if( play_sounds ) { - //replay_emit_frame_sounds( next ); + for( u32 i=0; i<_replay2.sfx_queue_length; i ++ ) + net_sfx_play( &_replay2.sfx_queue[i] ); + _replay2.sfx_queue_length = 0; + _replay2_decode(); } } - _replay_player.cursor_frame_offset = current_offset; - _replay_player.cursor = t; - _replay_player.animation_dirty = 1; + _replay2.cursor = t; + _replay2.animation_dirty = 1; } void _replay2_imgui( ui_context *ctx ) @@ -484,7 +773,7 @@ void _replay2_imgui( ui_context *ctx ) if( skaterift.activity != k_skaterift_replay ) return; - if( _replay_player.hide_ui ) + if( _replay2.hide_ui ) return; if( vg_input.display_input_method != k_input_method_controller ) @@ -492,43 +781,106 @@ void _replay2_imgui( ui_context *ctx ) ui_capture_mouse( ctx, 1 ); } - replay2 *replay = _replay_player.replay; - VG_ASSERT( replay ); + if( _replay2.type == k_replay_type_network ) + { + if( _remote_replay.state < k_remote_replay_state_ready ) + { + ui_rect box = { vg.window_x/2 - 200, vg.window_y/2-80, 400, 160 }; + ui_fill( ctx, box, ui_opacity( GUI_COL_DARK, 0.36f ) ); + ui_rect titlebox, boxbox, boxboxline; + ui_split_ratio( box, k_ui_axis_h, 0.5f, 8, titlebox, boxbox ); + + ctx->font = &vgf_default_title; + ui_text( ctx, titlebox, "Downloading", 1, k_ui_align_middle_center, 0 ); + ctx->font = &vgf_default_large; + + rect_copy( boxbox, boxboxline ); + boxboxline[2] -= 16; + boxboxline[3] = 32; + ui_rect_center( boxbox, boxboxline ); + + f32 blockw = boxboxline[2] / (f32)_remote_replay.total_chunks; + for( u32 i=0; i<_remote_replay.total_chunks; i ++ ) + { + ui_rect chunkbox = { boxboxline[0]+4 + blockw*(f32)i, boxboxline[1], blockw-8, boxboxline[3] }; + struct remote_replay_chunk *chunk = &_remote_replay.chunks[i]; - f64 start = _replay_player.start_t, - end = _replay_player.end_t; + if( chunk->state == k_chunk_state_broken ) + ui_fill( ctx, chunkbox, ui_colour( ctx, k_ui_red ) ); + else + { + if( i < _remote_replay.chunks_downloaded ) + ui_fill( ctx, chunkbox, ui_colour( ctx, k_ui_fg ) ); + else + ui_outline( ctx, chunkbox, -2, ui_colour( ctx, k_ui_fg+2 ), 0 ); + } + } + + ui_rect exit_button = { box[0] + box[2] - 48, box[1], 48, 48 }; + if( ui_button_text( ctx, exit_button, "X", 1 ) == k_ui_button_click ) + { + skaterift.activity = k_skaterift_default; + replay2_close_player(); + } + + if( _remote_replay.state == k_remote_replay_state_failed ) + { + ui_text( ctx, box, "Failed", 1, k_ui_align_middle_center, 0 ); + } + else /* assume downloading */ + { + ui_text( ctx, box, "Downloading", 1, k_ui_align_middle_center, 0 ); + } + + return; + } + } + + vg_queue *buffer = _replay2_player_buffer(); + if( buffer->allocation_count < 2 ) + { + ctx->font = &vgf_default_large; + ui_rect box = { vg.window_x/2 - 200, 40, 400, ctx->font->sy }; + ui_text( ctx, box, KRED "\x06\x02--- Corrupt replay ---", 1, k_ui_align_center, 0 ); + // TODO + return; + } + + ctx->font = &vgf_default_small; + f64 start = _replay2.start_t, + end = _replay2.end_t; f64 len = end - start, - cur = (_replay_player.cursor - start) / len; + cur = (_replay2.cursor - start) / len; /* mainbar */ ui_rect timeline = { 8, vg.window_y-(32+8), vg.window_x-16, 32 }; ui_rect start_box; ui_split( timeline, k_ui_axis_v, 32, 8, start_box, timeline ); - const char *start_text = (_replay_player.replay_control == k_replay_control_play)? "||": ">"; + const char *start_text = (_replay2.replay_control == k_replay_control_play)? "||": ">"; if( menu_button_rect( ctx, start_box, 0, 1, start_text ) ) { - _replay_player.replay_control ^= k_replay_control_play; + _replay2.replay_control ^= k_replay_control_play; } ui_fill( ctx, timeline, ui_colour( ctx, k_ui_bg ) ); /* for remote replays */ - if( _replay_player.highlight ) + if( _replay2.highlight ) { - f64 x = _replay_player.highlight_start / len, - w = _replay_player.highlight_length / len; + f64 x = _replay2.highlight_start / len, + w = _replay2.highlight_length / len; ui_rect highlight = { timeline[0] + x*(f64)timeline[2], timeline[1] + timeline[3] -1, (f64)timeline[2]*w, 2 }; ui_fill( ctx, highlight, ui_colour( ctx, k_ui_green ) ); } /* cursor frame block */ - replay2_frame *frame_cursor = vg_queue_data( &replay->buffer, _replay_player.cursor_frame_offset ); + replay2_frame *frame_cursor = vg_queue_data( buffer, _replay2.cursor_frame_offset ); u32 next_frame_offset; - if( vg_queue_next( &replay->buffer, _replay_player.cursor_frame_offset, &next_frame_offset ) ) + if( vg_queue_next( buffer, _replay2.cursor_frame_offset, &next_frame_offset ) ) { - replay2_frame *next_frame = vg_queue_data( &replay->buffer, next_frame_offset ); + replay2_frame *next_frame = vg_queue_data( buffer, next_frame_offset ); f64 l = (next_frame->time - frame_cursor->time )/len, s = (frame_cursor->time - start) / len; ui_rect box = { timeline[0] + s*(f64)timeline[2], timeline[1], @@ -564,9 +916,9 @@ void _replay2_imgui( ui_context *ctx ) } #endif - char buffer[ 128 ]; - snprintf( buffer, 128, "-%.2fs", (end-_replay_player.cursor) ); - ui_text( ctx, timeline, buffer, 1, k_ui_align_middle_left, 0 ); + char text[ 128 ]; + snprintf( text, 128, "-%.2fs", (end-_replay2.cursor) ); + ui_text( ctx, timeline, text, 1, k_ui_align_middle_left, 0 ); ui_text( ctx, timeline, "0s", 1, k_ui_align_middle_right, 0 ); /* helpers */ @@ -583,7 +935,7 @@ void _replay2_imgui( ui_context *ctx ) vg_strnull( &str, buf, sizeof(buf) ); vg_input_string( &str, input_button_list[k_srbind_replay_play], 1 ); - vg_strcat( &str, (_replay_player.replay_control == k_replay_control_play)? "\x07 Pause": "\x07 Play" ); + vg_strcat( &str, (_replay2.replay_control == k_replay_control_play)? "\x07 Pause": "\x07 Play" ); ui_text( ctx, helper_list_l, buf, 1, k_ui_align_left, 0 ); helper_list_l[1] -= helper_list_l[3]+2; @@ -606,7 +958,7 @@ void _replay2_imgui( ui_context *ctx ) ui_text( ctx, helper_list_r, buf, 1, k_ui_align_right, 0 ); helper_list_l[1] -= helper_list_r[3]+2; - if( _replay_player.use_freecam ) + if( _replay2.use_freecam ) { ui_rect box = { vg.window_x/2 - 200, 40, 400, ctx->font->sy }; ui_text( ctx, box, KYEL "\x06\x02--- Freecam Enabled ---", 1, k_ui_align_center, 0 ); @@ -628,7 +980,98 @@ void _replay2_imgui( ui_context *ctx ) if( ui_clicking( ctx, UI_MOUSE_LEFT ) && start_in_timeline ) { f64 mouse_t = start + ((f64)(ctx->mouse[0]-timeline[0]) / (f64)timeline[2])*len; + if( mouse_t < _replay2.start_t ) mouse_t = _replay2.start_t; + if( mouse_t > _replay2.end_t ) mouse_t = _replay2.end_t; _replay2_seek( mouse_t, 1 ); } } } + +/* local replay + * ----------------------------------------------------------------------------------------------------------------- */ + +void _replay2_record_local_frame(void) +{ + vg_queue *buffer = &_replay2.buffer; + + f64 delta = 9999999.9; + if( buffer->allocation_count ) + { + replay2_frame *frame = vg_queue_data( buffer, buffer->head_offset ); + delta = vg.time - frame->time; + } + + if( delta < 1.0/30.0 ) + return; + + bool save_glider = 0; + if( localplayer.have_glider || localplayer.glider_orphan || localplayer.subsystem == k_player_subsystem_glide ) + save_glider = 1; + + u32 animator_size = vg_align8( player_subsystems[localplayer.subsystem]->animator_size ), + glider_size = save_glider? vg_align8( sizeof(struct replay_glider_data) ): 0, + sfx_size = vg_align8( localplayer.local_sfx_buffer_count * sizeof(struct net_sfx) ), + total_size = sizeof(replay2_frame) + animator_size + glider_size + sfx_size; + + replay2_frame *dest_frame = vg_queue_alloc( buffer, total_size, NULL ); + if( !dest_frame ) + { + while( buffer->allocation_count ) + { + vg_queue_pop( buffer ); + dest_frame = vg_queue_alloc( buffer, total_size, NULL ); + if( dest_frame ) + break; + } + + if( !dest_frame ) + { + vg_error( "Replay frame tried to allocate which was (way!) too big (%u bytes)\n", total_size ); + return; + } + } + + dest_frame->time = vg.time; + dest_frame->local.animator_size = animator_size; + dest_frame->local.glider_size = glider_size; + dest_frame->local.sfx_count = localplayer.local_sfx_buffer_count; + dest_frame->local.subsystem = localplayer.subsystem; + dest_frame->local.boundary = localplayer.boundary_hash; + + /* camera */ + v3_copy( localplayer.cam.pos, dest_frame->local.camera.pos ); + dest_frame->local.camera.fov = localplayer.cam.fov; + if( localplayer.gate_waiting ) + { + m4x3_mulv( localplayer.gate_waiting->transport, dest_frame->local.camera.pos, dest_frame->local.camera.pos ); + + v3f v0; + v3_angles_vector( localplayer.cam.angles, v0 ); + m3x3_mulv( localplayer.gate_waiting->transport, v0, v0 ); + v3_angles( v0, dest_frame->local.camera.angles ); + } + else + v3_copy( localplayer.cam.angles, dest_frame->local.camera.angles ); + + void *data_animator = (void *)dest_frame->local.data, + *data_glider = (void *)dest_frame->local.data + animator_size, + *data_sfx = (void *)dest_frame->local.data + animator_size + glider_size; + + /* animator */ + memcpy( data_animator, player_subsystems[localplayer.subsystem]->animator_data, animator_size ); + + /* glider */ + if( save_glider ) + { + struct replay_glider_data *inf = data_glider; + inf->have_glider = localplayer.have_glider; + inf->glider_orphan = localplayer.glider_orphan; + inf->t = player_glide.t; + v3_copy( player_glide.rb.co, inf->co ); + v4_copy( player_glide.rb.q, inf->q ); + } + + /* sound effects */ + memcpy( data_sfx, localplayer.local_sfx_buffer, sizeof(struct net_sfx)*localplayer.local_sfx_buffer_count ); + localplayer.local_sfx_buffer_count = 0; +} diff --git a/src/replay2.h b/src/replay2.h index 3759895..8f9a288 100644 --- a/src/replay2.h +++ b/src/replay2.h @@ -2,25 +2,37 @@ #include "vg/vg_mem_queue.h" #include "player_effects.h" -typedef struct replay2 replay2; -struct replay2 +typedef struct replay2_frame replay2_frame; +struct replay2_frame { - enum replay_type + f64 time; // duplicated from net_frame + + union { - k_replay_type_local, - k_replay_type_network - } - type; + struct + { + u32 frame_size; + netmsg_playerframe frame; + } + net; - vg_queue buffer; + struct + { + vg_camera camera; + u16 animator_size, glider_size, sfx_count, subsystem, + boundary, unused0, unused1, unused2; + u8 data[]; + } + local; + }; }; -typedef struct replay2_frame replay2_frame; -struct replay2_frame +struct replay_glider_data { - f64 time; // duplicated from net_frame - u32 net_frame_size; - netmsg_playerframe net_frame; + bool have_glider, glider_orphan; + f32 t; + v3f co; + v4f q; }; struct _remote_replay @@ -54,30 +66,49 @@ struct _remote_replay k_remote_replay_state_waitnext, k_remote_replay_state_downloading, - + k_remote_replay_state_failed, k_remote_replay_state_ready, - k_remote_replay_state_failed } state; i64 last_second; f64 end_offset, start_offset; /* from the download */ - replay2 replay; + v2f cam0, cam1; + struct interp_frame interp0, interp1; + vg_queue buffer; } extern _remote_replay; -struct _replay_player +struct _replay2 { - replay2 *replay; + enum replay_type + { + k_replay_type_local, + k_replay_type_network + } + type; + + vg_queue buffer; /* TODO: Modifiers / keyframes lane */ u32 cursor_frame_offset; f64 cursor; - enum replay_control replay_control; + enum replay_control { + k_replay_control_scrub = 0x00, + k_replay_control_play = 0x01, + k_replay_control_resume= 0x02 + } + replay_control; f32 track_velocity; - vg_camera replay_freecam; + bool cursor_decoded; + + struct net_sfx sfx_queue[ 8 ]; + u32 sfx_queue_length; + f64 sfx_basetime; + + vg_camera replay_freecam, playback_cam; bool use_freecam; bool hide_ui; v3f freecam_v, freecam_w; @@ -95,11 +126,14 @@ struct _replay_player m4x3f *final_mtx, glider_mtx; struct player_board_pose board_pose; } -extern _replay_player; +extern _replay2; void _replay2_init(void); void _replay2_pre_update(void); void _replay2_imgui( ui_context *ctx ); -void _replay2_open_player( replay2 *replay, bool end ); +void _replay2_open_player( enum replay_type type, bool end ); void _replay2_render_player( world_instance *world, vg_camera *cam ); void _replay2_seek( f64 t, bool play_sounds ); +void _replay2_get_camera( vg_camera *cam ); +void _replay2_decode(void); +void _replay2_record_local_frame(void); diff --git a/src/skaterift.c b/src/skaterift.c index eb7ff71..2e16be1 100644 --- a/src/skaterift.c +++ b/src/skaterift.c @@ -123,7 +123,6 @@ static void game_load_co( vg_coroutine *co ) vg_loader_step( skateshop_init, NULL ); vg_loader_step( world_map_init, NULL ); vg_loader_step( ent_tornado_init, NULL ); - vg_loader_step( skaterift_replay_init, NULL ); vg_loader_step( skaterift_load_player_content, NULL ); vg_loader_step( _replay2_init, NULL ); @@ -233,7 +232,6 @@ void vg_pre_update(void) player__pre_update(); } - skaterift_replay_pre_update(); _replay2_pre_update(); remote_sfx_pre_update(); @@ -354,17 +352,7 @@ static void skaterift_composite_maincamera(void) * ------------------------------------------------------------------ */ if( skaterift.activity == k_skaterift_replay ) { - if( player_replay.use_freecam ) - { - freecam_preupdate(); - v3_copy( player_replay.replay_freecam.pos, g_render.cam.pos ); - v3_copy( player_replay.replay_freecam.angles, g_render.cam.angles ); - g_render.cam.fov = player_replay.replay_freecam.fov; - } - else - { - skaterift_get_replay_cam( &g_render.cam ); - } + _replay2_get_camera( &g_render.cam ); } g_render.cam.nearz = 0.1f; @@ -414,13 +402,13 @@ static void render_main_game(void) } else if( skaterift.activity == k_skaterift_replay ) { - player__animate_from_replay( &player_replay.local ); + //FIXME + //player__animate_from_replay( &player_replay.local ); } else { player__animate(); - skaterift_record_frame( &player_replay.local, localplayer.deferred_frame_record ); - localplayer.deferred_frame_record = 0; + _replay2_record_local_frame(); } animate_remote_players(); @@ -620,7 +608,6 @@ void vg_framebuffer_resize( int w, int h ) #include "player_ragdoll.c" #include "player_remote.c" #include "player_render.c" -#include "player_replay.c" #include "player_skate.c" #include "player_walk.c" #include "render.c" @@ -669,24 +656,26 @@ static void _handle_vg_signal( vg_signal_id id, bool state ) int main( int argc, const char *argv[] ) { vg_init( argc, argv, "Voyager Game Engine" ); + network_set_host( "skaterift.com", NULL ); - const char *arg; - if( vg_long_opt( "noauth", "Disable server authentication" ) ) - network_client.auth_mode = eServerModeNoAuthentication; + { + const char *arg; + if( vg_long_opt( "noauth", "Disable server authentication" ) ) + network_client.auth_mode = eServerModeNoAuthentication; - if( (arg = vg_long_opt_arg( "server", "Specify server address" )) ) - network_set_host( arg, NULL ); + if( (arg = vg_long_opt_arg( "server", "Specify server address" )) ) + network_set_host( arg, NULL ); - if( vg_long_opt( "demo", "Turn demo mode on" ) ) - g_client.demo_mode = 1; + if( vg_long_opt( "demo", "Turn demo mode on" ) ) + g_client.demo_mode = 1; - if( vg_long_opt( "nosteam", "Disable steam integration (offline)" ) ) - g_client.nosteam = 1; + if( vg_long_opt( "nosteam", "Disable steam integration (offline)" ) ) + g_client.nosteam = 1; - if( (arg = vg_long_opt_arg( "world", "Specify path to world to load" )) ) - skaterift.override_load_world = arg; + if( (arg = vg_long_opt_arg( "world", "Specify path to world to load" )) ) + skaterift.override_load_world = arg; + } - network_set_host( "skaterift.com", NULL ); vg_mem.use_libc_malloc = 0; vg_set_mem_quota( 200*1024*1024 ); skaterift.sig_world = _vg_tower_create_signal( "World Loaded" ); diff --git a/src/world_load.c b/src/world_load.c index 24bb911..ab35480 100644 --- a/src/world_load.c +++ b/src/world_load.c @@ -225,9 +225,6 @@ static void async_world_loader_done( void *userdata ) THREAD_0; _world.loader_state = k_world_loader_init; _world.loader_instance->complete = 1; - - if( !_world.loader_preview_mode ) - menu_on_world_change( _world.main.addon_id ); } struct world_load_info @@ -380,6 +377,7 @@ void async_worldsave_go( vg_async_task *task ) _world.loader_state = k_world_loader_done; _world.load_addon = 0; _vg_tower_set_flag( skaterift.sig_world, 1 ); + menu_on_world_change( _world.main.addon_id ); } void load_world_savedata_t1( void *userdata ) -- 2.25.1