calculating dependencies
This commit is contained in:
parent
211605c20c
commit
d1c0520316
195
src/lib.rs
195
src/lib.rs
|
@ -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| ¶m.ty)
|
||||||
|
.filter_map(|ty| ty.referenced_type()),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
types
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum Types {
|
pub enum Types {
|
||||||
Class(Class),
|
Class(Class),
|
||||||
|
|
|
@ -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))
|
||||||
|
|
Loading…
Reference in a new issue