removed deref impl as it was unsound
- started on sdk generator, can classify and sort objects into packages - parse enums
This commit is contained in:
parent
41dbc1bdd0
commit
f12f48c83f
175
src/lib.rs
175
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<HashMap<String, UClass>>,
|
||||
}
|
||||
|
||||
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<S>(&self, class_name: S) -> Option<UClass>
|
||||
where
|
||||
S: Into<String>,
|
||||
{
|
||||
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<UObject, Vec<UObject>> {
|
||||
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::<UObject, Vec<UObject>>::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<UObject, Vec<UObject>>) -> 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<UObject>,
|
||||
) -> 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("<invalid-name>".to_string()))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
log::info!("enum: {}", enm.as_uobject().get_full_name_or_default());
|
||||
log::info!("{names:#?}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
42
src/types.rs
42
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<core_types::UObject>,
|
||||
}
|
||||
|
||||
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<core_types::UClass>,
|
||||
}
|
||||
|
||||
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<H: std::hash::Hasher>(&self, state: &mut H) {
|
||||
self.deref().hash(state);
|
||||
self.as_uobject().hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -64,25 +59,17 @@ pub struct UField {
|
|||
inner: NonNull<core_types::UField>,
|
||||
}
|
||||
|
||||
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<H: std::hash::Hasher>(&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<Self::Item> {
|
||||
if let Some(next) = self
|
||||
.class
|
||||
.as_ref()
|
||||
.ustruct
|
||||
.super_field
|
||||
.map(|inner| inner.cast::<core_types::UClass>())
|
||||
.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
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue