@@ -21,18 +21,24 @@ public class HookInstance
21
21
22
22
public bool Enabled ;
23
23
public MethodInfo TargetMethod ;
24
- public string GeneratedSource ;
24
+ public string PatchSourceCode ;
25
25
26
- private string shortSignature ;
26
+ private readonly string shortSignature ;
27
27
private PatchProcessor patchProcessor ;
28
- private HarmonyMethod patchDelegate ;
29
- private MethodInfo patchDelegateMethodInfo ;
28
+
29
+ private MethodInfo postfix ;
30
+ private MethodInfo prefix ;
31
+ private MethodInfo finalizer ;
32
+ private MethodInfo transpiler ;
30
33
31
34
public HookInstance ( MethodInfo targetMethod )
32
35
{
33
36
this . TargetMethod = targetMethod ;
34
37
this . shortSignature = $ "{ targetMethod . DeclaringType . Name } .{ targetMethod . Name } ";
35
- if ( GenerateProcessorAndDelegate ( ) )
38
+
39
+ GenerateDefaultPatchSourceCode ( targetMethod ) ;
40
+
41
+ if ( CompileAndGenerateProcessor ( PatchSourceCode ) )
36
42
Patch ( ) ;
37
43
}
38
44
@@ -41,30 +47,53 @@ public HookInstance(MethodInfo targetMethod)
41
47
// TypeDefinition.Definition
42
48
private static readonly PropertyInfo pi_Definition = ReflectionUtility . GetPropertyInfo ( typeof ( TypeDefinition ) , "Definition" ) ;
43
49
44
- private bool GenerateProcessorAndDelegate ( )
50
+ public bool CompileAndGenerateProcessor ( string patchSource )
45
51
{
52
+ Unpatch ( ) ;
53
+
46
54
try
47
55
{
48
56
patchProcessor = ExplorerCore . Harmony . CreateProcessor ( TargetMethod ) ;
49
57
50
58
// Dynamically compile the patch method
51
59
52
- scriptEvaluator . Run ( GeneratePatchSourceCode ( TargetMethod ) ) ;
60
+ var codeBuilder = new StringBuilder ( ) ;
61
+
62
+ codeBuilder . AppendLine ( $ "public class DynamicPatch_{ DateTime . Now . Ticks } ") ;
63
+ codeBuilder . AppendLine ( "{" ) ;
64
+ codeBuilder . AppendLine ( patchSource ) ;
65
+ codeBuilder . AppendLine ( "}" ) ;
66
+
67
+ scriptEvaluator . Run ( codeBuilder . ToString ( ) ) ;
53
68
54
69
if ( ScriptEvaluator . _reportPrinter . ErrorsCount > 0 )
55
70
throw new FormatException ( $ "Unable to compile the generated patch!") ;
56
71
57
72
// TODO: Publicize MCS to avoid this reflection
58
- // Get the last defined type in the source file
59
- var typeContainer = ( ( CompilationSourceFile ) fi_sourceFile . GetValue ( scriptEvaluator ) ) . Containers . Last ( ) ;
60
- // Get the TypeSpec from the TypeDefinition, then get its "MetaInfo" (System.Type), then get the method called Patch.
61
- this . patchDelegateMethodInfo = ( ( TypeSpec ) pi_Definition . GetValue ( ( Class ) typeContainer , null ) )
62
- . GetMetaInfo ( )
63
- . GetMethod ( "Patch" , ReflectionUtility . FLAGS ) ;
73
+ // Get the most recent Patch type in the source file
74
+ var typeContainer = ( ( CompilationSourceFile ) fi_sourceFile . GetValue ( scriptEvaluator ) )
75
+ . Containers
76
+ . Last ( it => it . MemberName . Name . StartsWith ( "DynamicPatch_" ) ) ;
77
+ // Get the TypeSpec from the TypeDefinition, then get its "MetaInfo" (System.Type )
78
+ var patchClass = ( ( TypeSpec ) pi_Definition . GetValue ( ( Class ) typeContainer , null ) ) . GetMetaInfo ( ) ;
64
79
65
- // Actually create the harmony patch
66
- this . patchDelegate = new HarmonyMethod ( patchDelegateMethodInfo ) ;
67
- patchProcessor . AddPostfix ( patchDelegate ) ;
80
+ // Create the harmony patches as defined
81
+
82
+ postfix = patchClass . GetMethod ( "Postfix" , ReflectionUtility . FLAGS ) ;
83
+ if ( postfix != null )
84
+ patchProcessor . AddPostfix ( new HarmonyMethod ( postfix ) ) ;
85
+
86
+ prefix = patchClass . GetMethod ( "Prefix" , ReflectionUtility . FLAGS ) ;
87
+ if ( prefix != null )
88
+ patchProcessor . AddPrefix ( new HarmonyMethod ( prefix ) ) ;
89
+
90
+ finalizer = patchClass . GetMethod ( "Finalizer" , ReflectionUtility . FLAGS ) ;
91
+ if ( finalizer != null )
92
+ patchProcessor . AddFinalizer ( new HarmonyMethod ( finalizer ) ) ;
93
+
94
+ transpiler = patchClass . GetMethod ( "Transpiler" , ReflectionUtility . FLAGS ) ;
95
+ if ( transpiler != null )
96
+ patchProcessor . AddTranspiler ( new HarmonyMethod ( transpiler ) ) ;
68
97
69
98
return true ;
70
99
}
@@ -75,16 +104,12 @@ private bool GenerateProcessorAndDelegate()
75
104
}
76
105
}
77
106
78
- private string GeneratePatchSourceCode ( MethodInfo targetMethod )
107
+ private string GenerateDefaultPatchSourceCode ( MethodInfo targetMethod )
79
108
{
80
109
var codeBuilder = new StringBuilder ( ) ;
81
-
82
- codeBuilder . AppendLine ( $ "public class DynamicPatch_{ DateTime . Now . Ticks } ") ;
83
- codeBuilder . AppendLine ( "{" ) ;
84
-
85
110
// Arguments
86
111
87
- codeBuilder . Append ( " public static void Patch (System.Reflection.MethodBase __originalMethod" ) ;
112
+ codeBuilder . Append ( "public static void Postfix (System.Reflection.MethodBase __originalMethod" ) ;
88
113
89
114
if ( ! targetMethod . IsStatic )
90
115
codeBuilder . Append ( $ ", { targetMethod . DeclaringType . FullName } __instance") ;
@@ -106,55 +131,53 @@ private string GeneratePatchSourceCode(MethodInfo targetMethod)
106
131
107
132
// Patch body
108
133
109
- codeBuilder . AppendLine ( " {" ) ;
134
+ codeBuilder . AppendLine ( "{" ) ;
110
135
111
- codeBuilder . AppendLine ( " try {" ) ;
136
+ codeBuilder . AppendLine ( " try {" ) ;
112
137
113
138
// Log message
114
139
115
140
var logMessage = new StringBuilder ( ) ;
116
- logMessage . AppendLine ( $ "$@ \" Patch called: { shortSignature } ") ;
117
-
141
+ logMessage . Append ( $ "Patch called: { shortSignature } \\ n ") ;
142
+
118
143
if ( ! targetMethod . IsStatic )
119
- logMessage . AppendLine ( "__instance: {__instance.ToString()}" ) ;
144
+ logMessage . Append ( "__instance: {__instance.ToString()}\\ n " ) ;
120
145
121
146
paramIdx = 0 ;
122
147
foreach ( var param in parameters )
123
148
{
149
+ logMessage . Append ( $ "Parameter { paramIdx } { param . Name } : ") ;
124
150
Type pType = param . ParameterType ;
125
151
if ( pType . IsByRef ) pType = pType . GetElementType ( ) ;
126
152
if ( pType . IsValueType )
127
- logMessage . AppendLine ( $ "Parameter { paramIdx } { param . Name } : {{__{ paramIdx } .ToString()}}") ;
153
+ logMessage . Append ( $ "{{__{ paramIdx } .ToString()}}") ;
128
154
else
129
- logMessage . AppendLine ( $ "Parameter { paramIdx } { param . Name } : {{__{ paramIdx } ?.ToString() ?? \" null\" }}") ;
155
+ logMessage . Append ( $ "{{__{ paramIdx } ?.ToString() ?? \" null\" }}") ;
156
+ logMessage . Append ( "\\ n" ) ;
130
157
paramIdx ++ ;
131
158
}
132
159
133
160
if ( targetMethod . ReturnType != typeof ( void ) )
134
161
{
162
+ logMessage . Append ( "Return value: " ) ;
135
163
if ( targetMethod . ReturnType . IsValueType )
136
- logMessage . AppendLine ( "Return value: {__result.ToString()}") ;
164
+ logMessage . Append ( " {__result.ToString()}") ;
137
165
else
138
- logMessage . AppendLine ( "Return value: {__result?.ToString() ?? \" null\" }" ) ;
166
+ logMessage . Append ( "{__result?.ToString() ?? \" null\" }" ) ;
167
+ logMessage . Append ( "\\ n" ) ;
139
168
}
140
169
141
- logMessage . Append ( '"' ) ;
142
-
143
- codeBuilder . AppendLine ( $ " UnityExplorer.ExplorerCore.Log({ logMessage } );") ;
144
- codeBuilder . AppendLine ( " }" ) ;
145
- codeBuilder . AppendLine ( " catch (System.Exception ex) {" ) ;
146
- codeBuilder . AppendLine ( $ " UnityExplorer.ExplorerCore.LogWarning($\" Exception in patch of { shortSignature } :\\ n{{ex}}\" );") ;
147
- codeBuilder . AppendLine ( " }" ) ;
148
-
149
- // End patch body
150
-
170
+ codeBuilder . AppendLine ( $ " UnityExplorer.ExplorerCore.Log($\" { logMessage } \" );") ;
171
+ codeBuilder . AppendLine ( " }" ) ;
172
+ codeBuilder . AppendLine ( " catch (System.Exception ex) {" ) ;
173
+ codeBuilder . AppendLine ( $ " UnityExplorer.ExplorerCore.LogWarning($\" Exception in patch of { shortSignature } :\\ n{{ex}}\" );") ;
151
174
codeBuilder . AppendLine ( " }" ) ;
152
175
153
- // End class
176
+ // End patch body
154
177
155
178
codeBuilder . AppendLine ( "}" ) ;
156
179
157
- return GeneratedSource = codeBuilder . ToString ( ) ;
180
+ return PatchSourceCode = codeBuilder . ToString ( ) ;
158
181
}
159
182
160
183
public void TogglePatch ( )
@@ -181,12 +204,16 @@ public void Patch()
181
204
182
205
public void Unpatch ( )
183
206
{
184
- if ( ! Enabled )
185
- return ;
186
-
187
207
try
188
208
{
189
- this . patchProcessor . Unpatch ( patchDelegateMethodInfo ) ;
209
+ if ( prefix != null )
210
+ patchProcessor . Unpatch ( prefix ) ;
211
+ if ( postfix != null )
212
+ patchProcessor . Unpatch ( postfix ) ;
213
+ if ( finalizer != null )
214
+ patchProcessor . Unpatch ( finalizer ) ;
215
+ if ( transpiler != null )
216
+ patchProcessor . Unpatch ( transpiler ) ;
190
217
Enabled = false ;
191
218
}
192
219
catch ( Exception ex )
0 commit comments