feature: first
All checks were successful
Build / Compute Version (push) Successful in 4s
Build / Build Nuget package (CringeBootstrap.Abstractions) (push) Successful in 2m47s
Build / Build Nuget package (CringePlugins) (push) Successful in 5m31s
Build / Build Nuget package (NuGet) (push) Successful in 6m2s
Build / Build Nuget package (SharedCringe) (push) Successful in 7m25s
Build / Build Launcher (push) Successful in 9m11s

This commit is contained in:
zznty
2022-10-28 01:58:54 +07:00
commit aa979e9519
81 changed files with 6162 additions and 0 deletions

View File

@@ -0,0 +1,19 @@
using HarmonyLib;
using Sandbox.Game.World;
namespace CringeLauncher.Patches;
[HarmonyPatch(typeof(MyScriptManager), nameof(MyScriptManager.Init))]
public static class DarkTardMissingNamespacePatch
{
private static void Prefix(Dictionary<string, string> ___m_compatibilityChanges)
{
___m_compatibilityChanges["using System.Runtime.Remoting.Metadata.W3cXsd2001;"] = "";
___m_compatibilityChanges["using System.IO.Ports;"] = "";
___m_compatibilityChanges["using System.Runtime.Remoting;"] = "";
___m_compatibilityChanges["using System.Runtime.Remoting.Messaging;"] = "";
___m_compatibilityChanges["using System.Numerics;"] = "";
___m_compatibilityChanges["using System.Runtime.Remoting.Lifetime;"] = "";
___m_compatibilityChanges["using System.Net.Configuration;"] = "";
}
}

View File

@@ -0,0 +1,30 @@
using System.Reflection;
using System.Reflection.Emit;
using HarmonyLib;
namespace CringeLauncher.Patches;
// eos is disabled
// [HarmonyPatch]
public class EosInitPatch
{
private static MethodInfo TargetMethod() =>
AccessTools.Method(Type.GetType("VRage.EOS.MyEOSNetworking, VRage.EOS", true), "Init");
private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
{
var ins = instructions.ToList();
var stIndex = ins.FindIndex(b => b.opcode == OpCodes.Stloc_1);
ins.InsertRange(stIndex, new []
{
new CodeInstruction(OpCodes.Dup),
new(OpCodes.Ldc_I4_2), // PlatformFlags.DisableOverlay
new(OpCodes.Conv_I8),
CodeInstruction.Call("Epic.OnlineServices.Platform.Options:set_Flags"),
});
return ins;
}
}

View File

@@ -0,0 +1,122 @@
using System.Diagnostics;
using System.Reflection;
using System.Runtime.Loader;
using System.Xml.Serialization;
using CringeBootstrap.Abstractions;
using CringePlugins.Utils;
using HarmonyLib;
using Sandbox.Game.World;
using VRage;
using VRage.FileSystem;
using VRage.Game;
using VRage.Game.Common;
using VRage.Game.Components;
using VRage.Game.Definitions;
using VRage.Game.Entity.UseObject;
using VRage.ObjectBuilders;
using VRage.ObjectBuilders.Private;
using VRage.Plugins;
namespace CringeLauncher.Patches;
[HarmonyPatch]
public static class IntrospectionPatches
{
[HarmonyPrefix, HarmonyPatch(typeof(Assembly), nameof(Assembly.GetTypes))]
private static bool GetTypesPrefix(Assembly __instance, ref Type[] __result)
{
if (AssemblyLoadContext.GetLoadContext(__instance) is ICoreLoadContext || __instance.FullName?.StartsWith("System.") == true)
return true;
Debug.WriteLine($"Blocking GetTypes for {__instance.FullName}");
__result = [];
return false;
}
[HarmonyPrefix, HarmonyPatch(typeof(AccessTools), nameof(AccessTools.GetTypesFromAssembly))]
private static bool GetTypesHarmonyPrefix(Assembly assembly, ref Type[] __result)
{
if (AssemblyLoadContext.GetLoadContext(assembly) is ICoreLoadContext)
return true;
__result = IntrospectionContext.Global.CollectAttributedTypes<HarmonyAttribute>(assembly.GetMainModule())
.ToArray();
return false;
}
[HarmonyPrefix, HarmonyPatch(typeof(MySession), "PrepareBaseSession", typeof(MyObjectBuilder_Checkpoint), typeof(MyObjectBuilder_Sector))]
private static void PrepareSessionPrefix()
{
// i hate keen for that in MyUseObjectFactory..cctor
// MyUseObjectFactory.RegisterAssemblyTypes(Assembly.LoadFrom(Path.Combine(MyFileSystem.ExePath, "Sandbox.Game.dll")));
MyUseObjectFactory.RegisterAssemblyTypes(MyPlugins.SandboxGameAssembly);
}
[HarmonyPrefix, HarmonyPatch(typeof(MyPlugins), nameof(MyPlugins.LoadPlugins))]
private static bool LoadPluginsPrefix(List<Assembly> assemblies, List<IPlugin> ___m_plugins, List<IHandleInputPlugin> ___m_handleInputPlugins)
{
foreach (var type in assemblies.SelectMany(b => IntrospectionContext.Global.CollectDerivedTypes<IPlugin>(b.GetMainModule())))
{
var instance = Activator.CreateInstance(type);
if (instance is IPlugin plugin)
___m_plugins.Add(plugin);
if (instance is IHandleInputPlugin handleInputPlugin)
___m_handleInputPlugins.Add(handleInputPlugin);
}
return false;
}
[HarmonyPrefix, HarmonyPatch(typeof(MyXmlSerializerManager), "TryLoadSerializerFrom")]
private static bool LoadSerializerPrefix(string assemblyName, string typeName, ref XmlSerializer? __result)
{
if (AssemblyLoadContext.GetLoadContext(typeof(IntrospectionPatches).Assembly) is not ICoreLoadContext context)
return false;
var assembly = context.ResolveFromAssemblyName(new(assemblyName));
if (assembly?.GetType($"Microsoft.Xml.Serialization.GeneratedAssembly.{typeName}Serializer") is not { } type)
return false;
__result = Activator.CreateInstance(type) as XmlSerializer;
return false;
}
[HarmonyPrefix, HarmonyPatch(typeof(MyXmlSerializerManager), nameof(MyXmlSerializerManager.RegisterFromAssembly))]
private static bool XmlManagerRegisterPrefix(Assembly assembly) => AssemblyLoadContext.GetLoadContext(assembly) is ICoreLoadContext;
[HarmonyPatch]
private static class GameAssembliesPatch
{
private static IEnumerable<MethodInfo> TargetMethods()
{
return AccessTools.GetDeclaredMethods(typeof(MyPlugins))
.Where(b => b.Name.StartsWith("Register") &&
b.GetParameters() is [var param] && param.ParameterType == typeof(string));
}
private static bool Prefix([HarmonyArgument(0)] string file)
{
var name = AssemblyName.GetAssemblyName(Path.Join(MyFileSystem.ExePath, file));
ref var staticAssembly = ref AccessTools.StaticFieldRefAccess<Assembly>(typeof(MyPlugins), name.Name switch
{
"Sandbox.Common" => "m_sandboxAssembly",
"Sandbox.Game" => "m_sandboxGameAssembly",
"SpaceEngineers.Game" => "m_gamePluginAssembly",
"SpaceEngineers.ObjectBuilders" => "m_gameObjBuildersPlugin",
_ => throw new ArgumentOutOfRangeException(null, $"Unknown assembly name: {name}")
});
staticAssembly = AssemblyLoadContext.GetLoadContext(typeof(GameAssembliesPatch).Assembly)!
.LoadFromAssemblyName(name);
return false;
}
}
}

View File

@@ -0,0 +1,70 @@
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.Loader;
using CringeBootstrap.Abstractions;
using CringeLauncher.Loader;
using HarmonyLib;
using Sandbox.Game.World;
using VRage.Scripting;
namespace CringeLauncher.Patches;
[HarmonyPatch]
public static class ModAssemblyLoadContextPatches
{
private static ModAssemblyLoadContext? _currentSessionContext;
[HarmonyPatch(typeof(MyScriptCompiler), nameof(MyScriptCompiler.Compile), MethodType.Async)]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> CompilerTranspiler(IEnumerable<CodeInstruction> instructions, MethodBase original)
{
var matcher = new CodeMatcher(instructions);
var load1Method = AccessTools.DeclaredMethod(typeof(Assembly), nameof(Assembly.Load), [typeof(byte[]), typeof(byte[])]);
var load2Method = AccessTools.DeclaredMethod(typeof(Assembly), nameof(Assembly.Load), [typeof(byte[])]);
matcher.SearchForward(i => i.Calls(load1Method))
.InsertAndAdvance(new(OpCodes.Ldarg_0), CodeInstruction.LoadField(original.DeclaringType, "target"))
.SetInstruction(CodeInstruction.CallClosure((byte[] assembly, byte[] symbols, MyApiTarget target) =>
{
if (target is not MyApiTarget.Mod) return Assembly.Load(assembly, symbols);
ArgumentNullException.ThrowIfNull(_currentSessionContext, "No session context");
return _currentSessionContext.LoadFromStream(new MemoryStream(assembly), new MemoryStream(symbols));
}));
matcher.SearchForward(i => i.Calls(load2Method))
.InsertAndAdvance(new(OpCodes.Ldarg_0), CodeInstruction.LoadField(original.DeclaringType, "target"))
.SetInstruction(CodeInstruction.CallClosure((byte[] assembly, MyApiTarget target) =>
{
if (target is not MyApiTarget.Mod) return Assembly.Load(assembly);
ArgumentNullException.ThrowIfNull(_currentSessionContext, "No session context");
return _currentSessionContext.LoadFromStream(new MemoryStream(assembly));
}));
return matcher.Instructions();
}
[HarmonyPatch(typeof(MySession), nameof(MySession.Load))]
[HarmonyPatch(typeof(MySession), "LoadMultiplayer")]
[HarmonyPrefix]
private static void LoadPrefix()
{
if (_currentSessionContext is not null)
throw new InvalidOperationException("Previous session context was not disposed");
if (AssemblyLoadContext.GetLoadContext(typeof(MySession).Assembly) is not ICoreLoadContext coreContext)
throw new NotSupportedException("Mod loading is not supported in this context");
_currentSessionContext = new ModAssemblyLoadContext(coreContext);
}
[HarmonyPatch(typeof(MySession), nameof(MySession.Unload))]
[HarmonyPostfix]
private static void UnloadPostfix()
{
if (_currentSessionContext is null) return;
_currentSessionContext.Unload();
_currentSessionContext = null;
}
}

View File

@@ -0,0 +1,309 @@
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<string> LoadedModAssemblyNames = new();
private static readonly ConditionalWeakTable<MyProgrammableBlock, AssemblyLoadContext> LoadContexts = new();
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 FieldInfo CompilerErrorsField = AccessTools.Field(typeof(MyProgrammableBlock), "m_compilerErrors");
static ModScriptCompilerPatch()
{
MySession.OnUnloaded += OnUnloaded;
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()
{
LoadedModAssemblyNames.Clear();
if (!_modContext.Assemblies.Any())
return;
_modContext.Unload();
_modContext = new(null, true);
}
[HarmonyPatch(typeof(MyProgrammableBlock), "Compile")]
[HarmonyPrefix]
private static bool CompilePrefix(MyProgrammableBlock __instance, string program, string storage, bool instantiate,
ref MyProgrammableBlock.ScriptTerminationReason ___m_terminationReason,
MyIngameScriptComponent ___ScriptComponent)
{
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);
return false;
}
[HarmonyPatch(typeof(MyGuiScreenEditor), "CheckCodeButtonClicked")]
[HarmonyPrefix]
private static bool GuiCompilePrefix(List<string> ___m_compilerErrors, MyGuiScreenEditor __instance)
{
___m_compilerErrors.Clear();
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();
return false;
}
[HarmonyPatch(typeof(MyScriptCompiler), nameof(MyScriptCompiler.Compile))]
[HarmonyPrefix]
private static bool Prefix(ref Task<Assembly?> __result, MyApiTarget target, string assemblyName, IEnumerable<Script> scripts,
List<Message> messages, string friendlyName, bool enableDebugInformation = false)
{
__result = CompileAsync(_modContext, target, assemblyName, scripts, messages, friendlyName,
enableDebugInformation);
return false;
}
private static async Task CompileAsync(MyGuiScreenEditor editor, List<string> errors, string program, MyGuiScreenProgress progress)
{
var context = new AssemblyLoadContext(null, true);
var messages = new List<Message>();
var script = MyVRage.Platform.Scripting.GetIngameScript(program, "Program", nameof(MyGridProgram));
await CompileAsync(context, MyApiTarget.Ingame, "check", new[] { script }, messages,
"PB Code Editor");
errors.AddRange(messages.OrderBy(b => b.IsError ? 0 : 1).Select(b => b.Text));
context.Unload();
progress.CloseScreen();
if (errors.Count > 0)
{
var sb = new StringBuilder(errors.Sum(b => b.Length + Environment.NewLine.Length));
foreach (var error in errors)
{
sb.AppendLine(error);
}
MyScreenManager.AddScreen(new MyGuiScreenEditorError(sb.ToString()));
return;
}
var messageBox = MyGuiSandbox.CreateMessageBox(MyMessageBoxStyleEnum.Info, MyMessageBoxButtonsType.OK,
MyTexts.Get(MySpaceTexts.ProgrammableBlock_Editor_CompilationOk),
MyTexts.Get(MySpaceTexts.ProgrammableBlock_CodeEditor_Title));
MyGuiSandbox.AddScreen(messageBox);
}
private static async void CompileAsync(MyProgrammableBlock block,
string program,
string storage,
bool instantiate, MyIngameScriptComponent scriptComponent)
{
scriptComponent.NextUpdate = UpdateType.None;
scriptComponent.NeedsUpdate = MyEntityUpdateEnum.NONE;
SetDetailedInfoMethod.Invoke(block, new object?[] { "Compiling..." });
try
{
if (LoadContexts.TryGetValue(block, out var context))
{
AccessTools.FieldRefAccess<MyProgrammableBlock, IMyGridProgram?>(block, InstanceField) = null;
AccessTools.FieldRefAccess<MyProgrammableBlock, Assembly?>(block, AssemblyField) = null;
context.Unload();
}
LoadContexts.AddOrUpdate(block, context = new(null, true));
var messages = new List<Message>();
var assembly = await CompileAsync(context, MyApiTarget.Ingame,
$"pb_{block.EntityId}_{Random.Shared.NextInt64()}",
new[]
{
MyVRage.Platform.Scripting.GetIngameScript(
program, "Program", nameof(MyGridProgram))
}, messages, $"PB: {block.DisplayName} ({block.EntityId})");
AccessTools.FieldRefAccess<MyProgrammableBlock, Assembly?>(block, AssemblyField) = assembly;
var errors = AccessTools.FieldRefAccess<MyProgrammableBlock, List<string>>(block, CompilerErrorsField);
errors.Clear();
errors.AddRange(messages.Select(b => b.Text));
if (instantiate)
MySandboxGame.Static.Invoke(
() => CreateInstanceMethod.Invoke(block, new object?[] { assembly, errors, storage }),
nameof(CompileAsync));
}
catch (Exception e)
{
SetDetailedInfoMethod.Invoke(block, new object?[] { e.ToString() });
Log.Error(e);
}
}
private static async Task<Assembly?> CompileAsync(AssemblyLoadContext context, MyApiTarget target,
string assemblyName, IEnumerable<Script> scripts,
List<Message> messages, string? friendlyName,
bool enableDebugInformation = false)
{
friendlyName ??= "<No Name>";
var assemblyFileName = MakeAssemblyName(assemblyName);
Func<CSharpCompilation, SyntaxTree, SyntaxTree>? syntaxTreeInjector;
DiagnosticAnalyzer? whitelistAnalyzer;
switch (target)
{
case MyApiTarget.None:
whitelistAnalyzer = null;
syntaxTreeInjector = null;
break;
case MyApiTarget.Mod:
{
var modId = MyModWatchdog.AllocateModId(friendlyName);
whitelistAnalyzer = ModWhitelistAnalyzer;
syntaxTreeInjector = (c, st) => InjectMod(c, st, modId);
//skip if name exists already
if (!LoadedModAssemblyNames.Add(assemblyFileName))
{
Console.WriteLine($"{assemblyFileName} is already loaded, skipping");
return null;
}
break;
}
case MyApiTarget.Ingame:
syntaxTreeInjector = InjectInstructionCounter;
whitelistAnalyzer = ScriptWhitelistAnalyzer;
break;
default:
throw new ArgumentOutOfRangeException(nameof(target), target, "Invalid compilation target");
}
var compilation = CreateCompilation(assemblyFileName, scripts);
var compilationWithoutInjection = compilation;
var injectionFailed = false;
if (syntaxTreeInjector != null)
{
SyntaxTree[]? newSyntaxTrees = null;
try
{
var syntaxTrees = compilation.SyntaxTrees;
if (syntaxTrees.Length == 1)
{
newSyntaxTrees = new[] { syntaxTreeInjector(compilation, syntaxTrees[0]) };
}
else
{
var compilation1 = compilation;
newSyntaxTrees = await Task
.WhenAll(syntaxTrees.Select(
x => Task.Run(() => syntaxTreeInjector(compilation1, x)))).ConfigureAwait(false);
}
}
catch (Exception e)
{
Log.Warn(e);
injectionFailed = true;
}
if (newSyntaxTrees is not null)
compilation = compilation.RemoveAllSyntaxTrees().AddSyntaxTrees(newSyntaxTrees);
}
CompilationWithAnalyzers? analyticCompilation = null;
if (whitelistAnalyzer != null)
{
analyticCompilation = compilation.WithAnalyzers(ImmutableArray.Create(whitelistAnalyzer));
compilation = (CSharpCompilation)analyticCompilation.Compilation;
}
using var assemblyStream = new MemoryStream();
var emitResult = compilation.Emit(assemblyStream);
var success = emitResult.Success;
var myBlacklistSyntaxVisitor = new MyBlacklistSyntaxVisitor();
foreach (var syntaxTree in compilation.SyntaxTrees)
{
myBlacklistSyntaxVisitor.SetSemanticModel(compilation.GetSemanticModel(syntaxTree, false));
myBlacklistSyntaxVisitor.Visit(await syntaxTree.GetRootAsync());
}
if (myBlacklistSyntaxVisitor.HasAnyResult())
{
myBlacklistSyntaxVisitor.GetResultMessages(messages);
}
else
{
success = await EmitDiagnostics(analyticCompilation, emitResult, messages, success).ConfigureAwait(false);
assemblyStream.Seek(0, SeekOrigin.Begin);
if (injectionFailed) return null;
if (success)
return context.LoadFromStream(assemblyStream);
await EmitDiagnostics(analyticCompilation, compilationWithoutInjection.Emit(assemblyStream), messages,
false).ConfigureAwait(false);
}
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

View File

@@ -0,0 +1,22 @@
using Windows.Win32.Foundation;
using HarmonyLib;
using SharpDX.DXGI;
using VRage.Platform.Windows.Forms;
namespace CringeLauncher.Patches;
[HarmonyPatch]
public class RenderHookPatch
{
[HarmonyPrefix, HarmonyPatch(typeof(SwapChain), nameof(SwapChain.Present))]
private static void PresentPrefix()
{
ImGuiHandler.Instance?.DoRender();
}
[HarmonyPostfix, HarmonyPatch(typeof(MyGameForm), "OnLoad")]
private static void LoadPostfix(MyGameForm __instance)
{
ImGuiHandler.Instance?.HookWindow((HWND)__instance.Handle);
}
}

View File

@@ -0,0 +1,10 @@
using HarmonyLib;
using SpaceEngineers.Game;
namespace CringeLauncher.Patches;
[HarmonyPatch(typeof(SpaceEngineersGame), "InitializeRender")]
public static class RenderInitPatch
{
private static bool Prefix() => false;
}

View File

@@ -0,0 +1,30 @@
using System.Collections.Concurrent;
using System.Collections.Immutable;
using System.Reflection;
using HarmonyLib;
using VRage.Scripting;
namespace CringeLauncher.Patches;
[HarmonyPatch]
public static class ScriptCompilerInitializationPatch
{
private static MethodInfo TargetMethod()
{
return AccessTools.Method(Type.GetType("VRage.Scripting.MyVRageScriptingInternal, VRage.Scripting", true),
"Initialize");
}
private static bool Prefix(Thread updateThread, Type[] referencedTypes, string[] symbols)
{
MyModWatchdog.Init(updateThread);
MyScriptCompiler.Static.AddImplicitIngameNamespacesFromTypes(referencedTypes);
MyScriptCompiler.Static.AddConditionalCompilationSymbols(symbols);
using var batch = MyScriptCompiler.Static.Whitelist.OpenBatch();
batch.AllowTypes(MyWhitelistTarget.ModApi, typeof(ConcurrentQueue<>));
batch.AllowNamespaceOfTypes(MyWhitelistTarget.Both, typeof(ImmutableArray));
return false;
}
}

View File

@@ -0,0 +1,85 @@
using HarmonyLib;
using SharpDX.Direct3D11;
using SharpDX.DXGI;
using VRage.Platform.Windows.Render;
using VRage.Render11.Resources;
using VRageRender;
namespace CringeLauncher.Patches;
[HarmonyPatch]
public static class SwapChainPatch
{
internal static nint WindowHandle;
[HarmonyPrefix, HarmonyPatch(typeof(MyPlatformRender), nameof(MyPlatformRender.CreateSwapChain))]
private static bool SwapChainPrefix(nint windowHandle)
{
WindowHandle = windowHandle;
MyPlatformRender.DisposeSwapChain();
MyPlatformRender.Log.WriteLine("CreateDeviceInternal create swapchain");
if (MyPlatformRender.m_swapchain != null)
return false;
var chainDescription = new SwapChainDescription
{
BufferCount = 2,
Flags = SwapChainFlags.AllowModeSwitch,
IsWindowed = true,
ModeDescription = MyPlatformRender.GetCurrentModeDescriptor(MyPlatformRender.m_settings) with
{
Format = Format.R8G8B8A8_UNorm
},
SampleDescription = {
Count = 1,
Quality = 0
},
OutputHandle = windowHandle,
Usage = Usage.ShaderInput | Usage.RenderTargetOutput,
SwapEffect = SwapEffect.Discard
};
var factory = MyPlatformRender.GetFactory();
try
{
MyPlatformRender.m_swapchain = new SwapChain(factory, MyPlatformRender.DeviceInstance, chainDescription);
}
catch (Exception)
{
MyPlatformRender.Log.WriteLine("SwapChain factory = " + factory);
MyPlatformRender.Log.WriteLine("SwapChain Device = " + MyPlatformRender.DeviceInstance);
MyPlatformRender.PrintSwapChainDescriptionToLog(chainDescription);
throw;
}
factory.MakeWindowAssociation(windowHandle, WindowAssociationFlags.IgnoreAll);
return false;
}
[HarmonyPostfix, HarmonyPatch(typeof(MyRender11), nameof(MyRender11.CreateDeviceInternal))]
private static void CreateDevicePostfix()
{
ImGuiHandler.Instance ??= new ImGuiHandler(WindowHandle, MyRender11.DeviceInstance, MyRender11.RC.DeviceContext);
}
[HarmonyPrefix, HarmonyPatch(typeof(MyBackbuffer), MethodType.Constructor, typeof(SharpDX.Direct3D11.Resource))]
private static bool SwapChainBBPrefix(MyBackbuffer __instance, SharpDX.Direct3D11.Resource swapChainBB)
{
__instance.m_resource = swapChainBB;
__instance.m_rtv = new RenderTargetView(MyRender11.DeviceInstance, swapChainBB, new()
{
Format = Format.R8G8B8A8_UNorm_SRgb,
Dimension = RenderTargetViewDimension.Texture2D,
});
__instance.m_srv = new ShaderResourceView(MyRender11.DeviceInstance, swapChainBB);
ImGuiHandler.Rtv = new RenderTargetView(MyRender11.DeviceInstance, swapChainBB, new()
{
Format = Format.R8G8B8A8_UNorm,
Dimension = RenderTargetViewDimension.Texture2D,
});
return false;
}
}

View File

@@ -0,0 +1,14 @@
using HarmonyLib;
using VRage.Network;
namespace CringeLauncher.Patches;
[HarmonyPatch(typeof(MyTypeTable), "IsSerializableClass")]
public static class TypeTableRegisterPatch
{
private static void Postfix(Type type, ref bool __result)
{
if (type == typeof(Delegate) || type == typeof(MulticastDelegate))
__result = true;
}
}

View File

@@ -0,0 +1,20 @@
using System.Reflection;
using HarmonyLib;
using VRage.Scripting;
namespace CringeLauncher.Patches;
[HarmonyPatch]
public static class WhitelistAllowPatch
{
private static MethodInfo TargetMethod()
{
return AccessTools.Method(AccessTools.Inner(typeof(MyScriptWhitelist), "MyWhitelistBatch"), "AllowMembers");
}
private static void Prefix(ref MemberInfo[] members)
{
if (members.Any(b => b is null))
members = members.Where(b => b is { }).ToArray();
}
}

View File

@@ -0,0 +1,46 @@
using System.Collections.Concurrent;
using System.Collections.Immutable;
using System.ComponentModel;
using System.Text.RegularExpressions;
using HarmonyLib;
using VRage.FileSystem;
using VRage.Scripting;
namespace CringeLauncher.Patches;
[HarmonyPatch(typeof(MyScriptWhitelist), MethodType.Constructor, typeof(MyScriptCompiler))]
public static class WhitelistPatch
{
private static void Prefix(MyScriptCompiler scriptCompiler)
{
var baseDir = new FileInfo(typeof(Type).Assembly.Location).DirectoryName!;
scriptCompiler.AddReferencedAssemblies(
typeof(Type).Assembly.Location,
typeof(LinkedList<>).Assembly.Location,
typeof(Regex).Assembly.Location,
typeof(Enumerable).Assembly.Location,
typeof(ConcurrentBag<>).Assembly.Location,
typeof(ImmutableArray).Assembly.Location,
typeof(PropertyChangedEventArgs).Assembly.Location,
typeof(TypeConverter).Assembly.Location,
typeof(System.Diagnostics.TraceSource).Assembly.Location,
typeof(System.Security.Policy.Evidence).Assembly.Location,
Path.Combine(baseDir, "System.Xml.ReaderWriter.dll"),
Path.Combine(MyFileSystem.ExePath, "ProtoBuf.Net.dll"),
Path.Combine(MyFileSystem.ExePath, "ProtoBuf.Net.Core.dll"),
Path.Combine(baseDir, "netstandard.dll"),
Path.Combine(baseDir, "System.Runtime.dll"),
Path.Combine(MyFileSystem.ExePath, "Sandbox.Game.dll"),
Path.Combine(MyFileSystem.ExePath, "Sandbox.Common.dll"),
Path.Combine(MyFileSystem.ExePath, "Sandbox.Graphics.dll"),
Path.Combine(MyFileSystem.ExePath, "VRage.dll"),
Path.Combine(MyFileSystem.ExePath, "VRage.Library.dll"),
Path.Combine(MyFileSystem.ExePath, "VRage.Math.dll"),
Path.Combine(MyFileSystem.ExePath, "VRage.Game.dll"),
Path.Combine(MyFileSystem.ExePath, "VRage.Render.dll"),
Path.Combine(MyFileSystem.ExePath, "VRage.Input.dll"),
Path.Combine(MyFileSystem.ExePath, "SpaceEngineers.ObjectBuilders.dll"),
Path.Combine(MyFileSystem.ExePath, "SpaceEngineers.Game.dll"));
}
}

View File

@@ -0,0 +1,37 @@
using System.Reflection;
using System.Reflection.Emit;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using VRage.Scripting;
namespace CringeLauncher.Patches;
[HarmonyPatch]
public static class WhitelistRegistrationPatch
{
private static IEnumerable<MethodInfo> TargetMethods()
{
yield return AccessTools.Method(typeof(MyScriptWhitelist), "Register",
new[] { typeof(MyWhitelistTarget), typeof(INamespaceSymbol), typeof(Type) });
yield return AccessTools.Method(typeof(MyScriptWhitelist), "Register",
new[] { typeof(MyWhitelistTarget), typeof(ITypeSymbol), typeof(Type) });
}
private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
{
var ins = instructions.ToList();
var throwIns = ins.FindAll(b => b.opcode == OpCodes.Throw).Select(b => ins.IndexOf(b));
foreach (var index in throwIns)
{
var i = index;
do
{
ins[i] = new(OpCodes.Nop);
} while (ins[--i].opcode.FlowControl != FlowControl.Cond_Branch);
ins[index] = new(OpCodes.Ret);
}
return ins;
}
}

View File

@@ -0,0 +1,36 @@
using System.Reflection.Emit;
using System.Xml;
using HarmonyLib;
using VRage;
namespace CringeLauncher.Patches;
[HarmonyPatch(typeof(CustomRootWriter), "Init")]
public class XmlRootWriterPatch
{
private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
{
var ins = instructions.ToList();
var index = ins.FindIndex(b =>
b.opcode == OpCodes.Ldstr && b.operand is "xsi:type");
ins[index].operand = "xsi";
ins.InsertRange(index + 1, new[]
{
new CodeInstruction(OpCodes.Ldstr, "type"),
new CodeInstruction(OpCodes.Ldstr, "http://www.w3.org/2001/XMLSchema-instance")
});
var instruction = ins[ins.FindIndex(b => b.opcode == OpCodes.Callvirt)];
instruction.operand = AccessTools.Method(typeof(XmlWriter), "WriteAttributeString", new[]
{
typeof(string),
typeof(string),
typeof(string),
typeof(string)
});
return ins;
}
}