0

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

asked Sep 21, 2024 at 14:38
4
  • Maybe a better solution is to pass the requested field through a Func<Joint, float> instead of a field name as string: jointObject => jointObject.massScale. Commented Sep 21, 2024 at 16:04
  • @OlivierJacot-Descombes no, field inside string required Commented Sep 21, 2024 at 22:41
  • I know it may sound weird but have you tried GetProperty instead of GetMember (and GetFiedl)? Commented Sep 23, 2024 at 12:39
  • @tschmit007 yes, that also wasn't working Commented Sep 23, 2024 at 16:29

1 Answer 1

-2

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.GetMembers instead of System.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 is string, but how do you know that you provided a correct name and that you did not simply make a typo? Where does your requested come from? (Here is a hint for you: nameof). If you answer this question and are interested in knowing how to go around without System.Type.GetMember and strings, most likely I will be able to suggest the right technique for you.
  • Another typical mistake is the wrong BindingFlags value. 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.

answered Nov 14, 2024 at 2:21
Sign up to request clarification or add additional context in comments.

20 Comments

I already try ALL of that, check the question please before making an answer
Where is the declaration of the type you're reflecting in your question? And I doubt that you tried it all. Anyway, your question doesn't show those attempts. Look, if you need really working help, you need 1) try to follow the advice, 2) create short but comprehensive code to reproduce and provide it in your question. Not a fragment of your real code, but a comprehensive short code sample with a problem anyone can build and run. Mind you, your problem is not just easy to solve, but very easy to solve, in case you provide meaningful and comprehensive issue report.
1) You can see at "more info" all fields of type 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 question
BUT for you i will rewrite results: Joint.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!
there NO fields in il2cpp types, since cpp2il makes getter/setter for each pure c++ field that will directly change value of it. Also there no reason to change to usual for loop, but yeah, i already try that before making a question. And yes, again, there already output of that in my question at "More Info" section. And i already try almost any sensable combination of binding flags, including youre (check the code in question!). And that NOT a unity diagnostics, its unity explorer, that uses UnhollowerLib to fetch fields (and it works, but i wont put is as dependency)
|

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.