Open holodia opened 3 years ago
Hi,
Could you please provide example code for reproducing the issue? Unity version and target platform would be also helpful.
I tried to reproduce the issue with PC Windows IL2CPP build and I did not get that exception. I used example code from README.md and SerializableCallback<int, MyProduct>
callback.
Trying to get some internet points for anyone else that finds this in the future since I also ran into this.
This is how I fixed it, check out the class comments for how and why I think it fixes it. I'm too lazy to rewrite things up here, so just read the class comments 😂
/// <summary>
/// Since comparer nodes and other classes use the SerializableCallback library, which uses
/// reflection to make function calls. These classes/function calls are stripped by
/// the compiler at compile time. This means any function not manually called
/// (in code) gets removed at compile time. Mainly some InvokableCallback<T, J>
/// never get created or used at compile time. In the editor, this works fine
/// since it supports JIT compilation, mobile devices don't. So we manually create and
/// "use" these classes so they are not stripped.
///
/// Some thoughts:
/// It's strange since methods that have a single param don't get stripped. But
/// anytime there is a function with 2 or more parameters, it gets stripped and requires
/// this... Not sure why. My only guess would be the SerializableCallback library
/// serializes 1 param methods differently from X param methods. Notably, Unity
/// doesn't strip functions that are only used in UnityAction's. I wonder if this lib, or Unity
/// is using some engine feature?
/// Regardless, defining them manually for each method signature makes it work.
/// </summary>
public static class AOTStubsIL2CPP
{
public static void Stub()
{
// Quests
new QuestLineIntInvokable(null, string.Empty);
}
class QuestLineIntInvokable : InvokableCallback<QuestLine, int, bool>
{
public QuestLineIntInvokable(object target, string methodName) : base(target, methodName) { }
}
}
For my use case above, I needed a method that too 2 params, a QuestLine
(custom class in project) and an int
. At the bottom, I define the class. Then "use" it in code. From your error message, you can sort of "parse" what the method is.
Attempting to call method 'InvokableCallback`2[[**System.String**, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]::.ctor'
It looks like you're trying to call a function with the signature of: bool Foo(string bar)
. So your class might like something like this:
class FooBarInvokable : InvokableCallback<string, bool>
{
public FooBarInvokable (object target, string methodName) : base(target, methodName) { }
}
Hope this helps lol
I am no expert on C# compiler but as I understand it, methods are not being "stripped", they are not being created at all. Generic methods are being created by compiler - each type and combination of types it stumbles upon when it reads the code creates a separate method. Since here the methods are constructed in runtime, it does not create those combinations AOT.
As of why some methods with smaller number of parameters do exist - I don't know. In my case, 0 input and 1 output params callbacks were created, callbacks with 1 input and 1 output were not. Maybe compiler does create some basic types? No idea.
But this is the reason why even [UnityEngine.Scripting.Preserve] attribute or linker xml file won't work - the methods aren't stripped - they don't exist.
Callstack: