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;
|
mod core_types;
|
||||||
pub mod global_tables;
|
pub mod global_tables;
|
||||||
pub mod types;
|
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 anyhow::Context;
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use std::{hash::Hash, ops::Deref, ptr::NonNull};
|
use std::{hash::Hash, ptr::NonNull};
|
||||||
|
|
||||||
use crate::core_types::{self, FName, TArray};
|
use crate::core_types::{self, FName, TArray};
|
||||||
|
|
||||||
|
@ -12,6 +12,9 @@ pub struct UObject {
|
||||||
inner: NonNull<core_types::UObject>,
|
inner: NonNull<core_types::UObject>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsafe impl Send for UObject {}
|
||||||
|
unsafe impl Sync for UObject {}
|
||||||
|
|
||||||
impl Eq for UObject {}
|
impl Eq for UObject {}
|
||||||
|
|
||||||
impl PartialEq for UObject {
|
impl PartialEq for UObject {
|
||||||
|
@ -36,25 +39,17 @@ pub struct UClass {
|
||||||
inner: NonNull<core_types::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 Eq for UClass {}
|
||||||
|
|
||||||
impl PartialEq for UClass {
|
impl PartialEq for UClass {
|
||||||
fn eq(&self, other: &Self) -> bool {
|
fn eq(&self, other: &Self) -> bool {
|
||||||
self.deref().eq(other)
|
self.as_uobject().eq(&other.as_uobject())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Hash for UClass {
|
impl Hash for UClass {
|
||||||
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
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>,
|
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 Eq for UField {}
|
||||||
|
|
||||||
impl PartialEq for UField {
|
impl PartialEq for UField {
|
||||||
fn eq(&self, other: &Self) -> bool {
|
fn eq(&self, other: &Self) -> bool {
|
||||||
self.deref().eq(other)
|
self.as_uobject().eq(&other.as_uobject())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Hash for UField {
|
impl Hash for UField {
|
||||||
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
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;
|
type Item = UClass;
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
if let Some(next) = self
|
if let Some(next) = self.class.super_struct().map(|spr| spr.as_uobject().into()) {
|
||||||
.class
|
let item = core::mem::replace(&mut self.class, next);
|
||||||
.as_ref()
|
Some(item)
|
||||||
.ustruct
|
|
||||||
.super_field
|
|
||||||
.map(|inner| inner.cast::<core_types::UClass>())
|
|
||||||
.map(|inner| UClass::new(inner))
|
|
||||||
{
|
|
||||||
self.class = next.clone();
|
|
||||||
Some(next)
|
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue