Fix for game update when launcher has not been updated
All checks were successful
Build / Compute Version (push) Successful in 6s
Build / Build Nuget package (NuGet) (push) Successful in 1m0s
Build / Build Nuget package (SharedCringe) (push) Successful in 1m0s
Build / Build Nuget package (CringePlugins) (push) Successful in 1m16s
Build / Build Launcher (push) Successful in 1m51s
Build / Build Nuget package (CringeBootstrap.Abstractions) (push) Successful in 3m8s
All checks were successful
Build / Compute Version (push) Successful in 6s
Build / Build Nuget package (NuGet) (push) Successful in 1m0s
Build / Build Nuget package (SharedCringe) (push) Successful in 1m0s
Build / Build Nuget package (CringePlugins) (push) Successful in 1m16s
Build / Build Launcher (push) Successful in 1m51s
Build / Build Nuget package (CringeBootstrap.Abstractions) (push) Successful in 3m8s
Switch to ModScriptCompilerPatch for pb unloading
This commit is contained in:
6
CringeLauncher/Loader/PbAssemblyLoadContext.cs
Normal file
6
CringeLauncher/Loader/PbAssemblyLoadContext.cs
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
using CringeBootstrap.Abstractions;
|
||||||
|
using SharedCringe.Loader;
|
||||||
|
|
||||||
|
namespace CringeLauncher.Loader;
|
||||||
|
public class PbAssemblyLoadContext(ICoreLoadContext parentContext, string name)
|
||||||
|
: DerivedAssemblyLoadContext(parentContext, name);
|
@@ -1,4 +1,5 @@
|
|||||||
using System.Diagnostics;
|
#if false
|
||||||
|
using System.Diagnostics;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Reflection.Emit;
|
using System.Reflection.Emit;
|
||||||
using System.Runtime.Loader;
|
using System.Runtime.Loader;
|
||||||
@@ -92,3 +93,4 @@ public static class ModAssemblyLoadContextPatches //todo: use ModScriptCompilerP
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
@@ -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]
|
[HarmonyPatch]
|
||||||
public static class ModScriptCompilerPatch
|
public static class ModScriptCompilerPatch
|
||||||
{
|
{
|
||||||
private static readonly ILogger Log = LogManager.GetCurrentClassLogger();
|
private static readonly Logger Log = LogManager.GetCurrentClassLogger();
|
||||||
private static AssemblyLoadContext _modContext = new(null, true);
|
private static ModAssemblyLoadContext _modContext;
|
||||||
private static readonly HashSet<string> LoadedModAssemblyNames = new();
|
private static readonly HashSet<string> LoadedModAssemblyNames = [];
|
||||||
|
|
||||||
private static readonly ConditionalWeakTable<MyProgrammableBlock, AssemblyLoadContext> LoadContexts = new();
|
private static readonly ConditionalWeakTable<MyProgrammableBlock, PbAssemblyLoadContext> LoadContexts = [];
|
||||||
|
|
||||||
private static readonly FieldInfo InstanceField = AccessTools.Field(typeof(MyProgrammableBlock), "m_instance");
|
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 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, DiagnosticAnalyzer>(
|
||||||
|
MyScriptCompiler.Static, "m_modApiWhitelistDiagnosticAnalyzer");
|
||||||
|
|
||||||
|
private static readonly DiagnosticAnalyzer ScriptWhitelistAnalyzer =
|
||||||
|
AccessTools.FieldRefAccess<MyScriptCompiler, DiagnosticAnalyzer>(MyScriptCompiler.Static, "m_inGameWhitelistDiagnosticAnalyzer");
|
||||||
|
|
||||||
|
private static readonly Func<CSharpCompilation, SyntaxTree, int, SyntaxTree> InjectMod = AccessTools.MethodDelegate<Func<CSharpCompilation, SyntaxTree, int, SyntaxTree>>(
|
||||||
|
AccessTools.Method(typeof(MyScriptCompiler), "InjectMod"), MyScriptCompiler.Static);
|
||||||
|
|
||||||
|
private static readonly Func<CSharpCompilation, SyntaxTree, bool, SyntaxTree> InjectResourceMonitoring = AccessTools.MethodDelegate<Func<CSharpCompilation, SyntaxTree, bool, SyntaxTree>>(
|
||||||
|
AccessTools.Method(typeof(MyScriptCompiler), "InjectResourceMonitoring"), MyScriptCompiler.Static);
|
||||||
|
|
||||||
|
private static readonly Func<CompilationWithAnalyzers, EmitResult, List<Message>, bool, Task<bool>> EmitDiagnostics = AccessTools.MethodDelegate<Func<CompilationWithAnalyzers, EmitResult, List<Message>, bool, Task<bool>>>(
|
||||||
|
AccessTools.Method(typeof(MyScriptCompiler), "EmitDiagnostics"), MyScriptCompiler.Static);
|
||||||
|
|
||||||
|
private static readonly Func<string, string> MakeAssemblyName = AccessTools.MethodDelegate<Func<string, string>>(AccessTools.Method(typeof(MyScriptCompiler),
|
||||||
|
"MakeAssemblyName"));
|
||||||
|
|
||||||
|
private static readonly Func<MyScriptCompiler, string, IEnumerable<Script>, bool, CSharpCompilation> CreateCompilation =
|
||||||
|
AccessTools.MethodDelegate<Func<MyScriptCompiler, string, IEnumerable<Script>, bool, CSharpCompilation>>(AccessTools.Method(typeof(MyScriptCompiler),
|
||||||
|
"CreateCompilation"));
|
||||||
|
|
||||||
static ModScriptCompilerPatch()
|
static ModScriptCompilerPatch()
|
||||||
{
|
{
|
||||||
MySession.OnUnloaded += OnUnloaded;
|
MySession.OnUnloaded += OnUnloaded;
|
||||||
|
_modContext = new(CoreContext);
|
||||||
ModWhitelistAnalyzer =
|
|
||||||
AccessTools.FieldRefAccess<MyScriptCompiler, DiagnosticAnalyzer>(
|
|
||||||
MyScriptCompiler.Static, "m_modApiWhitelistDiagnosticAnalyzer");
|
|
||||||
ScriptWhitelistAnalyzer =
|
|
||||||
AccessTools.FieldRefAccess<MyScriptCompiler, DiagnosticAnalyzer>(
|
|
||||||
MyScriptCompiler.Static, "m_ingameWhitelistDiagnosticAnalyzer");
|
|
||||||
|
|
||||||
MetadataReferences =
|
|
||||||
AccessTools.FieldRefAccess<MyScriptCompiler, List<MetadataReference>>(
|
|
||||||
MyScriptCompiler.Static, "m_metadataReferences");
|
|
||||||
|
|
||||||
InjectMod = AccessTools.MethodDelegate<Func<CSharpCompilation, SyntaxTree, int, SyntaxTree>>(
|
|
||||||
AccessTools.Method(typeof(MyScriptCompiler), "InjectMod"), MyScriptCompiler.Static);
|
|
||||||
|
|
||||||
InjectInstructionCounter = AccessTools.MethodDelegate<Func<CSharpCompilation, SyntaxTree, SyntaxTree>>(
|
|
||||||
AccessTools.Method(typeof(MyScriptCompiler), "InjectInstructionCounter"), MyScriptCompiler.Static);
|
|
||||||
|
|
||||||
EmitDiagnostics = AccessTools.MethodDelegate<Func<CompilationWithAnalyzers, EmitResult, List<Message>, bool, Task<bool>>>(
|
|
||||||
AccessTools.Method(typeof(MyScriptCompiler), "EmitDiagnostics"), MyScriptCompiler.Static);
|
|
||||||
|
|
||||||
MakeAssemblyName =
|
|
||||||
AccessTools.MethodDelegate<Func<string, string>>(AccessTools.Method(typeof(MyScriptCompiler),
|
|
||||||
"MakeAssemblyName"));
|
|
||||||
|
|
||||||
CreateInstanceMethod = AccessTools.Method(typeof(MyProgrammableBlock), "CreateInstance");
|
|
||||||
SetDetailedInfoMethod = AccessTools.Method(typeof(MyProgrammableBlock), "SetDetailedInfo");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void OnUnloaded()
|
private static void OnUnloaded()
|
||||||
@@ -53,20 +78,20 @@ public static class ModScriptCompilerPatch
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
_modContext.Unload();
|
_modContext.Unload();
|
||||||
_modContext = new(null, true);
|
_modContext = new(CoreContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
[HarmonyPatch(typeof(MyProgrammableBlock), "Compile")]
|
[HarmonyPatch(typeof(MyProgrammableBlock), "Compile")]
|
||||||
[HarmonyPrefix]
|
[HarmonyPrefix]
|
||||||
private static bool CompilePrefix(MyProgrammableBlock __instance, string program, string storage, bool instantiate,
|
private static bool CompilePrefix(MyProgrammableBlock __instance, string program, string storage, bool instantiate,
|
||||||
ref MyProgrammableBlock.ScriptTerminationReason ___m_terminationReason,
|
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;
|
return false;
|
||||||
|
|
||||||
___m_terminationReason = MyProgrammableBlock.ScriptTerminationReason.None;
|
___m_terminationReason = MyProgrammableBlock.ScriptTerminationReason.None;
|
||||||
CompileAsync(__instance, program, storage, instantiate, ___ScriptComponent);
|
CompileAsync(__instance, program, storage, instantiate, ___m_scriptComponent);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -80,7 +105,15 @@ public static class ModScriptCompilerPatch
|
|||||||
MyScreenManager.AddScreen(progress);
|
MyScreenManager.AddScreen(progress);
|
||||||
|
|
||||||
if (__instance.Description.Text.Length > 0)
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -97,11 +130,11 @@ public static class ModScriptCompilerPatch
|
|||||||
|
|
||||||
private static async Task CompileAsync(MyGuiScreenEditor editor, List<string> errors, string program, MyGuiScreenProgress progress)
|
private static async Task CompileAsync(MyGuiScreenEditor editor, List<string> errors, string program, MyGuiScreenProgress progress)
|
||||||
{
|
{
|
||||||
var context = new AssemblyLoadContext(null, true);
|
var context = new PbAssemblyLoadContext(CoreContext, editor.Name);
|
||||||
var messages = new List<Message>();
|
var messages = new List<Message>();
|
||||||
var script = MyVRage.Platform.Scripting.GetIngameScript(program, "Program", nameof(MyGridProgram));
|
var script = MyVRage.Platform.Scripting.GetIngameScript(program, "Program", nameof(MyGridProgram));
|
||||||
await CompileAsync(context, MyApiTarget.Ingame, "check", new[] { script }, messages,
|
await CompileAsync(context, MyApiTarget.Ingame, "check", [script], messages,
|
||||||
"PB Code Editor");
|
"PB Code Editor", true);
|
||||||
|
|
||||||
errors.AddRange(messages.OrderBy(b => b.IsError ? 0 : 1).Select(b => b.Text));
|
errors.AddRange(messages.OrderBy(b => b.IsError ? 0 : 1).Select(b => b.Text));
|
||||||
context.Unload();
|
context.Unload();
|
||||||
@@ -131,32 +164,28 @@ public static class ModScriptCompilerPatch
|
|||||||
string storage,
|
string storage,
|
||||||
bool instantiate, MyIngameScriptComponent scriptComponent)
|
bool instantiate, MyIngameScriptComponent scriptComponent)
|
||||||
{
|
{
|
||||||
scriptComponent.NextUpdate = UpdateType.None;
|
|
||||||
scriptComponent.NeedsUpdate = MyEntityUpdateEnum.NONE;
|
scriptComponent.NeedsUpdate = MyEntityUpdateEnum.NONE;
|
||||||
|
scriptComponent.UpdateFrequency = UpdateFrequency.None;
|
||||||
|
|
||||||
SetDetailedInfoMethod.Invoke(block, new object?[] { "Compiling..." });
|
SetDetailedInfoMethod.Invoke(block, ["Compiling..."]);
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (LoadContexts.TryGetValue(block, out var context))
|
if (LoadContexts.TryGetValue(block, out var context))
|
||||||
{
|
{
|
||||||
AccessTools.FieldRefAccess<MyProgrammableBlock, IMyGridProgram?>(block, InstanceField) = null;
|
AccessTools.FieldRefAccess<MyProgrammableBlock, IMyGridProgram?>(block, InstanceField) = null;
|
||||||
AccessTools.FieldRefAccess<MyProgrammableBlock, Assembly?>(block, AssemblyField) = null;
|
AssemblyProperty.SetValue(block, null);
|
||||||
context.Unload();
|
context.Unload();
|
||||||
}
|
}
|
||||||
|
|
||||||
LoadContexts.AddOrUpdate(block, context = new(null, true));
|
LoadContexts.AddOrUpdate(block, context = new(CoreContext, $"pb_{block.EntityId}"));
|
||||||
|
|
||||||
var messages = new List<Message>();
|
var messages = new List<Message>();
|
||||||
var assembly = await CompileAsync(context, MyApiTarget.Ingame,
|
var assembly = await CompileAsync(context, MyApiTarget.Ingame, $"pb_{block.EntityId}_{Random.Shared.NextInt64()}",
|
||||||
$"pb_{block.EntityId}_{Random.Shared.NextInt64()}",
|
[MyVRage.Platform.Scripting.GetIngameScript(program, "Program", nameof(MyGridProgram))],
|
||||||
new[]
|
messages, $"PB: {block.DisplayName} ({block.EntityId})", true);
|
||||||
{
|
|
||||||
MyVRage.Platform.Scripting.GetIngameScript(
|
|
||||||
program, "Program", nameof(MyGridProgram))
|
|
||||||
}, messages, $"PB: {block.DisplayName} ({block.EntityId})");
|
|
||||||
|
|
||||||
AccessTools.FieldRefAccess<MyProgrammableBlock, Assembly?>(block, AssemblyField) = assembly;
|
AssemblyProperty.SetValue(block, assembly);
|
||||||
|
|
||||||
var errors = AccessTools.FieldRefAccess<MyProgrammableBlock, List<string>>(block, CompilerErrorsField);
|
var errors = AccessTools.FieldRefAccess<MyProgrammableBlock, List<string>>(block, CompilerErrorsField);
|
||||||
|
|
||||||
@@ -164,25 +193,26 @@ public static class ModScriptCompilerPatch
|
|||||||
errors.AddRange(messages.Select(b => b.Text));
|
errors.AddRange(messages.Select(b => b.Text));
|
||||||
|
|
||||||
if (instantiate)
|
if (instantiate)
|
||||||
MySandboxGame.Static.Invoke(
|
{
|
||||||
() => CreateInstanceMethod.Invoke(block, new object?[] { assembly, errors, storage }),
|
MySandboxGame.Static.Invoke(() => CreateInstanceMethod.Invoke(block, [assembly, errors, storage]),
|
||||||
nameof(CompileAsync));
|
nameof(CompileAsync));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
SetDetailedInfoMethod.Invoke(block, new object?[] { e.ToString() });
|
SetDetailedInfoMethod.Invoke(block, [e.ToString()]);
|
||||||
Log.Error(e);
|
Log.Error(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async Task<Assembly?> CompileAsync(AssemblyLoadContext context, MyApiTarget target,
|
private static async Task<Assembly?> CompileAsync(AssemblyLoadContext context, MyApiTarget target,
|
||||||
string assemblyName, IEnumerable<Script> scripts,
|
string assemblyName, IEnumerable<Script> scripts,
|
||||||
List<Message> messages, string? friendlyName,
|
List<Message> messages, string? friendlyName, bool trackMemoryUsage = false,
|
||||||
bool enableDebugInformation = false)
|
bool enableDebugInformation = false)
|
||||||
{
|
{
|
||||||
friendlyName ??= "<No Name>";
|
friendlyName ??= "<No Name>";
|
||||||
var assemblyFileName = MakeAssemblyName(assemblyName);
|
var assemblyFileName = MakeAssemblyName(assemblyName);
|
||||||
Func<CSharpCompilation, SyntaxTree, SyntaxTree>? syntaxTreeInjector;
|
Func<CSharpCompilation, SyntaxTree, bool, SyntaxTree>? syntaxTreeInjector;
|
||||||
DiagnosticAnalyzer? whitelistAnalyzer;
|
DiagnosticAnalyzer? whitelistAnalyzer;
|
||||||
switch (target)
|
switch (target)
|
||||||
{
|
{
|
||||||
@@ -194,7 +224,7 @@ public static class ModScriptCompilerPatch
|
|||||||
{
|
{
|
||||||
var modId = MyModWatchdog.AllocateModId(friendlyName);
|
var modId = MyModWatchdog.AllocateModId(friendlyName);
|
||||||
whitelistAnalyzer = ModWhitelistAnalyzer;
|
whitelistAnalyzer = ModWhitelistAnalyzer;
|
||||||
syntaxTreeInjector = (c, st) => InjectMod(c, st, modId);
|
syntaxTreeInjector = (c, st, _) => InjectMod(c, st, modId);
|
||||||
|
|
||||||
//skip if name exists already
|
//skip if name exists already
|
||||||
if (!LoadedModAssemblyNames.Add(assemblyFileName))
|
if (!LoadedModAssemblyNames.Add(assemblyFileName))
|
||||||
@@ -205,13 +235,13 @@ public static class ModScriptCompilerPatch
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case MyApiTarget.Ingame:
|
case MyApiTarget.Ingame:
|
||||||
syntaxTreeInjector = InjectInstructionCounter;
|
syntaxTreeInjector = InjectResourceMonitoring;
|
||||||
whitelistAnalyzer = ScriptWhitelistAnalyzer;
|
whitelistAnalyzer = ScriptWhitelistAnalyzer;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new ArgumentOutOfRangeException(nameof(target), target, "Invalid compilation target");
|
throw new ArgumentOutOfRangeException(nameof(target), target, "Invalid compilation target");
|
||||||
}
|
}
|
||||||
var compilation = CreateCompilation(assemblyFileName, scripts);
|
var compilation = CreateCompilation(MyScriptCompiler.Static, assemblyFileName, scripts, enableDebugInformation);
|
||||||
var compilationWithoutInjection = compilation;
|
var compilationWithoutInjection = compilation;
|
||||||
var injectionFailed = false;
|
var injectionFailed = false;
|
||||||
|
|
||||||
@@ -223,14 +253,14 @@ public static class ModScriptCompilerPatch
|
|||||||
var syntaxTrees = compilation.SyntaxTrees;
|
var syntaxTrees = compilation.SyntaxTrees;
|
||||||
if (syntaxTrees.Length == 1)
|
if (syntaxTrees.Length == 1)
|
||||||
{
|
{
|
||||||
newSyntaxTrees = new[] { syntaxTreeInjector(compilation, syntaxTrees[0]) };
|
newSyntaxTrees = [syntaxTreeInjector(compilation, syntaxTrees[0], trackMemoryUsage)];
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var compilation1 = compilation;
|
var compilation1 = compilation;
|
||||||
newSyntaxTrees = await Task
|
newSyntaxTrees = await Task
|
||||||
.WhenAll(syntaxTrees.Select(
|
.WhenAll(syntaxTrees.Select(
|
||||||
x => Task.Run(() => syntaxTreeInjector(compilation1, x)))).ConfigureAwait(false);
|
x => Task.Run(() => syntaxTreeInjector(compilation1, x, trackMemoryUsage)))).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
@@ -241,16 +271,15 @@ public static class ModScriptCompilerPatch
|
|||||||
|
|
||||||
if (newSyntaxTrees is not null)
|
if (newSyntaxTrees is not null)
|
||||||
compilation = compilation.RemoveAllSyntaxTrees().AddSyntaxTrees(newSyntaxTrees);
|
compilation = compilation.RemoveAllSyntaxTrees().AddSyntaxTrees(newSyntaxTrees);
|
||||||
|
|
||||||
}
|
}
|
||||||
CompilationWithAnalyzers? analyticCompilation = null;
|
CompilationWithAnalyzers? analyticCompilation = null;
|
||||||
if (whitelistAnalyzer != null)
|
if (whitelistAnalyzer != null)
|
||||||
{
|
{
|
||||||
analyticCompilation = compilation.WithAnalyzers(ImmutableArray.Create(whitelistAnalyzer));
|
analyticCompilation = compilation.WithAnalyzers([whitelistAnalyzer]);
|
||||||
compilation = (CSharpCompilation)analyticCompilation.Compilation;
|
compilation = (CSharpCompilation)analyticCompilation.Compilation;
|
||||||
}
|
}
|
||||||
|
|
||||||
using var assemblyStream = new MemoryStream();
|
await using var assemblyStream = new MemoryStream();
|
||||||
|
|
||||||
var emitResult = compilation.Emit(assemblyStream);
|
var emitResult = compilation.Emit(assemblyStream);
|
||||||
var success = emitResult.Success;
|
var success = emitResult.Success;
|
||||||
@@ -266,44 +295,17 @@ public static class ModScriptCompilerPatch
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
success = await EmitDiagnostics(analyticCompilation, emitResult, messages, success).ConfigureAwait(false);
|
success = await EmitDiagnostics(analyticCompilation!, emitResult, messages, success).ConfigureAwait(false);
|
||||||
assemblyStream.Seek(0, SeekOrigin.Begin);
|
assemblyStream.Seek(0, SeekOrigin.Begin);
|
||||||
if (injectionFailed) return null;
|
if (injectionFailed)
|
||||||
|
return null;
|
||||||
if (success)
|
if (success)
|
||||||
return context.LoadFromStream(assemblyStream);
|
return context.LoadFromStream(assemblyStream);
|
||||||
|
|
||||||
await EmitDiagnostics(analyticCompilation, compilationWithoutInjection.Emit(assemblyStream), messages,
|
await EmitDiagnostics(analyticCompilation!, compilationWithoutInjection.Emit(assemblyStream), messages,
|
||||||
false).ConfigureAwait(false);
|
false).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static readonly CSharpCompilationOptions CompilationOptions =
|
|
||||||
new(OutputKind.DynamicallyLinkedLibrary, optimizationLevel: OptimizationLevel.Release, platform: Platform.X64);
|
|
||||||
private static readonly CSharpParseOptions ParseOptions = new(LanguageVersion.CSharp11, DocumentationMode.None);
|
|
||||||
private static readonly DiagnosticAnalyzer ModWhitelistAnalyzer;
|
|
||||||
private static readonly DiagnosticAnalyzer ScriptWhitelistAnalyzer;
|
|
||||||
private static readonly List<MetadataReference> MetadataReferences;
|
|
||||||
private static readonly Func<CSharpCompilation, SyntaxTree, int, SyntaxTree> InjectMod;
|
|
||||||
private static readonly Func<CSharpCompilation, SyntaxTree, SyntaxTree> InjectInstructionCounter;
|
|
||||||
private static readonly Func<CompilationWithAnalyzers, EmitResult, List<Message>, bool, Task<bool>> EmitDiagnostics;
|
|
||||||
private static readonly Func<string, string> MakeAssemblyName;
|
|
||||||
private static readonly MethodInfo CreateInstanceMethod;
|
|
||||||
private static readonly MethodInfo SetDetailedInfoMethod;
|
|
||||||
|
|
||||||
|
|
||||||
private static CSharpCompilation CreateCompilation(string assemblyFile, IEnumerable<Script>? scripts)
|
|
||||||
{
|
|
||||||
if (scripts == null)
|
|
||||||
return CSharpCompilation.Create(assemblyFile, null, MetadataReferences,
|
|
||||||
CompilationOptions);
|
|
||||||
|
|
||||||
|
|
||||||
var parseOptions = ParseOptions.WithPreprocessorSymbols(MyScriptCompiler.Static.ConditionalCompilationSymbols);
|
|
||||||
var enumerable = scripts.Select(s => CSharpSyntaxTree.ParseText(s.Code, parseOptions, s.Name, Encoding.UTF8));
|
|
||||||
|
|
||||||
return CSharpCompilation.Create(assemblyFile, enumerable, MetadataReferences, CompilationOptions);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#endif
|
|
@@ -101,7 +101,8 @@ public static class BuiltInPackages
|
|||||||
|
|
||||||
private static Dependency AsDependency(this ResolvedPackage package, ImmutableDictionary<ManifestPackageKey, DependencyLibrary> libraries)
|
private static Dependency AsDependency(this ResolvedPackage package, ImmutableDictionary<ManifestPackageKey, DependencyLibrary> libraries)
|
||||||
{
|
{
|
||||||
if (!libraries.ContainsKey(new(package.Package.Id, package.Package.Version)))
|
//ignore the SE reference because the game can update without a launcher update
|
||||||
|
if (package.Entry.Id != SeReferenceAssemblies && !libraries.ContainsKey(new(package.Package.Id, package.Package.Version)))
|
||||||
throw new KeyNotFoundException($"Package {package.Package} not found in root dependencies manifest");
|
throw new KeyNotFoundException($"Package {package.Package} not found in root dependencies manifest");
|
||||||
|
|
||||||
return new Dependency(package.Package.Id, new(package.Package.Version));
|
return new Dependency(package.Package.Id, new(package.Package.Version));
|
||||||
|
Reference in New Issue
Block a user