Skip to content

Commit

Permalink
Add bxt_tas_studio_replay_views (#99)
Browse files Browse the repository at this point in the history
* add bxt_tas_studio_replay_views

* changes suggested

* only playback views when all accurate frames are received

* changes suggested
  • Loading branch information
khanghugo authored Jul 27, 2024
1 parent 42ca2bc commit 2b28140
Show file tree
Hide file tree
Showing 5 changed files with 219 additions and 11 deletions.
3 changes: 3 additions & 0 deletions bxt-strafe/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,8 @@ pub struct State {
// Number of frames for [`StrafeDir::LeftRight`] or [`StrafeDir::RightLeft`] which goes from
// `0` to `count - 1`.
pub strafe_cycle_frame_count: u32,
// In case of yaw and pitch override, this might be useful.
pub rendered_viewangles: Vec3,
}

impl State {
Expand All @@ -145,6 +147,7 @@ impl State {
jumped: false,
move_traces: ArrayVec::new(),
strafe_cycle_frame_count: 0,
rendered_viewangles: Vec3::ZERO,
};

rv.update_place(tracer);
Expand Down
1 change: 1 addition & 0 deletions src/hooks/bxt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,7 @@ pub struct OnTasPlaybackFrameData {
pub strafe_cycle_frame_count: u32,
pub prev_predicted_trace_fractions: [f32; 4],
pub prev_predicted_trace_normal_zs: [f32; 4],
pub rendered_viewangles: [f32; 3],
}

unsafe extern "C" fn on_tas_playback_frame(data: OnTasPlaybackFrameData) -> c_int {
Expand Down
23 changes: 23 additions & 0 deletions src/hooks/engine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -723,6 +723,14 @@ pub static SCR_DrawLoading: Pointer<unsafe extern "C" fn()> = Pointer::empty_pat
]),
my_SCR_DrawLoading as _,
);
pub static SCR_DrawPause: Pointer<unsafe extern "C" fn()> = Pointer::empty_patterns(
b"SCR_DrawPause\0",
// To find, search for "cz_worldmap". You are in SCR_DrawPause().
Patterns(&[
pattern!(D9 05 ?? ?? ?? ?? D8 1D ?? ?? ?? ?? DF E0 F6 C4 44 7B ?? A1 ?? ?? ?? ?? 85 C0 74 ?? E8 ?? ?? ?? ?? 85),
]),
my_SCR_DrawPause as _,
);
pub static scr_fov_value: Pointer<*mut c_float> = Pointer::empty(b"scr_fov_value\0");
pub static shm: Pointer<*mut *mut dma_t> = Pointer::empty(b"shm\0");
pub static sv: Pointer<*mut c_void> = Pointer::empty(b"sv\0");
Expand Down Expand Up @@ -987,6 +995,7 @@ static POINTERS: &[&dyn PointerTrait] = &[
&S_PaintChannels,
&S_TransferStereo16,
&SCR_DrawLoading,
&SCR_DrawPause,
&scr_fov_value,
&shm,
&sv,
Expand Down Expand Up @@ -2191,6 +2200,19 @@ pub mod exported {
})
}

#[export_name = "SCR_DrawPause"]
pub unsafe extern "C" fn my_SCR_DrawPause() {
abort_on_panic(move || {
let marker = MainThreadMarker::new();

if !tas_studio::should_draw_pause(marker) {
return;
}

SCR_DrawPause.get(marker)();
})
}

