From 0933915c64d03a48acff38df2119a40ea2a57919 Mon Sep 17 00:00:00 2001
From: zznty <94796179+zznty@users.noreply.github.com>
Date: Thu, 10 Oct 2024 00:38:19 +0700
Subject: [PATCH] add bootstrap and plugins prototype
---
.../CringeBootstrap.Abstractions.csproj | 10 +
.../ICoreLoadContext.cs | 9 +
CringeBootstrap.Abstractions/ICorePlugin.cs | 7 +
.../packages.lock.json | 6 +
CringeBootstrap/CringeBootstrap.csproj | 25 ++
.../GameDirectoryAssemblyLoadContext.cs | 67 +++
CringeBootstrap/Program.cs | 32 ++
CringeBootstrap/packages.lock.json | 409 ++++++++++++++++++
CringeLauncher.sln | 20 +-
CringeLauncher/CringeLauncher.csproj | 39 +-
CringeLauncher/ImGuiHandler.cs | 89 ++++
CringeLauncher/Launcher.cs | 48 +-
CringeLauncher/NativeMethods.txt | 2 +
CringeLauncher/Patches/EosInitPatch.cs | 3 +-
.../Patches/IntrospectionPatches.cs | 159 +++++++
CringeLauncher/Patches/RenderHookPatch.cs | 26 ++
CringeLauncher/Patches/SwapChainPatch.cs | 78 ++++
CringeLauncher/Program.cs | 12 -
CringeLauncher/packages.lock.json | 138 +++++-
.../Abstractions/IRenderComponent.cs | 6 +
CringePlugins/CringePlugins.csproj | 29 ++
CringePlugins/Globals.cs | 3 +
.../Loader/PluginAssemblyLoadContext.cs | 38 ++
CringePlugins/Loader/PluginInstance.cs | 55 +++
CringePlugins/Loader/PluginMetadata.cs | 21 +
CringePlugins/Render/RenderHandler.cs | 48 ++
CringePlugins/Utils/IntrospectionContext.cs | 49 +++
CringePlugins/packages.lock.json | 80 ++++
NuGet.config | 6 +
PluginLoader/Compiler/RoslynReferences.cs | 3 +-
PluginLoader/PluginLoader.csproj | 5 +-
PluginLoader/packages.lock.json | 41 +-
32 files changed, 1487 insertions(+), 76 deletions(-)
create mode 100644 CringeBootstrap.Abstractions/CringeBootstrap.Abstractions.csproj
create mode 100644 CringeBootstrap.Abstractions/ICoreLoadContext.cs
create mode 100644 CringeBootstrap.Abstractions/ICorePlugin.cs
create mode 100644 CringeBootstrap.Abstractions/packages.lock.json
create mode 100644 CringeBootstrap/CringeBootstrap.csproj
create mode 100644 CringeBootstrap/GameDirectoryAssemblyLoadContext.cs
create mode 100644 CringeBootstrap/Program.cs
create mode 100644 CringeBootstrap/packages.lock.json
create mode 100644 CringeLauncher/ImGuiHandler.cs
create mode 100644 CringeLauncher/NativeMethods.txt
create mode 100644 CringeLauncher/Patches/IntrospectionPatches.cs
create mode 100644 CringeLauncher/Patches/RenderHookPatch.cs
create mode 100644 CringeLauncher/Patches/SwapChainPatch.cs
delete mode 100644 CringeLauncher/Program.cs
create mode 100644 CringePlugins/Abstractions/IRenderComponent.cs
create mode 100644 CringePlugins/CringePlugins.csproj
create mode 100644 CringePlugins/Globals.cs
create mode 100644 CringePlugins/Loader/PluginAssemblyLoadContext.cs
create mode 100644 CringePlugins/Loader/PluginInstance.cs
create mode 100644 CringePlugins/Loader/PluginMetadata.cs
create mode 100644 CringePlugins/Render/RenderHandler.cs
create mode 100644 CringePlugins/Utils/IntrospectionContext.cs
create mode 100644 CringePlugins/packages.lock.json
create mode 100644 NuGet.config
diff --git a/CringeBootstrap.Abstractions/CringeBootstrap.Abstractions.csproj b/CringeBootstrap.Abstractions/CringeBootstrap.Abstractions.csproj
new file mode 100644
index 0000000..0a6adc3
--- /dev/null
+++ b/CringeBootstrap.Abstractions/CringeBootstrap.Abstractions.csproj
@@ -0,0 +1,10 @@
+
+
+
+ net8.0
+ enable
+ enable
+ true
+
+
+
diff --git a/CringeBootstrap.Abstractions/ICoreLoadContext.cs b/CringeBootstrap.Abstractions/ICoreLoadContext.cs
new file mode 100644
index 0000000..d65fd94
--- /dev/null
+++ b/CringeBootstrap.Abstractions/ICoreLoadContext.cs
@@ -0,0 +1,9 @@
+using System.Reflection;
+
+namespace CringeBootstrap.Abstractions;
+
+public interface ICoreLoadContext
+{
+ Assembly? ResolveFromAssemblyName(AssemblyName assemblyName);
+ nint ResolveUnmanagedDll(string unmanagedDllName);
+}
\ No newline at end of file
diff --git a/CringeBootstrap.Abstractions/ICorePlugin.cs b/CringeBootstrap.Abstractions/ICorePlugin.cs
new file mode 100644
index 0000000..6083483
--- /dev/null
+++ b/CringeBootstrap.Abstractions/ICorePlugin.cs
@@ -0,0 +1,7 @@
+namespace CringeBootstrap.Abstractions;
+
+public interface ICorePlugin : IDisposable
+{
+ void Initialize(string[] args);
+ void Run();
+}
\ No newline at end of file
diff --git a/CringeBootstrap.Abstractions/packages.lock.json b/CringeBootstrap.Abstractions/packages.lock.json
new file mode 100644
index 0000000..807ab82
--- /dev/null
+++ b/CringeBootstrap.Abstractions/packages.lock.json
@@ -0,0 +1,6 @@
+{
+ "version": 1,
+ "dependencies": {
+ "net8.0": {}
+ }
+}
\ No newline at end of file
diff --git a/CringeBootstrap/CringeBootstrap.csproj b/CringeBootstrap/CringeBootstrap.csproj
new file mode 100644
index 0000000..2bbb0fd
--- /dev/null
+++ b/CringeBootstrap/CringeBootstrap.csproj
@@ -0,0 +1,25 @@
+
+
+
+ Exe
+ net8.0-windows10.0.19041.0
+ enable
+ enable
+ true
+ preview
+ true
+ true
+ true
+ win-x64
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/CringeBootstrap/GameDirectoryAssemblyLoadContext.cs b/CringeBootstrap/GameDirectoryAssemblyLoadContext.cs
new file mode 100644
index 0000000..7a45136
--- /dev/null
+++ b/CringeBootstrap/GameDirectoryAssemblyLoadContext.cs
@@ -0,0 +1,67 @@
+using System.Collections.Immutable;
+using System.Diagnostics;
+using System.Reflection;
+using System.Runtime.Loader;
+using CringeBootstrap.Abstractions;
+
+namespace CringeBootstrap;
+
+public class GameDirectoryAssemblyLoadContext : AssemblyLoadContext, ICoreLoadContext
+{
+ private static readonly ImmutableHashSet ReferenceAssemblies = ["netstandard"];
+ private readonly Dictionary _assemblyNames = [];
+
+ public GameDirectoryAssemblyLoadContext(string dir) : base("CringeBootstrap")
+ {
+ var files = Directory.GetFiles(dir, "*.dll");
+ foreach (var file in files)
+ {
+ if (File.Exists(Path.Join(AppContext.BaseDirectory, Path.GetFileName(file))))
+ continue;
+
+ try
+ {
+ var name = AssemblyName.GetAssemblyName(file);
+
+ AddOverride(name, file);
+ }
+ catch (BadImageFormatException)
+ {
+ // if we are trying to load native image
+ }
+ }
+ }
+
+ public void AddOverride(AssemblyName name, string file)
+ {
+ var key = name.Name ?? name.FullName[..','];
+
+ if (key.StartsWith("System.") || ReferenceAssemblies.Contains(key))
+ return;
+
+ _assemblyNames.TryAdd(key, file);
+ }
+
+ public void AddDependencyOverride(string name)
+ {
+ AddOverride(new(name), Path.Join(AppContext.BaseDirectory, name + ".dll"));
+ }
+
+ protected override Assembly? Load(AssemblyName name)
+ {
+ var key = name.Name ?? name.FullName[..','];
+
+ try
+ {
+ return _assemblyNames.TryGetValue(key, out var value) ? LoadFromAssemblyPath(value) : null;
+ }
+ catch (BadImageFormatException e)
+ {
+ Debug.WriteLine(e);
+ return null;
+ }
+ }
+
+ public Assembly? ResolveFromAssemblyName(AssemblyName assemblyName) => Load(assemblyName);
+ public nint ResolveUnmanagedDll(string unmanagedDllName) => LoadUnmanagedDll(unmanagedDllName);
+}
\ No newline at end of file
diff --git a/CringeBootstrap/Program.cs b/CringeBootstrap/Program.cs
new file mode 100644
index 0000000..ea856cd
--- /dev/null
+++ b/CringeBootstrap/Program.cs
@@ -0,0 +1,32 @@
+using System.Diagnostics;
+using System.Reflection;
+using System.Runtime.Loader;
+using CringeBootstrap;
+using CringeBootstrap.Abstractions;
+using Velopack;
+
+#if DEBUG
+while (!Debugger.IsAttached)
+ Thread.Sleep(100);
+#endif
+
+VelopackApp.Build().Run();
+
+AssemblyLoadContext.Default.Resolving += (loadContext, name) =>
+{
+ Debug.WriteLine($"resolving {name} in {loadContext}");
+ return null;
+};
+
+var dir = Path.GetDirectoryName(args[0])!;
+var context = new GameDirectoryAssemblyLoadContext(dir);
+
+context.AddDependencyOverride("CringeLauncher");
+context.AddDependencyOverride("PluginLoader");
+
+var launcher = context.LoadFromAssemblyName(new AssemblyName("CringeLauncher"));
+
+using var corePlugin = (ICorePlugin) launcher.CreateInstance("CringeLauncher.Launcher")!;
+
+corePlugin.Initialize(args);
+corePlugin.Run();
\ No newline at end of file
diff --git a/CringeBootstrap/packages.lock.json b/CringeBootstrap/packages.lock.json
new file mode 100644
index 0000000..befcb61
--- /dev/null
+++ b/CringeBootstrap/packages.lock.json
@@ -0,0 +1,409 @@
+{
+ "version": 1,
+ "dependencies": {
+ "net8.0-windows10.0.19041": {
+ "Velopack": {
+ "type": "Direct",
+ "requested": "[0.0.630-g9c52e40, )",
+ "resolved": "0.0.630-g9c52e40",
+ "contentHash": "4xNKtV+vyZPdlaQMNeen7p3WqGoq7CkVVkneywod1kTM3zKphQQwxo6KESGxsolwImXM8cZk4E1Zu64SYbaJhQ==",
+ "dependencies": {
+ "Microsoft.Extensions.Logging.Abstractions": "8.0.0",
+ "NuGet.Versioning": "6.10.1"
+ }
+ },
+ "dnlib": {
+ "type": "Transitive",
+ "resolved": "4.4.0",
+ "contentHash": "cKHI720q+zfEEvzklWVGt6B0TH3AibAyJbpUJl4U6KvTP13tycfnqJpkGHRZ/oQ45BTIoIxIwltHIJVDN+iCqQ=="
+ },
+ "ImGui.NET.DirectX": {
+ "type": "Transitive",
+ "resolved": "1.91.0.1",
+ "contentHash": "PpW1gQ9g97h6Hm/h/tkSBOmsBYgGwN8wKNmlJomcQFD/zRY1HPkJZz18XRSfRLHPmH2eeh4hhhZv1KHug7dF9g==",
+ "dependencies": {
+ "System.Buffers": "4.5.1",
+ "System.Numerics.Vectors": "4.5.0",
+ "System.Runtime.CompilerServices.Unsafe": "6.0.0"
+ }
+ },
+ "Lib.Harmony.Thin": {
+ "type": "Transitive",
+ "resolved": "2.3.3",
+ "contentHash": "jsaFv7XnWJnyfyvFbkgIkZtV6tWMteNUcDK3idq+3LwPqpTFNxsOv2eKmj4qqP8QR8UynG1Y9AUaC/+dVruMHg==",
+ "dependencies": {
+ "MonoMod.Core": "1.1.0",
+ "System.Text.Json": "8.0.1"
+ }
+ },
+ "Microsoft.Bcl.AsyncInterfaces": {
+ "type": "Transitive",
+ "resolved": "5.0.0",
+ "contentHash": "W8DPQjkMScOMTtJbPwmPyj9c3zYSFGawDW3jwlBOOsnY+EzZFLgNQ/UMkK35JmkNOVPdCyPr2Tw7Vv9N+KA3ZQ=="
+ },
+ "Microsoft.CodeAnalysis.Analyzers": {
+ "type": "Transitive",
+ "resolved": "3.3.4",
+ "contentHash": "AxkxcPR+rheX0SmvpLVIGLhOUXAKG56a64kV9VQZ4y9gR9ZmPXnqZvHJnmwLSwzrEP6junUF11vuc+aqo5r68g=="
+ },
+ "Microsoft.CodeAnalysis.Common": {
+ "type": "Transitive",
+ "resolved": "4.11.0",
+ "contentHash": "djf8ujmqYImFgB04UGtcsEhHrzVqzHowS+EEl/Yunc5LdrYrZhGBWUTXoCF0NzYXJxtfuD+UVQarWpvrNc94Qg==",
+ "dependencies": {
+ "Microsoft.CodeAnalysis.Analyzers": "3.3.4",
+ "System.Collections.Immutable": "8.0.0",
+ "System.Reflection.Metadata": "8.0.0"
+ }
+ },
+ "Microsoft.CodeAnalysis.CSharp": {
+ "type": "Transitive",
+ "resolved": "4.11.0",
+ "contentHash": "6XYi2EusI8JT4y2l/F3VVVS+ISoIX9nqHsZRaG6W5aFeJ5BEuBosHfT/ABb73FN0RZ1Z3cj2j7cL28SToJPXOw==",
+ "dependencies": {
+ "Microsoft.CodeAnalysis.Analyzers": "3.3.4",
+ "Microsoft.CodeAnalysis.Common": "[4.11.0]",
+ "System.Collections.Immutable": "8.0.0",
+ "System.Reflection.Metadata": "8.0.0"
+ }
+ },
+ "Microsoft.Extensions.DependencyInjection.Abstractions": {
+ "type": "Transitive",
+ "resolved": "8.0.0",
+ "contentHash": "cjWrLkJXK0rs4zofsK4bSdg+jhDLTaxrkXu4gS6Y7MAlCvRyNNgwY/lJi5RDlQOnSZweHqoyvgvbdvQsRIW+hg=="
+ },
+ "Microsoft.Extensions.Logging.Abstractions": {
+ "type": "Transitive",
+ "resolved": "8.0.0",
+ "contentHash": "arDBqTgFCyS0EvRV7O3MZturChstm50OJ0y9bDJvAcmEPJm0FFpFyjU/JLYyStNGGey081DvnQYlncNX5SJJGA==",
+ "dependencies": {
+ "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0"
+ }
+ },
+ "Microsoft.Extensions.ObjectPool": {
+ "type": "Transitive",
+ "resolved": "5.0.10",
+ "contentHash": "pp9tbGqIhdEXL6Q1yJl+zevAJSq4BsxqhS1GXzBvEsEz9DDNu9GLNzgUy2xyFc4YjB4m4Ff2YEWTnvQvVYdkvQ=="
+ },
+ "Mono.Cecil": {
+ "type": "Transitive",
+ "resolved": "0.11.5",
+ "contentHash": "fxfX+0JGTZ8YQeu1MYjbBiK2CYTSzDyEeIixt+yqKKTn7FW8rv7JMY70qevup4ZJfD7Kk/VG/jDzQQTpfch87g=="
+ },
+ "MonoMod.Backports": {
+ "type": "Transitive",
+ "resolved": "1.1.0",
+ "contentHash": "GUAjCrCZEddqHKHFA7Lh61PgTzoKY7gfBShFe0hQe0p8iynHhBK3TWGyRi+QIw/PGfaRPwx6c33CPGFURBVM6g==",
+ "dependencies": {
+ "MonoMod.ILHelpers": "1.0.1"
+ }
+ },
+ "MonoMod.Core": {
+ "type": "Transitive",
+ "resolved": "1.1.0",
+ "contentHash": "Ks8RntZGVcktr2QF/AovTEbuOkrgXz6omjrvT5LRveOIQJuy+IFuEQPBVWu+cSKVIoZD5XkpRFvlVrItgPIrXw==",
+ "dependencies": {
+ "Mono.Cecil": "0.11.5",
+ "MonoMod.Backports": "1.1.0",
+ "MonoMod.ILHelpers": "1.0.1",
+ "MonoMod.Utils": "25.0.4"
+ }
+ },
+ "MonoMod.ILHelpers": {
+ "type": "Transitive",
+ "resolved": "1.0.1",
+ "contentHash": "6djj/Hz+/eTomo1H/sJEJNxBz2ZdhXjvH0MOmyU2xRtbjaIfBQuyVV0zNUbJhMY/8qoWrz7WXfskfFhdaY0afA=="
+ },
+ "MonoMod.Utils": {
+ "type": "Transitive",
+ "resolved": "25.0.4",
+ "contentHash": "cB94MaZtFD9u4clYEFTwM4jGXnJnzXsxYF3yBpMZKHhXOas66tMF2frbdYte023i0MH4C5iRJbDjxHmA4x5VgA==",
+ "dependencies": {
+ "Mono.Cecil": "0.11.5",
+ "MonoMod.Backports": "1.1.0",
+ "MonoMod.ILHelpers": "1.0.1"
+ }
+ },
+ "NLog": {
+ "type": "Transitive",
+ "resolved": "5.3.4",
+ "contentHash": "gLy7+O1hEYJXIlcTr1/VWjGXrZTQFZzYNO18IWasD64pNwz0BreV+nHLxWKXWZzERRzoKnsk2XYtwLkTVk7J1A=="
+ },
+ "NuGet.Versioning": {
+ "type": "Transitive",
+ "resolved": "6.10.1",
+ "contentHash": "tovHZ3OlMVmsTdhv2z5nwnnhoA1ryhfJMyVQ9/+iv6d3h78fp230XaGy3K/iVcLwB50DdfNfIsitW97KSOWDFg=="
+ },
+ "protobuf-net": {
+ "type": "Transitive",
+ "resolved": "1.0.0",
+ "contentHash": "kTGOK0E87473sOImOjgZOnz3kTC2aMLffoRWQLYNuBLJnwNNmjanF9IkevZ9Q7yYLeABQfcF3BpeepuMntMVNw=="
+ },
+ "SharpDX": {
+ "type": "Transitive",
+ "resolved": "4.2.0-keen-cringe",
+ "contentHash": "LaJN3h1Gi1FWVdef2I5WtOH9gwzKCBniH0CragarbkN2QheYY6Lqm+91PcOfp1w/4wdVb+k8Kjv3sO393Tphtw=="
+ },
+ "SixLabors.Core": {
+ "type": "Transitive",
+ "resolved": "1.0.0-beta0007",
+ "contentHash": "s9aPl6yxwcvoKRD0u0zjkCISZCCifbUi9/XVFjdvlx5Pt7vRYmGV0anq1EEftUjIEHbEu5aNBipbUSBIV2CE7w==",
+ "dependencies": {
+ "System.Runtime.CompilerServices.Unsafe": "4.5.1"
+ }
+ },
+ "SpaceEngineersDedicated.ReferenceAssemblies": {
+ "type": "Transitive",
+ "resolved": "1.204.18",
+ "contentHash": "GT7/9CBMx4jjor41zLOOl87YYM/JdJD8xp9ccXyuhP2oUaz25H3ZmCQuGeAuZNENKru1a/7hZrId4PwlMDGoew==",
+ "dependencies": {
+ "SharpDX": "4.2.0-keen-cringe",
+ "protobuf-net": "1.0.0"
+ }
+ },
+ "Steamworks.NET": {
+ "type": "Transitive",
+ "resolved": "20.1.0",
+ "contentHash": "+GntwnyJ5tCNvUIaQxv2+ehDvZJzGUqlSB5xRBk1hTj1qqBJ6s4vK/OfGD/jae7aTmXiGSm8wpJORosNtQevJQ=="
+ },
+ "System.Buffers": {
+ "type": "Transitive",
+ "resolved": "4.5.1",
+ "contentHash": "Rw7ijyl1qqRS0YQD/WycNst8hUUMgrMH4FCn1nNm27M4VxchZ1js3fVjQaANHO5f3sN4isvP4a+Met9Y4YomAg=="
+ },
+ "System.CodeDom": {
+ "type": "Transitive",
+ "resolved": "8.0.0",
+ "contentHash": "WTlRjL6KWIMr/pAaq3rYqh0TJlzpouaQ/W1eelssHgtlwHAH25jXTkUphTYx9HaIIf7XA6qs/0+YhtLEQRkJ+Q=="
+ },
+ "System.Collections.Immutable": {
+ "type": "Transitive",
+ "resolved": "8.0.0",
+ "contentHash": "AurL6Y5BA1WotzlEvVaIDpqzpIPvYnnldxru8oXJU2yFxFUy3+pNXjXd1ymO+RA0rq0+590Q8gaz2l3Sr7fmqg=="
+ },
+ "System.Configuration.ConfigurationManager": {
+ "type": "Transitive",
+ "resolved": "8.0.0",
+ "contentHash": "JlYi9XVvIREURRUlGMr1F6vOFLk7YSY4p1vHo4kX3tQ0AGrjqlRWHDi66ImHhy6qwXBG3BJ6Y1QlYQ+Qz6Xgww==",
+ "dependencies": {
+ "System.Diagnostics.EventLog": "8.0.0",
+ "System.Security.Cryptography.ProtectedData": "8.0.0"
+ }
+ },
+ "System.Diagnostics.EventLog": {
+ "type": "Transitive",
+ "resolved": "8.0.0",
+ "contentHash": "fdYxcRjQqTTacKId/2IECojlDSFvp7LP5N78+0z/xH7v/Tuw5ZAxu23Y6PTCRinqyu2ePx+Gn1098NC6jM6d+A=="
+ },
+ "System.Diagnostics.PerformanceCounter": {
+ "type": "Transitive",
+ "resolved": "8.0.0",
+ "contentHash": "lX6DXxtJqVGWw7N/QmVoiCyVQ+Q/Xp+jVXPr3gLK1jJExSn1qmAjJQeb8gnOYeeBTG3E3PmG1nu92eYj/TEjpg==",
+ "dependencies": {
+ "System.Configuration.ConfigurationManager": "8.0.0"
+ }
+ },
+ "System.Formats.Asn1": {
+ "type": "Transitive",
+ "resolved": "6.0.0",
+ "contentHash": "T6fD00dQ3NTbPDy31m4eQUwKW84s03z0N2C8HpOklyeaDgaJPa/TexP4/SkORMSOwc7WhKifnA6Ya33AkzmafA=="
+ },
+ "System.Management": {
+ "type": "Transitive",
+ "resolved": "8.0.0",
+ "contentHash": "jrK22i5LRzxZCfGb+tGmke2VH7oE0DvcDlJ1HAKYU8cPmD8XnpUT0bYn2Gy98GEhGjtfbR/sxKTVb+dE770pfA==",
+ "dependencies": {
+ "System.CodeDom": "8.0.0"
+ }
+ },
+ "System.Numerics.Vectors": {
+ "type": "Transitive",
+ "resolved": "4.5.0",
+ "contentHash": "QQTlPTl06J/iiDbJCiepZ4H//BVraReU4O4EoRw1U02H5TLUIT7xn3GnDp9AXPSlJUDyFs4uWjWafNX6WrAojQ=="
+ },
+ "System.Private.ServiceModel": {
+ "type": "Transitive",
+ "resolved": "4.10.3",
+ "contentHash": "BcUV7OERlLqGxDXZuIyIMMmk1PbqBblLRbAoigmzIUx/M8A+8epvyPyXRpbgoucKH7QmfYdQIev04Phx2Co08A==",
+ "dependencies": {
+ "Microsoft.Bcl.AsyncInterfaces": "5.0.0",
+ "Microsoft.Extensions.ObjectPool": "5.0.10",
+ "System.Numerics.Vectors": "4.5.0",
+ "System.Reflection.DispatchProxy": "4.7.1",
+ "System.Security.Cryptography.Xml": "6.0.1",
+ "System.Security.Principal.Windows": "5.0.0"
+ }
+ },
+ "System.Reflection.DispatchProxy": {
+ "type": "Transitive",
+ "resolved": "4.7.1",
+ "contentHash": "C1sMLwIG6ILQ2bmOT4gh62V6oJlyF4BlHcVMrOoor49p0Ji2tA8QAoqyMcIhAdH6OHKJ8m7BU+r4LK2CUEOKqw=="
+ },
+ "System.Reflection.Metadata": {
+ "type": "Transitive",
+ "resolved": "8.0.0",
+ "contentHash": "ptvgrFh7PvWI8bcVqG5rsA/weWM09EnthFHR5SCnS6IN+P4mj6rE1lBDC4U8HL9/57htKAqy4KQ3bBj84cfYyQ==",
+ "dependencies": {
+ "System.Collections.Immutable": "8.0.0"
+ }
+ },
+ "System.Runtime.CompilerServices.Unsafe": {
+ "type": "Transitive",
+ "resolved": "6.0.0",
+ "contentHash": "/iUeP3tq1S0XdNNoMz5C9twLSrM/TH+qElHkXWaPvuNOt+99G75NrV0OS2EqHx5wMN7popYjpc8oTjC1y16DLg=="
+ },
+ "System.Security.AccessControl": {
+ "type": "Transitive",
+ "resolved": "6.0.0",
+ "contentHash": "AUADIc0LIEQe7MzC+I0cl0rAT8RrTAKFHl53yHjEUzNVIaUlhFY11vc2ebiVJzVBuOzun6F7FBA+8KAbGTTedQ=="
+ },
+ "System.Security.Cryptography.Pkcs": {
+ "type": "Transitive",
+ "resolved": "6.0.1",
+ "contentHash": "ynmbW2GjIGg9K1wXmVIRs4IlyDolf0JXNpzFQ8JCVgwM+myUC2JeUggl2PwQig2PNVMegKmN1aAx7WPQ8tI3vA==",
+ "dependencies": {
+ "System.Formats.Asn1": "6.0.0"
+ }
+ },
+ "System.Security.Cryptography.ProtectedData": {
+ "type": "Transitive",
+ "resolved": "8.0.0",
+ "contentHash": "+TUFINV2q2ifyXauQXRwy4CiBhqvDEDZeVJU7qfxya4aRYOKzVBpN+4acx25VcPB9ywUN6C0n8drWl110PhZEg=="
+ },
+ "System.Security.Cryptography.Xml": {
+ "type": "Transitive",
+ "resolved": "6.0.1",
+ "contentHash": "5e5bI28T0x73AwTsbuFP4qSRzthmU2C0Gqgg3AZ3KTxmSyA+Uhk31puA3srdaeWaacVnHhLdJywCzqOiEpbO/w==",
+ "dependencies": {
+ "System.Security.AccessControl": "6.0.0",
+ "System.Security.Cryptography.Pkcs": "6.0.1"
+ }
+ },
+ "System.Security.Principal.Windows": {
+ "type": "Transitive",
+ "resolved": "5.0.0",
+ "contentHash": "t0MGLukB5WAVU9bO3MGzvlGnyJPgUlcwerXn1kzBRjwLKixT96XV0Uza41W49gVd8zEMFu9vQEFlv0IOrytICA=="
+ },
+ "System.Text.Encodings.Web": {
+ "type": "Transitive",
+ "resolved": "8.0.0",
+ "contentHash": "yev/k9GHAEGx2Rg3/tU6MQh4HGBXJs70y7j1LaM1i/ER9po+6nnQ6RRqTJn1E7Xu0fbIFK80Nh5EoODxrbxwBQ=="
+ },
+ "System.Text.Json": {
+ "type": "Transitive",
+ "resolved": "8.0.1",
+ "contentHash": "7AWk2za1hSEJBppe/Lg+uDcam2TrDqwIKa9XcPssSwyjC2xa39EKEGul3CO5RWNF+hMuZG4zlBDrvhBdDTg4lg==",
+ "dependencies": {
+ "System.Text.Encodings.Web": "8.0.0"
+ }
+ },
+ "Torch.SixLabors.ImageSharp": {
+ "type": "Transitive",
+ "resolved": "1.0.0-beta6",
+ "contentHash": "WJ7ocT79HgmuKi0+ltpvXTiMI80UcI3DeS8XSfYwJtTB1tcQws6zLPGuUwra6qe6qRrFfpABeDP3xvHV1rJgfg==",
+ "dependencies": {
+ "SixLabors.Core": "1.0.0-beta0007",
+ "System.Runtime.CompilerServices.Unsafe": "4.5.1"
+ }
+ },
+ "cringebootstrap.abstractions": {
+ "type": "Project"
+ },
+ "cringelauncher": {
+ "type": "Project",
+ "dependencies": {
+ "CringeBootstrap.Abstractions": "[1.0.0, )",
+ "CringePlugins": "[1.0.0, )",
+ "ImGui.NET.DirectX": "[1.91.0.1, )",
+ "PluginLoader": "[1.0.0, )",
+ "System.Diagnostics.PerformanceCounter": "[8.0.0, )",
+ "System.Management": "[8.0.0, )",
+ "System.Private.ServiceModel": "[4.10.3, )",
+ "Torch.SixLabors.ImageSharp": "[1.0.0-beta6, )",
+ "Velopack": "[0.0.630-g9c52e40, )",
+ "dnlib": "[4.4.0, )"
+ }
+ },
+ "cringeplugins": {
+ "type": "Project",
+ "dependencies": {
+ "CringeBootstrap.Abstractions": "[1.0.0, )",
+ "NLog": "[5.3.4, )",
+ "SpaceEngineersDedicated.ReferenceAssemblies": "[1.*, )",
+ "dnlib": "[4.4.0, )"
+ }
+ },
+ "pluginloader": {
+ "type": "Project",
+ "dependencies": {
+ "Lib.Harmony.Thin": "[2.3.3, )",
+ "Microsoft.CodeAnalysis.CSharp": "[4.11.0, )",
+ "NLog": "[5.3.4, )",
+ "SpaceEngineersDedicated.ReferenceAssemblies": "[1.*, )",
+ "Steamworks.NET": "[20.1.0, )"
+ }
+ }
+ },
+ "net8.0-windows10.0.19041/win-x64": {
+ "ImGui.NET.DirectX": {
+ "type": "Transitive",
+ "resolved": "1.91.0.1",
+ "contentHash": "PpW1gQ9g97h6Hm/h/tkSBOmsBYgGwN8wKNmlJomcQFD/zRY1HPkJZz18XRSfRLHPmH2eeh4hhhZv1KHug7dF9g==",
+ "dependencies": {
+ "System.Buffers": "4.5.1",
+ "System.Numerics.Vectors": "4.5.0",
+ "System.Runtime.CompilerServices.Unsafe": "6.0.0"
+ }
+ },
+ "Steamworks.NET": {
+ "type": "Transitive",
+ "resolved": "20.1.0",
+ "contentHash": "+GntwnyJ5tCNvUIaQxv2+ehDvZJzGUqlSB5xRBk1hTj1qqBJ6s4vK/OfGD/jae7aTmXiGSm8wpJORosNtQevJQ=="
+ },
+ "System.Diagnostics.EventLog": {
+ "type": "Transitive",
+ "resolved": "8.0.0",
+ "contentHash": "fdYxcRjQqTTacKId/2IECojlDSFvp7LP5N78+0z/xH7v/Tuw5ZAxu23Y6PTCRinqyu2ePx+Gn1098NC6jM6d+A=="
+ },
+ "System.Diagnostics.PerformanceCounter": {
+ "type": "Transitive",
+ "resolved": "8.0.0",
+ "contentHash": "lX6DXxtJqVGWw7N/QmVoiCyVQ+Q/Xp+jVXPr3gLK1jJExSn1qmAjJQeb8gnOYeeBTG3E3PmG1nu92eYj/TEjpg==",
+ "dependencies": {
+ "System.Configuration.ConfigurationManager": "8.0.0"
+ }
+ },
+ "System.Management": {
+ "type": "Transitive",
+ "resolved": "8.0.0",
+ "contentHash": "jrK22i5LRzxZCfGb+tGmke2VH7oE0DvcDlJ1HAKYU8cPmD8XnpUT0bYn2Gy98GEhGjtfbR/sxKTVb+dE770pfA==",
+ "dependencies": {
+ "System.CodeDom": "8.0.0"
+ }
+ },
+ "System.Security.AccessControl": {
+ "type": "Transitive",
+ "resolved": "6.0.0",
+ "contentHash": "AUADIc0LIEQe7MzC+I0cl0rAT8RrTAKFHl53yHjEUzNVIaUlhFY11vc2ebiVJzVBuOzun6F7FBA+8KAbGTTedQ=="
+ },
+ "System.Security.Cryptography.Pkcs": {
+ "type": "Transitive",
+ "resolved": "6.0.1",
+ "contentHash": "ynmbW2GjIGg9K1wXmVIRs4IlyDolf0JXNpzFQ8JCVgwM+myUC2JeUggl2PwQig2PNVMegKmN1aAx7WPQ8tI3vA==",
+ "dependencies": {
+ "System.Formats.Asn1": "6.0.0"
+ }
+ },
+ "System.Security.Principal.Windows": {
+ "type": "Transitive",
+ "resolved": "5.0.0",
+ "contentHash": "t0MGLukB5WAVU9bO3MGzvlGnyJPgUlcwerXn1kzBRjwLKixT96XV0Uza41W49gVd8zEMFu9vQEFlv0IOrytICA=="
+ },
+ "System.Text.Encodings.Web": {
+ "type": "Transitive",
+ "resolved": "8.0.0",
+ "contentHash": "yev/k9GHAEGx2Rg3/tU6MQh4HGBXJs70y7j1LaM1i/ER9po+6nnQ6RRqTJn1E7Xu0fbIFK80Nh5EoODxrbxwBQ=="
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/CringeLauncher.sln b/CringeLauncher.sln
index 88beb5a..1d54ef4 100644
--- a/CringeLauncher.sln
+++ b/CringeLauncher.sln
@@ -1,9 +1,15 @@
Microsoft Visual Studio Solution File, Format Version 12.00
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CringeLauncher", "CringeLauncher\CringeLauncher.csproj", "{219C897E-452D-49B5-80C4-F3008718C16A}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CringeBootstrap", "CringeBootstrap\CringeBootstrap.csproj", "{219C897E-452D-49B5-80C4-F3008718C16A}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PluginLoader", "PluginLoader\PluginLoader.csproj", "{A7C22A74-56EA-4DC2-89AA-A1134BFB8497}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CringeLauncher", "CringeLauncher\CringeLauncher.csproj", "{2A1B48E9-ED82-4EEB-A18A-E4148DFE3A19}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CringeBootstrap.Abstractions", "CringeBootstrap.Abstractions\CringeBootstrap.Abstractions.csproj", "{12AA2BBC-E795-4065-AF4A-9A44AFF69D92}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CringePlugins", "CringePlugins\CringePlugins.csproj", "{16F4D4BF-D363-4C71-8364-ACD0D63B0AE8}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -18,5 +24,17 @@ Global
{A7C22A74-56EA-4DC2-89AA-A1134BFB8497}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A7C22A74-56EA-4DC2-89AA-A1134BFB8497}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A7C22A74-56EA-4DC2-89AA-A1134BFB8497}.Release|Any CPU.Build.0 = Release|Any CPU
+ {2A1B48E9-ED82-4EEB-A18A-E4148DFE3A19}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {2A1B48E9-ED82-4EEB-A18A-E4148DFE3A19}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {2A1B48E9-ED82-4EEB-A18A-E4148DFE3A19}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {2A1B48E9-ED82-4EEB-A18A-E4148DFE3A19}.Release|Any CPU.Build.0 = Release|Any CPU
+ {12AA2BBC-E795-4065-AF4A-9A44AFF69D92}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {12AA2BBC-E795-4065-AF4A-9A44AFF69D92}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {12AA2BBC-E795-4065-AF4A-9A44AFF69D92}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {12AA2BBC-E795-4065-AF4A-9A44AFF69D92}.Release|Any CPU.Build.0 = Release|Any CPU
+ {16F4D4BF-D363-4C71-8364-ACD0D63B0AE8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {16F4D4BF-D363-4C71-8364-ACD0D63B0AE8}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {16F4D4BF-D363-4C71-8364-ACD0D63B0AE8}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {16F4D4BF-D363-4C71-8364-ACD0D63B0AE8}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
EndGlobal
diff --git a/CringeLauncher/CringeLauncher.csproj b/CringeLauncher/CringeLauncher.csproj
index b04d0e7..5a49894 100644
--- a/CringeLauncher/CringeLauncher.csproj
+++ b/CringeLauncher/CringeLauncher.csproj
@@ -1,40 +1,47 @@
- Exe
net8.0-windows10.0.19041.0
+ win-x64
enable
enable
true
preview
- true
true
- true
- win-x64
- https://nuget.storage.yandexcloud.net/index.json
+ true
-
+
+
+
+
- all
- runtime; build; native; contentfiles; analyzers; buildtransitive
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
-
-
-
-
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
diff --git a/CringeLauncher/ImGuiHandler.cs b/CringeLauncher/ImGuiHandler.cs
new file mode 100644
index 0000000..3c10b97
--- /dev/null
+++ b/CringeLauncher/ImGuiHandler.cs
@@ -0,0 +1,89 @@
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Runtime.Versioning;
+using Windows.Win32;
+using Windows.Win32.Foundation;
+using Windows.Win32.UI.WindowsAndMessaging;
+using CringePlugins.Render;
+using ImGuiNET;
+using SharpDX.Direct3D11;
+using static ImGuiNET.ImGui;
+
+namespace CringeLauncher;
+
+internal class ImGuiHandler : IDisposable
+{
+ private readonly DeviceContext _deviceContext;
+ private static nint _wndproc;
+
+ public static ImGuiHandler? Instance;
+
+ public RenderTargetView? Rtv;
+ private readonly RenderHandler _renderHandler;
+
+ public ImGuiHandler(nint windowHandle, Device1 device, DeviceContext deviceContext)
+ {
+ _deviceContext = deviceContext;
+
+ _renderHandler = new RenderHandler();
+
+ CreateContext();
+
+ ImGui_ImplWin32_Init(windowHandle);
+ ImGui_ImplDX11_Init(device.NativePointer, deviceContext.NativePointer);
+
+ _wndproc = PInvoke.GetWindowLongPtr((HWND)windowHandle, WINDOW_LONG_PTR_INDEX.GWL_WNDPROC);
+
+ unsafe
+ {
+ delegate* unmanaged[Stdcall] wndProcHook = &WndProcHook;
+
+ PInvoke.SetWindowLongPtr((HWND)windowHandle, WINDOW_LONG_PTR_INDEX.GWL_WNDPROC, (nint)wndProcHook);
+ }
+
+ var io = GetIO();
+
+ io.ConfigWindowsMoveFromTitleBarOnly = true;
+ io.ConfigFlags |= ImGuiConfigFlags.DockingEnable | ImGuiConfigFlags.ViewportsEnable;
+ }
+
+ public void DoRender()
+ {
+ if (Rtv is null)
+ throw new InvalidOperationException("Rtv is null");
+
+ ImGui_ImplDX11_NewFrame();
+ ImGui_ImplWin32_NewFrame();
+ NewFrame();
+
+ _renderHandler.OnFrame();
+
+ Render();
+
+ _deviceContext.ClearState();
+ _deviceContext.OutputMerger.SetRenderTargets(Rtv);
+
+ ImGui_ImplDX11_RenderDrawData(GetDrawData());
+
+ UpdatePlatformWindows();
+ RenderPlatformWindowsDefault();
+ }
+
+ [UnmanagedCallersOnly(CallConvs = [typeof(CallConvStdcall)])]
+ private static int WndProcHook(HWND hWnd, int msg, nint wParam, nint lParam)
+ {
+ var hookResult = ImGui_ImplWin32_WndProcHandler(hWnd, msg, wParam, lParam);
+ return hookResult == 0 ? CallWindowProc(_wndproc, hWnd, msg, wParam, lParam) : hookResult;
+ }
+
+ [DllImport("USER32.dll", ExactSpelling = true, EntryPoint = "CallWindowProcW")]
+ [DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
+ [SupportedOSPlatform("windows5.0")]
+ private static extern int CallWindowProc(nint lpPrevWndFunc, HWND hWnd, int msg, nint wParam, nint lParam);
+
+ public void Dispose()
+ {
+ _deviceContext.Dispose();
+ _renderHandler.Dispose();
+ }
+}
\ No newline at end of file
diff --git a/CringeLauncher/Launcher.cs b/CringeLauncher/Launcher.cs
index a84472e..c3873da 100644
--- a/CringeLauncher/Launcher.cs
+++ b/CringeLauncher/Launcher.cs
@@ -1,4 +1,8 @@
-using CringeLauncher.Utils;
+using System.Diagnostics;
+using System.Reflection;
+using System.Runtime.Loader;
+using CringeBootstrap.Abstractions;
+using CringeLauncher.Utils;
using HarmonyLib;
using Sandbox;
using Sandbox.Engine.Multiplayer;
@@ -10,6 +14,7 @@ using SpaceEngineers.Game;
using SpaceEngineers.Game.Achievements;
using SpaceEngineers.Game.GUI;
using Steamworks;
+using Velopack;
using VRage;
using VRage.Audio;
using VRage.EOS;
@@ -26,11 +31,11 @@ using VRageRender;
namespace CringeLauncher;
-public class Launcher : IDisposable
+public class Launcher : ICorePlugin
{
private const uint AppId = 244850U;
private SpaceEngineersGame? _game;
- private readonly Harmony _harmony = new("CringeLauncher");
+ private readonly Harmony _harmony = new("CringeBootstrap");
public void Initialize(string[] args)
{
@@ -42,6 +47,11 @@ public class Launcher : IDisposable
_harmony.PatchAll(typeof(Launcher).Assembly);
SteamAPI.Init();
MyPlugins.LoadPlugins([typeof(PluginLoader.Main).Assembly]);
+
+ #if !DEBUG
+ CheckUpdates().GetAwaiter().GetResult();
+ #endif
+
PluginLoader.Main.Instance.Splash?.SetText("Initializing game...");
PluginLoader.Main.Instance.Splash?.SetBarValue(0);
InitTexts();
@@ -62,6 +72,9 @@ public class Launcher : IDisposable
{
MyPlatformGameSettings.SIMPLIFIED_SIMULATION_OVERRIDE = false;
}
+
+ MyFileSystem.ExePath = Path.GetDirectoryName(args.ElementAtOrDefault(0) ?? Assembly.GetExecutingAssembly().Location)!;
+ MyFileSystem.RootPath = new DirectoryInfo(MyFileSystem.ExePath).Parent!.FullName;
MyInitializer.InvokeBeforeRun(AppId, MyPerGameSettings.BasicGameInfo.ApplicationName,
MyVRage.Platform.System.GetRootPath(), MyVRage.Platform.System.GetAppDataPath(),true, 3, () =>
{
@@ -88,6 +101,35 @@ public class Launcher : IDisposable
public void Run() => _game?.Run();
+ private async Task CheckUpdates()
+ {
+ void Report(string s, float p)
+ {
+ PluginLoader.Main.Instance.Splash?.Invoke(() =>
+ {
+ PluginLoader.Main.Instance.Splash?.SetText(s);
+ PluginLoader.Main.Instance.Splash?.SetBarValue(p);
+ });
+ }
+
+ PluginLoader.Main.Instance.Splash?.SetText("Checking for updates...");
+
+ var mgr = new UpdateManager("https://the.place/you-host/updates");
+
+ // check for new version
+ var newVersion = await mgr.CheckForUpdatesAsync();
+ if (newVersion == null)
+ return; // no update available
+
+ // download new version
+ await mgr.DownloadUpdatesAsync(newVersion, i => Report("Downloading update...", i / 100f));
+
+ Report("Restarting for update", 1f);
+
+ // install new version and restart app
+ mgr.ApplyUpdatesAndRestart(newVersion);
+ }
+
#region Keen shit
private static void InitThreadPool()
diff --git a/CringeLauncher/NativeMethods.txt b/CringeLauncher/NativeMethods.txt
new file mode 100644
index 0000000..49c2ec8
--- /dev/null
+++ b/CringeLauncher/NativeMethods.txt
@@ -0,0 +1,2 @@
+GetWindowLongPtr
+SetWindowLongPtr
\ No newline at end of file
diff --git a/CringeLauncher/Patches/EosInitPatch.cs b/CringeLauncher/Patches/EosInitPatch.cs
index e1352d1..c68037b 100644
--- a/CringeLauncher/Patches/EosInitPatch.cs
+++ b/CringeLauncher/Patches/EosInitPatch.cs
@@ -4,7 +4,8 @@ using HarmonyLib;
namespace CringeLauncher.Patches;
-[HarmonyPatch]
+// eos is disabled
+// [HarmonyPatch]
public class EosInitPatch
{
private static MethodInfo TargetMethod() =>
diff --git a/CringeLauncher/Patches/IntrospectionPatches.cs b/CringeLauncher/Patches/IntrospectionPatches.cs
new file mode 100644
index 0000000..bea3b41
--- /dev/null
+++ b/CringeLauncher/Patches/IntrospectionPatches.cs
@@ -0,0 +1,159 @@
+using System.Diagnostics;
+using System.Reflection;
+using System.Runtime.Loader;
+using CringeBootstrap.Abstractions;
+using CringeLauncher.Utils;
+using CringePlugins.Utils;
+using HarmonyLib;
+using VRage.FileSystem;
+using VRage.Game;
+using VRage.Game.Common;
+using VRage.Game.Components;
+using VRage.Game.Definitions;
+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;
+
+#if DEBUG
+ Debugger.Break();
+
+ __result = [];
+ return false;
+#else
+ throw new NotSupportedException($"Getting types from {__instance} is not supported");
+#endif
+ }
+
+ [HarmonyPrefix, HarmonyPatch(typeof(MyPlugins), nameof(MyPlugins.LoadPlugins))]
+ private static bool LoadPluginsPrefix(List assemblies, List ___m_plugins, List ___m_handleInputPlugins)
+ {
+ foreach (var type in assemblies.SelectMany(b => IntrospectionContext.Global.CollectDerivedTypes(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(MyObjectBuilderSerializerKeen), nameof(MyObjectBuilderSerializerKeen.RegisterFromAssembly))]
+ private static bool RegisterXmlSerializersPrefix(
+ MyObjectFactory ___m_objectFactory, Assembly assembly)
+ {
+ Register(___m_objectFactory, assembly);
+ return false;
+ }
+
+ [HarmonyPrefix, HarmonyPatch(typeof(MyComponentFactory), nameof(MyComponentFactory.RegisterFromAssembly))]
+ private static bool RegisterComponentsPrefix(
+ MyObjectFactory ___m_objectFactory, Assembly assembly)
+ {
+ Register(___m_objectFactory, assembly);
+ return false;
+ }
+
+ [HarmonyTranspiler,
+ HarmonyPatch(typeof(MyDefinitionManagerBase), nameof(MyDefinitionManagerBase.RegisterTypesFromAssembly))]
+ private static IEnumerable RegisterDefinitionTypesTranspiler(
+ IEnumerable instructions)
+ {
+ var getTypesMethod = AccessTools.DeclaredMethod(typeof(Assembly), nameof(Assembly.GetTypes));
+ var getDefinitionTypesMethod = AccessTools.DeclaredMethod(typeof(IntrospectionPatches), nameof(GetDefinitionTypes));
+ return instructions.MethodReplacer(getTypesMethod, getDefinitionTypesMethod);
+ }
+
+ private static Type[] GetDefinitionTypes(Assembly assembly)
+ {
+ return IntrospectionContext.Global.CollectAttributedTypes(assembly.GetMainModule())
+ .ToArray();
+ }
+
+ [HarmonyTranspiler,
+ HarmonyPatch(typeof(MyObjectBuilderType), nameof(MyObjectBuilderType.RegisterFromAssembly))]
+ private static IEnumerable RegisterObjectBuilderTypesTranspiler(
+ IEnumerable instructions)
+ {
+ var getTypesMethod = AccessTools.DeclaredMethod(typeof(Assembly), nameof(Assembly.GetTypes));
+ var getDefinitionTypesMethod = AccessTools.DeclaredMethod(typeof(IntrospectionPatches), nameof(GetObjectBuilderTypes));
+ return instructions.MethodReplacer(getTypesMethod, getDefinitionTypesMethod);
+ }
+
+ private static Type[] GetObjectBuilderTypes(Assembly assembly)
+ {
+ return IntrospectionContext.Global.CollectDerivedTypes(assembly.GetMainModule())
+ .ToArray();
+ }
+
+ [HarmonyTranspiler,
+ HarmonyPatch(typeof(MyComponentTypeFactory), nameof(MyComponentTypeFactory.RegisterFromAssembly), typeof(Assembly))]
+ private static IEnumerable RegisterComponentTypesTranspiler(IEnumerable instructions)
+ {
+ var getTypesMethod = AccessTools.DeclaredMethod(typeof(Assembly), nameof(Assembly.GetTypes));
+ var getDefinitionTypesMethod = AccessTools.DeclaredMethod(typeof(IntrospectionPatches), nameof(GetComponentTypes));
+ return instructions.MethodReplacer(getTypesMethod, getDefinitionTypesMethod);
+ }
+
+ private static Type[] GetComponentTypes(Assembly assembly)
+ {
+ return IntrospectionContext.Global.CollectDerivedTypes(assembly.GetMainModule())
+ .ToArray();
+ }
+
+ private static void Register(MyObjectFactory factory, Assembly assembly)
+ where TAttribute : MyFactoryTagAttribute where TCreatedObjectBase : class
+ {
+ foreach (var type in IntrospectionContext.Global.CollectAttributedTypes(assembly.GetMainModule()))
+ {
+ foreach (var attribute in type.GetCustomAttributes())
+ {
+ factory.RegisterDescriptor(attribute, type);
+ }
+ }
+ }
+
+ [HarmonyPatch]
+ private static class GameAssembliesPatch
+ {
+ private static IEnumerable 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(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;
+ }
+ }
+}
\ No newline at end of file
diff --git a/CringeLauncher/Patches/RenderHookPatch.cs b/CringeLauncher/Patches/RenderHookPatch.cs
new file mode 100644
index 0000000..2fdad4b
--- /dev/null
+++ b/CringeLauncher/Patches/RenderHookPatch.cs
@@ -0,0 +1,26 @@
+using System.Reflection;
+using System.Reflection.Emit;
+using HarmonyLib;
+using VRage.Render11.Sprites;
+using VRageRender;
+
+namespace CringeLauncher.Patches;
+
+[HarmonyPatch(typeof(MyRender11), nameof(MyRender11.FullDraw))]
+public class RenderHookPatch
+{
+ private static IEnumerable Transpiler(IEnumerable instructions)
+ {
+ var placedHook = false;
+ var method = AccessTools.Method(typeof(MySpritesManager), nameof(MySpritesManager.FrameEnd));
+ foreach (var instruction in instructions)
+ {
+ if (!placedHook && instruction.Calls(method))
+ {
+ yield return CodeInstruction.CallClosure(() => ImGuiHandler.Instance?.DoRender());
+ placedHook = true;
+ }
+ yield return instruction;
+ }
+ }
+}
\ No newline at end of file
diff --git a/CringeLauncher/Patches/SwapChainPatch.cs b/CringeLauncher/Patches/SwapChainPatch.cs
new file mode 100644
index 0000000..c5f704c
--- /dev/null
+++ b/CringeLauncher/Patches/SwapChainPatch.cs
@@ -0,0 +1,78 @@
+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
+{
+ [HarmonyPrefix, HarmonyPatch(typeof(MyPlatformRender), nameof(MyPlatformRender.CreateSwapChain))]
+ private static bool SwapChainPrefix(nint 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);
+
+ ImGuiHandler.Instance ??= new ImGuiHandler(windowHandle, MyRender11.DeviceInstance, MyRender11.RC.DeviceContext);
+
+ return false;
+ }
+
+ [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.Instance!.Rtv = new RenderTargetView(MyRender11.DeviceInstance, swapChainBB, new()
+ {
+ Format = Format.R8G8B8A8_UNorm,
+ Dimension = RenderTargetViewDimension.Texture2D,
+ });
+
+ return false;
+ }
+}
\ No newline at end of file
diff --git a/CringeLauncher/Program.cs b/CringeLauncher/Program.cs
deleted file mode 100644
index 257b2c2..0000000
--- a/CringeLauncher/Program.cs
+++ /dev/null
@@ -1,12 +0,0 @@
-using System.Diagnostics;
-using CringeLauncher;
-
-#if DEBUG
-while (!Debugger.IsAttached)
- Thread.Sleep(100);
-#endif
-
-using var launcher = new Launcher();
-
-launcher.Initialize(args);
-launcher.Run();
\ No newline at end of file
diff --git a/CringeLauncher/packages.lock.json b/CringeLauncher/packages.lock.json
index 6b2776f..ac8a9e0 100644
--- a/CringeLauncher/packages.lock.json
+++ b/CringeLauncher/packages.lock.json
@@ -2,12 +2,40 @@
"version": 1,
"dependencies": {
"net8.0-windows10.0.19041": {
+ "dnlib": {
+ "type": "Direct",
+ "requested": "[4.4.0, )",
+ "resolved": "4.4.0",
+ "contentHash": "cKHI720q+zfEEvzklWVGt6B0TH3AibAyJbpUJl4U6KvTP13tycfnqJpkGHRZ/oQ45BTIoIxIwltHIJVDN+iCqQ=="
+ },
+ "ImGui.NET.DirectX": {
+ "type": "Direct",
+ "requested": "[1.91.0.1, )",
+ "resolved": "1.91.0.1",
+ "contentHash": "PpW1gQ9g97h6Hm/h/tkSBOmsBYgGwN8wKNmlJomcQFD/zRY1HPkJZz18XRSfRLHPmH2eeh4hhhZv1KHug7dF9g==",
+ "dependencies": {
+ "System.Buffers": "4.5.1",
+ "System.Numerics.Vectors": "4.5.0",
+ "System.Runtime.CompilerServices.Unsafe": "6.0.0"
+ }
+ },
"Krafs.Publicizer": {
"type": "Direct",
"requested": "[2.2.1, )",
"resolved": "2.2.1",
"contentHash": "QGI4nMGQbKsuFUUboixVHu4mv3lHB5RejIa7toIlzTmwLkuCYYEpUBJjmy3OpXYyj5dVSZAXVbr4oeMSloE67Q=="
},
+ "Microsoft.Windows.CsWin32": {
+ "type": "Direct",
+ "requested": "[0.3.106, )",
+ "resolved": "0.3.106",
+ "contentHash": "Mx5fK7uN6fwLR4wUghs6//HonAnwPBNmC2oonyJVhCUlHS/r6SUS3NkBc3+gaQiv+0/9bqdj1oSCKQFkNI+21Q==",
+ "dependencies": {
+ "Microsoft.Windows.SDK.Win32Docs": "0.1.42-alpha",
+ "Microsoft.Windows.SDK.Win32Metadata": "60.0.34-preview",
+ "Microsoft.Windows.WDK.Win32Metadata": "0.11.4-experimental"
+ }
+ },
"System.Diagnostics.PerformanceCounter": {
"type": "Direct",
"requested": "[8.0.0, )",
@@ -50,6 +78,16 @@
"System.Runtime.CompilerServices.Unsafe": "4.5.1"
}
},
+ "Velopack": {
+ "type": "Direct",
+ "requested": "[0.0.630-g9c52e40, )",
+ "resolved": "0.0.630-g9c52e40",
+ "contentHash": "4xNKtV+vyZPdlaQMNeen7p3WqGoq7CkVVkneywod1kTM3zKphQQwxo6KESGxsolwImXM8cZk4E1Zu64SYbaJhQ==",
+ "dependencies": {
+ "Microsoft.Extensions.Logging.Abstractions": "8.0.0",
+ "NuGet.Versioning": "6.10.1"
+ }
+ },
"Lib.Harmony.Thin": {
"type": "Transitive",
"resolved": "2.3.3",
@@ -71,21 +109,36 @@
},
"Microsoft.CodeAnalysis.Common": {
"type": "Transitive",
- "resolved": "4.8.0",
- "contentHash": "/jR+e/9aT+BApoQJABlVCKnnggGQbvGh7BKq2/wI1LamxC+LbzhcLj4Vj7gXCofl1n4E521YfF9w0WcASGg/KA==",
+ "resolved": "4.11.0",
+ "contentHash": "djf8ujmqYImFgB04UGtcsEhHrzVqzHowS+EEl/Yunc5LdrYrZhGBWUTXoCF0NzYXJxtfuD+UVQarWpvrNc94Qg==",
"dependencies": {
"Microsoft.CodeAnalysis.Analyzers": "3.3.4",
- "System.Collections.Immutable": "7.0.0",
- "System.Reflection.Metadata": "7.0.0",
- "System.Runtime.CompilerServices.Unsafe": "6.0.0"
+ "System.Collections.Immutable": "8.0.0",
+ "System.Reflection.Metadata": "8.0.0"
}
},
"Microsoft.CodeAnalysis.CSharp": {
"type": "Transitive",
- "resolved": "4.8.0",
- "contentHash": "+3+qfdb/aaGD8PZRCrsdobbzGs1m9u119SkkJt8e/mk3xLJz/udLtS2T6nY27OTXxBBw10HzAbC8Z9w08VyP/g==",
+ "resolved": "4.11.0",
+ "contentHash": "6XYi2EusI8JT4y2l/F3VVVS+ISoIX9nqHsZRaG6W5aFeJ5BEuBosHfT/ABb73FN0RZ1Z3cj2j7cL28SToJPXOw==",
"dependencies": {
- "Microsoft.CodeAnalysis.Common": "[4.8.0]"
+ "Microsoft.CodeAnalysis.Analyzers": "3.3.4",
+ "Microsoft.CodeAnalysis.Common": "[4.11.0]",
+ "System.Collections.Immutable": "8.0.0",
+ "System.Reflection.Metadata": "8.0.0"
+ }
+ },
+ "Microsoft.Extensions.DependencyInjection.Abstractions": {
+ "type": "Transitive",
+ "resolved": "8.0.0",
+ "contentHash": "cjWrLkJXK0rs4zofsK4bSdg+jhDLTaxrkXu4gS6Y7MAlCvRyNNgwY/lJi5RDlQOnSZweHqoyvgvbdvQsRIW+hg=="
+ },
+ "Microsoft.Extensions.Logging.Abstractions": {
+ "type": "Transitive",
+ "resolved": "8.0.0",
+ "contentHash": "arDBqTgFCyS0EvRV7O3MZturChstm50OJ0y9bDJvAcmEPJm0FFpFyjU/JLYyStNGGey081DvnQYlncNX5SJJGA==",
+ "dependencies": {
+ "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0"
}
},
"Microsoft.Extensions.ObjectPool": {
@@ -93,6 +146,24 @@
"resolved": "5.0.10",
"contentHash": "pp9tbGqIhdEXL6Q1yJl+zevAJSq4BsxqhS1GXzBvEsEz9DDNu9GLNzgUy2xyFc4YjB4m4Ff2YEWTnvQvVYdkvQ=="
},
+ "Microsoft.Windows.SDK.Win32Docs": {
+ "type": "Transitive",
+ "resolved": "0.1.42-alpha",
+ "contentHash": "Z/9po23gUA9aoukirh2ItMU2ZS9++Js9Gdds9fu5yuMojDrmArvY2y+tq9985tR3cxFxpZO1O35Wjfo0khj5HA=="
+ },
+ "Microsoft.Windows.SDK.Win32Metadata": {
+ "type": "Transitive",
+ "resolved": "60.0.34-preview",
+ "contentHash": "TA3DUNi4CTeo+ItTXBnGZFt2159XOGSl0UOlG5vjDj4WHqZjhwYyyUnzOtrbCERiSaP2Hzg7otJNWwOSZgutyA=="
+ },
+ "Microsoft.Windows.WDK.Win32Metadata": {
+ "type": "Transitive",
+ "resolved": "0.11.4-experimental",
+ "contentHash": "bf5MCmUyZf0gBlYQjx9UpRAZWBkRndyt9XicR+UNLvAUAFTZQbu6YaX/sNKZlR98Grn0gydfh/yT4I3vc0AIQA==",
+ "dependencies": {
+ "Microsoft.Windows.SDK.Win32Metadata": "60.0.34-preview"
+ }
+ },
"Mono.Cecil": {
"type": "Transitive",
"resolved": "0.11.5",
@@ -134,8 +205,13 @@
},
"NLog": {
"type": "Transitive",
- "resolved": "5.2.8",
- "contentHash": "jAIELkWBs1CXFPp986KSGpDFQZHCFccO+LMbKBTTNm42KifaI1mYzFMFQQfuGmGMTrCx0TFPhDjHDE4cLAZWiQ=="
+ "resolved": "5.3.4",
+ "contentHash": "gLy7+O1hEYJXIlcTr1/VWjGXrZTQFZzYNO18IWasD64pNwz0BreV+nHLxWKXWZzERRzoKnsk2XYtwLkTVk7J1A=="
+ },
+ "NuGet.Versioning": {
+ "type": "Transitive",
+ "resolved": "6.10.1",
+ "contentHash": "tovHZ3OlMVmsTdhv2z5nwnnhoA1ryhfJMyVQ9/+iv6d3h78fp230XaGy3K/iVcLwB50DdfNfIsitW97KSOWDFg=="
},
"protobuf-net": {
"type": "Transitive",
@@ -169,6 +245,11 @@
"resolved": "20.1.0",
"contentHash": "+GntwnyJ5tCNvUIaQxv2+ehDvZJzGUqlSB5xRBk1hTj1qqBJ6s4vK/OfGD/jae7aTmXiGSm8wpJORosNtQevJQ=="
},
+ "System.Buffers": {
+ "type": "Transitive",
+ "resolved": "4.5.1",
+ "contentHash": "Rw7ijyl1qqRS0YQD/WycNst8hUUMgrMH4FCn1nNm27M4VxchZ1js3fVjQaANHO5f3sN4isvP4a+Met9Y4YomAg=="
+ },
"System.CodeDom": {
"type": "Transitive",
"resolved": "8.0.0",
@@ -176,8 +257,8 @@
},
"System.Collections.Immutable": {
"type": "Transitive",
- "resolved": "7.0.0",
- "contentHash": "dQPcs0U1IKnBdRDBkrCTi1FoajSTBzLcVTpjO4MBCMC7f4pDOIPzgBoX8JjG7X6uZRJ8EBxsi8+DR1JuwjnzOQ=="
+ "resolved": "8.0.0",
+ "contentHash": "AurL6Y5BA1WotzlEvVaIDpqzpIPvYnnldxru8oXJU2yFxFUy3+pNXjXd1ymO+RA0rq0+590Q8gaz2l3Sr7fmqg=="
},
"System.Configuration.ConfigurationManager": {
"type": "Transitive",
@@ -210,10 +291,10 @@
},
"System.Reflection.Metadata": {
"type": "Transitive",
- "resolved": "7.0.0",
- "contentHash": "MclTG61lsD9sYdpNz9xsKBzjsmsfCtcMZYXz/IUr2zlhaTaABonlr1ESeompTgM+Xk+IwtGYU7/voh3YWB/fWw==",
+ "resolved": "8.0.0",
+ "contentHash": "ptvgrFh7PvWI8bcVqG5rsA/weWM09EnthFHR5SCnS6IN+P4mj6rE1lBDC4U8HL9/57htKAqy4KQ3bBj84cfYyQ==",
"dependencies": {
- "System.Collections.Immutable": "7.0.0"
+ "System.Collections.Immutable": "8.0.0"
}
},
"System.Runtime.CompilerServices.Unsafe": {
@@ -266,18 +347,41 @@
"System.Text.Encodings.Web": "8.0.0"
}
},
+ "cringebootstrap.abstractions": {
+ "type": "Project"
+ },
+ "cringeplugins": {
+ "type": "Project",
+ "dependencies": {
+ "CringeBootstrap.Abstractions": "[1.0.0, )",
+ "NLog": "[5.3.4, )",
+ "SpaceEngineersDedicated.ReferenceAssemblies": "[1.*, )",
+ "dnlib": "[4.4.0, )"
+ }
+ },
"pluginloader": {
"type": "Project",
"dependencies": {
"Lib.Harmony.Thin": "[2.3.3, )",
- "Microsoft.CodeAnalysis.CSharp": "[4.8.0, )",
- "NLog": "[5.2.8, )",
+ "Microsoft.CodeAnalysis.CSharp": "[4.11.0, )",
+ "NLog": "[5.3.4, )",
"SpaceEngineersDedicated.ReferenceAssemblies": "[1.*, )",
"Steamworks.NET": "[20.1.0, )"
}
}
},
"net8.0-windows10.0.19041/win-x64": {
+ "ImGui.NET.DirectX": {
+ "type": "Direct",
+ "requested": "[1.91.0.1, )",
+ "resolved": "1.91.0.1",
+ "contentHash": "PpW1gQ9g97h6Hm/h/tkSBOmsBYgGwN8wKNmlJomcQFD/zRY1HPkJZz18XRSfRLHPmH2eeh4hhhZv1KHug7dF9g==",
+ "dependencies": {
+ "System.Buffers": "4.5.1",
+ "System.Numerics.Vectors": "4.5.0",
+ "System.Runtime.CompilerServices.Unsafe": "6.0.0"
+ }
+ },
"System.Diagnostics.PerformanceCounter": {
"type": "Direct",
"requested": "[8.0.0, )",
diff --git a/CringePlugins/Abstractions/IRenderComponent.cs b/CringePlugins/Abstractions/IRenderComponent.cs
new file mode 100644
index 0000000..67f556b
--- /dev/null
+++ b/CringePlugins/Abstractions/IRenderComponent.cs
@@ -0,0 +1,6 @@
+namespace CringePlugins.Abstractions;
+
+public interface IRenderComponent
+{
+ void OnFrame();
+}
\ No newline at end of file
diff --git a/CringePlugins/CringePlugins.csproj b/CringePlugins/CringePlugins.csproj
new file mode 100644
index 0000000..e0e6f91
--- /dev/null
+++ b/CringePlugins/CringePlugins.csproj
@@ -0,0 +1,29 @@
+
+
+
+ net8.0
+ enable
+ enable
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+
+
diff --git a/CringePlugins/Globals.cs b/CringePlugins/Globals.cs
new file mode 100644
index 0000000..ee489ac
--- /dev/null
+++ b/CringePlugins/Globals.cs
@@ -0,0 +1,3 @@
+using System.Runtime.CompilerServices;
+
+[assembly: InternalsVisibleTo("CringeLauncher")]
\ No newline at end of file
diff --git a/CringePlugins/Loader/PluginAssemblyLoadContext.cs b/CringePlugins/Loader/PluginAssemblyLoadContext.cs
new file mode 100644
index 0000000..c43264b
--- /dev/null
+++ b/CringePlugins/Loader/PluginAssemblyLoadContext.cs
@@ -0,0 +1,38 @@
+using System.Reflection;
+using System.Runtime.Loader;
+using CringeBootstrap.Abstractions;
+
+namespace CringePlugins.Loader;
+
+internal class PluginAssemblyLoadContext : AssemblyLoadContext
+{
+ private readonly ICoreLoadContext _parentContext;
+ private readonly string _entrypointPath;
+ private readonly AssemblyDependencyResolver _dependencyResolver;
+ private Assembly? _assembly;
+
+ internal PluginAssemblyLoadContext(ICoreLoadContext parentContext, string entrypointPath) : base($"Plugin Context {Path.GetFileNameWithoutExtension(entrypointPath)}", true)
+ {
+ _parentContext = parentContext;
+ _entrypointPath = entrypointPath;
+ _dependencyResolver = new(entrypointPath);
+ }
+
+ public Assembly LoadEntrypoint() => _assembly ??= LoadFromAssemblyPath(_entrypointPath);
+
+ protected override Assembly? Load(AssemblyName assemblyName)
+ {
+ if (_dependencyResolver.ResolveAssemblyToPath(assemblyName) is { } path)
+ return LoadFromAssemblyPath(path);
+
+ return _parentContext.ResolveFromAssemblyName(assemblyName);
+ }
+
+ protected override nint LoadUnmanagedDll(string unmanagedDllName)
+ {
+ if (_dependencyResolver.ResolveUnmanagedDllToPath(unmanagedDllName) is { } path)
+ return LoadUnmanagedDllFromPath(path);
+
+ return _parentContext.ResolveUnmanagedDll(unmanagedDllName);
+ }
+}
\ No newline at end of file
diff --git a/CringePlugins/Loader/PluginInstance.cs b/CringePlugins/Loader/PluginInstance.cs
new file mode 100644
index 0000000..eb12577
--- /dev/null
+++ b/CringePlugins/Loader/PluginInstance.cs
@@ -0,0 +1,55 @@
+using System.Runtime.Loader;
+using CringeBootstrap.Abstractions;
+using CringePlugins.Utils;
+using VRage.Plugins;
+
+namespace CringePlugins.Loader;
+
+internal sealed class PluginInstance
+{
+ private readonly string _entrypointPath;
+ private PluginAssemblyLoadContext? _context;
+ private IPlugin? _instance;
+ private IHandleInputPlugin? _handleInputInstance;
+ public PluginMetadata Metadata { get; }
+
+ public PluginInstance(PluginMetadata metadata, string entrypointPath)
+ {
+ _entrypointPath = entrypointPath;
+ Metadata = metadata;
+ }
+
+ public PluginInstance(string entrypointPath) : this(PluginMetadata.ReadFromEntrypoint(entrypointPath), entrypointPath)
+ {
+ }
+
+ public void Instantiate()
+ {
+ if (AssemblyLoadContext.GetLoadContext(typeof(PluginInstance).Assembly) is not ICoreLoadContext parentContext)
+ throw new NotSupportedException("Plugin instantiation is not supported in this context");
+
+ _context = new PluginAssemblyLoadContext(parentContext, _entrypointPath);
+
+ var entrypoint = _context.LoadEntrypoint();
+
+ var plugins = IntrospectionContext.Global.CollectDerivedTypes(entrypoint.GetMainModule()).ToArray();
+
+ if (plugins.Length == 0)
+ throw new InvalidOperationException("Entrypoint does not contain any plugins");
+ if (plugins.Length > 1)
+ throw new InvalidOperationException("Entrypoint contains multiple plugins");
+
+ _instance = (IPlugin) Activator.CreateInstance(plugins[0])!;
+ _handleInputInstance = _instance as IHandleInputPlugin;
+ }
+
+ public void RegisterLifetime()
+ {
+ if (_instance is null)
+ throw new InvalidOperationException("Must call Instantiate first");
+
+ MyPlugins.m_plugins.Add(_instance);
+ if (_handleInputInstance is not null)
+ MyPlugins.m_handleInputPlugins.Add(_handleInputInstance);
+ }
+}
\ No newline at end of file
diff --git a/CringePlugins/Loader/PluginMetadata.cs b/CringePlugins/Loader/PluginMetadata.cs
new file mode 100644
index 0000000..df9728f
--- /dev/null
+++ b/CringePlugins/Loader/PluginMetadata.cs
@@ -0,0 +1,21 @@
+using System.Reflection;
+using dnlib.DotNet;
+
+namespace CringePlugins.Loader;
+
+public record PluginMetadata(string Name, Version Version)
+{
+ public static PluginMetadata ReadFromEntrypoint(string entrypointPath)
+ {
+ var module = ModuleDefMD.Load(entrypointPath);
+
+ var titleAttribute = module.CustomAttributes.Find(typeof(AssemblyTitleAttribute).FullName);
+ var versionAttribute = module.CustomAttributes.Find(typeof(AssemblyVersionAttribute).FullName);
+
+ var name = titleAttribute?.ConstructorArguments[0].Value as string ?? module.FullName;
+ if (!Version.TryParse(versionAttribute?.ConstructorArguments[0].Value as string ?? "0.0.0.0", out var version))
+ version = new();
+
+ return new(name, version);
+ }
+}
\ No newline at end of file
diff --git a/CringePlugins/Render/RenderHandler.cs b/CringePlugins/Render/RenderHandler.cs
new file mode 100644
index 0000000..1406144
--- /dev/null
+++ b/CringePlugins/Render/RenderHandler.cs
@@ -0,0 +1,48 @@
+using System.Collections.Concurrent;
+using CringePlugins.Abstractions;
+using NLog;
+
+namespace CringePlugins.Render;
+
+public sealed class RenderHandler : IDisposable
+{
+ private static readonly Logger Log = LogManager.GetCurrentClassLogger();
+
+ private static RenderHandler? _current;
+ public static RenderHandler Current => _current ?? throw new InvalidOperationException("Render is not yet initialized");
+
+ private readonly ConcurrentBag _components = [];
+
+ internal RenderHandler()
+ {
+ _current = this;
+ }
+
+ public void RegisterComponent(TComponent instance) where TComponent : IRenderComponent
+ {
+ _components.Add(new ComponentRegistration(typeof(TComponent), instance));
+ }
+
+ internal void OnFrame()
+ {
+ foreach (var (instanceType, renderComponent) in _components)
+ {
+ try
+ {
+ renderComponent.OnFrame();
+ }
+ catch (Exception e)
+ {
+ Log.Error(e, "Component {TypeName} failed to render a new frame", instanceType);
+ }
+ }
+ }
+
+ private record ComponentRegistration(Type InstanceType, IRenderComponent Instance);
+
+ public void Dispose()
+ {
+ _current = null;
+ _components.Clear();
+ }
+}
\ No newline at end of file
diff --git a/CringePlugins/Utils/IntrospectionContext.cs b/CringePlugins/Utils/IntrospectionContext.cs
new file mode 100644
index 0000000..d58158b
--- /dev/null
+++ b/CringePlugins/Utils/IntrospectionContext.cs
@@ -0,0 +1,49 @@
+using System.Reflection;
+using dnlib.DotNet;
+
+namespace CringePlugins.Utils;
+
+public class IntrospectionContext
+{
+ public static IntrospectionContext Global { get; } = new();
+
+ private readonly ModuleContext _context = ModuleDef.CreateModuleContext();
+
+ public IEnumerable CollectAttributedTypes(Module module, bool allowAbstract = false) where TAttribute : Attribute
+ {
+ var moduleDef = ModuleDefMD.Load(module, _context);
+
+ return moduleDef.GetTypes()
+ .Where(b => b.CustomAttributes.IsDefined(typeof(TAttribute).FullName) && (allowAbstract || !b.IsAbstract))
+ .Select(b => module.GetType(b.FullName, true, false)!);
+ }
+
+ public IEnumerable CollectDerivedTypes(Module module, bool allowAbstract = false)
+ {
+ var moduleDef = ModuleDefMD.Load(module, _context);
+
+ var token = moduleDef.ImportAsTypeSig(typeof(T));
+
+ return moduleDef.GetTypes()
+ .Where(b => (typeof(T).IsInterface
+ ? b.Interfaces.Any(i => i.Interface.FullName == token.FullName)
+ : MatchBaseType(b, token)) && (allowAbstract || !b.IsAbstract))
+ .Select(b => module.GetType(b.FullName, true, false)!);
+ }
+
+ private static bool MatchBaseType(ITypeDefOrRef? defOrRef, TypeSig token)
+ {
+ while ((defOrRef = defOrRef.GetBaseType()) != null)
+ {
+ if (defOrRef.FullName == token.FullName)
+ return true;
+ }
+
+ return false;
+ }
+}
+
+public static class AssemblyExtensions
+{
+ public static Module GetMainModule(this Assembly assembly) => assembly.GetModule(assembly.GetName().Name! + ".dll") ?? assembly.GetModules()[0];
+}
\ No newline at end of file
diff --git a/CringePlugins/packages.lock.json b/CringePlugins/packages.lock.json
new file mode 100644
index 0000000..23ff5bf
--- /dev/null
+++ b/CringePlugins/packages.lock.json
@@ -0,0 +1,80 @@
+{
+ "version": 1,
+ "dependencies": {
+ "net8.0": {
+ "dnlib": {
+ "type": "Direct",
+ "requested": "[4.4.0, )",
+ "resolved": "4.4.0",
+ "contentHash": "cKHI720q+zfEEvzklWVGt6B0TH3AibAyJbpUJl4U6KvTP13tycfnqJpkGHRZ/oQ45BTIoIxIwltHIJVDN+iCqQ=="
+ },
+ "Krafs.Publicizer": {
+ "type": "Direct",
+ "requested": "[2.2.1, )",
+ "resolved": "2.2.1",
+ "contentHash": "QGI4nMGQbKsuFUUboixVHu4mv3lHB5RejIa7toIlzTmwLkuCYYEpUBJjmy3OpXYyj5dVSZAXVbr4oeMSloE67Q=="
+ },
+ "NLog": {
+ "type": "Direct",
+ "requested": "[5.3.4, )",
+ "resolved": "5.3.4",
+ "contentHash": "gLy7+O1hEYJXIlcTr1/VWjGXrZTQFZzYNO18IWasD64pNwz0BreV+nHLxWKXWZzERRzoKnsk2XYtwLkTVk7J1A=="
+ },
+ "SpaceEngineersDedicated.ReferenceAssemblies": {
+ "type": "Direct",
+ "requested": "[1.*, )",
+ "resolved": "1.204.18",
+ "contentHash": "GT7/9CBMx4jjor41zLOOl87YYM/JdJD8xp9ccXyuhP2oUaz25H3ZmCQuGeAuZNENKru1a/7hZrId4PwlMDGoew==",
+ "dependencies": {
+ "SharpDX": "4.2.0-keen-cringe",
+ "protobuf-net": "1.0.0"
+ }
+ },
+ "ImGui.NET.DirectX": {
+ "type": "Transitive",
+ "resolved": "1.91.0.1",
+ "contentHash": "PpW1gQ9g97h6Hm/h/tkSBOmsBYgGwN8wKNmlJomcQFD/zRY1HPkJZz18XRSfRLHPmH2eeh4hhhZv1KHug7dF9g==",
+ "dependencies": {
+ "System.Buffers": "4.5.1",
+ "System.Numerics.Vectors": "4.5.0",
+ "System.Runtime.CompilerServices.Unsafe": "6.0.0"
+ }
+ },
+ "protobuf-net": {
+ "type": "Transitive",
+ "resolved": "1.0.0",
+ "contentHash": "kTGOK0E87473sOImOjgZOnz3kTC2aMLffoRWQLYNuBLJnwNNmjanF9IkevZ9Q7yYLeABQfcF3BpeepuMntMVNw=="
+ },
+ "SharpDX": {
+ "type": "Transitive",
+ "resolved": "4.2.0-keen-cringe",
+ "contentHash": "LaJN3h1Gi1FWVdef2I5WtOH9gwzKCBniH0CragarbkN2QheYY6Lqm+91PcOfp1w/4wdVb+k8Kjv3sO393Tphtw=="
+ },
+ "System.Buffers": {
+ "type": "Transitive",
+ "resolved": "4.5.1",
+ "contentHash": "Rw7ijyl1qqRS0YQD/WycNst8hUUMgrMH4FCn1nNm27M4VxchZ1js3fVjQaANHO5f3sN4isvP4a+Met9Y4YomAg=="
+ },
+ "System.Numerics.Vectors": {
+ "type": "Transitive",
+ "resolved": "4.5.0",
+ "contentHash": "QQTlPTl06J/iiDbJCiepZ4H//BVraReU4O4EoRw1U02H5TLUIT7xn3GnDp9AXPSlJUDyFs4uWjWafNX6WrAojQ=="
+ },
+ "System.Runtime.CompilerServices.Unsafe": {
+ "type": "Transitive",
+ "resolved": "6.0.0",
+ "contentHash": "/iUeP3tq1S0XdNNoMz5C9twLSrM/TH+qElHkXWaPvuNOt+99G75NrV0OS2EqHx5wMN7popYjpc8oTjC1y16DLg=="
+ },
+ "cringebootstrap.abstractions": {
+ "type": "Project"
+ },
+ "cringerender": {
+ "type": "Project",
+ "dependencies": {
+ "ImGui.NET.DirectX": "[1.91.0.1, )",
+ "SpaceEngineersDedicated.ReferenceAssemblies": "[1.*, )"
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/NuGet.config b/NuGet.config
new file mode 100644
index 0000000..3be5aa7
--- /dev/null
+++ b/NuGet.config
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/PluginLoader/Compiler/RoslynReferences.cs b/PluginLoader/Compiler/RoslynReferences.cs
index 0d8ebfa..b64515d 100644
--- a/PluginLoader/Compiler/RoslynReferences.cs
+++ b/PluginLoader/Compiler/RoslynReferences.cs
@@ -1,4 +1,5 @@
using System.Reflection;
+using System.Runtime.Loader;
using System.Text;
using HarmonyLib;
using Microsoft.CodeAnalysis;
@@ -101,7 +102,7 @@ public static class RoslynReferences
{
try
{
- aRef = Assembly.Load(name);
+ aRef = AssemblyLoadContext.GetLoadContext(typeof(RoslynReferences).Assembly)!.LoadFromAssemblyName(name);
return true;
}
catch (IOException)
diff --git a/PluginLoader/PluginLoader.csproj b/PluginLoader/PluginLoader.csproj
index 400dd00..77c4e3b 100644
--- a/PluginLoader/PluginLoader.csproj
+++ b/PluginLoader/PluginLoader.csproj
@@ -6,7 +6,6 @@
true
true
true
- https://nuget.storage.yandexcloud.net/index.json
@@ -18,9 +17,9 @@
all
runtime; build; native; contentfiles; analyzers; buildtransitive
-
+
-
+
diff --git a/PluginLoader/packages.lock.json b/PluginLoader/packages.lock.json
index a14d556..048b816 100644
--- a/PluginLoader/packages.lock.json
+++ b/PluginLoader/packages.lock.json
@@ -20,18 +20,21 @@
},
"Microsoft.CodeAnalysis.CSharp": {
"type": "Direct",
- "requested": "[4.8.0, )",
- "resolved": "4.8.0",
- "contentHash": "+3+qfdb/aaGD8PZRCrsdobbzGs1m9u119SkkJt8e/mk3xLJz/udLtS2T6nY27OTXxBBw10HzAbC8Z9w08VyP/g==",
+ "requested": "[4.11.0, )",
+ "resolved": "4.11.0",
+ "contentHash": "6XYi2EusI8JT4y2l/F3VVVS+ISoIX9nqHsZRaG6W5aFeJ5BEuBosHfT/ABb73FN0RZ1Z3cj2j7cL28SToJPXOw==",
"dependencies": {
- "Microsoft.CodeAnalysis.Common": "[4.8.0]"
+ "Microsoft.CodeAnalysis.Analyzers": "3.3.4",
+ "Microsoft.CodeAnalysis.Common": "[4.11.0]",
+ "System.Collections.Immutable": "8.0.0",
+ "System.Reflection.Metadata": "8.0.0"
}
},
"NLog": {
"type": "Direct",
- "requested": "[5.2.8, )",
- "resolved": "5.2.8",
- "contentHash": "jAIELkWBs1CXFPp986KSGpDFQZHCFccO+LMbKBTTNm42KifaI1mYzFMFQQfuGmGMTrCx0TFPhDjHDE4cLAZWiQ=="
+ "requested": "[5.3.4, )",
+ "resolved": "5.3.4",
+ "contentHash": "gLy7+O1hEYJXIlcTr1/VWjGXrZTQFZzYNO18IWasD64pNwz0BreV+nHLxWKXWZzERRzoKnsk2XYtwLkTVk7J1A=="
},
"SpaceEngineersDedicated.ReferenceAssemblies": {
"type": "Direct",
@@ -56,13 +59,12 @@
},
"Microsoft.CodeAnalysis.Common": {
"type": "Transitive",
- "resolved": "4.8.0",
- "contentHash": "/jR+e/9aT+BApoQJABlVCKnnggGQbvGh7BKq2/wI1LamxC+LbzhcLj4Vj7gXCofl1n4E521YfF9w0WcASGg/KA==",
+ "resolved": "4.11.0",
+ "contentHash": "djf8ujmqYImFgB04UGtcsEhHrzVqzHowS+EEl/Yunc5LdrYrZhGBWUTXoCF0NzYXJxtfuD+UVQarWpvrNc94Qg==",
"dependencies": {
"Microsoft.CodeAnalysis.Analyzers": "3.3.4",
- "System.Collections.Immutable": "7.0.0",
- "System.Reflection.Metadata": "7.0.0",
- "System.Runtime.CompilerServices.Unsafe": "6.0.0"
+ "System.Collections.Immutable": "8.0.0",
+ "System.Reflection.Metadata": "8.0.0"
}
},
"Mono.Cecil": {
@@ -116,22 +118,17 @@
},
"System.Collections.Immutable": {
"type": "Transitive",
- "resolved": "7.0.0",
- "contentHash": "dQPcs0U1IKnBdRDBkrCTi1FoajSTBzLcVTpjO4MBCMC7f4pDOIPzgBoX8JjG7X6uZRJ8EBxsi8+DR1JuwjnzOQ=="
+ "resolved": "8.0.0",
+ "contentHash": "AurL6Y5BA1WotzlEvVaIDpqzpIPvYnnldxru8oXJU2yFxFUy3+pNXjXd1ymO+RA0rq0+590Q8gaz2l3Sr7fmqg=="
},
"System.Reflection.Metadata": {
"type": "Transitive",
- "resolved": "7.0.0",
- "contentHash": "MclTG61lsD9sYdpNz9xsKBzjsmsfCtcMZYXz/IUr2zlhaTaABonlr1ESeompTgM+Xk+IwtGYU7/voh3YWB/fWw==",
+ "resolved": "8.0.0",
+ "contentHash": "ptvgrFh7PvWI8bcVqG5rsA/weWM09EnthFHR5SCnS6IN+P4mj6rE1lBDC4U8HL9/57htKAqy4KQ3bBj84cfYyQ==",
"dependencies": {
- "System.Collections.Immutable": "7.0.0"
+ "System.Collections.Immutable": "8.0.0"
}
},
- "System.Runtime.CompilerServices.Unsafe": {
- "type": "Transitive",
- "resolved": "6.0.0",
- "contentHash": "/iUeP3tq1S0XdNNoMz5C9twLSrM/TH+qElHkXWaPvuNOt+99G75NrV0OS2EqHx5wMN7popYjpc8oTjC1y16DLg=="
- },
"System.Text.Encodings.Web": {
"type": "Transitive",
"resolved": "8.0.0",