diff --git a/src/menu/config.rs b/src/menu/config.rs index a41876e..cdecf60 100644 --- a/src/menu/config.rs +++ b/src/menu/config.rs @@ -187,9 +187,9 @@ pub trait ConfigBasicMenuItemCommandMethods { } extern "C" fn open_anime_all_ondispose(this: &mut ProcInst, _method_info: OptionalMethod) { - this.parent.get_class().get_virtual_method("OpenAnimeAll").map(|method| { + this.parent.as_ref().unwrap().get_class().get_virtual_method("OpenAnimeAll").map(|method| { let open_anime_all = unsafe { std::mem::transmute::<_, extern "C" fn(&ProcInst, &MethodInfo)>(method.method_info.method_ptr) }; - open_anime_all(this.parent, method.method_info); + open_anime_all(this.parent.as_ref().unwrap(), method.method_info); }); } diff --git a/src/proc.rs b/src/proc.rs index c74c591..b05eb63 100644 --- a/src/proc.rs +++ b/src/proc.rs @@ -1,19 +1,28 @@ //! Methods and traits related to the [`ProcInst`] system. use unity::prelude::*; -use std::cell::UnsafeCell; pub mod desc; use desc::*; +pub mod inst; +pub use inst::*; + #[repr(C)] pub struct Proc; impl Proc { + pub fn get_root_hi() -> &'static mut ProcInst { + unsafe { proc_getroothi(None) } + } pub fn get_root_def() -> &'static mut ProcInst { unsafe { proc_getrootdef(None) } } + pub fn get_root_low() -> &'static mut ProcInst { + unsafe { proc_getrootlow(None) } + } + pub fn vsync(vsync_mode: i32) -> &'static mut ProcDesc { unsafe { proc_vsync(vsync_mode, None) } } @@ -23,72 +32,6 @@ impl Proc { } } -/// Represents a Instruction unit for a [`Proc`]. -/// -/// The ProcInst is chained to other ProcInsts to be executed in order by one of the three Proc instances of the game. -/// -/// They act as a high-level virtual machine to execute [instructions](crate::proc::ProcDesc) in sequence. Said instructions are queued in a ProcDesc array. -/// -/// A lot of classes inherit from it, so implement [`IsProcInst`] on them to represent this relation. -/// -/// If it is not possible for some reason, use the [cast](ProcInst::cast) methods to represent the chains as a ProcInst derivate of your choice. -/// -/// Example: -/// -/// ``` -/// pub fn createmenubind_hook(proc: &mut Il2CppObject) { -/// let casted_child = proc.child.cast_mut::(); -/// } -/// ``` -/// -/// Keep in mind that [`IsProcInst`] is much more preferable, and [cast](ProcInst::cast) should only be used as a last resort. -#[repr(C)] -#[unity::class("App", "ProcInst")] -pub struct ProcInst { - descs: &'static mut UnsafeCell>, - pub desc_index: i32, - pub name: Option<&'static Il2CppString>, - pub hashcode: i32, - /// The ProcInst this instance is attached to - pub parent: &'static mut ProcInst, - pub child: Option<&'static mut ProcInst>, - pub prev: Option<&'static mut ProcInst>, - pub next: Option<&'static mut ProcInst>, - /// Note: Observed a ProcVoidMethod being set here - persistent: *const u8, - /// Note: Actually a bitfield to mark ProcInsts for death (to be destroyed) - pub state: i32, - pub suspend: i32, - wait_time: f32, - tick_time: f32, - // RawValueStack - stack: &'static Il2CppObject, -} - -impl Drop for ProcInst { - fn drop(&mut self) { - panic!("ProcInst dropped"); - } -} - -impl ProcInst { - pub fn get_descs(&self) -> &Il2CppArray<&'static mut ProcDesc> { - unsafe { &*self.descs.get() } - } - - pub fn get_descs_mut(&self) -> &mut Il2CppArray<&'static mut ProcDesc> { - unsafe {&mut *self.descs.get() } - } - - pub fn cast>(&self) -> &T { - unsafe { std::mem::transmute::<&ProcInst, &T>(self) } - } - - pub fn cast_mut>(&mut self) -> &mut T { - unsafe { std::mem::transmute::<&mut ProcInst, &mut T>(self) } - } -} - /// Trait to simulate inheritance for [`ProcInst`]. /// /// If the trait is in scope, it is automatically implemented for objects that implement `AsMut`. @@ -100,9 +43,6 @@ pub trait Bindable { } } -impl Bindable for ProcInst { } - - #[unity::from_offset("App", "Proc", "WaitIsLoading")] fn proc_waitisloading( method_info: OptionalMethod, @@ -114,11 +54,21 @@ fn proc_vsync( method_info: OptionalMethod, ) -> &'static mut ProcDesc; +#[unity::from_offset("App", "Proc", "GetRootHi")] +fn proc_getroothi( + method_info: OptionalMethod, +) -> &'static mut ProcInst; + #[unity::from_offset("App", "Proc", "GetRootDef")] fn proc_getrootdef( method_info: OptionalMethod, ) -> &'static mut ProcInst; +#[unity::from_offset("App", "Proc", "GetRootLow")] +fn proc_getrootlow( + method_info: OptionalMethod, +) -> &'static mut ProcInst; + #[unity::from_offset("App", "Proc", "Label")] fn proc_label( label: i32, @@ -148,17 +98,6 @@ fn proc_end( method_info: OptionalMethod, ) -> &'static mut ProcDesc; -#[unity::from_offset("App", "ProcInst", "CreateBind")] -pub fn procinst_createbind( - this: &T, - parent: &P, - descs: &'static Il2CppArray<&'static mut ProcDesc>, - name: &'static Il2CppString, - method_info: OptionalMethod, -); - -#[unity::from_offset("App", "ProcInst", "OnDispose")] -pub fn procinst_ondispose(this: &ProcInst, method_info: OptionalMethod); /// A structure representing a call to a method that returns nothing. #[repr(C)] diff --git a/src/proc/inst.rs b/src/proc/inst.rs new file mode 100644 index 0000000..d6a9f52 --- /dev/null +++ b/src/proc/inst.rs @@ -0,0 +1,108 @@ +use std::cell::UnsafeCell; + +use unity::prelude::*; + +use super::{Bindable, ProcDesc, RawValueStack}; + +/// Represents a Instruction unit for a [`Proc`]. +/// +/// The ProcInst is chained to other ProcInsts to be executed in order by one of the three Proc instances of the game. +/// +/// They act as a high-level virtual machine to execute [instructions](crate::proc::ProcDesc) in sequence. Said instructions are queued in a ProcDesc array. +/// +/// A lot of classes inherit from it, so implement [`IsProcInst`] on them to represent this relation. +/// +/// If it is not possible for some reason, use the [cast](ProcInst::cast) methods to represent the chains as a ProcInst derivate of your choice. +/// +/// Example: +/// +/// ``` +/// pub fn createmenubind_hook(proc: &mut Il2CppObject) { +/// let casted_child = proc.child.cast_mut::(); +/// } +/// ``` +/// +/// Keep in mind that [`IsProcInst`] is much more preferable, and [cast](ProcInst::cast) should only be used as a last resort. +#[repr(C)] +#[unity::class("App", "ProcInst")] +pub struct ProcInst { + descs: &'static mut UnsafeCell>, + pub desc_index: i32, + pub name: Option<&'static Il2CppString>, + /// Unique ID derived from the name of the ProcInst. + pub hashcode: i32, + /// The ProcInst this instance is attached to + pub parent: Option<&'static mut ProcInst>, + /// The next ProcInst to process. ProcInsts are processed from child to parent. + pub child: Option<&'static mut ProcInst>, + pub prev: Option<&'static mut ProcInst>, + pub next: Option<&'static mut ProcInst>, + /// Note: Observed a ProcVoidMethod being set here + persistent: *const u8, + /// Note: Actually a bitfield to mark ProcInsts for death (to be destroyed) + pub state: i32, + /// This is supposed to be a bool, but struct alignment said otherwise. + pub suspend: i32, + wait_time: f32, + tick_time: f32, + // RawValueStack + stack: &'static Il2CppObject, +} + +impl Drop for ProcInst { + fn drop(&mut self) { + panic!("ProcInst dropped"); + } +} + +impl ProcInst { + pub fn get_child(&'static self) -> &'static ProcInst { + // Ray: yes, this'd crash if null. I'll fix later. + *self.child.as_ref().unwrap() + } + + pub fn get_child_mut(&'static mut self) -> &'static mut ProcInst { + // Ray: yes, this'd crash if null. I'll fix later. + *self.child.as_mut().unwrap() + } + + pub fn get_next(&'static self) -> &'static ProcInst { + // Ray: yes, this'd crash if null. I'll fix later. + *self.next.as_ref().unwrap() + } + + pub fn get_next_mut(&'static mut self) -> &'static mut ProcInst { + // Ray: yes, this'd crash if null. I'll fix later. + *self.next.as_mut().unwrap() + } + + pub fn get_descs(&self) -> &Il2CppArray<&'static mut ProcDesc> { + unsafe { &*self.descs.get() } + } + + pub fn get_descs_mut(&self) -> &mut Il2CppArray<&'static mut ProcDesc> { + unsafe {&mut *self.descs.get() } + } + + pub fn cast>(&self) -> &T { + unsafe { std::mem::transmute::<&ProcInst, &T>(self) } + } + + pub fn cast_mut>(&mut self) -> &mut T { + unsafe { std::mem::transmute::<&mut ProcInst, &mut T>(self) } + } +} + +impl Bindable for ProcInst { } + +#[unity::from_offset("App", "ProcInst", "CreateBind")] +pub fn procinst_createbind( + this: &T, + parent: &P, + descs: &'static Il2CppArray<&'static mut ProcDesc>, + name: &'static Il2CppString, + method_info: OptionalMethod, +); + +#[unity::from_offset("App", "ProcInst", "OnDispose")] +pub fn procinst_ondispose(this: &ProcInst, method_info: OptionalMethod); \ No newline at end of file