commonlibsse_ng\re\g/
GFxValue.rs

1use core::ffi::{CStr, c_char, c_void};
2use core::fmt;
3
4#[commonlibsse_ng_derive_internal::to_bitflags]
5#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
6#[repr(u32)]
7pub enum ValueType {
8    #[default]
9    Undefined = 0x00,
10    Null = 0x01,
11    Boolean = 0x02,
12    Number = 0x03,
13    String = 0x04,
14    StringW = 0x05,
15    Object = 0x06,
16    Array = 0x07,
17    DisplayObject = 0x08,
18
19    ManagedBit = 1 << 6,
20    ConvertBit = 1 << 7,
21    ValueMask = 0x0F,
22
23    /// `ConvertBit` | `ValueMask`
24    TypeMask = 1 << 7 | 0x0F,
25    // `ConvertBit` | `Boolean`,
26    ConvertBoolean = 1 << 7 | 0x02,
27    // `ConvertBit` | `Number`,
28    ConvertNumber = 1 << 7 | 0x03,
29    // `ConvertBit` | `String`,
30    ConvertString = 1 << 7 | 0x04,
31    // `ConvertBit` | `StringW`,
32    ConvertStringW = 1 << 7 | 0x05,
33}
34
35#[repr(C)]
36#[derive(Debug)]
37pub struct ObjectInterface {
38    pub movieRoot: *mut (),
39}
40
41impl ObjectInterface {
42    #[commonlibsse_ng_derive_internal::relocate_fn(se_id = 80222, ae_id = 82245)]
43    pub unsafe fn get_member(
44        &self,
45        data: *mut c_void,
46        name: *const c_char,
47        value: &mut GFxValue,
48        is_d_obj: bool,
49    ) {
50    }
51}
52
53union ValueUnion {
54    number: f64,
55    boolean: bool,
56    string: *const c_char,
57    managedString: *mut *const c_char,
58    wideString: *const u16,             // wchar_t
59    managedWideString: *mut *const u16, // wchar_t
60    obj: *mut c_void,
61}
62
63impl Default for ValueUnion {
64    fn default() -> Self {
65        Self { obj: core::ptr::null_mut() }
66    }
67}
68
69pub enum Value {
70    Undefined,
71    Null,
72    Boolean(bool),
73    Number(f64),
74    String(*const c_char),
75    ManagedString(*mut *const c_char),
76    WideString(*const u16),             // wchar_t
77    ManagedWideString(*mut *const u16), // wchar_t
78    Object(*mut c_void),
79}
80
81impl fmt::Debug for Value {
82    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
83        match self {
84            Self::Undefined => write!(f, "Value(Undefined)"),
85            Self::Null => write!(f, "Value(Null)"),
86            Self::Boolean(b) => write!(f, "Value(Boolean({}))", b),
87            Self::Number(n) => write!(f, "Value(Number({}))", n),
88            Self::String(s) => write!(f, "Value(String({:?}))", unsafe { CStr::from_ptr(*s) }),
89            Self::ManagedString(s) => {
90                write!(f, "Value(ManagedString({:?}))", unsafe { CStr::from_ptr(**s) })
91            }
92            Self::WideString(s) => write!(f, "Value(WideString({:?}))", s),
93            Self::ManagedWideString(s) => {
94                write!(f, "Value(ManagedWideString({:?}))", s)
95            }
96            Self::Object(o) => write!(f, "Value(Object({:?}))", o),
97        }
98    }
99}
100
101#[repr(C)]
102pub struct GFxValue {
103    /// FIXME: Unknown ptr lifetime
104    pub objectInterface: *mut ObjectInterface,
105    pub type_: ValueType,
106    pad0C: u32,
107    value: ValueUnion,
108}
109const _: () = assert!(core::mem::size_of::<GFxValue>() == 0x18);
110
111impl Default for GFxValue {
112    fn default() -> Self {
113        Self {
114            objectInterface: core::ptr::null_mut(),
115            type_: Default::default(),
116            pad0C: Default::default(),
117            value: Default::default(),
118        }
119    }
120}
121
122impl GFxValue {
123    #[inline]
124    pub fn is_object(&self) -> bool {
125        self.type_.contains(ValueType::Object | ValueType::Array | ValueType::DisplayObject)
126    }
127
128    #[inline]
129    pub const fn is_number(&self) -> bool {
130        self.type_.contains(ValueType::Number)
131    }
132
133    #[inline]
134    pub fn is_display_object(&self) -> bool {
135        self.type_ == ValueType::DisplayObject
136    }
137
138    pub fn get_value(&self) -> Option<Value> {
139        let managed_string = ValueType::ManagedBit | ValueType::String;
140        let managed_string_w = ValueType::ManagedBit | ValueType::StringW;
141
142        unsafe {
143            Some(match self.type_ {
144                ValueType::Undefined => Value::Undefined,
145                ValueType::Null => Value::Null,
146                ValueType::Boolean => Value::Boolean(self.value.boolean),
147                ValueType::Number => Value::Number(self.value.number),
148                value if value == managed_string => Value::ManagedString(self.value.managedString),
149                ValueType::String => Value::String(self.value.string),
150                value if value == managed_string_w => {
151                    Value::ManagedWideString(self.value.managedWideString)
152                }
153                ValueType::StringW => Value::WideString(self.value.wideString),
154                ValueType::Object => Value::Object(self.value.obj),
155                _ => return None,
156            })
157        }
158    }
159
160    pub fn get_member(&self, name: &CStr) -> Option<Self> {
161        if !self.is_object() {
162            return None;
163        }
164
165        let mut output = Self::default();
166        unsafe {
167            self.objectInterface.as_ref()?.get_member(
168                self.value.obj,
169                name.as_ptr(),
170                &mut output,
171                self.is_display_object(),
172            );
173        }
174
175        Some(output)
176    }
177}
178
179impl fmt::Debug for GFxValue {
180    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
181        let mut debug_struct = f.debug_struct("GFxValue");
182
183        debug_struct.field("objectInterface", &self.objectInterface);
184        debug_struct.field("type_", &self.type_);
185
186        let value = self.get_value();
187        debug_struct.field("value", &value);
188
189        debug_struct.finish()
190    }
191}