internal static List <GlobalIdentifier> MapGlobalIdentifiers(Il2CppMetadata metadata, PE.PE cppAssembly) { //Classes var ret = metadata.metadataUsageDic[1] .Select(kvp => new { kvp, type = cppAssembly.types[kvp.Value] }) .Select(t => new GlobalIdentifier { Name = Utils.GetTypeName(metadata, cppAssembly, t.type, true), Offset = cppAssembly.metadataUsages[t.kvp.Key], IdentifierType = GlobalIdentifier.Type.TYPE }).ToList(); //Idx 2 is exactly the same thing ret.AddRange(metadata.metadataUsageDic[2] .Select(kvp => new { kvp, type = cppAssembly.types[kvp.Value] }) .Select(t => new GlobalIdentifier { Name = Utils.GetTypeName(metadata, cppAssembly, t.type, true), Offset = cppAssembly.metadataUsages[t.kvp.Key], IdentifierType = GlobalIdentifier.Type.TYPE }) ); //Methods is idx 3 //Don't @ me, i prefer LINQ to foreach loops. //But that said this could be optimised to less t-ing ret.AddRange(metadata.metadataUsageDic[3] .Select(kvp => new { kvp, method = metadata.methodDefs[kvp.Value] }) .Select(t => new { t.kvp, t.method, type = metadata.typeDefs[t.method.declaringType] }) .Select(t => new { t.kvp, t.method, typeName = Utils.GetTypeName(metadata, cppAssembly, t.type) }) .Select(t => new { t.kvp, methodName = t.typeName + "." + metadata.GetStringFromIndex(t.method.nameIndex) + "()" }) .Select(t => new GlobalIdentifier { IdentifierType = GlobalIdentifier.Type.METHOD, Name = t.methodName, Offset = cppAssembly.metadataUsages[t.kvp.Key] }) ); //Fields is idx 4 ret.AddRange(metadata.metadataUsageDic[4] .Select(kvp => new { kvp, fieldRef = metadata.fieldRefs[kvp.Value] }) .Select(t => new { t.kvp, t.fieldRef, type = cppAssembly.types[t.fieldRef.typeIndex] }) .Select(t => new { t.type, t.kvp, t.fieldRef, typeDef = metadata.typeDefs[t.type.data.classIndex] }) .Select(t => new { t.type, t.kvp, fieldDef = metadata.fieldDefs[t.typeDef.firstFieldIdx + t.fieldRef.fieldIndex] }) .Select(t => new { t.kvp, fieldName = Utils.GetTypeName(metadata, cppAssembly, t.type, true) + "." + metadata.GetStringFromIndex(t.fieldDef.nameIndex) }) .Select(t => new GlobalIdentifier { IdentifierType = GlobalIdentifier.Type.FIELD, Name = t.fieldName, Offset = cppAssembly.metadataUsages[t.kvp.Key] }) ); //Literals ret.AddRange(metadata.metadataUsageDic[5] .Select(kvp => new GlobalIdentifier { IdentifierType = GlobalIdentifier.Type.LITERAL, Offset = cppAssembly.metadataUsages[kvp.Key], Name = $"{metadata.GetStringLiteralFromIndex(kvp.Value)}" }) ); foreach (var kvp in metadata.metadataUsageDic[6]) //kIl2CppMetadataUsageMethodRef { var methodSpec = cppAssembly.methodSpecs[kvp.Value]; var methodDef = metadata.methodDefs[methodSpec.methodDefinitionIndex]; var typeDef = metadata.typeDefs[methodDef.declaringType]; var typeName = Utils.GetTypeName(metadata, cppAssembly, typeDef); if (methodSpec.classIndexIndex != -1) { var classInst = cppAssembly.genericInsts[methodSpec.classIndexIndex]; typeName += Utils.GetGenericTypeParams(metadata, cppAssembly, classInst); } var methodName = typeName + "." + metadata.GetStringFromIndex(methodDef.nameIndex) + "()"; if (methodSpec.methodIndexIndex != -1) { var methodInst = cppAssembly.genericInsts[methodSpec.methodIndexIndex]; methodName += Utils.GetGenericTypeParams(metadata, cppAssembly, methodInst); } ret.Add(new GlobalIdentifier { Name = methodName, IdentifierType = GlobalIdentifier.Type.METHOD, Offset = cppAssembly.metadataUsages[kvp.Key] }); } return(ret); }