forked from Kylemc1413/NjsFixer
-
Notifications
You must be signed in to change notification settings - Fork 0
/
ReflectionUtil.cs
184 lines (158 loc) · 7.68 KB
/
ReflectionUtil.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using UnityEngine;
namespace NjsFixer
{
public static class ReflectionUtil
{
private const BindingFlags _allBindingFlags = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;
public static void SetPrivateField(this object obj, string fieldName, object value)
{
obj.GetType().GetField(fieldName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).SetValue(obj, value);
}
public static T GetPrivateField<T>(this object obj, string fieldName)
{
return (T)((object)obj.GetType().GetField(fieldName, BindingFlags.Instance | BindingFlags.NonPublic).GetValue(obj));
}
//Sets the value of a (static?) field in object "obj" with name "fieldName"
public static void SetField(this object obj, string fieldName, object value)
{
(obj is Type ? (Type)obj : obj.GetType())
.GetField(fieldName, _allBindingFlags)
.SetValue(obj, value);
}
//Gets the value of a (static?) field in object "obj" with name "fieldName"
public static object GetField(this object obj, string fieldName)
{
return (obj is Type ? (Type)obj : obj.GetType())
.GetField(fieldName, _allBindingFlags)
.GetValue(obj);
}
//Gets the value of a (static?) field in object "obj" with name "fieldName" (TYPED)
public static T GetField<T>(this object obj, string fieldName) => (T)GetField(obj, fieldName);
//Sets the value of a (static?) Property specified by the object "obj" and the name "propertyName"
public static void SetProperty(this object obj, string propertyName, object value)
{
(obj is Type ? (Type)obj : obj.GetType())
.GetProperty(propertyName, _allBindingFlags)
.SetValue(obj, value, null);
}
//Gets the value of a (static?) Property specified by the object "obj" and the name "propertyName"
public static object GetProperty(this object obj, string propertyName)
{
return (obj is Type ? (Type)obj : obj.GetType())
.GetProperty(propertyName, _allBindingFlags)
.GetValue(obj);
}
//Gets the value of a (static?) Property specified by the object "obj" and the name "propertyName" (TYPED)
public static T GetProperty<T>(this object obj, string propertyName) => (T)GetProperty(obj, propertyName);
//Invokes a (static?) private method with name "methodName" and params "methodParams", returns an object of the specified type
public static T InvokeMethod<T>(this object obj, string methodName, params object[] methodParams) => (T)InvokeMethod(obj, methodName, methodParams);
//Invokes a (static?) private method with name "methodName" and params "methodParams"
public static object InvokeMethod(this object obj, string methodName, params object[] methodParams)
{
return (obj is Type ? (Type)obj : obj.GetType())
.GetMethod(methodName, _allBindingFlags)
.Invoke(obj, methodParams);
}
//Returns a constructor with the specified parameters to the specified type or object
public static object InvokeConstructor(this object obj, params object[] constructorParams)
{
Type[] types = new Type[constructorParams.Length];
for (int i = 0; i < constructorParams.Length; i++) types[i] = constructorParams[i].GetType();
return (obj is Type ? (Type)obj : obj.GetType())
.GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, types, null)
.Invoke(constructorParams);
}
//Returns a Type object which can be used to invoke static methods with the above helpers
public static Type GetStaticType(string clazz)
{
return Type.GetType(clazz);
}
//Returns a list (of strings) of the names of all loaded assemblies
public static IEnumerable<Assembly> ListLoadedAssemblies()
{
return AppDomain.CurrentDomain.GetAssemblies();
}
//Returns a list of all loaded namespaces
//TODO: Check up on time complexity here, could potentially be parallelized
public static IEnumerable<string> ListNamespacesInAssembly(Assembly assembly)
{
IEnumerable<string> ret = Enumerable.Empty<string>();
ret = ret.Concat(assembly.GetTypes()
.Select(t => t.Namespace)
.Distinct()
.Where(n => n != null));
return ret.Distinct();
}
//Returns a list of classes in a namespace
//TODO: Check up on time complexity here, could potentially be parallelized
public static IEnumerable<string> ListClassesInNamespace(string ns)
{
//For each loaded assembly
foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
{
//If the assembly contains the desired namespace
if (assembly.GetTypes().Where(t => t.Namespace == ns).Any())
{
//Select the types we want from the namespace and return them
return assembly.GetTypes()
.Where(t => t.IsClass)
.Select(t => t.Name);
}
}
return null;
//Code to list reflectable classes
/*
ReflectionUtil.ListLoadedAssemblies().ToList().ForEach(x => {
if (x.GetName().Name == "BeatSaberMultiplayer")
{
Logger.Success($"ASSEMBLY: {x.GetName().Name}");
ReflectionUtil.ListNamespacesInAssembly(x).ToList().ForEach(y =>
{
Logger.Warning($"NAMESPACE: {y}");
ReflectionUtil.ListClassesInNamespace(y).ToList().ForEach(z =>
{
Logger.Warning($"CLASS: {z} : {((ReflectionUtil.GetStaticType(y + "." + z + "," + x) != null) ? "REFLECTABLE" : "NOT")}");
});
});
}
});
*/
}
//(Created by taz?) Copies a component to a destination object, keeping all its field values?
public static Behaviour CopyComponent(Behaviour original, Type originalType, Type overridingType, GameObject destination)
{
Behaviour copy = null;
try
{
copy = destination.AddComponent(overridingType) as Behaviour;
}
catch (Exception)
{
}
copy.enabled = false;
//Copy types of super classes as well as our class
Type type = originalType;
while (type != typeof(MonoBehaviour))
{
CopyForType(type, original, copy);
type = type.BaseType;
}
copy.enabled = true;
return copy;
}
//(Created by taz?) Copies a Component of Type type, and all its fields
private static void CopyForType(Type type, Component source, Component destination)
{
FieldInfo[] myObjectFields = type.GetFields(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.GetField | BindingFlags.SetField);
foreach (FieldInfo fi in myObjectFields)
{
fi.SetValue(destination, fi.GetValue(source));
}
}
}
}