@@ -20,14 +20,16 @@ You should have received a copy of the GNU General Public License
20
20
using Avalonia . Controls ;
21
21
using Avalonia . Interactivity ;
22
22
using Avalonia . Markup . Xaml ;
23
- using Newtonsoft . Json . Linq ;
23
+ using Mono . Cecil ;
24
+ using Mono . Cecil . Cil ;
24
25
using OTAPI . Client . Launcher . Targets ;
25
26
using OTAPI . Common ;
26
27
using OTAPI . Patcher . Targets ;
27
28
using System ;
28
- using System . ComponentModel ;
29
29
using System . IO ;
30
+ using System . Linq ;
30
31
using System . Runtime . InteropServices ;
32
+ using System . Threading . Tasks ;
31
33
32
34
namespace OTAPI . Client . Launcher ;
33
35
@@ -80,6 +82,8 @@ public MainWindow()
80
82
81
83
if ( Program . ConsoleWriter is not null )
82
84
Program . ConsoleWriter . LineReceived += OnConsoleLineReceived ;
85
+
86
+ PatchMonoMod ( ) ;
83
87
}
84
88
85
89
private void OnConsoleLineReceived ( string line )
@@ -204,13 +208,17 @@ public void OpenFolder(string folder)
204
208
process . Start ( ) ;
205
209
}
206
210
211
+ System . Threading . CancellationTokenSource CancellationTokenSource { get ; set ; } = new System . Threading . CancellationTokenSource ( ) ;
212
+
207
213
public void OnInstall ( object sender , RoutedEventArgs e )
208
214
{
209
215
if ( Context . IsInstalling || Context . InstallPath ? . Path is null || Context . LaunchTarget is null ) return ;
210
216
Context . IsInstalling = true ;
211
217
212
- new System . Threading . Thread ( ( ) =>
218
+ Task . Run ( async ( ) =>
213
219
{
220
+ CancellationTokenSource . Cancel ( ) ;
221
+ CancellationTokenSource = new ( ) ;
214
222
try
215
223
{
216
224
var target = new PCClientTarget ( ) ;
@@ -221,7 +229,7 @@ public void OnInstall(object sender, RoutedEventArgs e)
221
229
Context . InstallStatus = "Patching completed, installing to existing installation..." ;
222
230
223
231
Context . InstallPath . Target . StatusUpdate += ( sender , e ) => Context . InstallStatus = e . Text ;
224
- Context . InstallPath . Target . Install ( Context . InstallPath . Path ) ;
232
+ await Context . InstallPath . Target . InstallAsync ( Context . InstallPath . Path , CancellationTokenSource . Token ) ;
225
233
226
234
Context . InstallStatus = "Install completed" ;
227
235
@@ -235,6 +243,49 @@ public void OnInstall(object sender, RoutedEventArgs e)
235
243
Context . InstallStatus = "Err: " + ex . ToString ( ) ;
236
244
OnConsoleLineReceived ( ex . ToString ( ) ) ;
237
245
}
238
- } ) . Start ( ) ;
246
+ } ) ;
247
+ }
248
+
249
+ /// <summary>
250
+ /// Current MonoMod is outdated, and the new reorg is not ready yet, however we need v25 RD for NET9, yet Patcher v22 is the latest, and is not compatible with v25.
251
+ /// Ultimately the problem is OTAPI Client using both at once, unlike the server setup which doesnt.
252
+ /// For now, the intention is to replace the entire both with "return new string[0];" to prevent the GAC IL from being used (which it isn't anyway)
253
+ /// </summary>
254
+ void PatchMonoMod ( )
255
+ {
256
+ var bin = File . ReadAllBytes ( "MonoMod.dll" ) ;
257
+ using MemoryStream ms = new ( bin ) ;
258
+ var asm = AssemblyDefinition . ReadAssembly ( ms ) ;
259
+ var modder = asm . MainModule . Types . Single ( x => x . FullName == "MonoMod.MonoModder" ) ;
260
+ var gacPaths = modder . Methods . Single ( m => m . Name == "get_GACPaths" ) ;
261
+ var il = gacPaths . Body . GetILProcessor ( ) ;
262
+ if ( il . Body . Instructions . Count != 3 )
263
+ {
264
+ il . Body . Instructions . Clear ( ) ;
265
+ il . Emit ( OpCodes . Ldc_I4_0 ) ;
266
+ il . Emit ( OpCodes . Newarr , asm . MainModule . ImportReference ( typeof ( string ) ) ) ;
267
+ il . Emit ( OpCodes . Ret ) ;
268
+
269
+ // clear MonoModder.MatchingConditionals(cap, asmName), with "return false;"
270
+ var mc = modder . Methods . Single ( m => m . Name == "MatchingConditionals" && m . Parameters . Count == 2 && m . Parameters [ 1 ] . ParameterType . Name == "AssemblyNameReference" ) ;
271
+ il = mc . Body . GetILProcessor ( ) ;
272
+ mc . Body . Instructions . Clear ( ) ;
273
+ mc . Body . Variables . Clear ( ) ;
274
+ mc . Body . ExceptionHandlers . Clear ( ) ;
275
+ il . Emit ( OpCodes . Ldc_I4_1 ) ;
276
+ il . Emit ( OpCodes . Ret ) ;
277
+
278
+ var writerParams = modder . Methods . Single ( m => m . Name == "get_WriterParameters" ) ;
279
+ il = writerParams . Body . GetILProcessor ( ) ;
280
+ var get_Current = writerParams . Body . Instructions . Single ( x => x . Operand is MethodReference mref && mref . Name == "get_Current" ) ;
281
+ // replace get_Current with a number, and remove the bitwise checks
282
+ il . Remove ( get_Current . Next ) ;
283
+ il . Remove ( get_Current . Next ) ;
284
+ il . Replace ( get_Current , Instruction . Create (
285
+ OpCodes . Ldc_I4 , RuntimeInformation . IsOSPlatform ( OSPlatform . Windows ) ? 37 : 0
286
+ ) ) ;
287
+
288
+ asm . Write ( "MonoMod.dll" ) ;
289
+ }
239
290
}
240
291
}
0 commit comments