Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Auto inject Il2Cpp-Types #334

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open

Auto inject Il2Cpp-Types #334

wants to merge 3 commits into from

Conversation

PHPCore1
Copy link

@PHPCore1 PHPCore1 commented Nov 16, 2021

Description

With this change the LoadPlugin method will automatically search every Type which inherits Il2CppObjectBase in the plugin assembly and registers it

Motivation and Context

It makes creating new types easier, because you don't have to create a bunch of ClassInjector.RegisterTypeInIl2Cpp

How Has This Been Tested?

I tested it be creating a plugin which has multiple MonoBehaviour without ClassInjector.RegisterTypeInIl2Cpp and then adding them to a GameObject

Screenshots (if appropriate):

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)

Checklist:

  • My code follows the code style of this project.
  • My change requires a change to the documentation.
  • I have updated the documentation accordingly.

@simonkellly
Copy link
Contributor

Due to how interfaces are implemented, the set of interfaces that the class inherits from need to be specified manually, and I think that this may cause issues regarding this.

@ghorsington
Copy link
Contributor

Greetings!

Thanks for the contribution! Here are some of my points regarding this:

  • Have you tested if ordering affects this? For example, it is possible to have a setup where you have BaseObject : Il2CppObjectBase, FooObject : BaseObject and BarObject : FooObject. In that case, the injection order might matter which is why it should be tested and accounted for. And what about the case where a class inherits from another class that's in another assembly?
  • One addition I'd suggest is adding some sort of DontRegisterInIl2Cpp attribute with which plugin devs can prevent injecting types automatically. The attribute could be both assembly-wide, applied via
    // Don't inject anything in this assembly
    [assembly: DontRegisterInIl2Cpp]
    and type-specific, applied via
    [DontRegisterInIl2Cpp]
    class FooObject: Il2CppObjectBase
  • I have similar concerns that @simonkellly notes. That said, it should be possible to handle maybe with inheritance (and checking inherited types) or by adding an attribute for this.

Overall I think that the points I mentioned above should be addressed before this PR can be merged.

@PHPCore1
Copy link
Author

Greeting,
thanks for your thoughts on my changes.
I didn't thought about the part with the interfaces.
I already tested the part with superclasses and it's working fine, because ClassInjector.RegisterTypeInIl2Cpp automatically registers the base Type if it isn't registered already.
I'll fix the part with the interfaces and add the attribute you mentioned in the evening.

@js6pak
Copy link
Member

js6pak commented Nov 16, 2021

This also doesn't respect bepinex's caching for finding types with mono.cecil
Imo interface attribute should be built into unhollower

@PHPCore1
Copy link
Author

Greetings!

Thanks for the contribution! Here are some of my points regarding this:

  • Have you tested if ordering affects this? For example, it is possible to have a setup where you have BaseObject : Il2CppObjectBase, FooObject : BaseObject and BarObject : FooObject. In that case, the injection order might matter which is why it should be tested and accounted for. And what about the case where a class inherits from another class that's in another assembly?

  • One addition I'd suggest is adding some sort of DontRegisterInIl2Cpp attribute with which plugin devs can prevent injecting types automatically. The attribute could be both assembly-wide, applied via

    // Don't inject anything in this assembly
    [assembly: DontRegisterInIl2Cpp]

    and type-specific, applied via

    [DontRegisterInIl2Cpp]
    class FooObject: Il2CppObjectBase
  • I have similar concerns that @simonkellly notes. That said, it should be possible to handle maybe with inheritance (and checking inherited types) or by adding an attribute for this.

Overall I think that the points I mentioned above should be addressed before this PR can be merged.

I hope it's ok how I made it.
I'll commit the cache and cecil implementation later, because I run out of time.
There is now an attribute to disable Auto-Injection for Assembly or Type and an attribute to set the interfaces for a Type.

Copy link
Contributor

@ghorsington ghorsington left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here are some of my notes.

I think that it's fine if you don't have the time to finish it up right away, there is no hurry finishing this right this instant. When it comes to our plugin cache, this should not conflict with this as-is, but it would be preferable to use it as it prevents some early type resolving issues and helps with performance.

As for the interface attribute, I think it might be worth moving it to Unhollower side. If you don't have time to do it, I can probably look at it this week myself.

Comment on lines +9 to +20
[AttributeUsage(AttributeTargets.Class)]
public class Il2CppInterfaces : Attribute
{

public Type[] Interfaces { get; protected set; }

public Il2CppInterfaces(params Type[] interfaces)
{
Interfaces = interfaces;
}

}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suggest Il2CppImplementsAttribute as the name.

Also, I agree with @js6pak that maybe this can be moved to Unhollower's ClassInjector class. This would make manual injector much, much easier (and it makes sense to keep this attribute on Unhollower's side).

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok I'll move it to Unhollower

BepInEx.IL2CPP/PluginClassInjector.cs Show resolved Hide resolved
BepInEx.IL2CPP/PluginClassInjector.cs Show resolved Hide resolved
BepInEx.IL2CPP/PluginClassInjector.cs Show resolved Hide resolved
@ghorsington
Copy link
Contributor

ghorsington commented Nov 16, 2021

I adjusted the OP since this is potentially a breaking feature for older BE builds. Since now registering is opt-out instead of opt-in, there could be cases where undesired types get injected automatically.

Doesn't affect the PR itself (as it only potentially breaks previous BE builds), but marking this correctly is important for future reference.

@PHPCore1
Copy link
Author

This is fine, but I've got an idea how it wouldn't break older builds.
When I do the changes to Unhollower I will make Il2CppInterfacesAttribute optional and add a method, which will automatically pass all inherited interfaces from il2cpp to the type register, so it won't break older plugins.

@ghorsington
Copy link
Contributor

The overload is of course a good idea. That said, the reason this is a potentially breaking PR is because before BepInEx did not automatically inject types into Il2Cpp. In other words, the injection was "opt-in", as you had to specifically write code to inject your type.

Now with automatic injection, you have to instead specify which types you don't want to inject (or if you don't want to inject anything in your assembly automatically). As such, the injection becomes "opt-out", as you have to add an attribute to get back to current BepInEx behaviour.

This is likely not a major issue since in most cases you will always want to inject Il2Cpp types into Il2Cpp. However, those plugins that currently assume they can skip injection just by not injecting can break. As I mentioned, it is not a major issue IMO as this only affects Bleeding Edge build which are expected to be unstable and not compatible with each other.

@ghorsington
Copy link
Contributor

Unhollower version 0.4.20.0 released with changes from BepInEx/Il2CppInterop#17, you should be able to update it in your PR by updating BepInEx.IL2CPP.csproj

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants