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 TypeMask = 1 << 7 | 0x0F,
25 ConvertBoolean = 1 << 7 | 0x02,
27 ConvertNumber = 1 << 7 | 0x03,
29 ConvertString = 1 << 7 | 0x04,
31 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, managedWideString: *mut *const u16, 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), ManagedWideString(*mut *const u16), 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 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}