xc3_lib/bc/
skdy.rs

1use std::{cell::RefCell, rc::Rc};
2
3use crate::{parse_ptr64, parse_string_ptr64};
4use binrw::{BinRead, binread};
5use xc3_write::{
6    Xc3Write, Xc3WriteOffsets,
7    strings::{StringSectionUniqueSorted, WriteOptions},
8};
9
10use super::{BcList, BcList2, BcListN};
11
12// TODO: skeleton dynamics?
13#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
14#[derive(Debug, BinRead, Xc3Write, Xc3WriteOffsets, PartialEq, Clone)]
15#[br(magic(b"SKDY"))]
16#[xc3(magic(b"SKDY"))]
17pub struct Skdy {
18    #[br(parse_with = parse_ptr64)]
19    #[xc3(offset(u64))]
20    pub dynamics: Dynamics,
21}
22
23#[binread]
24#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
25#[derive(Debug, Xc3Write, PartialEq, Clone)]
26pub struct Dynamics {
27    pub unk1: BcList<()>,
28    pub unk2: u64,
29
30    #[br(temp, restore_position)]
31    offset: u64,
32
33    #[br(parse_with = parse_ptr64)]
34    #[xc3(offset(u64))]
35    pub unk3: DynamicsUnk1,
36
37    #[br(args_raw(offset))]
38    pub inner: DynamicsInner,
39}
40
41#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
42#[derive(Debug, BinRead, Xc3Write, PartialEq, Clone)]
43#[br(import_raw(size: u64))]
44pub enum DynamicsInner {
45    // XC1 and XC2 have 88 total bytes.
46    #[br(pre_assert(size == 88))]
47    Unk1(DynamicsInner1),
48
49    // XC3 has 96 total bytes.
50    #[br(pre_assert(size == 96))]
51    Unk2(DynamicsInner2),
52}
53
54#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
55#[derive(Debug, BinRead, Xc3Write, PartialEq, Clone)]
56pub struct DynamicsInner1 {
57    #[br(parse_with = parse_ptr64)]
58    #[xc3(offset(u64), align(16, 0xff))]
59    pub unk1: Option<DynamicsUnk2Legacy>,
60}
61
62#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
63#[derive(Debug, BinRead, Xc3Write, PartialEq, Clone)]
64pub struct DynamicsInner2 {
65    #[br(parse_with = parse_ptr64)]
66    #[xc3(offset(u64))]
67    pub unk1: Option<DynamicsUnk2>,
68
69    #[br(parse_with = parse_ptr64)]
70    #[xc3(offset(u64))]
71    pub unk2: Option<DynamicsUnk3>,
72}
73
74// TODO: Collisions?
75#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
76#[derive(Debug, BinRead, Xc3Write, PartialEq, Clone)]
77pub struct DynamicsUnk1 {
78    pub spheres: BcListN<Sphere, 16>,
79    pub capsules: BcListN<Capsule, 16>,
80    pub planes: BcListN<Plane, 16>,
81}
82
83#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
84#[derive(Debug, BinRead, Xc3Write, PartialEq, Clone)]
85pub struct Sphere {
86    pub unk1: u32,
87    pub unk2: i32,
88
89    // CO_SPHERE_
90    #[br(parse_with = parse_string_ptr64)]
91    #[xc3(offset(u64))]
92    pub name: String,
93
94    #[br(parse_with = parse_string_ptr64)]
95    #[xc3(offset(u64))]
96    pub bone_name: String,
97
98    pub unk4: u32,
99    pub unk5: i32,
100
101    pub unk6: [f32; 9],
102    // TODO: padding from alignment?
103    pub unk7: [i32; 3],
104}
105
106#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
107#[derive(Debug, BinRead, Xc3Write, PartialEq, Clone)]
108pub struct Capsule {
109    pub unk1: u32,
110    pub unk2: i32,
111
112    // CO_CAPSULE_
113    #[br(parse_with = parse_string_ptr64)]
114    #[xc3(offset(u64))]
115    pub name: String,
116
117    #[br(parse_with = parse_string_ptr64)]
118    #[xc3(offset(u64))]
119    pub bone_name: String,
120
121    pub unk4: u32,
122    pub unk5: i32,
123
124    pub unk6: [f32; 10],
125    // TODO: padding from alignment?
126    pub unk7: [i32; 2],
127}
128
129#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
130#[derive(Debug, BinRead, Xc3Write, PartialEq, Clone)]
131pub struct Plane {
132    pub unk1: u32,
133    pub unk2: i32,
134
135    // CO_PLANE_
136    #[br(parse_with = parse_string_ptr64)]
137    #[xc3(offset(u64))]
138    pub name: String,
139
140    #[br(parse_with = parse_string_ptr64)]
141    #[xc3(offset(u64))]
142    pub bone_name: String,
143
144    pub unk4: u32,
145    pub unk5: i32,
146
147    pub unk6: [f32; 8],
148}
149
150#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
151#[derive(Debug, BinRead, Xc3Write, PartialEq, Clone)]
152pub struct DynamicsUnk2 {
153    pub unk1: BcList<DynamicsUnk2Item>,
154}
155
156#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
157#[derive(Debug, BinRead, Xc3Write, PartialEq, Clone)]
158pub struct DynamicsUnk2Item {
159    // DS_
160    #[br(parse_with = parse_string_ptr64)]
161    #[xc3(offset(u64))]
162    pub name: String,
163
164    pub unk1: BcList<DynamicsUnk2ItemUnk1>,
165    pub unk2: BcList<[f32; 4]>,
166    pub sticks: BcList<Stick>,
167    pub springs: BcList<Spring>,
168    pub unk5: BcList<()>,
169}
170
171#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
172#[derive(Debug, BinRead, Xc3Write, PartialEq, Clone)]
173pub struct DynamicsUnk2ItemUnk1 {
174    // DN_
175    #[br(parse_with = parse_string_ptr64)]
176    #[xc3(offset(u64))]
177    pub name: String,
178
179    // DJ_
180    #[br(parse_with = parse_string_ptr64)]
181    #[xc3(offset(u64))]
182    pub bone_name: String,
183
184    pub unk1: [f32; 7],
185    pub unk2: u32,
186}
187
188#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
189#[derive(Debug, BinRead, Xc3Write, PartialEq, Clone)]
190pub struct Stick {
191    // DC_STICK_
192    #[br(parse_with = parse_string_ptr64)]
193    #[xc3(offset(u64))]
194    pub name: String,
195
196    pub unk1: [f32; 7],
197    pub unk2: u32,
198}
199
200#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
201#[derive(Debug, BinRead, Xc3Write, PartialEq, Clone)]
202pub struct Spring {
203    // DC_SPRING_
204    #[br(parse_with = parse_string_ptr64)]
205    #[xc3(offset(u64))]
206    pub name: String,
207
208    pub unk1: [f32; 5],
209    // TODO: padding from alignment?
210    pub unk5: i32,
211}
212
213// TODO: make this generic instead?
214#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
215#[derive(Debug, BinRead, Xc3Write, PartialEq, Clone)]
216pub struct DynamicsUnk2Legacy {
217    pub unk1: BcList<DynamicsUnk2ItemLegacy>,
218}
219
220#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
221#[derive(Debug, BinRead, Xc3Write, PartialEq, Clone)]
222pub struct DynamicsUnk2ItemLegacy {
223    // DS_
224    #[br(parse_with = parse_string_ptr64)]
225    #[xc3(offset(u64))]
226    pub name: String,
227
228    pub unk1: BcList<DynamicsUnk2ItemUnk1Legacy>,
229    pub unk2: BcList2<[f32; 4]>,
230    pub sticks: BcList<StickLegacy>,
231    pub springs: BcList<Spring>,
232    pub unk5: BcList<()>,
233}
234
235#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
236#[derive(Debug, BinRead, Xc3Write, PartialEq, Clone)]
237pub struct DynamicsUnk2ItemUnk1Legacy {
238    // DN_
239    #[br(parse_with = parse_string_ptr64)]
240    #[xc3(offset(u64))]
241    pub name1: String,
242
243    // DJ_
244    #[br(parse_with = parse_string_ptr64)]
245    #[xc3(offset(u64))]
246    pub name2: String,
247
248    pub unk1: [f32; 5],
249    pub unk2: u16,
250    // TODO: Alignment padding for all but the last element?
251    pub unk3: i16,
252}
253
254#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
255#[derive(Debug, BinRead, Xc3Write, PartialEq, Clone)]
256pub struct StickLegacy {
257    // DC_STICK_
258    #[br(parse_with = parse_string_ptr64)]
259    #[xc3(offset(u64))]
260    pub name: String,
261
262    pub unk1: f32,
263    pub unk2: u32,
264    pub unk3: f32,
265    pub unk4: u32,
266}
267
268#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
269#[derive(Debug, BinRead, Xc3Write, PartialEq, Clone)]
270pub struct DynamicsUnk3 {
271    pub unk1: BcList<DynamicsUnk3Item>,
272}
273
274#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
275#[derive(Debug, BinRead, Xc3Write, PartialEq, Clone)]
276pub struct DynamicsUnk3Item {
277    // CY_S_BG_
278    #[br(parse_with = parse_string_ptr64)]
279    #[xc3(offset(u64))]
280    pub name: String,
281
282    /// The name of the [DynamicsUnk2ItemUnk1].
283    #[br(parse_with = parse_string_ptr64)]
284    #[xc3(offset(u64))]
285    pub name2: String,
286
287    /// The name of the [DynamicsUnk2ItemUnk1].
288    #[br(parse_with = parse_string_ptr64)]
289    #[xc3(offset(u64))]
290    pub name3: String,
291
292    pub unk6: [f32; 6],
293
294    pub unk4: u32,
295    // TODO: padding from alignment?
296    pub unk5: i32,
297}
298
299impl Xc3WriteOffsets for DynamicsOffsets<'_> {
300    type Args = ();
301
302    fn write_offsets<W: std::io::Write + std::io::Seek>(
303        &self,
304        writer: &mut W,
305        base_offset: u64,
306        data_ptr: &mut u64,
307        endian: xc3_write::Endian,
308        _args: Self::Args,
309    ) -> xc3_write::Xc3Result<()> {
310        let string_section = Rc::new(RefCell::new(StringSectionUniqueSorted::default()));
311
312        if !self.unk1.0.data.is_empty() {
313            self.unk1
314                .write_offsets(writer, base_offset, data_ptr, endian, ())?;
315        }
316        self.unk3.write_full(
317            writer,
318            base_offset,
319            data_ptr,
320            endian,
321            string_section.clone(),
322        )?;
323        self.inner.write_offsets(
324            writer,
325            base_offset,
326            data_ptr,
327            endian,
328            string_section.clone(),
329        )?;
330
331        string_section.borrow().write(
332            writer,
333            data_ptr,
334            &WriteOptions {
335                start_alignment: 8,
336                start_padding_byte: 0xff,
337                string_alignment: 1,
338                string_padding_byte: 0,
339            },
340            endian,
341        )?;
342
343        Ok(())
344    }
345}
346
347impl Xc3WriteOffsets for DynamicsInnerOffsets<'_> {
348    type Args = Rc<RefCell<StringSectionUniqueSorted>>;
349
350    fn write_offsets<W: std::io::Write + std::io::Seek>(
351        &self,
352        writer: &mut W,
353        base_offset: u64,
354        data_ptr: &mut u64,
355        endian: xc3_write::Endian,
356        args: Self::Args,
357    ) -> xc3_write::Xc3Result<()> {
358        match self {
359            DynamicsInnerOffsets::Unk1(unk1) => {
360                unk1.write_offsets(writer, base_offset, data_ptr, endian, args)
361            }
362            DynamicsInnerOffsets::Unk2(unk2) => {
363                unk2.write_offsets(writer, base_offset, data_ptr, endian, args)
364            }
365        }
366    }
367}
368
369impl Xc3WriteOffsets for DynamicsInner1Offsets<'_> {
370    type Args = Rc<RefCell<StringSectionUniqueSorted>>;
371
372    fn write_offsets<W: std::io::Write + std::io::Seek>(
373        &self,
374        writer: &mut W,
375        base_offset: u64,
376        data_ptr: &mut u64,
377        endian: xc3_write::Endian,
378        args: Self::Args,
379    ) -> xc3_write::Xc3Result<()> {
380        self.unk1
381            .write_full(writer, base_offset, data_ptr, endian, args)?;
382        Ok(())
383    }
384}
385
386impl Xc3WriteOffsets for DynamicsInner2Offsets<'_> {
387    type Args = Rc<RefCell<StringSectionUniqueSorted>>;
388
389    fn write_offsets<W: std::io::Write + std::io::Seek>(
390        &self,
391        writer: &mut W,
392        base_offset: u64,
393        data_ptr: &mut u64,
394        endian: xc3_write::Endian,
395        args: Self::Args,
396    ) -> xc3_write::Xc3Result<()> {
397        self.unk1
398            .write_full(writer, base_offset, data_ptr, endian, args.clone())?;
399        self.unk2
400            .write_full(writer, base_offset, data_ptr, endian, args.clone())?;
401        Ok(())
402    }
403}
404
405impl Xc3WriteOffsets for DynamicsUnk1Offsets<'_> {
406    type Args = Rc<RefCell<StringSectionUniqueSorted>>;
407
408    fn write_offsets<W: std::io::Write + std::io::Seek>(
409        &self,
410        writer: &mut W,
411        base_offset: u64,
412        data_ptr: &mut u64,
413        endian: xc3_write::Endian,
414        args: Self::Args,
415    ) -> xc3_write::Xc3Result<()> {
416        self.spheres
417            .write_offsets(writer, base_offset, data_ptr, endian, args.clone())?;
418        self.capsules
419            .write_offsets(writer, base_offset, data_ptr, endian, args.clone())?;
420        self.planes
421            .write_offsets(writer, base_offset, data_ptr, endian, args.clone())?;
422        Ok(())
423    }
424}
425
426impl Xc3WriteOffsets for SphereOffsets<'_> {
427    type Args = Rc<RefCell<StringSectionUniqueSorted>>;
428
429    fn write_offsets<W: std::io::Write + std::io::Seek>(
430        &self,
431        _writer: &mut W,
432        _base_offset: u64,
433        _data_ptr: &mut u64,
434        _endian: xc3_write::Endian,
435        args: Self::Args,
436    ) -> xc3_write::Xc3Result<()> {
437        args.borrow_mut().insert_offset64(&self.name);
438        args.borrow_mut().insert_offset64(&self.bone_name);
439        Ok(())
440    }
441}
442
443impl Xc3WriteOffsets for CapsuleOffsets<'_> {
444    type Args = Rc<RefCell<StringSectionUniqueSorted>>;
445
446    fn write_offsets<W: std::io::Write + std::io::Seek>(
447        &self,
448        _writer: &mut W,
449        _base_offset: u64,
450        _data_ptr: &mut u64,
451        _endian: xc3_write::Endian,
452        args: Self::Args,
453    ) -> xc3_write::Xc3Result<()> {
454        args.borrow_mut().insert_offset64(&self.name);
455        args.borrow_mut().insert_offset64(&self.bone_name);
456        Ok(())
457    }
458}
459
460impl Xc3WriteOffsets for PlaneOffsets<'_> {
461    type Args = Rc<RefCell<StringSectionUniqueSorted>>;
462
463    fn write_offsets<W: std::io::Write + std::io::Seek>(
464        &self,
465        _writer: &mut W,
466        _base_offset: u64,
467        _data_ptr: &mut u64,
468        _endian: xc3_write::Endian,
469        args: Self::Args,
470    ) -> xc3_write::Xc3Result<()> {
471        args.borrow_mut().insert_offset64(&self.name);
472        args.borrow_mut().insert_offset64(&self.bone_name);
473        Ok(())
474    }
475}
476
477impl Xc3WriteOffsets for DynamicsUnk2Offsets<'_> {
478    type Args = Rc<RefCell<StringSectionUniqueSorted>>;
479
480    fn write_offsets<W: std::io::Write + std::io::Seek>(
481        &self,
482        writer: &mut W,
483        base_offset: u64,
484        data_ptr: &mut u64,
485        endian: xc3_write::Endian,
486        args: Self::Args,
487    ) -> xc3_write::Xc3Result<()> {
488        self.unk1
489            .write_offsets(writer, base_offset, data_ptr, endian, args.clone())?;
490        Ok(())
491    }
492}
493
494impl Xc3WriteOffsets for DynamicsUnk2ItemOffsets<'_> {
495    type Args = Rc<RefCell<StringSectionUniqueSorted>>;
496
497    fn write_offsets<W: std::io::Write + std::io::Seek>(
498        &self,
499        writer: &mut W,
500        base_offset: u64,
501        data_ptr: &mut u64,
502        endian: xc3_write::Endian,
503        args: Self::Args,
504    ) -> xc3_write::Xc3Result<()> {
505        args.borrow_mut().insert_offset64(&self.name);
506        self.unk1
507            .write_offsets(writer, base_offset, data_ptr, endian, args.clone())?;
508        self.unk2
509            .write_offsets(writer, base_offset, data_ptr, endian, ())?;
510        self.sticks
511            .write_offsets(writer, base_offset, data_ptr, endian, args.clone())?;
512        self.springs
513            .write_offsets(writer, base_offset, data_ptr, endian, args.clone())?;
514        self.unk5
515            .write_offsets(writer, base_offset, data_ptr, endian, ())?;
516        Ok(())
517    }
518}
519
520impl Xc3WriteOffsets for DynamicsUnk2ItemUnk1Offsets<'_> {
521    type Args = Rc<RefCell<StringSectionUniqueSorted>>;
522
523    fn write_offsets<W: std::io::Write + std::io::Seek>(
524        &self,
525        _writer: &mut W,
526        _base_offset: u64,
527        _data_ptr: &mut u64,
528        _endian: xc3_write::Endian,
529        args: Self::Args,
530    ) -> xc3_write::Xc3Result<()> {
531        args.borrow_mut().insert_offset64(&self.name);
532        args.borrow_mut().insert_offset64(&self.bone_name);
533        Ok(())
534    }
535}
536
537impl Xc3WriteOffsets for StickOffsets<'_> {
538    type Args = Rc<RefCell<StringSectionUniqueSorted>>;
539
540    fn write_offsets<W: std::io::Write + std::io::Seek>(
541        &self,
542        _writer: &mut W,
543        _base_offset: u64,
544        _data_ptr: &mut u64,
545        _endian: xc3_write::Endian,
546        args: Self::Args,
547    ) -> xc3_write::Xc3Result<()> {
548        args.borrow_mut().insert_offset64(&self.name);
549        Ok(())
550    }
551}
552
553impl Xc3WriteOffsets for SpringOffsets<'_> {
554    type Args = Rc<RefCell<StringSectionUniqueSorted>>;
555
556    fn write_offsets<W: std::io::Write + std::io::Seek>(
557        &self,
558        _writer: &mut W,
559        _base_offset: u64,
560        _data_ptr: &mut u64,
561        _endian: xc3_write::Endian,
562        args: Self::Args,
563    ) -> xc3_write::Xc3Result<()> {
564        args.borrow_mut().insert_offset64(&self.name);
565        Ok(())
566    }
567}
568
569impl Xc3WriteOffsets for DynamicsUnk2LegacyOffsets<'_> {
570    type Args = Rc<RefCell<StringSectionUniqueSorted>>;
571
572    fn write_offsets<W: std::io::Write + std::io::Seek>(
573        &self,
574        writer: &mut W,
575        base_offset: u64,
576        data_ptr: &mut u64,
577        endian: xc3_write::Endian,
578        args: Self::Args,
579    ) -> xc3_write::Xc3Result<()> {
580        self.unk1
581            .write_offsets(writer, base_offset, data_ptr, endian, args.clone())?;
582        Ok(())
583    }
584}
585
586impl Xc3WriteOffsets for DynamicsUnk2ItemLegacyOffsets<'_> {
587    type Args = Rc<RefCell<StringSectionUniqueSorted>>;
588
589    fn write_offsets<W: std::io::Write + std::io::Seek>(
590        &self,
591        writer: &mut W,
592        base_offset: u64,
593        data_ptr: &mut u64,
594        endian: xc3_write::Endian,
595        args: Self::Args,
596    ) -> xc3_write::Xc3Result<()> {
597        args.borrow_mut().insert_offset64(&self.name);
598        self.unk1
599            .write_offsets(writer, base_offset, data_ptr, endian, args.clone())?;
600        self.unk2
601            .write_offsets(writer, base_offset, data_ptr, endian, ())?;
602        self.sticks
603            .write_offsets(writer, base_offset, data_ptr, endian, args.clone())?;
604        self.springs
605            .write_offsets(writer, base_offset, data_ptr, endian, args.clone())?;
606        self.unk5
607            .write_offsets(writer, base_offset, data_ptr, endian, ())?;
608        Ok(())
609    }
610}
611
612impl Xc3WriteOffsets for DynamicsUnk2ItemUnk1LegacyOffsets<'_> {
613    type Args = Rc<RefCell<StringSectionUniqueSorted>>;
614
615    fn write_offsets<W: std::io::Write + std::io::Seek>(
616        &self,
617        _writer: &mut W,
618        _base_offset: u64,
619        _data_ptr: &mut u64,
620        _endian: xc3_write::Endian,
621        args: Self::Args,
622    ) -> xc3_write::Xc3Result<()> {
623        args.borrow_mut().insert_offset64(&self.name1);
624        args.borrow_mut().insert_offset64(&self.name2);
625        Ok(())
626    }
627}
628
629impl Xc3WriteOffsets for StickLegacyOffsets<'_> {
630    type Args = Rc<RefCell<StringSectionUniqueSorted>>;
631
632    fn write_offsets<W: std::io::Write + std::io::Seek>(
633        &self,
634        _writer: &mut W,
635        _base_offset: u64,
636        _data_ptr: &mut u64,
637        _endian: xc3_write::Endian,
638        args: Self::Args,
639    ) -> xc3_write::Xc3Result<()> {
640        args.borrow_mut().insert_offset64(&self.name);
641        Ok(())
642    }
643}
644
645impl Xc3WriteOffsets for DynamicsUnk3Offsets<'_> {
646    type Args = Rc<RefCell<StringSectionUniqueSorted>>;
647
648    fn write_offsets<W: std::io::Write + std::io::Seek>(
649        &self,
650        writer: &mut W,
651        base_offset: u64,
652        data_ptr: &mut u64,
653        endian: xc3_write::Endian,
654        args: Self::Args,
655    ) -> xc3_write::Xc3Result<()> {
656        self.unk1
657            .write_offsets(writer, base_offset, data_ptr, endian, args)
658    }
659}
660
661impl Xc3WriteOffsets for DynamicsUnk3ItemOffsets<'_> {
662    type Args = Rc<RefCell<StringSectionUniqueSorted>>;
663
664    fn write_offsets<W: std::io::Write + std::io::Seek>(
665        &self,
666        _writer: &mut W,
667        _base_offset: u64,
668        _data_ptr: &mut u64,
669        _endian: xc3_write::Endian,
670        args: Self::Args,
671    ) -> xc3_write::Xc3Result<()> {
672        args.borrow_mut().insert_offset64(&self.name);
673        args.borrow_mut().insert_offset64(&self.name2);
674        args.borrow_mut().insert_offset64(&self.name3);
675        Ok(())
676    }
677}