From a87161f2f5679da9192b7bd5bb0f52455a006b91 Mon Sep 17 00:00:00 2001 From: pas2704 Date: Tue, 13 May 2025 20:32:43 -0400 Subject: [PATCH] Fix for game update when launcher has not been updated Switch to ModScriptCompilerPatch for pb unloading --- .../Loader/PbAssemblyLoadContext.cs | 6 + .../Patches/ModAssemblyLoadContextPatches.cs | 6 +- .../Patches/ModScriptCompilerPatch.cs | 240 +++++++++--------- CringePlugins/Resolver/BuiltInPackages.cs | 3 +- 4 files changed, 133 insertions(+), 122 deletions(-) create mode 100644 CringeLauncher/Loader/PbAssemblyLoadContext.cs diff --git a/CringeLauncher/Loader/PbAssemblyLoadContext.cs b/CringeLauncher/Loader/PbAssemblyLoadContext.cs new file mode 100644 index 0000000..cfd4e25 --- /dev/null +++ b/CringeLauncher/Loader/PbAssemblyLoadContext.cs @@ -0,0 +1,6 @@ +using CringeBootstrap.Abstractions; +using SharedCringe.Loader; + +namespace CringeLauncher.Loader; +public class PbAssemblyLoadContext(ICoreLoadContext parentContext, string name) + : DerivedAssemblyLoadContext(parentContext, name); diff --git a/CringeLauncher/Patches/ModAssemblyLoadContextPatches.cs b/CringeLauncher/Patches/ModAssemblyLoadContextPatches.cs index 7410998..27e9e0b 100644 --- a/CringeLauncher/Patches/ModAssemblyLoadContextPatches.cs +++ b/CringeLauncher/Patches/ModAssemblyLoadContextPatches.cs @@ -1,4 +1,5 @@ -using System.Diagnostics; +#if false +using System.Diagnostics; using System.Reflection; using System.Reflection.Emit; using System.Runtime.Loader; @@ -91,4 +92,5 @@ public static class ModAssemblyLoadContextPatches //todo: use ModScriptCompilerP _currentSessionContext = new ModAssemblyLoadContext(coreContext); } } -} \ No newline at end of file +} +#endif \ No newline at end of file diff --git a/CringeLauncher/Patches/ModScriptCompilerPatch.cs b/CringeLauncher/Patches/ModScriptCompilerPatch.cs index d40dd31..0463b72 100644 --- a/CringeLauncher/Patches/ModScriptCompilerPatch.cs +++ b/CringeLauncher/Patches/ModScriptCompilerPatch.cs @@ -1,49 +1,74 @@ -namespace CringeLauncher.Patches; +using CringeBootstrap.Abstractions; +using CringeLauncher.Loader; +using HarmonyLib; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Emit; +using NLog; +using Sandbox; +using Sandbox.Game; +using Sandbox.Game.Entities.Blocks; +using Sandbox.Game.EntityComponents; +using Sandbox.Game.Gui; +using Sandbox.Game.Localization; +using Sandbox.Game.World; +using Sandbox.Graphics.GUI; +using Sandbox.ModAPI; +using Sandbox.ModAPI.Ingame; +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.Loader; +using System.Text; +using VRage; +using VRage.ModAPI; +using VRage.Scripting; +using Message = VRage.Scripting.Message; + +namespace CringeLauncher.Patches; -#if false [HarmonyPatch] public static class ModScriptCompilerPatch { - private static readonly ILogger Log = LogManager.GetCurrentClassLogger(); - private static AssemblyLoadContext _modContext = new(null, true); - private static readonly HashSet LoadedModAssemblyNames = new(); + private static readonly Logger Log = LogManager.GetCurrentClassLogger(); + private static ModAssemblyLoadContext _modContext; + private static readonly HashSet LoadedModAssemblyNames = []; - private static readonly ConditionalWeakTable LoadContexts = new(); + private static readonly ConditionalWeakTable LoadContexts = []; private static readonly FieldInfo InstanceField = AccessTools.Field(typeof(MyProgrammableBlock), "m_instance"); - private static readonly FieldInfo AssemblyField = AccessTools.Field(typeof(MyProgrammableBlock), "m_assembly"); + private static readonly PropertyInfo AssemblyProperty = AccessTools.Property(typeof(MyProgrammableBlock), "CurrentAssembly"); private static readonly FieldInfo CompilerErrorsField = AccessTools.Field(typeof(MyProgrammableBlock), "m_compilerErrors"); + private static readonly MethodInfo CreateInstanceMethod = AccessTools.Method(typeof(MyProgrammableBlock), "CreateInstance"); + private static readonly MethodInfo SetDetailedInfoMethod = AccessTools.Method(typeof(MyProgrammableBlock), "SetDetailedInfo"); + private static readonly ICoreLoadContext CoreContext = (ICoreLoadContext)AssemblyLoadContext.GetLoadContext(typeof(MySession).Assembly)!; + + private static readonly DiagnosticAnalyzer ModWhitelistAnalyzer = AccessTools.FieldRefAccess( + MyScriptCompiler.Static, "m_modApiWhitelistDiagnosticAnalyzer"); + + private static readonly DiagnosticAnalyzer ScriptWhitelistAnalyzer = + AccessTools.FieldRefAccess(MyScriptCompiler.Static, "m_inGameWhitelistDiagnosticAnalyzer"); + + private static readonly Func InjectMod = AccessTools.MethodDelegate>( + AccessTools.Method(typeof(MyScriptCompiler), "InjectMod"), MyScriptCompiler.Static); + + private static readonly Func InjectResourceMonitoring = AccessTools.MethodDelegate>( + AccessTools.Method(typeof(MyScriptCompiler), "InjectResourceMonitoring"), MyScriptCompiler.Static); + + private static readonly Func, bool, Task> EmitDiagnostics = AccessTools.MethodDelegate, bool, Task>>( + AccessTools.Method(typeof(MyScriptCompiler), "EmitDiagnostics"), MyScriptCompiler.Static); + + private static readonly Func MakeAssemblyName = AccessTools.MethodDelegate>(AccessTools.Method(typeof(MyScriptCompiler), + "MakeAssemblyName")); + + private static readonly Func, bool, CSharpCompilation> CreateCompilation = + AccessTools.MethodDelegate, bool, CSharpCompilation>>(AccessTools.Method(typeof(MyScriptCompiler), + "CreateCompilation")); static ModScriptCompilerPatch() { MySession.OnUnloaded += OnUnloaded; - - ModWhitelistAnalyzer = - AccessTools.FieldRefAccess( - MyScriptCompiler.Static, "m_modApiWhitelistDiagnosticAnalyzer"); - ScriptWhitelistAnalyzer = - AccessTools.FieldRefAccess( - MyScriptCompiler.Static, "m_ingameWhitelistDiagnosticAnalyzer"); - - MetadataReferences = - AccessTools.FieldRefAccess>( - MyScriptCompiler.Static, "m_metadataReferences"); - - InjectMod = AccessTools.MethodDelegate>( - AccessTools.Method(typeof(MyScriptCompiler), "InjectMod"), MyScriptCompiler.Static); - - InjectInstructionCounter = AccessTools.MethodDelegate>( - AccessTools.Method(typeof(MyScriptCompiler), "InjectInstructionCounter"), MyScriptCompiler.Static); - - EmitDiagnostics = AccessTools.MethodDelegate, bool, Task>>( - AccessTools.Method(typeof(MyScriptCompiler), "EmitDiagnostics"), MyScriptCompiler.Static); - - MakeAssemblyName = - AccessTools.MethodDelegate>(AccessTools.Method(typeof(MyScriptCompiler), - "MakeAssemblyName")); - - CreateInstanceMethod = AccessTools.Method(typeof(MyProgrammableBlock), "CreateInstance"); - SetDetailedInfoMethod = AccessTools.Method(typeof(MyProgrammableBlock), "SetDetailedInfo"); + _modContext = new(CoreContext); } private static void OnUnloaded() @@ -51,22 +76,22 @@ public static class ModScriptCompilerPatch LoadedModAssemblyNames.Clear(); if (!_modContext.Assemblies.Any()) return; - + _modContext.Unload(); - _modContext = new(null, true); + _modContext = new(CoreContext); } - + [HarmonyPatch(typeof(MyProgrammableBlock), "Compile")] [HarmonyPrefix] private static bool CompilePrefix(MyProgrammableBlock __instance, string program, string storage, bool instantiate, ref MyProgrammableBlock.ScriptTerminationReason ___m_terminationReason, - MyIngameScriptComponent ___ScriptComponent) + MyIngameScriptComponent ___m_scriptComponent) { - if (!MySession.Static.EnableIngameScripts || __instance.CubeGrid is {IsPreview: true} or {CreatePhysics: false}) + if (!MySession.Static.EnableIngameScripts || __instance.CubeGrid is { IsPreview: true } or { CreatePhysics: false }) return false; ___m_terminationReason = MyProgrammableBlock.ScriptTerminationReason.None; - CompileAsync(__instance, program, storage, instantiate, ___ScriptComponent); + CompileAsync(__instance, program, storage, instantiate, ___m_scriptComponent); return false; } @@ -78,13 +103,21 @@ public static class ModScriptCompilerPatch var progress = new MyGuiScreenProgress(MyTexts.Get(MySpaceTexts.ProgrammableBlock_Editor_CheckingCode)); MyScreenManager.AddScreen(progress); - + if (__instance.Description.Text.Length > 0) - CompileAsync(__instance, ___m_compilerErrors, __instance.Description.Text.ToString(), progress).Wait(); - + { + var task = CompileAsync(__instance, ___m_compilerErrors, __instance.Description.Text.ToString(), progress); + task.ConfigureAwait(false).GetAwaiter().GetResult(); + + MyScreenManager.RemoveScreen(progress); + + MyVRage.Platform.ImeProcessor?.RegisterActiveScreen(__instance); + __instance.FocusedControl = __instance.Description; + } + return false; } - + [HarmonyPatch(typeof(MyScriptCompiler), nameof(MyScriptCompiler.Compile))] [HarmonyPrefix] private static bool Prefix(ref Task __result, MyApiTarget target, string assemblyName, IEnumerable