replay almst done
authorhgn <hgodden00@gmail.com>
Mon, 21 Apr 2025 04:44:38 +0000 (05:44 +0100)
committerhgn <hgodden00@gmail.com>
Mon, 21 Apr 2025 04:44:38 +0000 (05:44 +0100)
19 files changed:
src/ent_route.c
src/freecam.c
src/gameserver.c
src/menu.c
src/network_requests.c
src/player.c
src/player.h
src/player_common.c
src/player_remote.c
src/player_remote.h
src/player_render.c
src/player_render.h
src/player_replay.c [deleted file]
src/player_replay.h [deleted file]
src/player_skate.c
src/replay2.c
src/replay2.h
src/skaterift.c
src/world_load.c

index 7dd48d057da2e56b9e740d6973cf49ee095cf229..48f4bd7881df5df1e4c6337dea701df6e0918a1a 100644 (file)
@@ -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 ) )
index d961ed6c5ce5c3a415e13105cd8160ce09986fec..c0a0f57a91aceaba5297965c5cac308ee4dcebee 100644 (file)
@@ -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 );
 }
index 7a9909bd7423625513810526da8290ffc23094d9..051d8feefcd11ef7bd2fdc63249b33f94ebf82d0 100644 (file)
@@ -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 ) )
index d36cca830bb697a35ed9450711216130cfe40530..1296bddbba02833bfeb4ec28692d5613530cda4e 100644 (file)
@@ -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;
index 5f76a8808f8a5c97d4a815ec6596278eb88eaf6e..3413c5b7e40d07c14d88862906902f0e9f6ac49b 100644 (file)
@@ -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 );
index bc6326829a02990f25df7289664699b4e887e372..a02d57155d1f840ff635865de8cd01042a68b6a5 100644 (file)
@@ -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; i<len; i++ ){
+   else 
+   {
+      for( u32 i=0; i<len; i++ )
+      {
          struct net_sfx *a = &buffer[i];
-         if( a->priority < 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 );
 
index 5311e7e34c5964de1c7f3356ae1d65bfe7201605..7ec7183a90dba9afb3966210fb3aca6cdca09814 100644 (file)
@@ -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;
index 1ecbae9a8eefa08ee7ae49d3cf602ae78ffb5041..f8ebdbfe6d1f6f1a86a9c3dcd22836a1f4721890 100644 (file)
@@ -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();
index 74a0cdab851db2a9aef5f0048e1c4f25a62b9d89..7c54d858542c534da967ea572d88946d3e29bfec 100644 (file)
@@ -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; i<frame->sound_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( i<max_sfx_out )
       {
-         struct net_sfx *dst = NULL;
-         for( u32 j=0; j<NETWORK_SFX_QUEUE_LENGTH; j ++ )
-         {
-            struct net_sfx *sj = &netplayers.sfx_queue[j];
-            if( sj->system == 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; i<NETWORK_SFX_QUEUE_LENGTH; i ++ ){
+   for( u32 i=0; i<NETWORK_SFX_QUEUE_LENGTH; i ++ )
+   {
       struct net_sfx *si = &netplayers.sfx_queue[i];
 
-      if( si->system != 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;
          }
index a6bd72cc1252a29db3d61705781799aa07ea65cb..ecbc03346bfaad89c2ca3f557cb615cd92eddd9b 100644 (file)
@@ -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 );
index 0f5b6c74d9b5ec617dfb65b00815ae5856681b33..ebcd8bd4605edc2f0d663c010d7c9b034de8015d 100644 (file)
@@ -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)
 {
index 0c891546f8fd0b71fbaf9dde2588cf7e5366e7eb..b2491a708d8794ca8483ac0794c6a05e26ecd6b6 100644 (file)
@@ -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 (file)
index c8666be..0000000
+++ /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<k_replay_framedata_rows; i++ ){
-      data_table[i][0] = total;
-      total += vg_align8(data_table[i][1]);
-
-      if( total > 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; i<k_replay_framedata_rows; i++ )
-   {
-      frame->data_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; i<count; i ++ ){
-      net_sfx_play( buffer + i );
-   }
-}
-
-int replay_seek( replay_buffer *replay, f64 t )
-{
-   if( !replay->head ) 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; i<player_replay.keyframe_count-1; i ++ )
-      {
-         replay_keyframe *kf = &player_replay.keyframes[i];
-
-         if( (kf[0].time<=replay->cursor) && (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; i<localplayer.ragdoll.part_count; i ++ ){
-            rigidbody *rb = &localplayer.ragdoll.parts[i].rb;
-            v3_copy( rb->co, 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; i<localplayer.ragdoll.part_count; i ++ ){
-         struct ragdoll_part *part = &localplayer.ragdoll.parts[i];
-         rigidbody *rb = &part->rb;
-
-         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; i<k_replay_framedata_rows; i++ )
-      {
-         player__debugtext( ctx, 1, "[%u]: [%hu, %hu]\n", i,
-              replay->statehead->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; i<player_replay.keyframe_count; i ++ )
-   {
-      replay_keyframe *kf = &player_replay.keyframes[i];
-      f64 t = (kf->time-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; j<player_replay.keyframe_count; j ++ )
-               {
-                  if( player_replay.keyframes[j].time == mouse_t )
-                  {
-                     player_replay.active_keyframe = j;
-                     break;
-                  }
-               }
-            }
-
-            if( pos_correct )
-            {
-               tag[0] = ctx->mouse[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; j<player_replay.keyframe_count-1; j ++ )
-                  player_replay.keyframes[j] = player_replay.keyframes[j+1];
-
-               player_replay.keyframe_count --;
-               player_replay.active_keyframe = -1;
-            }
-
-            ui_rect btn1 = { tray[0]+48, tray[1], 16, 16 };
-
-            enum ui_button_state mask_using = 
-                  k_ui_button_holding_inside |
-                  k_ui_button_holding_outside |
-                  k_ui_button_click;
-
-            if( ui_button_text( ctx, btn1, "E", 1 ) & mask_using )
-            {
-               replay_fly_edit_keyframe( ctx, kf );
-               vg_ui_set_mouse_pos( btn1[0]+8, btn1[1]+8 );
-            }
-         }
-      }
-
-      ui_fill( ctx, tag, ui_colour( ctx, k_ui_blue ) );
-      lx = x;
-   }
-
-   /* adding keyframes */
-   if( ui_inside_rect( script, ctx->mouse ) )
-   {
-      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 (file)
index d1f190d..0000000
+++ /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);
index 9c20d7324e7fc4afbec2bf1a5561869ef1f8e865..569ef943fabaa5b35361e42194c71b533d3b8ab8 100644 (file)
@@ -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 )
index ce019049695976d677d1d88177f96ba24c8af426..04bcc05551cffd6879b79cb7755c3ad960bb3ed9 100644 (file)
@@ -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( &current_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( &current_frame->local.camera, &next_frame->local.camera, t, &_replay2.playback_cam );
+         }
+         else
+         {
+            sys0->pose( animator0, &pose );
+            vg_camera_copy( &current_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( &current_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; (i<next_frame->local.sfx_count) && (_replay2.sfx_queue_length<max_sfx); i ++ )
+         {
+            struct net_sfx *dst = &_replay2.sfx_queue[ _replay2.sfx_queue_length ++ ];
+            memcpy( dst, &sfx_src[i], sizeof(struct net_sfx) );
+         }
+
+         _replay2.sfx_basetime = next_frame->time;
+      }
+      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;
+}
index 375989503a2dbc86e29ee7bff8694694834a0b45..8f9a288680ab44b5ecce66ae1e66fa83f6fedbe7 100644 (file)
@@ -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);
index eb7ff717e2e0a2b92b83be9538471baec7d9bf82..2e16be10ebdda4c78ecc604b4ef6eb0df72be395 100644 (file)
@@ -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" );
index 24bb911468ae2cf0923ff157a582de7dc3617286..ab3548079f03cb8024c2edf199d3298bc02a68bb 100644 (file)
@@ -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 )