Skip to content

Commit

Permalink
v1.1.0, bugfix for missing data in modified anim
Browse files Browse the repository at this point in the history
  • Loading branch information
ssbucarlos committed Dec 3, 2022
1 parent 37974fe commit be63293
Show file tree
Hide file tree
Showing 5 changed files with 232 additions and 75 deletions.
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "wifisafe_anim_splicer"
version = "1.0.0"
version = "1.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
Expand Down
303 changes: 230 additions & 73 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,94 +21,251 @@ fn main() -> Result<()> {
let modified_anim = ssbh_lib::formats::anim::Anim::from_file(&args.modified_anim)
.with_context(|| format!("coult not read modified anim `{}`", &args.modified_anim.display()))?;

// Validate Anim Versions
if let Anim::V12{..} = &reference_anim {
return Err(anyhow::format_err!("v12 reference anim not supported!"))
}
if let Anim::V12{..} = &modified_anim {
return Err(anyhow::format_err!("v12 modified anim not supported!"))
}

// Gather reference data
let mut reference_node_name_to_buffer = std::collections::HashMap::new();
let mut reference_node_name_to_track = std::collections::HashMap::new();

match &reference_anim {
Anim::V12 {..} => {
return Err(anyhow::format_err!("v12 reference anim not supported!"))
},
Anim::V21 {groups, buffer , .. } | Anim::V20 {groups, buffer , .. } => {
for group in &groups.elements{
if group.group_type != GroupType::Transform{
continue
}
for node in &group.nodes.elements{
let track = &node.tracks.elements[0];
let node_name = String::from(node.name.to_str().unwrap());
let start_index = track.data_offset as usize;
let end_index = (track.data_offset as u64 + track.data_size) as usize;
let buffer_slice = &buffer.elements[start_index..end_index];
reference_node_name_to_buffer.insert(node_name.clone(), buffer_slice);
reference_node_name_to_track.insert(node_name.clone(), track);

}
let mut reference_node_names = Vec::new();
if let Anim::V21 {groups, buffer , .. } | Anim::V20 {groups, buffer , .. } = &reference_anim {
for group in &groups.elements{
if group.group_type != GroupType::Transform{
continue
}
},
for node in &group.nodes.elements{
let track = &node.tracks.elements[0];
let node_name = String::from(node.name.to_str().unwrap());
let start_index = track.data_offset as usize;
let end_index = (track.data_offset as u64 + track.data_size) as usize;
let buffer_slice = &buffer.elements[start_index..end_index];
reference_node_name_to_buffer.insert(node_name.clone(), buffer_slice);
reference_node_name_to_track.insert(node_name.clone(), track);
reference_node_names.push(node.name.clone());
}
}
}

// Find out and keep track which groups exist in the modified animation
// A user may provide only the vis track for instance, but the expected
// result is that the existing transform and mat tracks would remain in
// the spliced anim.
let mut modified_group_types: Vec<GroupType> = Vec::new();
if let Anim::V21 {groups, .. } | Anim::V20 {groups, .. } = &modified_anim{
for group in &groups.elements{
modified_group_types.push(group.group_type);
}
}

// Now format the new buffer
let mut current_offset: u64 = 0;
let mut new_buffer = SsbhByteBuffer::new();
let mut new_groups: SsbhArray<ssbh_lib::formats::anim::Group> = SsbhArray::new();
match &modified_anim {
Anim::V12 {..} => {
return Err(anyhow::format_err!("v12 modified anim not supported!")
)},
Anim::V20{groups, buffer, ..} | Anim::V21{groups, buffer, ..} => {
for modified_group in &groups.elements{
let mut new_group = ssbh_lib::formats::anim::Group{
group_type: modified_group.group_type,
nodes: SsbhArray::new()
// First just go through the vanilla anim's bone data and just copy all those buffers as-is.
// Then we can just grab any new bone data and the vis/mat tracks from the modified anim
let mut new_transform_group = ssbh_lib::formats::anim::Group{
group_type: ssbh_lib::formats::anim::GroupType::Transform,
nodes: SsbhArray::new()
};
if let Anim::V20{groups, ..} | Anim::V21{groups, ..} = &reference_anim{
for reference_group in &groups.elements{
if reference_group.group_type != GroupType::Transform{
continue;
}
for reference_node in &reference_group.nodes.elements{
let mut new_node = ssbh_lib::formats::anim::Node{
name: reference_node.name.clone(),
tracks: SsbhArray::new()
};
for modified_node in &modified_group.nodes.elements{
let mut new_node = ssbh_lib::formats::anim::Node{
name: modified_node.name.clone(),
tracks: SsbhArray::new()
for reference_track in &reference_node.tracks.elements{
let new_track = ssbh_lib::formats::anim::TrackV2{
name: reference_track.name.clone(),
flags: reference_track.flags,
frame_count: reference_track.frame_count,
transform_flags: reference_track.transform_flags,
data_offset: current_offset as u32,
data_size: reference_track.data_size
};
for modified_track in &modified_node.tracks.elements{
let reference_track = reference_node_name_to_track.get(modified_node.name.to_str().unwrap());
let new_track = match reference_track{
Some(reference_track) => {
ssbh_lib::formats::anim::TrackV2{
name: reference_track.name.clone(),
flags: reference_track.flags,
frame_count: reference_track.frame_count,
transform_flags: reference_track.transform_flags,
data_offset: current_offset as u32,
data_size: reference_track.data_size
}
},
None => {
ssbh_lib::formats::anim::TrackV2{
name: modified_track.name.clone(),
flags: modified_track.flags,
frame_count: modified_track.frame_count,
transform_flags: modified_track.transform_flags,
data_offset: current_offset as u32,
data_size: modified_track.data_size
}
}
};
if let Some(reference_track) = reference_track {
let reference_buffer = reference_node_name_to_buffer.get(modified_node.name.to_str().unwrap()).unwrap();
new_buffer.elements.extend_from_slice(&reference_buffer);
current_offset += reference_track.data_size;
} else {
let start_index = modified_track.data_offset as usize;
let end_index = (modified_track.data_offset as u64 + modified_track.data_size) as usize;
let modified_buffer = &buffer.elements[start_index..end_index];
new_buffer.elements.extend_from_slice(&modified_buffer);
current_offset += modified_track.data_size;
};
new_node.tracks.elements.push(new_track);
}
new_group.nodes.elements.push(new_node);
let reference_buffer = reference_node_name_to_buffer.get(reference_node.name.to_str().unwrap()).unwrap();
new_buffer.elements.extend_from_slice(&reference_buffer);
current_offset += reference_track.data_size;
new_node.tracks.elements.push(new_track);
}
new_groups.elements.push(new_group);
new_transform_group.nodes.elements.push(new_node);
}
}
}

// At this point, only one transform group has been made.
// Gather new bone data to finish the new transform group
if let Anim::V20{groups, buffer, ..} | Anim::V21{groups, buffer, ..} = &modified_anim{
for modified_group in &groups.elements{
for modified_node in &modified_group.nodes.elements{
if reference_node_names.contains(&modified_node.name){
continue;
}
let mut new_node = ssbh_lib::formats::anim::Node{
name: modified_node.name.clone(),
tracks: SsbhArray::new()
};
for modified_track in &modified_node.tracks.elements{
let new_track = ssbh_lib::formats::anim::TrackV2{
name: modified_track.name.clone(),
flags: modified_track.flags,
frame_count: modified_track.frame_count,
transform_flags: modified_track.transform_flags,
data_offset: current_offset as u32,
data_size: modified_track.data_size
};
let start_index = modified_track.data_offset as usize;
let end_index = (modified_track.data_offset as u64 + modified_track.data_size) as usize;
let modified_buffer = &buffer.elements[start_index..end_index];
new_buffer.elements.extend_from_slice(&modified_buffer);
current_offset += modified_track.data_size;
new_node.tracks.elements.push(new_track);
}
new_transform_group.nodes.elements.push(new_node);
}
}
}
new_groups.elements.push(new_transform_group);

// Now we need to grab the mat/vis groups from the modified anim
if let Anim::V20{groups, buffer, ..} | Anim::V21{groups, buffer, ..} = &modified_anim{
for modified_group in &groups.elements{
if modified_group.group_type == GroupType::Transform{
continue
}
let mut new_group = ssbh_lib::formats::anim::Group{
group_type: modified_group.group_type,
nodes: SsbhArray::new()
};
for modified_node in &modified_group.nodes.elements{
let mut new_node = ssbh_lib::formats::anim::Node{
name: modified_node.name.clone(),
tracks: SsbhArray::new()
};
for modified_track in &modified_node.tracks.elements{
let new_track = ssbh_lib::formats::anim::TrackV2{
name: modified_track.name.clone(),
flags: modified_track.flags,
frame_count: modified_track.frame_count,
transform_flags: modified_track.transform_flags,
data_offset: current_offset as u32,
data_size: modified_track.data_size
};
let start_index = modified_track.data_offset as usize;
let end_index = (modified_track.data_offset as u64 + modified_track.data_size) as usize;
let modified_buffer = &buffer.elements[start_index..end_index];
new_buffer.elements.extend_from_slice(&modified_buffer);
current_offset += modified_track.data_size;
new_node.tracks.elements.push(new_track);
}
new_group.nodes.elements.push(new_node);
}
new_groups.elements.push(new_group);
}
}

// Now account for a case where the modified anim only contains one of either the Vis or Mat group,
// so the reference anim may contain the other group.
if let Anim::V20{groups, ..} | Anim::V21{groups, ..} = &reference_anim{
for reference_group in &groups.elements{
if reference_group.group_type == GroupType::Transform{
continue;
}
if modified_group_types.contains(&reference_group.group_type){
continue;
}
let mut new_group = ssbh_lib::formats::anim::Group{
group_type: reference_group.group_type,
nodes: SsbhArray::new()
};
for reference_node in &reference_group.nodes.elements{
let mut new_node = ssbh_lib::formats::anim::Node{
name: reference_node.name.clone(),
tracks: SsbhArray::new()
};
for reference_track in &reference_node.tracks.elements{
let new_track = ssbh_lib::formats::anim::TrackV2{
name: reference_track.name.clone(),
flags: reference_track.flags,
frame_count: reference_track.frame_count,
transform_flags: reference_track.transform_flags,
data_offset: current_offset as u32,
data_size: reference_track.data_size
};
let reference_buffer = reference_node_name_to_buffer.get(reference_node.name.to_str().unwrap()).unwrap();
new_buffer.elements.extend_from_slice(&reference_buffer);
current_offset += reference_track.data_size;
new_node.tracks.elements.push(new_track);
}
new_group.nodes.elements.push(new_node);
}
new_groups.elements.push(new_group);
}
}

/*
if let Anim::V20{groups, buffer, ..} | Anim::V21{groups, buffer, ..} = &modified_anim{
for modified_group in &groups.elements{
let mut new_group = ssbh_lib::formats::anim::Group{
group_type: modified_group.group_type,
nodes: SsbhArray::new()
};
for modified_node in &modified_group.nodes.elements{
let mut new_node = ssbh_lib::formats::anim::Node{
name: modified_node.name.clone(),
tracks: SsbhArray::new()
};
for modified_track in &modified_node.tracks.elements{
let reference_track = reference_node_name_to_track.get(modified_node.name.to_str().unwrap());
let new_track = match reference_track{
Some(reference_track) => {
ssbh_lib::formats::anim::TrackV2{
name: reference_track.name.clone(),
flags: reference_track.flags,
frame_count: reference_track.frame_count,
transform_flags: reference_track.transform_flags,
data_offset: current_offset as u32,
data_size: reference_track.data_size
}
},
None => {
ssbh_lib::formats::anim::TrackV2{
name: modified_track.name.clone(),
flags: modified_track.flags,
frame_count: modified_track.frame_count,
transform_flags: modified_track.transform_flags,
data_offset: current_offset as u32,
data_size: modified_track.data_size
}
}
};
if let Some(reference_track) = reference_track {
let reference_buffer = reference_node_name_to_buffer.get(modified_node.name.to_str().unwrap()).unwrap();
new_buffer.elements.extend_from_slice(&reference_buffer);
current_offset += reference_track.data_size;
} else {
let start_index = modified_track.data_offset as usize;
let end_index = (modified_track.data_offset as u64 + modified_track.data_size) as usize;
let modified_buffer = &buffer.elements[start_index..end_index];
new_buffer.elements.extend_from_slice(&modified_buffer);
current_offset += modified_track.data_size;
};
new_node.tracks.elements.push(new_track);
}
new_group.nodes.elements.push(new_node);
}
new_groups.elements.push(new_group);
}
}
*/
let new_anim = match reference_anim {
Anim::V20 {final_frame_index, unk1, unk2, name, .. } => {
Ok(Anim::V20 {
Expand Down
Binary file added test/c08attackstep2_modified.nuanmb
Binary file not shown.
Binary file added test/c08attackstep2_vanilla.nuanmb
Binary file not shown.

0 comments on commit be63293

Please sign in to comment.