Skip to content

Commit

Permalink
Rebase around YaLTeR#58 and suggested changes
Browse files Browse the repository at this point in the history
  • Loading branch information
khanghugo committed Feb 18, 2023
1 parent 6f7ea24 commit 1456a05
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 17 deletions.
33 changes: 23 additions & 10 deletions src/hooks/engine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -176,12 +176,17 @@ pub static ClientDLL_UpdateClientData: Pointer<unsafe extern "C" fn()> = Pointer
]),
my_ClientDLL_UpdateClientData as _,
);
pub static cl: Pointer<*mut client_state_t> = Pointer::empty(
// There is no use for this in Windows yet so there won't be Windows offset for now.
b"cl\0");
pub static cl_stats: Pointer<*mut [i32; 32]> = Pointer::empty(
// Not a real symbol name.
b"cl_stats\0");
pub static cls: Pointer<*mut client_static_s> = Pointer::empty(b"cls\0");
pub static cls_demos: Pointer<*mut client_static_s_demos> = Pointer::empty(
// Not a real symbol name.
b"cls_demos\0",
);
pub static cls_demoframecount: Pointer<*mut c_int> = Pointer::empty(b"cls_demoframecount\0");
pub static Cmd_AddMallocCommand: Pointer<
unsafe extern "C" fn(*const c_char, unsafe extern "C" fn(), c_int),
> = Pointer::empty_patterns(
Expand Down Expand Up @@ -839,9 +844,10 @@ static POINTERS: &[&dyn PointerTrait] = &[
&ClientDLL_HudRedraw,
&ClientDLL_HudVidInit,
&ClientDLL_UpdateClientData,
&cl,
&cl_stats,
&cls,
&cls_demos,
&cls_demoframecount,
&Cmd_AddMallocCommand,
&Cmd_Argc,
&Cmd_Argv,
Expand Down Expand Up @@ -960,6 +966,11 @@ pub struct dma_t {
pub buffer: *mut c_uchar,
}

#[repr(C)]
pub struct client_state_t {
pub max_edicts: c_int,
}

#[repr(C)]
pub struct client_static_s {
pub state: c_int,
Expand Down Expand Up @@ -1162,8 +1173,8 @@ unsafe fn find_pointers(marker: MainThreadMarker) {
pointer.set(marker, ptr);
}

cl_stats.set(marker, cl.offset(marker, 174892));
cls_demos.set(marker, cls.offset(marker, 15960));
cls_demoframecount.set(marker, cls.offset(marker, 16776));
frametime_remainder.set(marker, CL_Move.by_offset(marker, 452));
idum.set(marker, ran1.by_offset(marker, 2));
ran1_iy.set(marker, ran1.by_offset(marker, 13));
Expand Down Expand Up @@ -1217,13 +1228,6 @@ pub unsafe fn find_pointers(marker: MainThreadMarker, base: *mut c_void, size: u
_ => (),
}

let ptr = &CL_PlayDemo_f;
match ptr.pattern_index(marker) {
// 8684
Some(0) => cls_demoframecount.set(marker, ptr.by_offset(marker, 735)),
_ => (),
}

let ptr = &Cmd_AddMallocCommand;
match ptr.pattern_index(marker) {
// 6153
Expand Down Expand Up @@ -1405,6 +1409,15 @@ pub unsafe fn find_pointers(marker: MainThreadMarker, base: *mut c_void, size: u
_ => (),
}

let ptr = &R_DrawViewModel;
match ptr.pattern_index(marker) {
// 8684
Some(0) => {
cl_stats.set(marker, ptr.by_offset(marker, 129));
}
_ => ()
}

let ptr = &R_SetFrustum;
match ptr.pattern_index(marker) {
// 6153
Expand Down
42 changes: 35 additions & 7 deletions src/modules/capture/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ impl Module for Capture {
&BXT_CAP_VOLUME,
&BXT_CAP_SOUND_EXTRA,
&BXT_CAP_SLOWDOWN,
&BXT_CAP_SEEMLESS,
&BXT_CAP_SAMPLING_EXPOSURE,
&BXT_CAP_FORCE_FALLBACK,
&BXT_CAP_OVERRIDE_FFMPEG_ARGS,
Expand Down Expand Up @@ -98,6 +99,17 @@ Slowdown factor for the recording.
For example, `2` means that the video will be two times slower than the realtime playback. \
Especially useful for TASes.",
);
static BXT_CAP_SEEMLESS: CVar = CVar::new(
b"_bxt_cap_seemless\0",
b"1\0",
"\
Skipping recording non-gameplay frames such as one frame in main menu or loading screen.
Set to `0` to disable. Set to `1` to enable. \
Any value greater than `1` will be the extra amount of frames skipped \
as soon as a demo or a map is loaded. The recommended value for such situation \
should be `7` (six first frames will not be captured).",
);
static BXT_CAP_SAMPLING_MIN_FPS: CVar = CVar::new(
b"_bxt_cap_sampling_min_fps\0",
b"7200\0",
Expand Down Expand Up @@ -560,6 +572,9 @@ pub unsafe fn on_cl_disconnect(marker: MainThreadMarker) {
}

{
// Reset frame skip for next demo load
FRAME_SKIP.set(marker, 0);

// Safety: no engine functions are called while the reference is active.
let cls_demos = &*engine::cls_demos.get(marker);

Expand Down Expand Up @@ -607,15 +622,17 @@ pub fn prevent_toggle_console(marker: MainThreadMarker) -> bool {
INSIDE_KEY_EVENT.get(marker)
}

static FRAME_SKIP: MainThreadCell<u32> = MainThreadCell::new(0);

pub unsafe fn time_passed(marker: MainThreadMarker) {
let mut state = STATE.borrow_mut(marker);
let State::Recording(ref mut recorder) = *state else { return };

let cls_demos = &*engine::cls_demos.get(marker);
let frame_count = *engine::cls_demoframecount.get(marker);
let cl_stats = (*engine::cl_stats.get(marker))[2];
let cls = &*engine::cls.get(marker);
let cls_demos = &*engine::cls_demos.get(marker);

if BXT_CAP_SEEMLESS.as_bool(marker) {
if BXT_CAP_SKIP_NON_GAMEPLAY_FRAMES.as_bool(marker) {
if cls.state != 5 {
// ca_dedicated=0,
// ca_disconnected=1,
Expand All @@ -625,10 +642,21 @@ pub unsafe fn time_passed(marker: MainThreadMarker) {
// ca_active=5
return;
} else {
if cls_demos.demoplayback == 1 && frame_count < BXT_CAP_SEEMLESS.as_f32(marker) as i32 {
// demoplayback is updated to 1 after state 4 is done
// frame 0 are skipped by default because they are non-frames
return;
// demoplayback is updated to 1 after state 4 is done.
// The current implementation will skip all the frames until some viewmodel values are set.
if cls_demos.demoplayback == 1 {
if cl_stats == 0 {
// For some reasons, the true first frame is recorded. That frame is in this condition...
// That's a good thing because it technically captures all non-loading frames.
return;
}
else {
// Alternative use of the cvar
if FRAME_SKIP.get(marker) + 1 < BXT_CAP_SKIP_NON_GAMEPLAY_FRAMES.as_f32(marker) as u32 {
FRAME_SKIP.set(marker, FRAME_SKIP.get(marker) + 1);
return;
}
}
}
}
}
Expand Down

0 comments on commit 1456a05

Please sign in to comment.