calculating dependencies

This commit is contained in:
Janis 2023-04-20 23:43:56 +02:00
parent 211605c20c
commit d1c0520316
2 changed files with 134 additions and 65 deletions

View file

@ -22,20 +22,19 @@ pub mod sdk {
}; };
use anyhow::Context; use anyhow::Context;
use rayon::prelude::{IntoParallelRefIterator, ParallelIterator}; use rayon::prelude::{IntoParallelIterator, IntoParallelRefIterator, ParallelIterator};
use crate::{ use crate::{
global_tables::objects::{FindClass, GOBJECTS}, global_tables::objects::{FindClass, GOBJECTS},
v2_types::{ v2_types::{
any_type::{self, AnyProperty}, any_type::{self, AnyField, AnyObject, AnyProperty, AnyStruct},
traits::{ traits::{
AsUObject, StaticClass, UArrayPropertyTrait, UBytePropertyTrait, AsUObject, StaticClass, UArrayPropertyTrait, UBytePropertyTrait,
UEnumPropertyTrait, UEnumTrait, UFunctionTrait, UObjectNonConst, UEnumPropertyTrait, UEnumTrait, UFunctionTrait, UObjectNonConst,
UObjectPropertyBaseTrait, UObjectTrait, UPropertyTrait, UStructNonConst, UObjectPropertyBaseTrait, UObjectTrait, UPropertyTrait, UStructNonConst,
UStructPropertyTrait, UStructTrait, UStructPropertyTrait, UStructTrait,
}, },
EFunctionFlags, EPropertyFlags, UAnyType, UClass, UEnum, UFunction, UObject, EFunctionFlags, EPropertyFlags, UAnyType, UClass, UEnum, UFunction, UObject, UStruct,
UScriptStruct, UStruct,
}, },
}; };
@ -86,23 +85,18 @@ pub mod sdk {
pub struct Package { pub struct Package {
package: UObject, package: UObject,
objects: Vec<UObject>, objects: Vec<UObject>,
dependencies: Vec<UObject>,
} }
#[derive(Debug)] #[derive(Debug)]
pub struct ProcessedPackage { pub struct ProcessedPackage {
pub package: UObject, pub package: UObject,
pub types: HashMap<UObject, Types>, pub types: HashMap<UObject, Types>,
pub package_dependencies: Vec<UObject>, pub package_dependencies: HashMap<UObject, Vec<UObject>>,
} }
impl Package { impl Package {
pub fn new(package: UObject, objects: Vec<UObject>) -> Self { pub fn new(package: UObject, objects: Vec<UObject>) -> Self {
Self { Self { package, objects }
package,
objects,
dependencies: Vec::new(),
}
} }
pub fn process(self) -> ProcessedPackage { pub fn process(self) -> ProcessedPackage {
@ -110,35 +104,47 @@ pub mod sdk {
.objects .objects
.par_iter() .par_iter()
.filter_map(|&object| { .filter_map(|&object| {
let ty = UAnyType::from_uobject(object.as_uobject()); match AnyObject::from_object(object) {
log::trace!("ty: {ty:?}"); AnyObject::Field(field) => match AnyField::from_field(field) {
AnyField::Enum(enm) => {
match ty { if let Ok(enm) = Self::process_enum(enm) {
UAnyType::UClass(class) => { return Some((object, Types::Enum(enm)));
if let Ok(class) = self.process_struct(unsafe { class.cast() }) { }
return Some((object, Types::Class(class)));
} }
} AnyField::Struct(strt) => match AnyStruct::from_struct(strt) {
UAnyType::UScriptStruct(class) => { strt @ AnyStruct::ScriptStruct(_) | strt @ AnyStruct::Class(_) => {
if let Ok(class) = self.process_struct(unsafe { class.cast() }) { if let Ok(class) = self.process_struct(unsafe { strt.cast() }) {
return Some((object, Types::Class(class))); return Some((object, Types::Class(class)));
} }
} }
UAnyType::UEnum(obj) => { _ => {}
if let Ok(enm) = Self::process_enum(obj) { },
return Some((object, Types::Enum(enm))); _ => {}
} },
}
_ => {} _ => {}
} }
None None
}) })
.collect::<HashMap<_, _>>(); .collect::<HashMap<_, _>>();
let mut dependencies = types
.iter()
.filter_map(|(_, ty)| match ty {
Types::Class(class) => Some(class.referenced_types()),
_ => None,
})
.map(|refs| refs.into_iter())
.flatten()
.fold_into_packages();
// remove any objects in Self
dependencies.remove(&self.package);
ProcessedPackage { ProcessedPackage {
package: self.package, package: self.package,
types, types,
package_dependencies: self.dependencies, package_dependencies: dependencies,
} }
} }
@ -146,25 +152,20 @@ pub mod sdk {
let name = strct let name = strct
.get_name() .get_name()
.context("failed to get struct or class name")?; .context("failed to get struct or class name")?;
let is_struct = strct.is_a(&UScriptStruct::static_class().unwrap()); let full_name = strct
.get_full_name()
.context("failed to get struct or class full name")?;
let is_class = strct.is_a(&UClass::static_class().unwrap()); let is_class = strct.is_a(&UClass::static_class().unwrap());
// process outers for classes let super_struct = if let Some(spr) = *strct.super_field() {
if !is_struct { if spr != strct {
if let Some(outer) = strct.outer() {
if outer.is_a(&UStruct::static_class().unwrap()) {
// depend on this
}
}
}
let super_struct = if let Some(spr) = *strct.super_field() && spr != strct {
if spr.package_object() != self.package {
log::warn!("encountered external dependency");
// TODO: return dependency on strct.package_object()
}
Some(spr) Some(spr)
} else {None}; } else {
None
}
} else {
None
};
let (fields, methods) = self.process_children(strct)?; let (fields, methods) = self.process_children(strct)?;
@ -175,6 +176,7 @@ pub mod sdk {
super_class: super_struct, super_class: super_struct,
fields, fields,
methods, methods,
full_name,
}) })
} }
@ -466,14 +468,46 @@ pub mod sdk {
} }
} }
pub struct Sdk {} trait FoldIntoPackages: Iterator<Item = UObject> + Sized {
fn fold_into_packages(self) -> HashMap<UObject, Vec<UObject>> {
self.map(|obj| (obj.package_object(), 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
},
)
}
}
impl<T> FoldIntoPackages for T where T: Iterator<Item = UObject> {}
pub struct Sdk {
pub packages: HashMap<UObject, ProcessedPackage>,
}
impl Sdk { impl Sdk {
pub fn new() -> Self { pub fn new() -> Self {
Self {} let packages = Self::package_objects();
let packages = packages
.into_par_iter()
.map(|pkg| pkg.process())
.map(|pkg| (pkg.package, pkg))
.collect();
Self { packages }
} }
pub fn package_objects(&self) -> Vec<Package> { pub fn package_objects() -> Vec<Package> {
let gobjects = GOBJECTS.read().unwrap(); let gobjects = GOBJECTS.read().unwrap();
let objects = gobjects.as_objects().unwrap(); let objects = gobjects.as_objects().unwrap();
@ -482,22 +516,7 @@ pub mod sdk {
// ensure item contains object // ensure item contains object
.filter_map(|item| item.object()) .filter_map(|item| item.object())
// get package object // get package object
.map(|obj| (obj.package_object(), obj)) .fold_into_packages();
.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 sorted_objects
.into_iter() .into_iter()
@ -654,6 +673,22 @@ pub mod sdk {
Class(UStruct), Class(UStruct),
} }
impl Type {
pub fn referenced_type(&self) -> Option<UObject> {
match self {
Type::Ptr(t) | Type::Ref(t) | Type::Array(t) | Type::RawArray { ty: t, .. } => {
t.referenced_type()
}
Type::WeakPtr(o) | Type::SoftPtr(o) | Type::LazyPtr(o) | Type::AssetPtr(o) => {
Some(o.as_uobject())
}
Type::Class(o) => Some(o.as_uobject()),
Type::Primitive(_) | Type::Name | Type::String | Type::Text => None,
Type::Enum { enum_type, .. } => Some(enum_type.as_uobject()),
}
}
}
#[derive(Debug)] #[derive(Debug)]
pub struct ClassField { pub struct ClassField {
pub offset: u32, pub offset: u32,
@ -683,11 +718,41 @@ pub mod sdk {
pub is_class: bool, pub is_class: bool,
pub size: u32, pub size: u32,
pub name: String, pub name: String,
pub full_name: String,
pub super_class: Option<UStruct>, pub super_class: Option<UStruct>,
pub fields: Vec<ClassField>, pub fields: Vec<ClassField>,
pub methods: Vec<ClassMethod>, pub methods: Vec<ClassMethod>,
} }
impl Class {
pub fn referenced_types(&self) -> Vec<UObject> {
let mut types = Vec::new();
self.super_class.map(|obj| types.push(obj.as_uobject()));
for field in &self.fields {
types.extend(field.ty.referenced_type());
}
for method in &self.methods {
types.extend(
method
.return_type
.as_ref()
.and_then(|ty| ty.referenced_type()),
);
types.extend(
method
.parameters
.iter()
.map(|param| &param.ty)
.filter_map(|ty| ty.referenced_type()),
);
}
types
}
}
#[derive(Debug)] #[derive(Debug)]
pub enum Types { pub enum Types {
Class(Class), Class(Class),

View file

@ -804,6 +804,10 @@ pub mod traits {
.unwrap_or(self.as_uobject()) .unwrap_or(self.as_uobject())
} }
fn is_in_package(&self, package: super::UObject) -> bool {
self.package_object() == package
}
fn is_a(&self, other: &super::UClass) -> bool { fn is_a(&self, other: &super::UClass) -> bool {
self.class() self.class()
.map(|class| class.iter_super_classes().contains(other)) .map(|class| class.iter_super_classes().contains(other))