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#[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 #[br(pre_assert(size == 88))]
47 Unk1(DynamicsInner1),
48
49 #[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#[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 #[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 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 #[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 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 #[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 #[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 #[br(parse_with = parse_string_ptr64)]
176 #[xc3(offset(u64))]
177 pub name: String,
178
179 #[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 #[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 #[br(parse_with = parse_string_ptr64)]
205 #[xc3(offset(u64))]
206 pub name: String,
207
208 pub unk1: [f32; 5],
209 pub unk5: i32,
211}
212
213#[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 #[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 #[br(parse_with = parse_string_ptr64)]
240 #[xc3(offset(u64))]
241 pub name1: String,
242
243 #[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 pub unk3: i16,
252}
253
254#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
255#[derive(Debug, BinRead, Xc3Write, PartialEq, Clone)]
256pub struct StickLegacy {
257 #[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 #[br(parse_with = parse_string_ptr64)]
279 #[xc3(offset(u64))]
280 pub name: String,
281
282 #[br(parse_with = parse_string_ptr64)]
284 #[xc3(offset(u64))]
285 pub name2: String,
286
287 #[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 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}