1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
pub mod fighter_data;
pub mod fighter_data_common;
use byteorder::{BigEndian, ReadBytesExt};
use crate::script::Script;
use crate::script;
use crate::util;
use fighter_data::ArcFighterData;
use fighter_data_common::ArcFighterDataCommon;
pub(crate) fn arc_sakurai(data: &[u8]) -> ArcSakurai {
let size = (&data[0x00..]).read_i32::<BigEndian>().unwrap();
let lookup_entry_offset = (&data[0x04..]).read_i32::<BigEndian>().unwrap();
let lookup_entry_count = (&data[0x08..]).read_i32::<BigEndian>().unwrap();
let section_count = (&data[0x0c..]).read_i32::<BigEndian>().unwrap();
let external_subroutine_count = (&data[0x10..]).read_i32::<BigEndian>().unwrap();
let lookup_entries_offset = ARC_SAKURAI_HEADER_SIZE + lookup_entry_offset as usize;
let sections_offset = lookup_entries_offset + lookup_entry_count as usize * 4;
let external_subroutines_offset = sections_offset + section_count as usize * ARC_SAKURAI_SECTION_HEADER_SIZE;
let string_table_offset = external_subroutines_offset + external_subroutine_count as usize * EXTERNAL_SUBROUTINE_SIZE;
let parent_data = &data[ARC_SAKURAI_HEADER_SIZE ..];
let mut lookup_entries = vec!();
for i in 0..lookup_entry_count {
let offset = lookup_entry_offset as usize + i as usize * 4;
let entry_offset = (&data[offset..]).read_i32::<BigEndian>().unwrap();
lookup_entries.push(entry_offset);
}
let mut external_subroutines = vec!();
for i in 0..external_subroutine_count {
let mut offsets = vec!();
let offset = external_subroutines_offset + i as usize * EXTERNAL_SUBROUTINE_SIZE;
let mut offset_linked_list = (&data[offset..]).read_i32::<BigEndian>().unwrap();
let string_offset = (&data[offset + 4 ..]).read_i32::<BigEndian>().unwrap();
let name = String::from(util::parse_str(&data[string_table_offset + string_offset as usize ..]).unwrap());
while offset_linked_list > 0 && offset_linked_list < size {
offsets.push(offset_linked_list);
offset_linked_list = (&data[ARC_SAKURAI_HEADER_SIZE + offset_linked_list as usize..]).read_i32::<BigEndian>().unwrap();
}
external_subroutines.push(ExternalSubroutine { name, offsets });
}
let mut sections = vec!();
for i in 0..section_count {
let offset = sections_offset + i as usize * ARC_SAKURAI_SECTION_HEADER_SIZE;
let data_offset = (&data[offset ..]).read_i32::<BigEndian>().unwrap();
let string_offset = (&data[offset + 4 ..]).read_i32::<BigEndian>().unwrap();
let name = String::from(util::parse_str(&data[string_table_offset + string_offset as usize ..]).unwrap());
let data = &data[ARC_SAKURAI_HEADER_SIZE + data_offset as usize..];
let mut section_data = match name.as_str() {
"data" => SectionData::FighterData(fighter_data::arc_fighter_data(parent_data, data)),
"dataCommon" => SectionData::FighterDataCommon(fighter_data_common::arc_fighter_data_common(parent_data, data)),
_ => SectionData::None
};
if name.starts_with("gameAnimCmd_") || name.starts_with("effectAnimCmd_") || name.starts_with("statusAnimCmdGroup_") || name.starts_with("statusAnimCmdPre_") {
section_data = SectionData::Script(SectionScript {
name: name.clone(),
script: script::new_script(parent_data, data_offset),
});
}
sections.push(ArcSakuraiSection { name, data: section_data });
}
let mut all_scripts = vec!();
let mut all_scripts_sub = vec!();
for section in §ions {
match §ion.data {
SectionData::FighterData(data) => {
all_scripts.push(data.entry_actions.as_slice());
all_scripts.push(data.exit_actions.as_slice());
all_scripts.push(data.subaction_main.as_slice());
all_scripts.push(data.subaction_gfx.as_slice());
all_scripts.push(data.subaction_sfx.as_slice());
all_scripts.push(data.subaction_other.as_slice());
}
SectionData::FighterDataCommon(data_common) => {
all_scripts.push(data_common.entry_actions.as_slice());
all_scripts.push(data_common.exit_actions.as_slice());
}
SectionData::Script(script) => {
all_scripts_sub.push(script.script.clone());
}
_ => { }
}
}
all_scripts.push(all_scripts_sub.as_slice());
let ignore_origins: Vec<_> = external_subroutines.iter().flat_map(|x| x.offsets.iter().cloned()).collect();
let mut fragment_scripts = script::fragment_scripts(parent_data, all_scripts.as_slice(), ignore_origins.as_slice());
fragment_scripts.sort_by_key(|x| x.offset);
ArcSakurai { lookup_entries, sections, external_subroutines, fragment_scripts }
}
const ARC_SAKURAI_HEADER_SIZE: usize = 0x20;
#[derive(Debug)]
pub struct ArcSakurai {
lookup_entries: Vec<i32>,
pub sections: Vec<ArcSakuraiSection>,
pub external_subroutines: Vec<ExternalSubroutine>,
pub fragment_scripts: Vec<Script>,
}
const ARC_SAKURAI_SECTION_HEADER_SIZE: usize = 0x8;
#[derive(Debug)]
pub struct ArcSakuraiSection {
pub name: String,
pub data: SectionData,
}
#[derive(Debug)]
pub enum SectionData {
FighterData (ArcFighterData),
FighterDataCommon (ArcFighterDataCommon),
Script (SectionScript),
None,
}
#[derive(Debug)]
pub struct SectionScript {
pub name: String,
pub script: Script,
}
const EXTERNAL_SUBROUTINE_SIZE: usize = 0x8;
#[derive(Debug)]
pub struct ExternalSubroutine {
pub name: String,
pub offsets: Vec<i32>,
}