il2cpp_bridge_rs/structs/core/members/
field.rs1use crate::api;
3use crate::structs::core::{Class, Type, ValueType};
4use std::ffi::c_void;
5
6#[derive(Debug, Clone)]
8pub struct Field {
9 pub address: *mut c_void,
11 pub name: String,
13 pub type_info: Type,
15 pub class: Option<*const Class>,
17 pub offset: i32,
19 pub flags: i32,
21 pub is_static: bool,
23 pub is_literal: bool,
25 pub is_readonly: bool,
27 pub is_not_serialized: bool,
29 pub is_special_name: bool,
31 pub is_pinvoke_impl: bool,
33 pub instance: Option<*mut c_void>,
35}
36
37unsafe impl Send for Field {}
38unsafe impl Sync for Field {}
39
40impl std::fmt::Display for Field {
41 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
42 write!(f, "{}", self.fmt_field())
43 }
44}
45
46impl Field {
47 fn fmt_field(&self) -> String {
52 let access = self.get_attribute();
53 let qualifier = if self.is_literal {
54 "const ".to_string()
55 } else {
56 let mut s = String::new();
57 if self.is_static {
58 s.push_str("static ");
59 }
60 if self.is_readonly {
61 s.push_str("readonly ");
62 }
63 s
64 };
65
66 format!(
67 "{} {}{} {}; // 0x{:X}",
68 access,
69 qualifier,
70 self.type_info.cpp_name(),
71 self.name,
72 self.offset
73 )
74 }
75
76 pub unsafe fn get_value<T: Copy + 'static>(&self) -> Result<T, String> {
81 if self.is_static {
82 if let Some(class) = self.class {
83 if (*class).is_generic {
84 return Err("Cannot read static field of generic class".to_string());
85 }
86 }
87
88 if std::any::TypeId::of::<T>() == std::any::TypeId::of::<ValueType>() {
89 let class = self
90 .class
91 .ok_or_else(|| "Field does not have a parent class reference".to_string())?;
92
93 let static_data = api::class_get_static_field_data((*class).address);
94 if static_data.is_null() {
95 return Err("Static field data is null".to_string());
96 }
97
98 let address = static_data as usize + self.offset as usize;
99
100 let field_type = api::field_get_type(self.address);
101 let type_class = api::class_from_type(field_type);
102
103 if type_class.is_null() {
104 return Err("Failed to resolve field type class".to_string());
105 }
106
107 let vt = ValueType::from_ptr_with_class(address as *mut c_void, type_class);
108 return Ok(std::ptr::read(&vt as *const _ as *const T));
109 }
110
111 let mut value: T = std::mem::zeroed();
112 api::field_static_get_value(self.address, &mut value as *mut T as *mut c_void);
113 Ok(value)
114 } else {
115 let instance = self.instance.ok_or_else(|| {
116 format!(
117 "Field '{}' is an instance field but no instance was provided. Use Object::field or set the instance manually.",
118 self.name
119 )
120 })?;
121
122 if std::any::TypeId::of::<T>() == std::any::TypeId::of::<ValueType>() {
123 let field_type = api::field_get_type(self.address);
124 if field_type.is_null() {
125 return Err("Failed to get field type".to_string());
126 }
127 let type_class = api::class_from_type(field_type);
128 if type_class.is_null() {
129 return Err("Failed to resolve class from field type".to_string());
130 }
131
132 let address = instance as usize + self.offset as usize;
133 let vt = ValueType::from_ptr_with_class(address as *mut c_void, type_class);
134 return Ok(std::ptr::read(&vt as *const _ as *const T));
135 }
136
137 let address = instance as usize + self.offset as usize;
138 crate::memory::rw::read(address).map_err(|e| e.to_string())
139 }
140 }
141
142 pub unsafe fn set_value<T: Copy>(&self, value: T) -> Result<(), String> {
147 if self.is_static {
148 api::field_static_set_value(self.address, &value as *const T as *mut c_void);
149 Ok(())
150 } else {
151 let instance = self.instance.ok_or_else(|| {
152 format!(
153 "Field '{}' is an instance field but no instance was provided. Use Object::field or set the instance manually.",
154 self.name
155 )
156 })?;
157
158 let address = instance as usize + self.offset as usize;
159 crate::memory::rw::write(address, value).map_err(|e| e.to_string())
160 }
161 }
162
163 fn get_attribute(&self) -> &'static str {
165 match self.flags & api::FIELD_ATTRIBUTE_FIELD_ACCESS_MASK {
166 api::FIELD_ATTRIBUTE_PRIVATE => "private",
167 api::FIELD_ATTRIBUTE_PUBLIC => "public",
168 api::FIELD_ATTRIBUTE_FAMILY => "protected",
169 api::FIELD_ATTRIBUTE_ASSEMBLY => "internal",
170 api::FIELD_ATTRIBUTE_FAM_AND_ASSEM => "private protected",
171 api::FIELD_ATTRIBUTE_FAM_OR_ASSEM => "protected internal",
172 _ => "private",
173 }
174 }
175
176 pub fn get_parent(&self) -> *mut c_void {
181 unsafe { api::field_get_parent(self.address) }
182 }
183}