1use crate::{ArchiveError, BinArchive, BinArchiveReader, BinArchiveWriter};
2
3type Result<T> = std::result::Result<T, ArchiveError>;
4
5#[derive(Default, Debug, Clone)]
7pub struct AssetSpec {
8 pub name: Option<String>,
9 pub conditional1: Option<String>,
10 pub conditional2: Option<String>,
11 pub body_model: Option<String>,
12 pub body_texture: Option<String>,
13 pub head_model: Option<String>,
14 pub head_texture: Option<String>,
15 pub hair_model: Option<String>,
16
17 pub hair_texture: Option<String>,
18 pub outer_clothing_model: Option<String>,
19 pub outer_clothing_texture: Option<String>,
20 pub underwear_model: Option<String>,
21 pub underwear_texture: Option<String>,
22 pub mount_model: Option<String>,
23 pub mount_texture: Option<String>,
24 pub mount_outer_clothing_model: Option<String>,
25
26 pub mount_outer_clothing_texture: Option<String>,
27 pub weapon_model_dual: Option<String>,
28 pub weapon_model: Option<String>,
29 pub skeleton: Option<String>,
30 pub mount_skeleton: Option<String>,
31 pub accessory1_model: Option<String>,
32 pub accessory1_texture: Option<String>,
33 pub accessory2_model: Option<String>,
34
35 pub accessory2_texture: Option<String>,
36 pub accessory3_model: Option<String>,
37 pub accessory3_texture: Option<String>,
38 pub attack_animation: Option<String>,
39 pub attack_animation2: Option<String>,
40 pub visual_effect: Option<String>,
41 pub hid: Option<String>,
42 pub footstep_sound: Option<String>,
43
44 pub clothing_sound: Option<String>,
45 pub voice: Option<String>,
46 pub hair_color: [u8; 4],
47 pub use_hair_color: bool,
48 pub skin_color: [u8; 4],
49 pub use_skin_color: bool,
50 pub weapon_trail_color: [u8; 4],
51 pub use_weapon_trail_color: bool,
52 pub model_size: f32,
53 pub use_model_size: bool,
54 pub head_size: f32,
55 pub use_head_size: bool,
56 pub pupil_y: f32,
57 pub use_pupil_y: bool,
58
59 pub unk3: u32,
60 pub use_unk3: bool,
61 pub unk4: u32,
62 pub use_unk4: bool,
63 pub unk5: u32,
64 pub use_unk5: bool,
65 pub unk6: u32,
66 pub use_unk6: bool,
67 pub on_hit_effect: u32,
68 pub use_on_hit_effect: bool,
69 pub unk7: u32,
70 pub use_unk7: bool,
71 pub unk8: u32,
72 pub use_unk8: bool,
73 pub unk9: u32,
74 pub use_unk9: bool,
75
76 pub unk10: u32,
77 pub use_unk10: bool,
78 pub unk11: u32,
79 pub use_unk11: bool,
80 pub unk12: u32,
81 pub use_unk12: bool,
82 pub unk13: u32,
83 pub use_unk13: bool,
84}
85
86fn read_flag_str(
87 reader: &mut BinArchiveReader,
88 flags: &[u8],
89 index: usize,
90) -> Result<Option<String>> {
91 let byte = index / 8;
92 let bit_index = index % 8;
93 if byte >= flags.len() || (flags[byte] & (1 << bit_index)) == 0 {
94 Ok(None)
95 } else {
96 reader.read_string()
97 }
98}
99
100fn write_flag_str(writer: &mut BinArchiveWriter, value: &Option<String>) -> Result<()> {
101 match value {
102 Some(value) => {
103 writer.write_string(Some(value))?;
104 }
105 None => {}
106 }
107 Ok(())
108}
109
110fn read_color(reader: &mut BinArchiveReader) -> Result<[u8; 4]> {
111 let mut arr: [u8; 4] = [0, 0, 0, 0];
112 let bytes = reader.read_bytes(4)?;
113 arr.copy_from_slice(&bytes);
114 Ok(arr)
115}
116
117fn count_bits(byte: u8) -> usize {
118 let mut count = 0;
119 for i in 0..8 {
120 if (byte & (1 << i)) != 0 {
121 count += 1;
122 }
123 }
124 count
125}
126
127impl AssetSpec {
128 pub fn new() -> Self {
129 AssetSpec {
130 ..Default::default()
131 }
132 }
133
134 pub fn from_stream(reader: &mut BinArchiveReader) -> Result<Self> {
135 let mut flag_count = 3;
136 let raw = reader.read_u8()?;
137 if (raw & 0b1) == 1 {
138 flag_count += 4;
139 }
140 let mut flags = vec![raw];
141 flags.extend(reader.read_bytes(flag_count)?);
142
143 let mut spec = AssetSpec::new();
144 spec.name = reader.read_string()?;
145 spec.conditional1 = read_flag_str(reader, &flags, 1)?;
146 spec.conditional2 = read_flag_str(reader, &flags, 2)?;
147 spec.body_model = read_flag_str(reader, &flags, 3)?;
148 spec.body_texture = read_flag_str(reader, &flags, 4)?;
149 spec.head_model = read_flag_str(reader, &flags, 5)?;
150 spec.head_texture = read_flag_str(reader, &flags, 6)?;
151 spec.hair_model = read_flag_str(reader, &flags, 7)?;
152
153 spec.hair_texture = read_flag_str(reader, &flags, 8)?;
154 spec.outer_clothing_model = read_flag_str(reader, &flags, 9)?;
155 spec.outer_clothing_texture = read_flag_str(reader, &flags, 10)?;
156 spec.underwear_model = read_flag_str(reader, &flags, 11)?;
157 spec.underwear_texture = read_flag_str(reader, &flags, 12)?;
158 spec.mount_model = read_flag_str(reader, &flags, 13)?;
159 spec.mount_texture = read_flag_str(reader, &flags, 14)?;
160 spec.mount_outer_clothing_model = read_flag_str(reader, &flags, 15)?;
161
162 spec.mount_outer_clothing_texture = read_flag_str(reader, &flags, 16)?;
163 spec.weapon_model_dual = read_flag_str(reader, &flags, 17)?;
164 spec.weapon_model = read_flag_str(reader, &flags, 18)?;
165 spec.skeleton = read_flag_str(reader, &flags, 19)?;
166 spec.mount_skeleton = read_flag_str(reader, &flags, 20)?;
167 spec.accessory1_model = read_flag_str(reader, &flags, 21)?;
168 spec.accessory1_texture = read_flag_str(reader, &flags, 22)?;
169 spec.accessory2_model = read_flag_str(reader, &flags, 23)?;
170
171 spec.accessory2_texture = read_flag_str(reader, &flags, 24)?;
172 spec.accessory3_model = read_flag_str(reader, &flags, 25)?;
173 spec.accessory3_texture = read_flag_str(reader, &flags, 26)?;
174 spec.attack_animation = read_flag_str(reader, &flags, 27)?;
175 spec.attack_animation2 = read_flag_str(reader, &flags, 28)?;
176 spec.visual_effect = read_flag_str(reader, &flags, 29)?;
177 spec.hid = read_flag_str(reader, &flags, 30)?;
178 spec.footstep_sound = read_flag_str(reader, &flags, 31)?;
179
180 if flag_count > 3 {
181 spec.clothing_sound = read_flag_str(reader, &flags, 32)?;
182 spec.voice = read_flag_str(reader, &flags, 33)?;
183 if (flags[4] & 0b100) != 0 {
184 spec.use_hair_color = true;
185 spec.hair_color = read_color(reader)?;
186 }
187 if (flags[4] & 0b1000) != 0 {
188 spec.use_skin_color = true;
189 spec.skin_color = read_color(reader)?;
190 }
191 if (flags[4] & 0b10000) != 0 {
192 spec.use_weapon_trail_color = true;
193 spec.weapon_trail_color = read_color(reader)?;
194 }
195 if (flags[4] & 0b100000) != 0 {
196 spec.use_model_size = true;
197 spec.model_size = reader.read_f32()?;
198 }
199 if (flags[4] & 0b1000000) != 0 {
200 spec.use_head_size = true;
201 spec.head_size = reader.read_f32()?;
202 }
203 if (flags[4] & 0b10000000) != 0 {
204 spec.use_pupil_y = true;
205 spec.pupil_y = reader.read_f32()?;
206 }
207 if (flags[5] & 0b1) != 0 {
208 spec.unk3 = reader.read_u32()?;
209 spec.use_unk3 = true;
210 }
211 if (flags[5] & 0b10) != 0 {
212 spec.unk4 = reader.read_u32()?;
213 spec.use_unk4 = true;
214 }
215 if (flags[5] & 0b100) != 0 {
216 spec.unk5 = reader.read_u32()?;
217 spec.use_unk5 = true;
218 }
219 if (flags[5] & 0b1000) != 0 {
220 spec.unk6 = reader.read_u32()?;
221 spec.use_unk6 = true;
222 }
223 if (flags[5] & 0b10000) != 0 {
224 spec.on_hit_effect = reader.read_u32()?;
225 spec.use_on_hit_effect = true;
226 }
227 if (flags[5] & 0b100000) != 0 {
228 spec.unk7 = reader.read_u32()?;
229 spec.use_unk7 = true;
230 }
231 if (flags[5] & 0b1000000) != 0 {
232 spec.unk8 = reader.read_u32()?;
233 spec.use_unk8 = true;
234 }
235 if (flags[5] & 0b10000000) != 0 {
236 spec.unk9 = reader.read_u32()?;
237 spec.use_unk9 = true;
238 }
239 if (flags[6] & 0b1) != 0 {
240 spec.unk10 = reader.read_u32()?;
241 spec.use_unk10 = true;
242 }
243 if (flags[6] & 0b10) != 0 {
244 spec.unk11 = reader.read_u32()?;
245 spec.use_unk11 = true;
246 }
247 if (flags[6] & 0b100) != 0 {
248 spec.unk12 = reader.read_u32()?;
249 spec.use_unk12 = true;
250 }
251 if (flags[6] & 0b1000) != 0 {
252 spec.unk13 = reader.read_u32()?;
253 spec.use_unk13 = true;
254 }
255 }
256
257 Ok(spec)
258 }
259
260 fn compute_flags(&self) -> (Vec<u8>, usize) {
261 let mut flags: Vec<u8> = vec![0; 8];
262 flags[0] |= if self.conditional1.is_none() { 0 } else { 0b10 };
263 flags[0] |= if self.conditional2.is_none() {
264 0
265 } else {
266 0b100
267 };
268 flags[0] |= if self.body_model.is_none() { 0 } else { 0b1000 };
269 flags[0] |= if self.body_texture.is_none() {
270 0
271 } else {
272 0b10000
273 };
274 flags[0] |= if self.head_model.is_none() {
275 0
276 } else {
277 0b100000
278 };
279 flags[0] |= if self.head_texture.is_none() {
280 0
281 } else {
282 0b1000000
283 };
284 flags[0] |= if self.hair_model.is_none() {
285 0
286 } else {
287 0b10000000
288 };
289
290 flags[1] |= if self.hair_texture.is_none() { 0 } else { 0b1 };
291 flags[1] |= if self.outer_clothing_model.is_none() {
292 0
293 } else {
294 0b10
295 };
296 flags[1] |= if self.outer_clothing_texture.is_none() {
297 0
298 } else {
299 0b100
300 };
301 flags[1] |= if self.underwear_model.is_none() {
302 0
303 } else {
304 0b1000
305 };
306 flags[1] |= if self.underwear_texture.is_none() {
307 0
308 } else {
309 0b10000
310 };
311 flags[1] |= if self.mount_model.is_none() {
312 0
313 } else {
314 0b100000
315 };
316 flags[1] |= if self.mount_texture.is_none() {
317 0
318 } else {
319 0b1000000
320 };
321 flags[1] |= if self.mount_outer_clothing_model.is_none() {
322 0
323 } else {
324 0b10000000
325 };
326
327 flags[2] |= if self.mount_outer_clothing_texture.is_none() {
328 0
329 } else {
330 0b1
331 };
332 flags[2] |= if self.weapon_model_dual.is_none() {
333 0
334 } else {
335 0b10
336 };
337 flags[2] |= if self.weapon_model.is_none() {
338 0
339 } else {
340 0b100
341 };
342 flags[2] |= if self.skeleton.is_none() { 0 } else { 0b1000 };
343 flags[2] |= if self.mount_skeleton.is_none() {
344 0
345 } else {
346 0b10000
347 };
348 flags[2] |= if self.accessory1_model.is_none() {
349 0
350 } else {
351 0b100000
352 };
353 flags[2] |= if self.accessory1_texture.is_none() {
354 0
355 } else {
356 0b1000000
357 };
358 flags[2] |= if self.accessory2_model.is_none() {
359 0
360 } else {
361 0b10000000
362 };
363
364 flags[3] |= if self.accessory2_texture.is_none() {
365 0
366 } else {
367 0b1
368 };
369 flags[3] |= if self.accessory3_model.is_none() {
370 0
371 } else {
372 0b10
373 };
374 flags[3] |= if self.accessory3_texture.is_none() {
375 0
376 } else {
377 0b100
378 };
379 flags[3] |= if self.attack_animation.is_none() {
380 0
381 } else {
382 0b1000
383 };
384 flags[3] |= if self.attack_animation2.is_none() {
385 0
386 } else {
387 0b10000
388 };
389 flags[3] |= if self.visual_effect.is_none() {
390 0
391 } else {
392 0b100000
393 };
394 flags[3] |= if self.hid.is_none() { 0 } else { 0b1000000 };
395 flags[3] |= if self.footstep_sound.is_none() {
396 0
397 } else {
398 0b10000000
399 };
400
401 flags[4] |= if self.clothing_sound.is_none() {
402 0
403 } else {
404 0b1
405 };
406 flags[4] |= if self.voice.is_none() { 0 } else { 0b10 };
407 flags[4] |= if !self.use_hair_color { 0 } else { 0b100 };
408 flags[4] |= if !self.use_skin_color { 0 } else { 0b1000 };
409 flags[4] |= if !self.use_weapon_trail_color {
410 0
411 } else {
412 0b10000
413 };
414 flags[4] |= if !self.use_model_size { 0 } else { 0b100000 };
415 flags[4] |= if !self.use_head_size { 0 } else { 0b1000000 };
416 flags[4] |= if !self.use_pupil_y { 0 } else { 0b10000000 };
417
418 flags[5] |= if !self.use_unk3 { 0 } else { 0b1 };
419 flags[5] |= if !self.use_unk4 { 0 } else { 0b10 };
420 flags[5] |= if !self.use_unk5 { 0 } else { 0b100 };
421 flags[5] |= if !self.use_unk6 { 0 } else { 0b1000 };
422 flags[5] |= if !self.use_on_hit_effect { 0 } else { 0b10000 };
423 flags[5] |= if !self.use_unk7 { 0 } else { 0b100000 };
424 flags[5] |= if !self.use_unk8 { 0 } else { 0b1000000 };
425 flags[5] |= if !self.use_unk9 { 0 } else { 0b10000000 };
426
427 flags[6] |= if !self.use_unk10 { 0 } else { 0b1 };
428 flags[6] |= if !self.use_unk11 { 0 } else { 0b10 };
429 flags[6] |= if !self.use_unk12 { 0 } else { 0b100 };
430 flags[6] |= if !self.use_unk13 { 0 } else { 0b1000 };
431
432 if flags[4] == 0 && flags[5] == 0 && flags[6] == 0 {
433 flags.resize(4, 0);
434 }
435 let mut size = flags.len() + 4;
436 for flag in &flags {
437 size += count_bits(*flag) * 4;
438 }
439 if flags.len() > 4 {
440 flags[0] |= 1;
441 }
442 (flags, size)
443 }
444
445 pub fn append(&self, archive: &mut BinArchive) -> Result<()> {
446 let (flags, size) = self.compute_flags();
447 let address = archive.size();
448 archive.allocate_at_end(size);
449 let mut writer = BinArchiveWriter::new(archive, address);
450 writer.write_bytes(&flags)?;
451 writer.write_string(self.name.as_deref())?;
452
453 write_flag_str(&mut writer, &self.conditional1)?;
454 write_flag_str(&mut writer, &self.conditional2)?;
455 write_flag_str(&mut writer, &self.body_model)?;
456 write_flag_str(&mut writer, &self.body_texture)?;
457 write_flag_str(&mut writer, &self.head_model)?;
458 write_flag_str(&mut writer, &self.head_texture)?;
459 write_flag_str(&mut writer, &self.hair_model)?;
460
461 write_flag_str(&mut writer, &self.hair_texture)?;
462 write_flag_str(&mut writer, &self.outer_clothing_model)?;
463 write_flag_str(&mut writer, &self.outer_clothing_texture)?;
464 write_flag_str(&mut writer, &self.underwear_model)?;
465 write_flag_str(&mut writer, &self.underwear_texture)?;
466 write_flag_str(&mut writer, &self.mount_model)?;
467 write_flag_str(&mut writer, &self.mount_texture)?;
468 write_flag_str(&mut writer, &self.mount_outer_clothing_model)?;
469
470 write_flag_str(&mut writer, &self.mount_outer_clothing_texture)?;
471 write_flag_str(&mut writer, &self.weapon_model_dual)?;
472 write_flag_str(&mut writer, &self.weapon_model)?;
473 write_flag_str(&mut writer, &self.skeleton)?;
474 write_flag_str(&mut writer, &self.mount_skeleton)?;
475 write_flag_str(&mut writer, &self.accessory1_model)?;
476 write_flag_str(&mut writer, &self.accessory1_texture)?;
477 write_flag_str(&mut writer, &self.accessory2_model)?;
478
479 write_flag_str(&mut writer, &self.accessory2_texture)?;
480 write_flag_str(&mut writer, &self.accessory3_model)?;
481 write_flag_str(&mut writer, &self.accessory3_texture)?;
482 write_flag_str(&mut writer, &self.attack_animation)?;
483 write_flag_str(&mut writer, &self.attack_animation2)?;
484 write_flag_str(&mut writer, &self.visual_effect)?;
485 write_flag_str(&mut writer, &self.hid)?;
486 write_flag_str(&mut writer, &self.footstep_sound)?;
487
488 if flags.len() > 4 {
489 write_flag_str(&mut writer, &self.clothing_sound)?;
490 write_flag_str(&mut writer, &self.voice)?;
491 if self.use_hair_color {
492 writer.write_bytes(&self.hair_color)?;
493 }
494 if self.use_skin_color {
495 writer.write_bytes(&self.skin_color)?;
496 }
497 if self.use_weapon_trail_color {
498 writer.write_bytes(&self.weapon_trail_color)?;
499 }
500 if self.use_model_size {
501 writer.write_f32(self.model_size)?;
502 }
503 if self.use_head_size {
504 writer.write_f32(self.head_size)?;
505 }
506 if self.use_pupil_y {
507 writer.write_f32(self.pupil_y)?;
508 }
509 if self.use_unk3 {
510 writer.write_u32(self.unk3)?;
511 }
512 if self.use_unk4 {
513 writer.write_u32(self.unk4)?;
514 }
515 if self.use_unk5 {
516 writer.write_u32(self.unk5)?;
517 }
518 if self.use_unk6 {
519 writer.write_u32(self.unk6)?;
520 }
521 if self.use_on_hit_effect {
522 writer.write_u32(self.on_hit_effect)?;
523 }
524 if self.use_unk7 {
525 writer.write_u32(self.unk7)?;
526 }
527 if self.use_unk8 {
528 writer.write_u32(self.unk8)?;
529 }
530 if self.use_unk9 {
531 writer.write_u32(self.unk9)?;
532 }
533 if self.use_unk10 {
534 writer.write_u32(self.unk10)?;
535 }
536 if self.use_unk11 {
537 writer.write_u32(self.unk11)?;
538 }
539 if self.use_unk12 {
540 writer.write_u32(self.unk12)?;
541 }
542 if self.use_unk13 {
543 writer.write_u32(self.unk13)?;
544 }
545 }
546 Ok(())
547 }
548}
549
550pub struct AssetBinary {
551 pub flags: u32,
552 pub specs: Vec<AssetSpec>,
553}
554
555impl AssetBinary {
556 pub fn new() -> Self {
557 AssetBinary { flags: 0, specs: Vec::new() }
558 }
559
560 pub fn from_archive(archive: &BinArchive) -> Result<Self> {
561 let mut binary = AssetBinary::new();
562 let mut reader = BinArchiveReader::new(archive, 0);
563 binary.flags = reader.read_u32()?;
564
565 let mut error = false;
567 while !error {
568 match AssetSpec::from_stream(&mut reader) {
569 Ok(spec) => {
570 binary.specs.push(spec);
571 }
572 Err(_) => {
573 error = true;
574 }
575 }
576 }
577 Ok(binary)
578 }
579
580 pub fn serialize(&self) -> Result<Vec<u8>> {
581 let mut archive = BinArchive::new();
582 archive.allocate_at_end(4);
583 archive.write_u32(0, self.flags)?;
584 for spec in &self.specs {
585 spec.append(&mut archive)?;
586 }
587 archive.allocate_at_end(4);
588 archive.serialize()
589 }
590}
591
592#[cfg(test)]
593mod test {
594 use super::*;
595 use crate::utils::load_test_file;
596
597 #[test]
598 fn round_trip() {
599 let file = load_test_file("AssetBinary_Test.bin");
600 let archive = BinArchive::from_bytes(&file).unwrap();
601 let asset_binary = AssetBinary::from_archive(&archive);
602 assert!(asset_binary.is_ok());
603 let asset_binary = asset_binary.unwrap();
604 let bytes = asset_binary.serialize().unwrap();
605 assert_eq!(file, bytes);
606 }
607}