Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TAS studio split and join sections of the script #110

Draft
wants to merge 19 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
split marker invalidations
  • Loading branch information
Eddio0141 committed Nov 27, 2024
commit 1a5ee7fd42218878d6109ffeed88cede0eb76e6f
46 changes: 27 additions & 19 deletions src/modules/tas_studio/editor/db.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ pub struct Branch {

pub script: HLTAS,
pub splits: Vec<SplitInfo>,
pub full_script: HLTAS,
pub stop_frame: u32,
}

Expand All @@ -43,6 +42,8 @@ pub struct SplitInfo {
// this is 1 index right after the split marker
// it is guaranteed to have a framebulk somewhere after this
pub start_idx: usize,
// for the sake of easier searching, the last framebulk index is stored
pub bulk_idx: usize,
// a split could have no name
// this could also be duplicate names, which becomes `None`
pub name: Option<String>,
Expand Down Expand Up @@ -78,23 +79,24 @@ impl SplitInfo {

let mut splits = Vec::new();

let mut i = 0usize;
let mut line_idx = 0usize;
let mut bulk_idx = 1usize;
// skip till there's at least 1 framebulk
for line in lines.by_ref() {
if matches!(line, Line::FrameBulk(_)) {
break;
}

i += 1;
if i >= stop_idx {
line_idx += 1;
if line_idx >= stop_idx {
return splits;
}
}

while let Some(line) = lines.next() {
// this is correct, if FrameBulk is at index 0, we are searching from index 1
i += 1;
if i >= stop_idx {
line_idx += 1;
if line_idx >= stop_idx {
return splits;
}

Expand All @@ -112,21 +114,21 @@ impl SplitInfo {
if Self::no_framebulks_left(&mut lines) {
break;
}
i += 1;
line_idx += 1;

name = Some(save_name.to_owned());
start_idx = i;
start_idx = line_idx;
split_type = SplitType::Save;
}
// this reset doesn't have a name, one with comment attached is handled below
Line::Reset { .. } => {
if Self::no_framebulks_left(&mut lines) {
break;
}
i += 1;
line_idx += 1;

name = None;
start_idx = i;
start_idx = line_idx;
split_type = SplitType::Reset;
}
Line::Comment(comment) => {
Expand All @@ -148,7 +150,7 @@ impl SplitInfo {
if Self::no_framebulks_left(&mut lines) {
break;
}
i += 1;
line_idx += 1;

SplitType::Reset
} else {
Expand All @@ -158,23 +160,28 @@ impl SplitInfo {

SplitType::Comment
};
i += 1;
line_idx += 1;

start_idx = i;
start_idx = line_idx;
let comment = comment.trim_start();
if comment.is_empty() {
name = None;
} else {
name = Some(comment.to_owned());
}
}
Line::FrameBulk(_) => {
bulk_idx += 1;
continue;
}
_ => continue,
}

splits.push(SplitInfo {
start_idx,
name,
split_type,
bulk_idx,
ready: false,
});
}
Expand Down Expand Up @@ -347,15 +354,13 @@ impl Db {
let script = HLTAS::from_str(&buffer)
.map_err(|err| eyre!("invalid script value, cannot parse: {err:?}"))?;

let full_script = script.clone();
let splits = SplitInfo::split_lines(full_script.lines.iter());
let splits = SplitInfo::split_lines(script.lines.iter());

Ok(Branch {
branch_id,
name,
is_hidden,
script,
full_script,
splits,
stop_frame,
})
Expand All @@ -382,16 +387,14 @@ impl Db {
let script = HLTAS::from_str(&buffer)
.map_err(|err| eyre!("invalid script value, cannot parse: {err:?}"))?;

let full_script = script.clone();
let splits = SplitInfo::split_lines(full_script.lines.iter());
let splits = SplitInfo::split_lines(script.lines.iter());

branches.push(Branch {
branch_id,
name,
is_hidden,
script,
stop_frame,
full_script,
splits,
})
}
Expand Down Expand Up @@ -719,30 +722,35 @@ mod tests {
let expected = vec![
SplitInfo {
start_idx: 2,
bulk_idx: 1,
name: Some("name".to_string()),
split_type: SplitType::Comment,
ready: false,
},
SplitInfo {
start_idx: 5,
bulk_idx: 3,
name: None,
split_type: SplitType::Comment,
ready: false,
},
SplitInfo {
start_idx: 9,
bulk_idx: 6,
name: Some("name2".to_string()),
split_type: SplitType::Save,
ready: false,
},
SplitInfo {
start_idx: 14,
bulk_idx: 10,
name: Some("name3".to_string()),
split_type: SplitType::Reset,
ready: false,
},
SplitInfo {
start_idx: 21,
bulk_idx: 15,
name: Some("name4".to_string()),
split_type: SplitType::Comment,
ready: false,
Expand Down
69 changes: 58 additions & 11 deletions src/modules/tas_studio/editor/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -673,6 +673,8 @@ impl Editor {
self.recompute_extra_camera_frame_data_if_needed();

self.generation = self.generation.wrapping_add(1);

self.invalidate_splits_fb_idx(frame_idx);
}

pub fn recompute_extra_camera_frame_data_if_needed(&mut self) {
Expand Down Expand Up @@ -3315,23 +3317,45 @@ impl Editor {
// if modified before or on split idx, it is invalid
// simply find the first split that is covered
// TODO: test
let splits = &mut self.branch_mut().branch.splits;
let splits = self.split_markers();
let last_line_idx = first_line_idx + count - 1;
let invalid_split_idx =
splits.partition_point(|s| s.start_idx < first_line_idx && s.start_idx > last_line_idx);

// offsets are applied for after the last_line_idx range
let offset_split_idx =
splits[invalid_split_idx..].partition_point(|s| s.start_idx < last_line_idx);
// TODO: unlikely, but what to do if overflow, or count is too big
let split_offset_cnt = isize::try_from(to_str.len())
.expect("Length of the replacement line is too huge to be isize")
- isize::try_from(count).expect("Number of lines to replace is too huge to be isize");
for split in splits[offset_split_idx..].iter_mut() {
split
.start_idx
.checked_add_signed(split_offset_cnt)
.expect("Split marker index is out of range to be usable, which shouldn't happen");
if offset_split_idx < splits.len() {
let split_offset_cnt = isize::try_from(to.len())
.expect("Length of the replacement line is too huge to be isize")
- isize::try_from(count)
.expect("Number of lines to replace is too huge to be isize");
// same thing as above, but for framebulks
let fb_to_cnt = to
.iter()
.filter(|l| matches!(l, Line::FrameBulk(_)))
.count();
let fb_count_cnt = from_lines
.iter()
.filter(|l| matches!(l, Line::FrameBulk(_)))
.count();
let bulk_offset_cnt = isize::try_from(fb_to_cnt)
.expect("Index of framebulk is too large for calculating as isize")
- isize::try_from(fb_count_cnt)
.expect("Index of framebulk is too large for calculating as isize");

// apply offsets
let splits = self.split_markers_mut();
for split in splits[offset_split_idx..].iter_mut() {
split
.start_idx
.checked_add_signed(split_offset_cnt)
.expect("Split marker index is out of range");
split
.bulk_idx
.checked_add_signed(bulk_offset_cnt)
.expect("Split marker framebulk index is out of range");
}
}

// handle `to` lines split info
Expand All @@ -3341,7 +3365,7 @@ impl Editor {
.chain(self.script().lines[offset_split_idx..].iter()),
to.len(),
);
let splits = &mut self.branch_mut().branch.splits;
let splits = self.split_markers_mut();
for (i, split) in to_splits.into_iter().enumerate() {
let mut split = split;
split.start_idx += first_line_idx;
Expand Down Expand Up @@ -4592,6 +4616,29 @@ impl Editor {

tri.end();
}

pub fn split_markers(&self) -> &[SplitInfo] {
&self.branch().branch.splits
}

pub fn split_markers_mut(&mut self) -> &mut Vec<SplitInfo> {
&mut self.branch_mut().branch.splits
}

/// Invalidates split markers with a framebulk index
pub fn invalidate_splits_fb_idx(&mut self, fb_idx: usize) {
let invalid_split_idx = self.invalid_split_idx_from_fb_idx(fb_idx);
let splits = self.split_markers_mut();
for split in splits[invalid_split_idx..].iter_mut() {
split.ready = false;
}
}

fn invalid_split_idx_from_fb_idx(&self, fb_idx: usize) -> usize {
// splits are invalid if bulk_idx is equals to fb_idx or higher
self.split_markers()
.partition_point(|s| s.bulk_idx < fb_idx)
}
}

fn perpendicular(prev: Vec3, next: Vec3) -> Vec3 {
Expand Down