diff --git a/src/lib.rs b/src/lib.rs index 326e123..fdd3c12 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,178 @@ mod core_types; pub mod global_tables; pub mod types; + +pub mod sdk { + use std::{ + collections::{hash_map::Entry, HashMap}, + sync::Mutex, + }; + + use anyhow::Context; + + use crate::{ + global_tables::objects::{FindClass, GOBJECTS}, + types::{traits::AsUObject, UAnyType, UClass, UEnum, UObject}, + }; + + pub const UOBJECT: &'static str = "Class CoreUObject.Object"; + pub const UCLASS: &'static str = "Class CoreUObject.Class"; + pub const UFUNCTION: &'static str = "Class CoreUObject.Function"; + pub const UFIELD: &'static str = "Class CoreUObject.Field"; + pub const UENUM: &'static str = "Class CoreUObject.Enum"; + pub const USTRUCT: &'static str = "Class CoreUObject.Struct"; + pub const USCRIPTSTRUCT: &'static str = "Class CoreUObject.ScriptStruct"; + + struct ClassCache { + classes: Mutex>, + } + + impl ClassCache { + pub fn new() -> Self { + Self { + classes: Mutex::new(HashMap::new()), + } + } + + fn identify_uobject(&self, object: UObject) -> UAnyType { + if object.is_a(&self.find_class(UENUM).expect("uenum")) { + UAnyType::UEnum(object.into()) + } else if object.is_a(&self.find_class(UFIELD).expect("ufield")) { + UAnyType::UField(object.into()) + } else if object.is_a(&self.find_class(USTRUCT).expect("ustruct")) { + UAnyType::UStruct(object.into()) + } else if object.is_a(&self.find_class(UFUNCTION).expect("ufunction")) { + UAnyType::UFunction(object.into()) + } else if object.is_a(&self.find_class(UCLASS).expect("uclass")) { + UAnyType::UClass(object.into()) + } else if object.is_a(&self.find_class(USCRIPTSTRUCT).expect("uscriptstruct")) { + UAnyType::UScriptStruct(object.into()) + } else { + UAnyType::UObject(object) + } + } + + pub fn cache_class(&mut self, class: UClass) -> anyhow::Result<()> { + let name = class.get_full_name()?; + self.classes.lock().unwrap().insert(name, class); + Ok(()) + } + } + + impl FindClass for ClassCache { + fn find_class(&self, class_name: S) -> Option + where + S: Into, + { + let class_name = class_name.into(); + + let class = self.classes.lock().unwrap().get(&class_name).cloned(); + + match class { + class @ Some(_) => class, + None => match GOBJECTS + .read() + .unwrap() + .as_objects() + .unwrap() + .find_class(&class_name) + { + Some(class) => { + self.classes + .lock() + .unwrap() + .insert(class_name, class.clone()); + Some(class) + } + None => None, + }, + } + } + } + + pub struct Sdk {} + + impl Sdk { + pub fn package_objects() -> HashMap> { + let gobjects = GOBJECTS.read().unwrap(); + let objects = gobjects.as_objects().unwrap(); + + let sorted_objects = objects + .iter() + // ensure item contains object + .filter_map(|item| item.object()) + // get package object + .filter_map(|obj| obj.outermost().map(|pkg| (pkg, obj))) + .fold( + HashMap::>::new(), + |mut acc, (pkg, obj)| { + match acc.entry(pkg) { + Entry::Occupied(mut entry) => { + entry.get_mut().push(obj); + } + Entry::Vacant(entry) => { + entry.insert(vec![obj]); + } + } + + acc + }, + ); + + sorted_objects + } + + pub fn process_packages(packages: HashMap>) -> anyhow::Result<()> { + let mut cache = ClassCache::new(); + + for (package, objects) in packages { + Self::process_package(&mut cache, package, objects)?; + } + + Ok(()) + } + + fn process_package( + cache: &mut ClassCache, + package: UObject, + objects: Vec, + ) -> anyhow::Result<()> { + cache + .cache_class(package.class().context("package had no class")?) + .context("package not of any base type")?; + + for object in objects { + cache + .cache_class(object.class().expect("object had no class?")) + .context("object not of any base type?")?; + + let ty = cache.identify_uobject(object); + log::debug!("ty: {ty:?}"); + + match ty { + UAnyType::UObject(_) => {} + UAnyType::UClass(_) => {} + UAnyType::UField(_) => {} + UAnyType::UScriptStruct(_) => {} + UAnyType::UProperty(_) => {} + UAnyType::UEnum(obj) => Self::process_enum(obj), + UAnyType::UStruct(_) => {} + UAnyType::UFunction(_) => {} + } + } + + Ok(()) + } + + fn process_enum(enm: UEnum) { + let names = enm + .get_names() + .iter() + .map(|name| name.get_name().unwrap_or("".to_string())) + .collect::>(); + + log::info!("enum: {}", enm.as_uobject().get_full_name_or_default()); + log::info!("{names:#?}"); + } + } +} diff --git a/src/types.rs b/src/types.rs index f068710..24092d9 100644 --- a/src/types.rs +++ b/src/types.rs @@ -1,6 +1,6 @@ use anyhow::Context; use itertools::Itertools; -use std::{hash::Hash, ops::Deref, ptr::NonNull}; +use std::{hash::Hash, ptr::NonNull}; use crate::core_types::{self, FName, TArray}; @@ -12,6 +12,9 @@ pub struct UObject { inner: NonNull, } +unsafe impl Send for UObject {} +unsafe impl Sync for UObject {} + impl Eq for UObject {} impl PartialEq for UObject { @@ -36,25 +39,17 @@ pub struct UClass { inner: NonNull, } -impl Deref for UClass { - type Target = UObject; - - fn deref(&self) -> &Self::Target { - unsafe { std::mem::transmute(&self) } - } -} - impl Eq for UClass {} impl PartialEq for UClass { fn eq(&self, other: &Self) -> bool { - self.deref().eq(other) + self.as_uobject().eq(&other.as_uobject()) } } impl Hash for UClass { fn hash(&self, state: &mut H) { - self.deref().hash(state); + self.as_uobject().hash(state); } } @@ -64,25 +59,17 @@ pub struct UField { inner: NonNull, } -impl Deref for UField { - type Target = UObject; - - fn deref(&self) -> &Self::Target { - unsafe { std::mem::transmute(&self) } - } -} - impl Eq for UField {} impl PartialEq for UField { fn eq(&self, other: &Self) -> bool { - self.deref().eq(other) + self.as_uobject().eq(&other.as_uobject()) } } impl Hash for UField { fn hash(&self, state: &mut H) { - self.deref().hash(state); + self.as_uobject().hash(state); } } @@ -262,16 +249,9 @@ impl Iterator for SuperClassIter { type Item = UClass; fn next(&mut self) -> Option { - if let Some(next) = self - .class - .as_ref() - .ustruct - .super_field - .map(|inner| inner.cast::()) - .map(|inner| UClass::new(inner)) - { - self.class = next.clone(); - Some(next) + if let Some(next) = self.class.super_struct().map(|spr| spr.as_uobject().into()) { + let item = core::mem::replace(&mut self.class, next); + Some(item) } else { None }