I have melonloader on il2cpp game and try to write mod for it.
I need to get field Joint.massScale from il2cppSystem.Object as ConfigurableJoint : Joint object.
That field exist in UnityExplorer:
enter image description here
And can user directly: enter image description here
What fails:
.GetMember and .GetMembers: they just don't include that field/property
MemberInfo member = anyObject.GetIl2CppType()
.GetMember(requested, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static)
.First();
Recursive GetMember:
static IEnumerable<MemberInfo> GetAllMembersRecursivly(Il2CppSystem.Type type) =>
type.GetMembers(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static)
.Concat(type.BaseType == Il2CppType.Of<Il2CppSystem.Object>() ? new MemberInfo[0] : GetAllMembersRecursivly(type.BaseType));
Same result
Maybe???
The only workaround i found is to hardcode that type like that:
if (cj != null && requested == "massScale" && !path.Any())
{
return ((v) => cj.massScale = v.Unbox<float>(), Il2CppType.Of<float>());
}
But that... MEH
More info:
I do some debugging and output all fields of type and its subtype:
base type: UnityEngine.ConfigurableJoint
fields:
set_targetPosition
set_xDrive
set_yDrive
set_zDrive
set_targetRotation
set_rotationDriveMode
set_slerpDrive
set_targetPosition_Injected
set_xDrive_Injected
set_yDrive_Injected
set_zDrive_Injected
set_targetRotation_Injected
set_slerpDrive_Injected
targetPosition
xDrive
yDrive
zDrive
targetRotation
rotationDriveMode
slerpDrive
base type: UnityEngine.Joint
fields:
get_connectedBody
set_connectedBody
set_axis
get_anchor
set_anchor
get_connectedAnchor
set_connectedAnchor
set_autoConfigureConnectedAnchor
set_enableCollision
set_enablePreprocessing
set_axis_Injected
get_anchor_Injected
set_anchor_Injected
get_connectedAnchor_Injected
set_connectedAnchor_Injected
connectedBody
axis
anchor
connectedAnchor
autoConfigureConnectedAnchor
enableCollision
enablePreprocessing
Flags: BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Declared for each subtype
1 Answer 1
You need to show the exact definition of the type you want to dig in using Reflection, but I can tell you the most typical mistakes leading to missing member information and the ways to overcome them.
- To start it, use
System.Type.GetMembersinstead ofSystem.Type.GetMember, traverse the array of all members, and try to find out what's missing. In nearly all cases it helps to resolve your issue. - More generally, you almost never need
System.Type.GetMember. The problem is that the first argument isstring, but how do you know that you provided a correct name and that you did not simply make a typo? Where does yourrequestedcome from? (Here is a hint for you:nameof). If you answer this question and are interested in knowing how to go around withoutSystem.Type.GetMemberand strings, most likely I will be able to suggest the right technique for you. - Another typical mistake is the wrong
BindingFlagsvalue. First, you need to use my first advice to see what are the correct features of your member. An even clearer approach is this: start with the following value:BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static. That's it, nothing else.
Added:
I got another idea: I don't know how the reflected data is presented by the UnityExplorer. It looks flat, but what if some type members come from nesting types? I forgot about them. By the way, on the picture from `UnityExplorer, the problematic member is invisible.
Anyway, this is the code I suggest to investigate the problematic type:
First of all, I want to show all the library types used in the code I'll show:
using Type = System.Type;
using Console = System.Console;
using MemberInfo = System.Reflection.MemberInfo;
using PropertyInfo = System.Reflection.PropertyInfo;
using FieldInfo = System.Reflection.FieldInfo;
using BindingFlags = System.Reflection.BindingFlags;
Now, this is the investigation code sending the information we need to know to System.Console:
public static class ReflectionSample {
static readonly BindingFlags flags =
BindingFlags.Static |
BindingFlags.Instance |
BindingFlags.Public |
BindingFlags.NonPublic;
public static void FindAll(Type type) {
MemberInfo[] members = type.GetMembers(flags);
foreach (var member in members) {
string memberOrField = string.Empty;
if (member is FieldInfo fieldInfo)
memberOrField = $"{fieldInfo.FieldType.Name} field";
else if (member is PropertyInfo property)
memberOrField = $"{property.PropertyType.Name} property";
else
memberOrField = "(method)";
Console.WriteLine(
// + is not nice, just to format code for the answer:
$"Declaring Type: {member.DeclaringType.Namespace}.{member.DeclaringType.Name}, " +
$"Member Type: {member.MemberType}, " +
$"Member Name: {member.Name}, " +
$"{memberOrField}");
Type[] nestedTypes = type.GetNestedTypes(flags);
foreach (var nestedType in nestedTypes)
// go recursive:
FindAll(nestedType);
} //loop
} //FindAll
} //ReflectionSample
Could you try it and report the result? You could, say, redirect the output to some file and copy its content to the text of your question.
20 Comments
ConfigurableJoint and Joint (check "base type: " line), plus you can see at screenshot that its Joint field. 2) Its impossible to make short code that reproduces that, since its don't work only at certain game at specific cpp2il decompile. And yes, everything you say there i try already before even making a question, and almost every result of that attempts i wrote on questionJoint.massScale field EXISTS. I can get/set that field directly and everything works fine. So type i was using is Joint. As you can see in More Info section there no field with that name for UnityEngine.Joint. As i was saying i already try .GetMembers at What Fails and More Info section. I literraly output everything that was returned by that method, and there no that field. Same for second tip. And you can check i use same binding flags at What Fails section (i try almost every combination). So again, read question first!Explore related questions
See similar questions with these tags.
Func<Joint, float>instead of a field name as string:jointObject => jointObject.massScale.