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
use std::ptr::NonNull;
use super::FieldInsHandle;
use crate::{
DLVector,
cs::{CSRideNode, CSThrowNode, ChrIns},
dlkr::DLPlainLightMutex,
position::HavokPosition,
rotation::EulerAngles,
};
use shared::{F32Vector4, Subclass, Superclass};
use vtable_rs::VPtr;
#[repr(C)]
#[shared::singleton("CSPairAnimManager")]
pub struct CSPairAnimManager {
unk0: DLVector<()>,
unk20: DLVector<CSPairAnimManager20Entry>,
unk40: DLVector<()>,
unk60: f32,
unk64: f32,
// Unknown 1-byte structure. Related to the p2p send but entirely unused?
unk68: isize,
// Unknown 1-byte structure. Related to the p2p receive but entirely unused?
// Referenced when receiving packet 18 (PairAnimStateUpdate) as well as packet 48 (ThrowEscHpUpdate).
unk70: isize,
pub mutex: DLPlainLightMutex,
unka8: DLVector<()>,
unkc0: [u8; 0xB8],
}
#[repr(C)]
pub struct CSPairAnimManager20Entry {
pub party_a: Option<NonNull<ChrIns>>,
pub party_b: Option<NonNull<ChrIns>>,
unk10: isize,
// Might be clear request? Set to true when clearing a `CSPairAnimNode`.
unk18: bool,
}
#[repr(C)]
/// Does the bookkeeping around paired animations where one party is forwarding animations to a
/// receiver. One such example is riding torrent, another would be backstabs.
/// Both parties will have one of these.
#[derive(Superclass)]
#[superclass(children(CSThrowNode, CSRideNode))]
pub struct CSPairAnimNode {
vftable: VPtr<dyn CSPairAnimNodeVmt, Self>,
unk8: isize,
pub owner: NonNull<ChrIns>,
/// Field ins handle of the `FieldIns` on the other end of this pair anim session.
pub counter_party: FieldInsHandle,
/// The position of the pair anim dummy poly when entering the pair anim session.
/// Set when entering a pair anim session. Updates with the world shift so it can be
/// safely used to measure distance when crossing chunks. Becomes identity (0.0, 0.0, 0.0, 1.0)
/// once the paired anim ends but will still apply world shift on the stored position despite
/// being inactive.
pub start_position: HavokPosition,
/// The rotation of the pair anim dummy poly when entering the pair anim session.
/// Populated when entering a pair anim "session". Becomes all zeroes once the paired anim ends.
pub start_rotation: EulerAngles,
// occupied? if true it also potentially removes an entry from CSPairAnimManager->0x20
// during the clearing procedure.
unk40: bool,
unk41: bool,
unk42: bool,
unk43: bool,
unk44: bool,
}
#[vtable_rs::vtable]
pub trait CSPairAnimNodeVmt {
fn destructor(&mut self);
/// Updates the module. Called every frame by game.
fn update(&mut self, delta: f32);
/// Sets all properties back to the initial state. If `unk40` is set it will do something with
/// an entry in `CSPairAnimManager->0x20` as well. Called as part of the CSThrowNode destructor
/// as well as the torrent dismount procedure.
fn reset(&mut self);
/// Displaces the start position by some world shift delta.
fn apply_world_shift(&mut self, position: F32Vector4);
// Returns 0 in base class.
fn unk20(&mut self);
// Returns 1 in base class.
fn unk28(&mut self);
// Returns 1 in base class.
fn unk30(&mut self);
// Returns immediately in base class.
fn unk38(&mut self);
// Sets everything to empty.
fn unk40(&mut self);
// Sends out a packet 18 describing the new start for remote CSPairAnimNodes
fn broadcast_start(&mut self, counter_party: &CSPairAnimNode);
// Returns immediately in base class.
fn unk50(&mut self);
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn proper_sizes() {
assert_eq!(0x50, size_of::<CSPairAnimNode>());
}
}