Refactor SceneManager / Transform; fix a number of bugs in scene/game object traversal#133
Refactor SceneManager / Transform; fix a number of bugs in scene/game object traversal#133mitchell-merry wants to merge 26 commits into
Conversation
…t of SceneManager and Scene
…ncy - by just shelling out to the Mono/il2cpp class code
|
|
||
| impl Class { | ||
| pub(super) fn get_name<const N: usize>( | ||
| pub fn get_from_component( |
There was a problem hiding this comment.
"component" isn't accurate here, but there's something in between the component and the class. not exactly sure what it is.
There was a problem hiding this comment.
[ ] TODO: figure out what it is
| })) | ||
| } | ||
|
|
||
| // TODO it's really dumb i have to split this by mono/il2cpp |
There was a problem hiding this comment.
we really need to implement some sort of strategy pattern here. The amount of code duplication is getting ridiculous
| game_object_activeself: 0x5E, | ||
| game_object_activeinhierarchy: 0x5F, | ||
| klass: 0x28, | ||
| klass_name: 0x48, |
There was a problem hiding this comment.
this changes depending on the mono version, which, of course it does.
Now we just store the offset to the object handle, and you have to use mono/il2cpp specific code to get the component
| /// (and so on), as well as a list of `Component`s, which are classes (eg. | ||
| /// `MonoBehaviour`) containing data we might want to retrieve for the auto | ||
| /// splitter logic. | ||
| fn root_game_objects<'a>( |
There was a problem hiding this comment.
This makes more conceptual sense to live on the Scene rather than the SceneManager
|
|
||
| /// Tries to find the specified root [`Transform`] from the | ||
| /// `DontDestroyOnLoad` Unity scene. | ||
| pub fn get_game_object_from_dont_destroy_on_load( |
There was a problem hiding this comment.
no replacement for this - get the DDoL scene from SceneManager, then call get_root_game_object as with any other Scene
|
|
||
| iter::from_fn(move || { | ||
| // TODO check if this is correct on other games | ||
| let [_prev, next, current]: [Address; 3] = match scene_manager.pointer_size { |
There was a problem hiding this comment.
note: there's a change here, previously we were using [first, _, third] where first was our next element.
That's wrong: https://gist.github.com/just-ero/92457b51baf85bd1e5b8c87de8c9835e#file-list-hpp it actually causes us to go in the reverse order in the list. That caused me some issues in Cuphead
| v_table: MonoVTableOffsets { vtable: 0x48 }, | ||
| }), | ||
| (BinaryFormat::ELF | BinaryFormat::MachO, Version::V3, PointerSize::Bit64) => { | ||
| Some(&Self { |
There was a problem hiding this comment.
Not sure why this indented a level... I didn't change any offsets here.
| const SIG_64_BIT_PE_1: Signature<13> = | ||
| Signature::new("48 83 EC 20 4C 8B ?5 ?? ?? ?? ?? 33 F6"); | ||
| const SIG_64_BIT_PE_2: Signature<13> = | ||
| Signature::new("48 83 EC 20 48 8B 2D ?? ?? ?? ?? 33 F6"); |
There was a problem hiding this comment.
note: In my testing, newer versions of unity (Unity 6000.4.5f1 specifically) didn't work with the old sig, so I just added this new one
| /// FIXME: This function is a bandaid while we don't have support for all | ||
| /// scene manager versions in asr. We should remove this by supporting | ||
| /// those versions without override. | ||
| pub fn attach_with_offsets( |
There was a problem hiding this comment.
note: Since getting all of the offsets on every unity version is quite a large task, I'm opting to just support passing in offsets manually for now.
…g the mono object and add getting the scene manager when it's not in the UnityPlayer module
|
|
||
| (pointer_size, base_address) | ||
| } else { | ||
| // If it's not in UnityPlayer, then it's in the main module (old unity versions) |
There was a problem hiding this comment.
note: I'm also adding support for older versions of Unity in this PR (well except for the offsets, which have to be overridden, which I'll do in later PRs)
| .ok_or(Error {}) | ||
| } | ||
| // FIXME: Untested on V2 | ||
| mono::Version::V2 | mono::Version::V3 => { |
There was a problem hiding this comment.
note: previous logic only ever did the equivalent of the V1 branch - I found that at least V3 (or like, newer versions, don't know if it's actually split on mono versions) have an extra dereference
Another one of the changes I made to asr that I need to upstream...
Why?
I'm now more and more often traversing the gameobject tree in my autosplitters. This has culminated in being able to get a field on a component of a gameobject in a scene: https://github.com/mitchell-merry/autosplitters-wasm/blob/94fbcef38134317b3a5bd7e549a483f18bed17c4/cuphead/src/memory.rs#L170 which does wonders for what's possible.
I have been maintaining a fork with a bunch of tweaks to asr to make this possible, and it's about time I upstream some of it.
get_game_object_from_dont_destroy_on_loaddoesn't really make sense as a specific function, since we can already get the DDoL scene + game objects on arbitrary scenesWhat?
root_game_objects,get_root_game_objectget_game_object_from_dont_destroy_on_load(replacement is to get the DDoL scene then callget_root_game_object, like any other scene)Scene#root_game_objectsnow readsnextinstead ofprev, so the objects are read in the correct orderTransform#find_transformwhich traverses the game object tree for you via a path of game object namesTransformintoGameObject&TransformTransform#get_namelogic toGameObject#get_name, addTransform#get_game_objecttoTransformand makeTransform#get_nameuse the above twoTransform#classesandTransform#get_classtoGameObjectTransform#get_classsplit intoGameObject#get_class_monoandGameObject#get_class_il2cppsince the offset ofklass.namedepends on the mono version / il2cpp version, same way as it does in the regular path dereferencing codeGameObject#is_active_in_hierarchyandGameObject#is_active_self, which are self-explanatoryTesting
TODO: