Skip to content

Commit

Permalink
Add support for bod1acc.bin + updateInfoParam files
Browse files Browse the repository at this point in the history
  • Loading branch information
maxcabd authored Jul 15, 2024
1 parent c00d1b1 commit 3269737
Show file tree
Hide file tree
Showing 17 changed files with 533 additions and 56 deletions.
7 changes: 5 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,10 @@ nuccbin supports a number of in game nuccChunkBinary param / bin formats. All fo
| --- | --- | --- | --- |
| [accessoriesParam](https://github.com/maxcabd/nuccbin/blob/main/src/nucc_binary/accessories_param.rs) | ✔️ | ✔️ | `json` |
| [accessoryParam](https://github.com/maxcabd/nuccbin/blob/main/src/nucc_binary/accessory_param.rs) | ✔️ | ✔️ | `json` |
| [accessoryExceptionParam](https://github.com/maxcabd/nuccbin/blob/main/src/nucc_binary/accessory_exception_param.rs) | ✔️ | ✔️ | `json` |
| [animeSongBgmParam](https://github.com/maxcabd/nuccbin/blob/main/src/nucc_binary/anime_song_bgm_param.rs) | ✔️ | ✔️ | `json` |
| [anmofs](https://github.com/maxcabd/nuccbin/blob/main/src/nucc_binary/anm_offset.rs) | ✔️ | ✔️ | `json` |
| [bod1acc](https://github.com/maxcabd/nuccbin/blob/main/src/nucc_binary/bodacc.rs) | ✔️ | ✔️ | `json` |
| [characode](https://github.com/maxcabd/nuccbin/blob/main/src/nucc_binary/characode.rs) | ✔️ | ✔️ | `json` |
| [CharaPoseParam](https://github.com/maxcabd/nuccbin/blob/main/src/nucc_binary/chara_pose_param.rs) | ✔️ | ✔️ | `json` |
| [characterSelectParam](https://github.com/maxcabd/nuccbin/blob/main/src/nucc_binary/character_select_param.rs) | ✔️ | ✔️ | `json` |
Expand All @@ -23,7 +25,7 @@ nuccbin supports a number of in game nuccChunkBinary param / bin formats. All fo
| [costumeBreakParam](https://github.com/maxcabd/nuccbin/blob/main/src/nucc_binary/costume_break_param.rs) | ✔️ | ✔️ | `json` |
| [costumeParam](https://github.com/maxcabd/nuccbin/blob/main/src/nucc_binary/costume_param.rs) | ✔️ | ✔️ | `json` |
| [dds](https://github.com/maxcabd/nuccbin/blob/main/src/nucc_binary/dds.rs) | ✔️ | ✔️ | `dds` |
| [DictionaryCharacterParam](https://github.com/maxcabd/nuccbin/blob/main/src/nucc_binary/dictionary_character_param.rs) | ✔️ | ✔️ | `json` |
| [DictionaryCharacterParam](https://github.com/maxcabd/nuccbin/blob/main/src/nucc_binary/dictionary_character_param.rs) | ✔️ | ✔️ | `dds` |
| [DlcInfoParam](https://github.com/maxcabd/nuccbin/blob/main/src/nucc_binary/dlc_info_param.rs) | ✔️ | ✔️ | `json` |
| [effectprm](https://github.com/maxcabd/nuccbin/blob/main/src/nucc_binary/effectprm.rs) | ✔️ | ✔️ | `json` |
| [ev](https://github.com/maxcabd/nuccbin/blob/main/src/nucc_binary/ev.rs) | ✔️ | ✔️ | `json` |
Expand All @@ -40,6 +42,7 @@ nuccbin supports a number of in game nuccChunkBinary param / bin formats. All fo
| [staffRollTextParam](https://github.com/maxcabd/nuccbin/blob/main/src/nucc_binary/staff_roll_text_param.rs) | ✔️ || `json` |
| [supportActionParam](https://github.com/maxcabd/nuccbin/blob/main/src/nucc_binary/support_action_param.rs) | ✔️ | ✔️ | `json` |
| [supportSkillRecoverySpeedParam](https://github.com/maxcabd/nuccbin/blob/main/src/nucc_binary/support_skill_recovery_speed_param.rs) | ✔️ | ✔️ | `json` |
| [updateInfoParam](https://github.com/maxcabd/nuccbin/blob/main/src/nucc_binary/update_info_param.rs) | ✔️ | ✔️ | `json` |
| [xml](https://github.com/maxcabd/nuccbin/blob/main/src/nucc_binary/xml.rs) | ✔️ | ✔️ | `xml` |


Expand All @@ -53,5 +56,5 @@ Special thanks goes to several members including:
* [PortableProductions](https://www.youtube.com/@PortableProductions) for reversing some formats.
* [Kuroha Saenoki](https://www.youtube.com/@KurohaSaenoki) for reversing some formats.
* [Valant96](https://www.youtube.com/@valant96) for information on some formats.
* [Xact](https://www.youtube.com/channel/UCluz3KlVGPDYNnJhNvOW_AA) for reversing some formats.
* [Xact](https://www.youtube.com/@valant96) for reversing some formats.
* and [SutandoTsukai181](https://github.com/SutandoTsukai181) for his initial work on the tool.
10 changes: 9 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
use strum_macros::{EnumString, EnumIter, Display};
use regex::Regex;

pub mod args;
pub mod nucc_binary;

#[derive(Debug, Copy, Clone, EnumString, EnumIter, Display, PartialEq)]
#[derive(Debug, Copy, Clone, EnumString, EnumIter, Display, PartialEq, Hash, Eq)]
pub enum NuccBinaryType {
AccessoriesParam,
AccessoryExceptionParam,
AccessoryParam,
AnimeSongBgmParam,
Anmofs,
BodAcc,
#[strum(ascii_case_insensitive)]
Characode,
CharaPoseParam,
Expand All @@ -30,13 +33,15 @@ pub enum NuccBinaryType {
PlayerSettingParam,
PlayerIcon,
Png,
PrmBas,
PrmLoad,
ProhibitedSubstringParam,
SkillIndexSettingParam,
Snd,
StaffRollTextParam,
SupportActionParam,
SupportSkillRecoverySpeedParam,
UpdateInfoParam,
Xml,
}

Expand All @@ -49,6 +54,7 @@ impl NuccBinaryType {
NuccBinaryType::AccessoryParam => { Regex::new(r"(accessoryParam\.bin)$").unwrap() },
NuccBinaryType::AnimeSongBgmParam => { Regex::new(r"(animeSongBgmParam\.bin)$").unwrap() },
NuccBinaryType::Anmofs => { Regex::new(r"(anm_offset)").unwrap() },
NuccBinaryType::BodAcc => { Regex::new(r"(bod1acc\.bin)$").unwrap() },
NuccBinaryType::Characode => { Regex::new(r"(characode\.bin)$").unwrap() },
NuccBinaryType::CharaPoseParam => { Regex::new(r"(CharaPoseParam\.bin)$").unwrap() },
NuccBinaryType::CharacterSelectParam => { Regex::new(r"(characterSelectParam\.bin)$").unwrap() },
Expand All @@ -69,13 +75,15 @@ impl NuccBinaryType {
NuccBinaryType::PlayerSettingParam => { Regex::new(r"(playerSettingParam\.bin)$").unwrap() },
NuccBinaryType::PlayerIcon => { Regex::new(r"(player_icon\.bin)$").unwrap() },
NuccBinaryType::Png => { Regex::new(r"(\.png)$").unwrap() },
NuccBinaryType::PrmBas => { Regex::new(r"(prm_bas)").unwrap() },
NuccBinaryType::PrmLoad => { Regex::new(r"(prm_load\.bin)$").unwrap() },
NuccBinaryType::ProhibitedSubstringParam => { Regex::new(r"(prohibitedSubstringParam\.bin)$").unwrap() },
NuccBinaryType::SkillIndexSettingParam => { Regex::new(r"(skillIndexSettingParam\.bin)$").unwrap() },
NuccBinaryType::Snd => { Regex::new(r"(snd.*\.bin)$").unwrap() },
NuccBinaryType::StaffRollTextParam => { Regex::new(r"(staffRollTextParam\.bin)$").unwrap() },
NuccBinaryType::SupportActionParam => { Regex::new(r"(supportActionParam\.bin)$").unwrap() },
NuccBinaryType::SupportSkillRecoverySpeedParam => { Regex::new(r"(supportSkillRecoverySpeedParam\.bin)$").unwrap() },
NuccBinaryType::UpdateInfoParam => { Regex::new(r"(updateInfoParam\.bin)$").unwrap() }
NuccBinaryType::Xml => { Regex::new(r"(\.xml)$").unwrap() }
}
}
Expand Down
14 changes: 4 additions & 10 deletions src/nucc_binary/accessories_param.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,10 +64,7 @@ pub struct AccessoriesParam {
#[serde(skip)]
pub version: u32,

pub entry_count: u16,

#[serde(skip)]
pub unk0: u16,
pub entry_count: u32,

#[serde(skip)]
pub entry_ptr: u64,
Expand Down Expand Up @@ -104,9 +101,7 @@ impl From<&[u8]> for AccessoriesParam {
let size = reader.read_be::<u32>().unwrap();
let version = reader.read_le::<u32>().unwrap();

let entry_count = reader.read_le::<u16>().unwrap();
let unk0 = reader.read_le::<u16>().unwrap();

let entry_count = reader.read_le::<u32>().unwrap();
let entry_ptr = reader.read_le::<u64>().unwrap();

let mut entries = Vec::new();
Expand Down Expand Up @@ -143,7 +138,6 @@ impl From<&[u8]> for AccessoriesParam {
size,
version,
entry_count,
unk0,
entry_ptr,
entries
}
Expand All @@ -155,13 +149,13 @@ impl From<AccessoriesParam> for Vec<u8> {
fn from(mut accessories_param: AccessoriesParam) -> Self {
let mut writer = Cursor::new(Vec::new());

accessories_param.entry_count = accessories_param.entries.len() as u16; // Update entry count
accessories_param.entry_count = accessories_param.entries.len() as u32; // Update entry count

writer.write_be(&accessories_param.size).unwrap();
writer.write_le(&1000u32).unwrap(); // Write the version

writer.write_le(&accessories_param.entry_count).unwrap();
writer.write_le(&accessories_param.unk0).unwrap();


writer.write_le(&8u64).unwrap(); // Write the ptr to the entries

Expand Down
3 changes: 1 addition & 2 deletions src/nucc_binary/anm_offset.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
use binrw::{binrw, BinReaderExt, BinWriterExt, NullString};
use binrw::io::{Cursor, Seek, SeekFrom};
use binrw::binrw;
use serde::{Serialize, Deserialize};


Expand Down
197 changes: 197 additions & 0 deletions src/nucc_binary/bodacc.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,197 @@
use binrw::{binrw, BinReaderExt, BinWriterExt, NullString};
use binrw::io::{Cursor, Seek, SeekFrom};
use serde::{Serialize, Deserialize};


use super::{NuccBinaryParsed, NuccBinaryType};

const HEADER_SIZE: usize = 0x14; // Size of NUCC Binary headers


// Format reversed by Zinogre344
#[allow(non_snake_case)]
#[binrw]
#[derive(Serialize, Deserialize, Debug)]
pub struct Entry {
#[serde(skip)]
pub accessory_ptr: u64,

#[serde(skip)]
#[brw(pad_after = 8)]
pub bone_name_ptr: u64,

#[serde(skip)]
#[brw(pad_after = 12)]
pub accessory_location_ptr: u64,

pub location: [f32; 3],

#[brw(pad_after = 12)]
pub rotation: [f32; 3],

#[brw(pad_after = 4)]
pub scale: [f32; 3],


#[brw(ignore)]
#[bw(map = |x| x.parse::<u8>().unwrap())]
pub accessory: String,

#[brw(ignore)]
#[bw(map = |x| x.parse::<u8>().unwrap())]
pub bone_name: String,

#[brw(ignore)]
#[bw(map = |x| x.parse::<u8>().unwrap())]
pub accessory_location: String,
}

#[binrw]
#[derive(Serialize, Deserialize, Debug)]
pub struct BodAcc {
#[serde(skip)]
pub size: u32,

#[serde(skip)]
pub version: u32,

pub entry_count: u32,

#[serde(skip)]
pub entry_ptr: u64,

#[br(count = entry_count)]
pub entries: Vec<Entry>
}


impl NuccBinaryParsed for BodAcc {
fn binary_type(&self) -> NuccBinaryType {
NuccBinaryType::BodAcc
}

fn extension(&self) -> String {
String::from(".json")
}

fn serialize(&self) -> Vec<u8> {
serde_json::to_string_pretty(self).unwrap().into()
}

fn deserialize(data: &[u8]) -> Self
where
Self: Sized,
{
serde_json::from_slice(data).unwrap()
}
}

impl From<&[u8]> for BodAcc {
fn from(data: &[u8]) -> Self {
let mut reader = Cursor::new(data);

let size = reader.read_be::<u32>().unwrap();
let version = reader.read_le::<u32>().unwrap();

let entry_count = reader.read_le::<u32>().unwrap();
let entry_ptr = reader.read_le::<u64>().unwrap();

let mut entries = Vec::new();
entries.reserve_exact(entry_count as usize); // Make sure we have enough space to avoid reallocations

for _ in 0..entry_count as usize {
let entry = reader.read_le::<Entry>().unwrap();
entries.push(entry);
}


fn read_string_from_ptr(reader: &mut Cursor<&[u8]>, ptr: u64, curent_offset: u64) -> String {
if ptr != 0 {
reader.seek(SeekFrom::Start(curent_offset as u64)).unwrap();
reader.seek(SeekFrom::Current(ptr as i64)).unwrap();
reader.read_be::<NullString>().unwrap().to_string()
} else {
String::from("")
}
}

for (current_offset, entry) in entries
.iter_mut()
.enumerate()
.map(|(i, e)| (((0x60 * i + HEADER_SIZE) as u64, e)))
{
entry.accessory = read_string_from_ptr(&mut reader, entry.accessory_ptr, current_offset);
entry.bone_name = read_string_from_ptr(&mut reader, entry.bone_name_ptr, current_offset + 0x8);
entry.accessory_location = read_string_from_ptr(&mut reader, entry.accessory_location_ptr, current_offset + 0x18);
}

BodAcc {
size,
version,
entry_count,
entry_ptr,
entries
}

}

}

impl From<BodAcc> for Vec<u8> {
fn from(mut bodacc: BodAcc) -> Self {
let mut writer = Cursor::new(Vec::new());

bodacc.entry_count = bodacc.entries.len() as u32; // Update entry count

writer.write_be(&bodacc.size).unwrap();
writer.write_le(&1000u32).unwrap(); // Write the version

writer.write_le(&bodacc.entry_count).unwrap();


writer.write_le(&8u64).unwrap(); // Write the ptr to the entries


writer.write_le(&bodacc.entries).unwrap();

fn write_ptr_to_string(
writer: &mut Cursor<Vec<u8>>,
string: &String,
current_offset: u64,
adjustment: u64,
) {
if !string.is_empty() {
writer.seek(SeekFrom::End(0)).unwrap();
let string_pos = writer.seek(SeekFrom::End(0)).unwrap();
writer.write_be::<NullString>(&NullString::from(string.clone())).unwrap();

// Align to 8 bytes
let pos = writer.seek(SeekFrom::Current(0)).unwrap() - string_pos;
if 8 - (pos % 8) != 8 {
writer.write_le::<Vec<u8>>(&vec![0; 8 - (pos % 8) as usize]).unwrap();
}

writer.seek(SeekFrom::Start((current_offset + adjustment) as u64)).unwrap();
writer.write_le::<u64>(&(string_pos - current_offset - &adjustment)).unwrap();

}
}
for (current_offset, entry) in bodacc.entries
.iter_mut()
.enumerate()
.map(|(i, e)| (((0x60 * i + HEADER_SIZE) as u64, e)))
{

write_ptr_to_string(&mut writer, &entry.accessory, current_offset as u64, 0x0);
write_ptr_to_string(&mut writer, &entry.bone_name, current_offset as u64, 0x8);
write_ptr_to_string(&mut writer, &entry.accessory_location, current_offset as u64, 0x18);
}

// Go to the start of buffer and write the size
writer.set_position(0);
writer.write_be::<u32>(&((writer.get_ref().len() - 4) as u32)).unwrap();

writer.into_inner()

}
}
Loading

0 comments on commit 3269737

Please sign in to comment.