#[export_name = "SV_Frame"]
pub unsafe extern "C" fn my_SV_Frame() {
abort_on_panic(move || {
Expand Down Expand Up @@ -2378,6 +2400,7 @@ pub mod exported {
let marker = MainThreadMarker::new();

campath::override_view(marker);
tas_studio::tas_playback_rendered_views(marker);

R_RenderView.get(marker)();
})
Expand Down
22 changes: 13 additions & 9 deletions src/modules/tas_studio/editor/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -516,6 +516,18 @@ impl Editor {
self.hovered_frame_idx.map(|idx| &self.branch().frames[idx])
}

pub fn has_all_accurate_frames(&self) -> bool {
let frame_count = self
.branch()
.branch
.script
.frame_bulks()
.map(|bulk| bulk.frame_count.get() as usize)
.sum::<usize>();

self.branch().first_predicted_frame == frame_count + 1
}

pub fn undo_log_len(&self) -> usize {
self.undo_log.len()
}
Expand Down Expand Up @@ -3056,16 +3068,8 @@ impl Editor {
return Err(ManualOpError::CannotDoDuringAdjustment);
}

let frame_count = self
.branch()
.branch
.script
.frame_bulks()
.map(|bulk| bulk.frame_count.get() as usize)
.sum::<usize>();

// Only smooth when we have all accurate frames.
if self.branch().first_predicted_frame != frame_count + 1 {
if !self.has_all_accurate_frames() {
return Err(ManualOpError::UserError(
"all frames must be accurate (simulated by the \
second game) to apply global smoothing"
Expand Down
181 changes: 179 additions & 2 deletions src/modules/tas_studio/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ impl Module for TasStudio {
&BXT_TAS_STUDIO_NEW,
&BXT_TAS_STUDIO_LOAD,
&BXT_TAS_STUDIO_CONVERT_HLTAS,
&BXT_TAS_STUDIO_REPLAY_VIEWS,
&BXT_TAS_STUDIO_REPLAY,
&BXT_TAS_STUDIO_SET_STOP_FRAME,
&BXT_TAS_STUDIO_SET_YAWSPEED,
Expand Down Expand Up @@ -393,11 +394,13 @@ fn norefresh_until_stop_frame_frame_idx(marker: MainThreadMarker, editor: &Edito
let norefresh_last_frames =
unsafe { bxt::BXT_TAS_NOREFRESH_UNTIL_LAST_FRAMES.get(marker)() } as usize;

if editor.stop_frame() == 0 {
let first_frame_idx = if editor.stop_frame() == 0 {
(editor.branch().frames.len() - 1).saturating_sub(norefresh_last_frames)
} else {
(editor.stop_frame() as usize).saturating_sub(norefresh_last_frames)
}
};

first_frame_idx.clamp(0, editor.branch().frames.len() - 1)
}

fn set_effective_norefresh_until_stop_frame(marker: MainThreadMarker, editor: &Editor) {
Expand Down Expand Up @@ -435,6 +438,89 @@ fn replay(marker: MainThreadMarker) {
};
}

static BXT_TAS_STUDIO_REPLAY_VIEWS: Command = Command::new(
b"bxt_tas_studio_replay_views\0",
handler!(
"bxt_tas_studio_replay_views
Replays the currently loaded camera views of TAS up to the stop frame.",
replay_views as fn(_)
),
);

fn replay_views(marker: MainThreadMarker) {
let mut state = STATE.borrow_mut(marker);
*state = match mem::take(&mut *state) {
State::Editing {
mut editor,
last_generation,
last_branch_idx,
simulate_at,
bridge,
} => {
if !editor.has_all_accurate_frames() {
con_print(
marker,
"You need to have second game done simulating to playback views.\n",
);

State::Editing {
editor,
last_generation,
last_branch_idx,
simulate_at,
bridge,
}
} else {
editor.cancel_ongoing_adjustments();

sdl::set_relative_mouse_mode(marker, true);
client::activate_mouse(marker, true);

// bxt_tas_norefresh_until_last_frames = 0 means 1 frame being played. Heh.
let start_frame = norefresh_until_stop_frame_frame_idx(marker, &editor);

engine::prepend_command(marker, "bxt_hud 0; hud_draw 0\n");

State::PlayingViews {
editor,
last_generation,
last_branch_idx,
simulate_at,
bridge,
current_frame: start_frame,
}
}
}
// Press play view again to stop.
State::PlayingViews {
editor,
last_generation,
last_branch_idx,
simulate_at,
bridge,
..
} => {
sdl::set_relative_mouse_mode(marker, false);
client::activate_mouse(marker, false);
engine::prepend_command(marker, "bxt_hud 1; hud_draw 1\n");
ENABLE_FREECAM_ON_CALCREFDEF.set(marker, true);

State::Editing {
editor,
last_generation,
last_branch_idx,
simulate_at,
bridge,
}
}
other => {
con_print(marker, "You need to be in the editor to playback views.\n");
other
}
};
}

static BXT_TAS_STUDIO_SET_STOP_FRAME: Command = Command::new(
b"bxt_tas_studio_set_stop_frame\0",
handler!(
Expand Down Expand Up @@ -1453,6 +1539,16 @@ enum State {
simulate_at: Option<Instant>,
bridge: Bridge,
},
/// Playing camera views, will open the editor afterwards.
/// Playback is inside Editing mode so original data will be restored.
PlayingViews {
editor: Editor,
last_generation: u16,
last_branch_idx: usize,
simulate_at: Option<Instant>,
bridge: Bridge,
current_frame: usize,
},
}

impl Default for State {
Expand Down Expand Up @@ -1562,9 +1658,87 @@ pub unsafe fn maybe_receive_messages_from_remote_server(marker: MainThreadMarker
editor.recompute_extra_camera_frame_data_if_needed();
}
State::PreparingToPlayToEditor(_, _, _) => unreachable!(),
State::PlayingViews { .. } => {
// Do nothing
// While PlayingViews is happening, nothing else happens or will happen.
// Because PlayingViews only starts when all accurate frames are received.
// Meaning there is nothing second game could do anything to affect the state.
}
}
}

pub fn should_draw_pause(marker: MainThreadMarker) -> bool {
!matches!(*STATE.borrow_mut(marker), State::PlayingViews { .. })
}

pub fn tas_playback_rendered_views(marker: MainThreadMarker) {
if !TasStudio.is_enabled(marker) {
return;
}

let mut state = STATE.borrow_mut(marker);
*state = match mem::take(&mut *state) {
State::PlayingViews {
editor,
last_generation,
last_branch_idx,
simulate_at,
bridge,
current_frame,
} => {
if current_frame == editor.stop_frame() as usize
|| current_frame >= editor.branch().frames.len()
{
sdl::set_relative_mouse_mode(marker, false);
client::activate_mouse(marker, false);
engine::prepend_command(marker, "bxt_hud 1; hud_draw 1\n");
ENABLE_FREECAM_ON_CALCREFDEF.set(marker, true);

State::Editing {
editor,
last_generation,
last_branch_idx,
simulate_at,
bridge,
}
} else {
let r_refdef_vieworg = unsafe { &mut *engine::r_refdef_vieworg.get(marker) };
let r_refdef_viewangles = unsafe { &mut *engine::r_refdef_viewangles.get(marker) };

let state = &editor.branch().frames[current_frame].state;

r_refdef_vieworg[0] = state.player.pos[0];
r_refdef_vieworg[1] = state.player.pos[1];
r_refdef_vieworg[2] = state.player.pos[2];

// We don't keep track of vieworg so just deduce it from here instead.
// It is not easy to keep track of vieworg because it isn't there to track.
// vieworg is calculated.
// It is also funny how vieworg is calculated here,
// but viewangles is passed from BXT.
r_refdef_vieworg[2] += 28.;
if state.player.ducking {
r_refdef_vieworg[2] -= 16.;
}

r_refdef_viewangles[0] = state.rendered_viewangles[0];

r_refdef_viewangles[1] = state.rendered_viewangles[1];

State::PlayingViews {
editor,
last_generation,
last_branch_idx,
simulate_at,
bridge,
current_frame: current_frame + 1,
}
}
}
other => other,
};
}

pub unsafe fn on_tas_playback_frame(
marker: MainThreadMarker,
data: OnTasPlaybackFrameData,
Expand Down Expand Up @@ -1604,6 +1778,9 @@ pub unsafe fn on_tas_playback_frame(
strafe_state.prev_frame_input.yaw = view_angles[1].to_radians();
}

// Store rendered viewangles.
strafe_state.rendered_viewangles = data.rendered_viewangles.into();

// We don't have a good way to extract real trace results from the movement code, so let's
// make up trace results based on previous frame's predicted fractions and normal Zs from
// BXT.
Expand Down

0 comments on commit 2b28140

Please sign in to comment.