fix imgui and plugin loading
This commit is contained in:
@@ -14,6 +14,7 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="NLog.Schema" Version="5.3.4" />
|
||||
<PackageReference Include="Velopack" Version="0.0.630-g9c52e40" />
|
||||
</ItemGroup>
|
||||
|
||||
|
34
CringeBootstrap/NLog.config
Normal file
34
CringeBootstrap/NLog.config
Normal file
@@ -0,0 +1,34 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<configuration>
|
||||
|
||||
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.nlog-project.org/schemas/NLog.xsd NLog.xsd"
|
||||
autoReload="true"
|
||||
internalLogLevel="Info">
|
||||
|
||||
<!-- the targets to write to -->
|
||||
<targets>
|
||||
<default-wrapper xsi:type="AsyncWrapper" overflowAction="Block" />
|
||||
|
||||
<!-- write logs to file -->
|
||||
<target xsi:type="File" name="allfile" archiveAboveSize="10485760" fileName="${specialfolder:folder=ApplicationData}/CringeLauncher/logs/log-${shortdate}.log"
|
||||
layout="${longdate}|${event-properties:item=EventId_Id}|${uppercase:${level}}|${message}" />
|
||||
|
||||
<target xsi:type="File" archiveAboveSize="10485760" name="error" fileName="${specialfolder:folder=ApplicationData}/CringeLauncher/logs/log-error-${shortdate}.log"
|
||||
layout="${longdate}|${event-properties:item=EventId_Id}|${uppercase:${level}}|${message} ${cringe-exception}" />
|
||||
|
||||
<target name="debugger" xsi:type="Debugger" layout="${message} ${cringe-exception}"/>
|
||||
|
||||
<target xsi:type="ColoredConsole" name="console" layout="[${longdate}] ${uppercase:${level}}: ${message} ${cringe-exception}" />
|
||||
</targets>
|
||||
|
||||
<!-- rules to map from logger name to target -->
|
||||
<rules>
|
||||
<logger name="*" level="Info,Error,Fatal" writeTo="allfile,debugger,console" />
|
||||
<logger name="*" level="Debug" writeTo="debugger" />
|
||||
<logger name="*" level="Error" writeTo="error,debugger" />
|
||||
</rules>
|
||||
</nlog>
|
||||
|
||||
</configuration>
|
@@ -12,17 +12,21 @@ while (!Debugger.IsAttached)
|
||||
|
||||
VelopackApp.Build().Run();
|
||||
|
||||
#if DEBUG
|
||||
AssemblyLoadContext.Default.Resolving += (loadContext, name) =>
|
||||
{
|
||||
Debug.WriteLine($"resolving {name} in {loadContext}");
|
||||
return null;
|
||||
};
|
||||
#endif
|
||||
|
||||
var dir = Path.GetDirectoryName(args[0])!;
|
||||
var context = new GameDirectoryAssemblyLoadContext(dir);
|
||||
|
||||
// a list of assemblies which are not in the game binaries but reference them
|
||||
context.AddDependencyOverride("CringeLauncher");
|
||||
context.AddDependencyOverride("PluginLoader");
|
||||
context.AddDependencyOverride("CringePlugins");
|
||||
|
||||
var launcher = context.LoadFromAssemblyName(new AssemblyName("CringeLauncher"));
|
||||
|
||||
|
@@ -2,6 +2,12 @@
|
||||
"version": 1,
|
||||
"dependencies": {
|
||||
"net8.0-windows10.0.19041": {
|
||||
"NLog.Schema": {
|
||||
"type": "Direct",
|
||||
"requested": "[5.3.4, )",
|
||||
"resolved": "5.3.4",
|
||||
"contentHash": "eMlf4Y0gx5KycV3cdptEocd9Y9h10fWhRVUKyuY9nF6a55eWJlpKHqCWQbgHjvbC/7cBfF8DsZG8dZbST2fpew=="
|
||||
},
|
||||
"Velopack": {
|
||||
"type": "Direct",
|
||||
"requested": "[0.0.630-g9c52e40, )",
|
||||
|
@@ -18,7 +18,7 @@ internal class ImGuiHandler : IDisposable
|
||||
|
||||
public static ImGuiHandler? Instance;
|
||||
|
||||
public RenderTargetView? Rtv;
|
||||
public static RenderTargetView? Rtv;
|
||||
private readonly RenderHandler _renderHandler;
|
||||
|
||||
public ImGuiHandler(nint windowHandle, Device1 device, DeviceContext deviceContext)
|
||||
@@ -29,6 +29,11 @@ internal class ImGuiHandler : IDisposable
|
||||
|
||||
CreateContext();
|
||||
|
||||
var io = GetIO();
|
||||
|
||||
io.ConfigWindowsMoveFromTitleBarOnly = true;
|
||||
io.ConfigFlags |= ImGuiConfigFlags.DockingEnable | ImGuiConfigFlags.ViewportsEnable;
|
||||
|
||||
ImGui_ImplWin32_Init(windowHandle);
|
||||
ImGui_ImplDX11_Init(device.NativePointer, deviceContext.NativePointer);
|
||||
|
||||
@@ -40,11 +45,6 @@ internal class ImGuiHandler : IDisposable
|
||||
|
||||
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()
|
||||
|
@@ -3,7 +3,9 @@ using System.Reflection;
|
||||
using System.Runtime.Loader;
|
||||
using CringeBootstrap.Abstractions;
|
||||
using CringeLauncher.Utils;
|
||||
using CringePlugins.Loader;
|
||||
using HarmonyLib;
|
||||
using NLog;
|
||||
using Sandbox;
|
||||
using Sandbox.Engine.Multiplayer;
|
||||
using Sandbox.Engine.Networking;
|
||||
@@ -36,9 +38,23 @@ public class Launcher : ICorePlugin
|
||||
private const uint AppId = 244850U;
|
||||
private SpaceEngineersGame? _game;
|
||||
private readonly Harmony _harmony = new("CringeBootstrap");
|
||||
private PluginsLifetime? _lifetime;
|
||||
|
||||
public void Initialize(string[] args)
|
||||
{
|
||||
LogManager.Setup()
|
||||
.SetupExtensions(s =>
|
||||
{
|
||||
s.RegisterLayoutRenderer("cringe-exception", e =>
|
||||
{
|
||||
if (e.Exception is null) return string.Empty;
|
||||
e.Exception.FormatStackTrace();
|
||||
return e.Exception.ToString();
|
||||
});
|
||||
});
|
||||
|
||||
LogManager.ReconfigExistingLoggers();
|
||||
|
||||
//environment variable for viktor's plugins
|
||||
Environment.SetEnvironmentVariable("SE_PLUGIN_DISABLE_METHOD_VERIFICATION", "True");
|
||||
|
||||
@@ -52,8 +68,12 @@ public class Launcher : ICorePlugin
|
||||
CheckUpdates().GetAwaiter().GetResult();
|
||||
#endif
|
||||
|
||||
PluginLoader.Main.Instance.Splash?.SetText("Initializing game...");
|
||||
PluginLoader.Main.Instance.Splash?.SetText("Initializing plugins...");
|
||||
PluginLoader.Main.Instance.Splash?.SetBarValue(0);
|
||||
|
||||
_lifetime = new PluginsLifetime();
|
||||
|
||||
PluginLoader.Main.Instance.Splash?.SetText("Initializing game...");
|
||||
InitTexts();
|
||||
SpaceEngineersGame.SetupBasicGameInfo();
|
||||
MyFinalBuildConstants.APP_VERSION = MyPerGameSettings.BasicGameInfo.GameVersion.GetValueOrDefault();
|
||||
|
@@ -1,26 +1,17 @@
|
||||
using System.Reflection;
|
||||
using System.Reflection.Emit;
|
||||
using Windows.Win32;
|
||||
using HarmonyLib;
|
||||
using VRage.Render11.Sprites;
|
||||
using VRageRender;
|
||||
|
||||
namespace CringeLauncher.Patches;
|
||||
|
||||
[HarmonyPatch(typeof(MyRender11), nameof(MyRender11.FullDraw))]
|
||||
[HarmonyPatch(typeof(MyRender11), nameof(MyRender11.Present))]
|
||||
public class RenderHookPatch
|
||||
{
|
||||
private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
|
||||
private static void Prefix()
|
||||
{
|
||||
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;
|
||||
}
|
||||
ImGuiHandler.Instance?.DoRender();
|
||||
}
|
||||
}
|
@@ -10,9 +10,12 @@ 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");
|
||||
|
||||
@@ -51,11 +54,15 @@ public static class SwapChainPatch
|
||||
}
|
||||
factory.MakeWindowAssociation(windowHandle, WindowAssociationFlags.IgnoreAll);
|
||||
|
||||
ImGuiHandler.Instance ??= new ImGuiHandler(windowHandle, MyRender11.DeviceInstance, MyRender11.RC.DeviceContext);
|
||||
|
||||
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)
|
||||
{
|
||||
@@ -67,7 +74,7 @@ public static class SwapChainPatch
|
||||
});
|
||||
__instance.m_srv = new ShaderResourceView(MyRender11.DeviceInstance, swapChainBB);
|
||||
|
||||
ImGuiHandler.Instance!.Rtv = new RenderTargetView(MyRender11.DeviceInstance, swapChainBB, new()
|
||||
ImGuiHandler.Rtv = new RenderTargetView(MyRender11.DeviceInstance, swapChainBB, new()
|
||||
{
|
||||
Format = Format.R8G8B8A8_UNorm,
|
||||
Dimension = RenderTargetViewDimension.Texture2D,
|
||||
|
108
CringeLauncher/Utils/ExceptionFormatter.cs
Normal file
108
CringeLauncher/Utils/ExceptionFormatter.cs
Normal file
@@ -0,0 +1,108 @@
|
||||
using System.Diagnostics;
|
||||
using System.Reflection;
|
||||
using System.Runtime.ExceptionServices;
|
||||
using System.Runtime.Loader;
|
||||
using System.Text;
|
||||
using HarmonyLib;
|
||||
|
||||
namespace CringeLauncher.Utils;
|
||||
|
||||
public static class ExceptionFormatter
|
||||
{
|
||||
private static readonly AccessTools.FieldRef<Exception, string> StackTraceField = AccessTools.FieldRefAccess<Exception, string>("_remoteStackTraceString");
|
||||
|
||||
public static void FormatStackTrace(this Exception exception)
|
||||
{
|
||||
var stackTrace = new StackTrace(exception, true);
|
||||
|
||||
var sb = new StringBuilder();
|
||||
|
||||
var i = 0;
|
||||
while (stackTrace.GetFrame(i++) is { } frame)
|
||||
{
|
||||
var method = frame.GetMethod();
|
||||
if (method is null)
|
||||
continue;
|
||||
|
||||
sb.Append("at ");
|
||||
if (method.DeclaringType is { } declaringType &&
|
||||
AssemblyLoadContext.GetLoadContext(declaringType.Assembly) is { } assemblyLoadContext)
|
||||
sb.Append(assemblyLoadContext).Append("//");
|
||||
|
||||
if (method.IsStatic)
|
||||
sb.Append("static ");
|
||||
|
||||
if (method is MethodInfo methodInfo)
|
||||
sb.Append(methodInfo.ReturnType, false);
|
||||
else
|
||||
sb.Append("new");
|
||||
|
||||
sb.Append(' ');
|
||||
|
||||
if (method.DeclaringType is null)
|
||||
sb.Append("<null>");
|
||||
else
|
||||
sb.Append(method.DeclaringType, true);
|
||||
|
||||
if (method is MethodInfo)
|
||||
{
|
||||
sb.Append('.');
|
||||
sb.Append(method.Name);
|
||||
}
|
||||
|
||||
if (method.ContainsGenericParameters)
|
||||
sb.Append(method.GetGenericArguments(), false);
|
||||
|
||||
sb.Append('(');
|
||||
|
||||
var parameters = method.GetParameters();
|
||||
for (var j = 0; j < parameters.Length; j++)
|
||||
{
|
||||
sb.Append(parameters[j].ParameterType, false);
|
||||
if (!string.IsNullOrEmpty(parameters[j].Name))
|
||||
sb.Append(' ').Append(parameters[j].Name);
|
||||
if (j < parameters.Length - 1)
|
||||
sb.Append(", ");
|
||||
}
|
||||
|
||||
sb.Append(')');
|
||||
|
||||
if (frame.GetFileName() is { } fileName)
|
||||
{
|
||||
sb.Append(" in ").Append(fileName).Append('(').Append(frame.GetFileLineNumber()).Append(':').Append(frame.GetFileColumnNumber()).Append(')');
|
||||
}
|
||||
|
||||
sb.AppendLine();
|
||||
}
|
||||
|
||||
ref var stackTraceString = ref StackTraceField(exception);
|
||||
|
||||
stackTraceString = sb.ToString();
|
||||
}
|
||||
|
||||
private static StringBuilder Append(this StringBuilder sb, Type type, bool fullName = false)
|
||||
{
|
||||
if (fullName && !string.IsNullOrEmpty(type.Namespace))
|
||||
sb.Append(type.Namespace).Append('.');
|
||||
sb.Append(type.Name);
|
||||
if (type.ContainsGenericParameters)
|
||||
sb.Append(type.GetGenericArguments(), fullName);
|
||||
|
||||
return sb;
|
||||
}
|
||||
|
||||
private static StringBuilder Append(this StringBuilder sb, Type[] genericArguments, bool fullName)
|
||||
{
|
||||
sb.Append('<');
|
||||
for (var i = 0; i < genericArguments.Length; i++)
|
||||
{
|
||||
sb.Append(genericArguments[i], fullName);
|
||||
if (i < genericArguments.Length - 1)
|
||||
sb.Append(", ");
|
||||
}
|
||||
|
||||
sb.Append('>');
|
||||
|
||||
return sb;
|
||||
}
|
||||
}
|
49
CringePlugins/Loader/PluginsLifetime.cs
Normal file
49
CringePlugins/Loader/PluginsLifetime.cs
Normal file
@@ -0,0 +1,49 @@
|
||||
using System.Collections.Immutable;
|
||||
using NLog;
|
||||
|
||||
namespace CringePlugins.Loader;
|
||||
|
||||
public class PluginsLifetime
|
||||
{
|
||||
private static readonly Logger Log = LogManager.GetCurrentClassLogger();
|
||||
|
||||
private readonly ImmutableArray<PluginInstance> _plugins;
|
||||
|
||||
public PluginsLifetime()
|
||||
{
|
||||
var dir = Directory.CreateDirectory(Path.Join(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "CringeLauncher", "plugins"));
|
||||
|
||||
var plugins = ImmutableArray<PluginInstance>.Empty.ToBuilder();
|
||||
|
||||
foreach (var directory in dir.EnumerateDirectories())
|
||||
{
|
||||
var files = directory.GetFiles("*.dll");
|
||||
|
||||
if (files.Length != 1) continue;
|
||||
|
||||
try
|
||||
{
|
||||
plugins.Add(new PluginInstance(files[0].FullName));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error(e, "Failed to load plugin {PluginPath}", files[0].FullName);
|
||||
}
|
||||
}
|
||||
|
||||
_plugins = plugins.ToImmutable();
|
||||
|
||||
foreach (var instance in _plugins)
|
||||
{
|
||||
try
|
||||
{
|
||||
instance.Instantiate();
|
||||
instance.RegisterLifetime();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error(e, "Failed to instantiate plugin {Plugin}", instance.Metadata);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user