3 #include "player_replay.h"
8 #include "player_walk.h"
9 #include "player_skate.h"
10 #include "player_dead.h"
11 #include "player_glide.h"
13 struct replay_globals player_replay
;
15 void replay_clear( replay_buffer
*replay
)
19 replay
->cursor_frame
= NULL
;
20 replay
->statehead
= NULL
;
21 replay
->cursor
= -99999.9;
24 void *replay_frame_data( replay_frame
*frame
, enum replay_framedata type
)
26 if( frame
->data_table
[type
][1] == 0 )
29 void *baseptr
= frame
;
30 return baseptr
+ frame
->data_table
[type
][0];
33 static u16
replay_frame_calculate_data_offsets(
34 u16 data_table
[k_replay_framedata_rows
][2] ){
36 u32 total
= vg_align8( sizeof(replay_frame
) );
37 for( u32 i
=0; i
<k_replay_framedata_rows
; i
++ ){
38 data_table
[i
][0] = total
;
39 total
+= vg_align8(data_table
[i
][1]);
42 vg_fatal_error( "Exceeded frame storage capacity\n" );
47 static void replay_tailpop( replay_buffer
*replay
){
48 if( replay
->cursor_frame
== replay
->tail
)
49 replay
->cursor_frame
= NULL
;
50 if( replay
->statehead
== replay
->tail
)
51 replay
->statehead
= NULL
;
53 replay
->tail
= replay
->tail
->r
;
56 replay
->tail
->l
= NULL
;
61 static replay_frame
*replay_newframe( replay_buffer
*replay
,
66 u16 data_table
[ k_replay_framedata_rows
][2];
67 data_table
[ k_replay_framedata_animator
][1] = animator_size
;
68 data_table
[ k_replay_framedata_gamestate
][1] = gamestate_size
;
69 data_table
[ k_replay_framedata_sfx
][1] = sfx_count
*sizeof(struct net_sfx
);
70 data_table
[ k_replay_framedata_internal_gamestate
][1] = 0;
72 data_table
[ k_replay_framedata_internal_gamestate
][1] =
73 sizeof( replay_gamestate
);
76 data_table
[ k_replay_framedata_glider
][1] = 0;
78 data_table
[ k_replay_framedata_glider
][1] =
79 sizeof(struct replay_glider_data
);
82 u32 nextsize
= replay_frame_calculate_data_offsets( data_table
);
84 replay_frame
*frame
= NULL
;
86 u32 headsize
= replay
->head
->total_size
,
87 nextpos
= ((void *)replay
->head
- replay
->data
) + headsize
;
89 if( nextpos
+ nextsize
> replay
->size
){
92 /* maintain contiguity */
93 while( replay
->tail
){
94 if( (void *)replay
->tail
- replay
->data
)
95 replay_tailpop( replay
);
101 u32 tailpos
= (void *)replay
->tail
- replay
->data
;
103 if( tailpos
>= nextpos
){
104 if( nextpos
+ nextsize
> tailpos
){
105 replay_tailpop( replay
);
112 frame
= replay
->data
+ nextpos
;
115 replay
->head
->r
= frame
;
118 frame
= replay
->data
;
120 for( u32 i
=0; i
<k_replay_framedata_rows
; i
++ ){
121 frame
->data_table
[i
][0] = data_table
[i
][0];
122 frame
->data_table
[i
][1] = data_table
[i
][1];
125 frame
->total_size
= nextsize
;
126 frame
->l
= replay
->head
;
128 replay
->head
= frame
;
129 if( !replay
->tail
) replay
->tail
= frame
;
130 if( gamestate_size
) replay
->statehead
= frame
;
135 static void replay_emit_frame_sounds( replay_frame
*frame
){
136 void *baseptr
= frame
;
137 u16
*inf
= frame
->data_table
[k_replay_framedata_sfx
];
138 struct net_sfx
*buffer
= baseptr
+ inf
[0];
139 u32 count
= inf
[1] / sizeof(struct net_sfx
);
141 for( u32 i
=0; i
<count
; i
++ ){
142 net_sfx_play( buffer
+ i
);
146 int replay_seek( replay_buffer
*replay
, f64 t
)
148 if( !replay
->head
) return 0;
150 if( t
< replay
->tail
->time
) t
= replay
->tail
->time
;
151 if( t
> replay
->head
->time
) t
= replay
->head
->time
;
153 if( !replay
->cursor_frame
) {
154 replay
->cursor
= replay
->head
->time
;
155 replay
->cursor_frame
= replay
->head
;
157 if( fabs(replay
->head
->time
-t
) > fabs(replay
->tail
->time
-t
) ){
158 replay
->cursor
= replay
->tail
->time
;
159 replay
->cursor_frame
= replay
->tail
;
163 f64 dir
= t
- replay
->cursor
;
164 if( dir
== 0.0 ) return 0;
165 dir
= vg_signf( dir
);
171 if( t
> replay
->cursor_frame
->time
) {
178 if( dir
> 0.0 ) next
= replay
->cursor_frame
->r
;
179 else next
= replay
->cursor_frame
->l
;
184 if( t
< next
->time
){
190 replay_emit_frame_sounds( next
);
192 replay
->cursor_frame
= next
;
193 replay
->cursor
= next
->time
;
202 replay_frame
*replay_find_recent_stateframe( replay_buffer
*replay
)
204 replay_frame
*frame
= replay
->cursor_frame
;
207 if( !frame
) return frame
;
208 if( frame
->data_table
[ k_replay_framedata_gamestate
][1] ) return frame
;
215 f32
replay_subframe_time( replay_buffer
*replay
)
217 replay_frame
*frame
= replay
->cursor_frame
;
218 if( !frame
) return 0.0f
;
219 replay_frame
*next
= frame
->r
;
221 f64 l
= next
->time
- frame
->time
,
222 t
= (l
<= (1.0/128.0))? 0.0: (replay
->cursor
- frame
->time
) / l
;
223 return vg_clampf( t
, 0.0f
, 1.0f
);
229 void replay_get_frame_camera( replay_frame
*frame
, vg_camera
*cam
)
231 cam
->fov
= frame
->cam_fov
;
232 v3_copy( frame
->cam_pos
, cam
->pos
);
233 v3_copy( frame
->cam_angles
, cam
->angles
);
236 void replay_get_camera( replay_buffer
*replay
, vg_camera
*cam
)
240 if( replay
->cursor_frame
){
241 replay_frame
*next
= replay
->cursor_frame
->r
;
246 replay_get_frame_camera( replay
->cursor_frame
, cam
);
247 replay_get_frame_camera( next
, &temp
);
248 vg_camera_lerp( cam
, &temp
, replay_subframe_time( replay
), cam
);
251 replay_get_frame_camera( replay
->cursor_frame
, cam
);
256 v3_zero( cam
->angles
);
266 void skaterift_record_frame( replay_buffer
*replay
, int force_gamestate
)
268 f64 delta
= 9999999.9,
269 statedelta
= 9999999.9;
272 delta
= vg
.time
- replay
->head
->time
;
274 if( replay
->statehead
)
275 statedelta
= vg
.time
- replay
->statehead
->time
;
277 const f64 k_replay_rate
= 1.0/30.0,
278 k_gamestate_rate
= 0.5;
284 if( force_gamestate
) save_state
= 1;
285 if( statedelta
> k_gamestate_rate
) save_state
= 1;
286 if( delta
> k_replay_rate
) save_frame
= 1;
287 if( save_state
) save_frame
= 1;
289 if( localplayer
.have_glider
|| localplayer
.glider_orphan
||
290 localplayer
.subsystem
== k_player_subsystem_glide
){
294 if( !save_frame
) return;
296 u16 gamestate_size
= 0;
298 /* TODO: have as part of system struct */
299 gamestate_size
= (u32
[]){
300 [k_player_subsystem_walk
] = sizeof(struct player_walk_state
),
301 [k_player_subsystem_drive
] = 0,
302 [k_player_subsystem_skate
] = sizeof(struct player_skate_state
),
303 [k_player_subsystem_dead
] = localplayer
.ragdoll
.part_count
*
304 sizeof(struct replay_rb
),
305 [k_player_subsystem_glide
] = sizeof(struct replay_rb
),
306 }[ localplayer
.subsystem
];
309 u16 animator_size
= player_subsystems
[localplayer
.subsystem
]->animator_size
;
311 replay_frame
*frame
= replay_newframe( replay
,
312 animator_size
, gamestate_size
,
313 localplayer
.local_sfx_buffer_count
,
315 frame
->system
= localplayer
.subsystem
;
318 replay_gamestate
*gs
=
319 replay_frame_data( frame
, k_replay_framedata_internal_gamestate
);
321 gs
->current_run_version
= world_static
.current_run_version
;
323 /* permanent block */
324 memcpy( &gs
->rb
, &localplayer
.rb
, sizeof(rigidbody
) );
325 memcpy( &gs
->glider_rb
, &player_glide
.rb
, sizeof(rigidbody
) );
326 memcpy( &gs
->cam_control
, &localplayer
.cam_control
,
327 sizeof(struct player_cam_controller
) );
328 v3_copy( localplayer
.angles
, gs
->angles
);
330 void *dst
= replay_frame_data( frame
, k_replay_framedata_gamestate
);
332 /* subsytem/dynamic block */
333 if( localplayer
.subsystem
== k_player_subsystem_walk
)
334 memcpy( dst
, &player_walk
.state
, gamestate_size
);
335 else if( localplayer
.subsystem
== k_player_subsystem_skate
)
336 memcpy( dst
, &player_skate
.state
, gamestate_size
);
337 else if( localplayer
.subsystem
== k_player_subsystem_dead
){
338 struct replay_rb
*arr
= dst
;
339 for( u32 i
=0; i
<localplayer
.ragdoll
.part_count
; i
++ ){
340 rigidbody
*rb
= &localplayer
.ragdoll
.parts
[i
].rb
;
341 v3_copy( rb
->co
, arr
[i
].co
);
342 v3_copy( rb
->w
, arr
[i
].w
);
343 v3_copy( rb
->v
, arr
[i
].v
);
344 v4_copy( rb
->q
, arr
[i
].q
);
347 else if( localplayer
.subsystem
== k_player_subsystem_glide
){
348 struct replay_rb
*arr
= dst
;
349 rigidbody
*rb
= &player_glide
.rb
;
350 v3_copy( rb
->co
, arr
[0].co
);
351 v3_copy( rb
->w
, arr
[0].w
);
352 v3_copy( rb
->v
, arr
[0].v
);
353 v4_copy( rb
->q
, arr
[0].q
);
358 struct replay_glider_data
*inf
=
359 replay_frame_data( frame
, k_replay_framedata_glider
);
361 inf
->have_glider
= localplayer
.have_glider
;
362 inf
->glider_orphan
= localplayer
.glider_orphan
;
363 inf
->t
= player_glide
.t
;
364 v3_copy( player_glide
.rb
.co
, inf
->co
);
365 v4_copy( player_glide
.rb
.q
, inf
->q
);
368 replay
->cursor
= vg
.time
;
369 replay
->cursor_frame
= frame
;
370 frame
->time
= vg
.time
;
373 v3_copy( localplayer
.cam
.pos
, frame
->cam_pos
);
374 if( localplayer
.gate_waiting
){
375 m4x3_mulv( localplayer
.gate_waiting
->transport
,
376 frame
->cam_pos
, frame
->cam_pos
);
379 v3_angles_vector( localplayer
.cam
.angles
, v0
);
380 m3x3_mulv( localplayer
.gate_waiting
->transport
, v0
, v0
);
381 v3_angles( v0
, frame
->cam_angles
);
384 v3_copy( localplayer
.cam
.angles
, frame
->cam_angles
);
386 frame
->cam_fov
= localplayer
.cam
.fov
;
389 void *dst
= replay_frame_data( frame
, k_replay_framedata_animator
),
390 *src
= player_subsystems
[localplayer
.subsystem
]->animator_data
;
391 memcpy( dst
, src
, animator_size
);
394 memcpy( replay_frame_data( frame
, k_replay_framedata_sfx
),
395 localplayer
.local_sfx_buffer
,
396 sizeof(struct net_sfx
)*localplayer
.local_sfx_buffer_count
);
398 localplayer
.local_sfx_buffer_count
= 0;
402 void skaterift_restore_frame( replay_frame
*frame
){
403 replay_gamestate
*gs
=
404 replay_frame_data( frame
, k_replay_framedata_internal_gamestate
);
405 void *src
= replay_frame_data( frame
, k_replay_framedata_gamestate
);
406 u16 src_size
= frame
->data_table
[ k_replay_framedata_gamestate
][1];
407 world_static
.current_run_version
= gs
->current_run_version
;
409 if(frame
->system
== k_player_subsystem_walk
){
410 memcpy( &player_walk
.state
, src
, src_size
);
412 else if( frame
->system
== k_player_subsystem_skate
){
413 memcpy( &player_skate
.state
, src
, src_size
);
415 else if( frame
->system
== k_player_subsystem_dead
){
416 player__dead_transition(0);
417 struct replay_rb
*arr
= src
;
419 for( u32 i
=0; i
<localplayer
.ragdoll
.part_count
; i
++ ){
420 struct ragdoll_part
*part
= &localplayer
.ragdoll
.parts
[i
];
421 rigidbody
*rb
= &part
->rb
;
423 v3_copy( arr
[i
].co
, rb
->co
);
424 v3_copy( arr
[i
].w
, rb
->w
);
425 v3_copy( arr
[i
].v
, rb
->v
);
426 v4_copy( arr
[i
].q
, rb
->q
);
428 v3_copy( arr
[i
].co
, part
->prev_co
);
429 v4_copy( arr
[i
].q
, part
->prev_q
);
430 rb_update_matrices( rb
);
433 else if( frame
->system
== k_player_subsystem_glide
){
434 struct replay_rb
*arr
= src
;
435 rigidbody
*rb
= &player_glide
.rb
;
436 v3_copy( arr
[0].co
, rb
->co
);
437 v3_copy( arr
[0].w
, rb
->w
);
438 v3_copy( arr
[0].v
, rb
->v
);
439 v4_copy( arr
[0].q
, rb
->q
);
440 rb_update_matrices( rb
);
443 localplayer
.subsystem
= frame
->system
;
445 /* restore the seperated glider data if we have it */
446 if( frame
->data_table
[ k_replay_framedata_glider
][1] ){
447 struct replay_glider_data
*inf
=
448 replay_frame_data( frame
, k_replay_framedata_glider
);
450 localplayer
.have_glider
= inf
->have_glider
;
451 localplayer
.glider_orphan
= inf
->glider_orphan
;
452 player_glide
.t
= inf
->t
;
455 localplayer
.have_glider
= 0;
456 localplayer
.glider_orphan
= 0;
457 player_glide
.t
= 0.0f
;
460 memcpy( &localplayer
.rb
, &gs
->rb
, sizeof(rigidbody
) );
461 memcpy( &player_glide
.rb
, &gs
->glider_rb
, sizeof(rigidbody
) );
462 v3_copy( gs
->angles
, localplayer
.angles
);
464 v3_copy( frame
->cam_pos
, localplayer
.cam
.pos
);
465 v3_copy( frame
->cam_angles
, localplayer
.cam
.angles
);
466 localplayer
.cam
.fov
= frame
->cam_fov
;
468 memcpy( &localplayer
.cam_control
, &gs
->cam_control
,
469 sizeof(struct player_cam_controller
) );
471 /* chop end off replay */
473 player_replay
.local
.statehead
= frame
;
474 player_replay
.local
.head
= frame
;
475 player_replay
.local
.cursor_frame
= frame
;
476 player_replay
.local
.cursor
= frame
->time
;
477 player_replay
.replay_control
= k_replay_control_scrub
;
478 skaterift
.activity
= k_skaterift_default
;
479 vg
.time
= frame
->time
;
482 static void skaterift_replay_resume(void){
483 replay_frame
*prev
= replay_find_recent_stateframe(&player_replay
.local
);
486 player_replay
.replay_control
= k_replay_control_resume
;
487 player_replay
.resume_target
= prev
;
488 player_replay
.resume_begin
= player_replay
.local
.cursor
;
489 player_replay
.resume_transition
= 0.0f
;
495 static void skaterift_replay_update_helpers(void);
497 void skaterift_replay_pre_update(void)
499 if( skaterift
.activity
!= k_skaterift_replay
) return;
501 if( player_replay
.replay_control
== k_replay_control_resume
)
503 if( player_replay
.local
.cursor_frame
== player_replay
.resume_target
||
504 player_replay
.local
.cursor_frame
== NULL
)
506 skaterift_restore_frame( player_replay
.resume_target
);
510 vg_slewf( &player_replay
.resume_transition
, 1.0f
,
511 vg
.time_frame_delta
* (1.0f
/1.0f
) );
513 if( player_replay
.resume_transition
>= 1.0f
)
514 skaterift_restore_frame( player_replay
.resume_target
);
516 f64 target
= vg_lerp( player_replay
.resume_begin
,
517 player_replay
.resume_target
->time
,
518 vg_smoothstepf( player_replay
.resume_transition
) );
519 if( replay_seek( &player_replay
.local
, target
) )
520 player_replay
.track_velocity
= 1.0f
;
522 player_replay
.track_velocity
= 0.0f
;
527 if( button_down( k_srbind_replay_play
) )
528 player_replay
.replay_control
= k_replay_control_play
;
529 if( button_down( k_srbind_replay_freecam
) ){
530 player_replay
.freecam
= player_replay
.freecam
^ 0x1;
532 if( player_replay
.freecam
)
533 replay_get_camera( &player_replay
.local
,
534 &player_replay
.replay_freecam
);
535 skaterift_replay_update_helpers();
538 f32 target_speed
= axis_state( k_sraxis_replay_h
) * 5.0;
539 if( button_press( k_srbind_reset
) )
540 target_speed
+= -2.0;
542 if( fabsf(target_speed
) > 0.01f
)
543 player_replay
.replay_control
= k_replay_control_scrub
;
545 if( player_replay
.replay_control
== k_replay_control_play
)
548 vg_slewf( &player_replay
.track_velocity
, target_speed
,
549 18.0f
*vg
.time_frame_delta
);
551 if( fabsf( player_replay
.track_velocity
) > 0.0001f
)
553 f64 target
= player_replay
.local
.cursor
;
554 target
+= player_replay
.track_velocity
* vg
.time_frame_delta
;
556 if( !replay_seek( &player_replay
.local
, target
) )
557 player_replay
.track_velocity
= 0.0f
;
560 if( button_down( k_srbind_mback
) )
562 if( player_replay
.local
.statehead
)
563 skaterift_restore_frame( player_replay
.local
.statehead
);
565 skaterift
.activity
= k_skaterift_default
;
566 srinput
.state
= k_input_state_resume
;
570 if( player_replay
.freecam
){
571 //freecam_preupdate();
574 if( button_down( k_srbind_replay_resume
) ){
575 skaterift_replay_resume();
581 static void skaterift_replay_update_helpers(void){
582 player_replay
.helper_resume
->greyed
= player_replay
.freecam
;
585 vg_strnull( &freecam_text
, player_replay
.helper_freecam
->text
,
586 GUI_HELPER_TEXT_LENGTH
);
587 vg_strcat( &freecam_text
, player_replay
.freecam
? "exit freecam": "freecam" );
590 void skaterift_replay_post_render(void)
592 #ifndef SR_ALLOW_REWIND_HUB
593 if( world_static
.active_instance
!= k_world_purpose_client
)
597 /* capture the current resume frame at the very last point */
598 if( button_down( k_srbind_reset
) )
600 if( skaterift
.activity
== k_skaterift_default
)
602 localplayer
.rewinded_since_last_gate
= 1;
603 skaterift
.activity
= k_skaterift_replay
;
604 skaterift_record_frame( &player_replay
.local
, 1 );
605 if( player_replay
.local
.head
)
607 player_replay
.local
.cursor
= player_replay
.local
.head
->time
;
608 player_replay
.local
.cursor_frame
= player_replay
.local
.head
;
610 player_replay
.replay_control
= k_replay_control_scrub
;
615 if( gui_new_helper( input_axis_list
[k_sraxis_replay_h
], &text
) )
616 vg_strcat( &text
, "scrub" );
618 if( (player_replay
.helper_resume
= gui_new_helper(
619 input_button_list
[k_srbind_replay_resume
], &text
)) )
620 vg_strcat( &text
, "resume" );
622 if( gui_new_helper( input_button_list
[k_srbind_replay_play
], &text
))
623 vg_strcat( &text
, "playback" );
625 player_replay
.helper_freecam
= gui_new_helper(
626 input_button_list
[k_srbind_replay_freecam
], &text
);
628 skaterift_replay_update_helpers();
633 void skaterift_replay_debug_info(void)
635 player__debugtext( 2, "replay info" );
636 replay_buffer
*replay
= &player_replay
.local
;
640 if( replay
->tail
) tail
= (void *)replay
->tail
- replay
->data
;
641 if( replay
->head
) head
= (void *)replay
->head
- replay
->data
;
643 player__debugtext( 1, "head @%u | tail @%u\n", head
, tail
);
645 if( replay
->statehead
){
646 for( u32 i
=0; i
<k_replay_framedata_rows
; i
++ ){
647 player__debugtext( 1, "[%u]: [%hu, %hu]\n", i
,
648 replay
->statehead
->data_table
[i
][0],
649 replay
->statehead
->data_table
[i
][1] );
651 u32 state
= (void *)replay
->statehead
- replay
->data
;
652 player__debugtext( 1, "gs @%u\n", state
);
653 player__debugtext( 1, "gamestate_size: %hu\n",
654 replay
->statehead
->data_table
[k_replay_framedata_gamestate
][1] );
657 player__debugtext( 1, "gs @NULL\n" );
659 f64 start
= replay
->cursor
,
660 end
= replay
->cursor
;
661 if( replay
->tail
) start
= replay
->tail
->time
;
662 if( replay
->head
) end
= replay
->head
->time
;
664 f64 cur
= replay
->cursor
- start
,
667 player__debugtext( 1, "cursor: %.2fs / %.2fs\n", cur
, len
);
670 void skaterift_replay_imgui(void)
672 if( skaterift
.activity
!= k_skaterift_replay
) return;
674 replay_buffer
*replay
= &player_replay
.local
;
675 f64 start
= replay
->cursor
,
676 end
= replay
->cursor
;
677 if( replay
->tail
) start
= replay
->tail
->time
;
678 if( replay
->head
) end
= replay
->head
->time
;
679 f64 len
= end
- start
,
680 cur
= (replay
->cursor
- start
) / len
;
687 ui_rect bar
= { 0, 0, vg
.window_x
, height
};
688 ui_fill( bar
, ui_colour( k_ui_bg
) );
690 /* cursor frame block */
691 if( replay
->cursor_frame
){
692 if( replay
->cursor_frame
->r
){
693 f64 l
= (replay
->cursor_frame
->r
->time
-replay
->cursor_frame
->time
)/len
,
694 s
= (replay
->cursor_frame
->time
- start
) / len
;
695 ui_rect box
= { s
*(f64
)vg
.window_x
, 0,
696 VG_MAX(4,(ui_px
)(l
*vg
.window_x
)), bar
[3]+2 };
697 ui_fill( box
, ui_colour( k_ui_bg
+4 ) );
702 ui_rect cusor
= { cur
* (f64
)vg
.window_x
- (cwidth
/2), 0,
704 ui_fill( cusor
, ui_colour( k_ui_bg
+7 ) );
706 /* latest state marker */
707 if( replay
->statehead
){
708 f64 t
= (replay
->statehead
->time
- start
) / len
;
709 ui_rect tag
= { t
*(f64
)vg
.window_x
, 0, 2, bar
[3]+8 };
710 ui_fill( tag
, ui_colour( k_ui_green
+k_ui_brighter
) );
713 /* previous state marker */
714 replay_frame
*prev
= replay_find_recent_stateframe( replay
);
716 f64 t
= (prev
->time
- start
) / len
;
717 ui_rect tag
= { t
*(f64
)vg
.window_x
, 0, 2, bar
[3]+8 };
718 ui_fill( tag
, ui_colour( k_ui_yellow
+k_ui_brighter
) );
723 snprintf( buffer
, 128, "-%.2fs\n", (end
-replay
->cursor
) );
724 ui_text( cusor
, buffer
, 1, k_ui_align_middle_left
, 0 );
726 snprintf( buffer
, 128, "-%.2fs\n", len
);
727 ui_text( bar
, buffer
, 1, k_ui_align_middle_left
, 0 );
728 ui_text( bar
, "0s", 1, k_ui_align_middle_right
, 0 );