ok now it works
This commit is contained in:
@@ -25,7 +25,6 @@ var context = new GameDirectoryAssemblyLoadContext(dir);
|
|||||||
|
|
||||||
// a list of assemblies which are not in the game binaries but reference them
|
// a list of assemblies which are not in the game binaries but reference them
|
||||||
context.AddDependencyOverride("CringeLauncher");
|
context.AddDependencyOverride("CringeLauncher");
|
||||||
context.AddDependencyOverride("PluginLoader");
|
|
||||||
context.AddDependencyOverride("CringePlugins");
|
context.AddDependencyOverride("CringePlugins");
|
||||||
|
|
||||||
var launcher = context.LoadFromAssemblyName(new AssemblyName("CringeLauncher"));
|
var launcher = context.LoadFromAssemblyName(new AssemblyName("CringeLauncher"));
|
||||||
|
@@ -135,10 +135,15 @@
|
|||||||
"resolved": "5.3.4",
|
"resolved": "5.3.4",
|
||||||
"contentHash": "gLy7+O1hEYJXIlcTr1/VWjGXrZTQFZzYNO18IWasD64pNwz0BreV+nHLxWKXWZzERRzoKnsk2XYtwLkTVk7J1A=="
|
"contentHash": "gLy7+O1hEYJXIlcTr1/VWjGXrZTQFZzYNO18IWasD64pNwz0BreV+nHLxWKXWZzERRzoKnsk2XYtwLkTVk7J1A=="
|
||||||
},
|
},
|
||||||
|
"NuGet.Frameworks": {
|
||||||
|
"type": "Transitive",
|
||||||
|
"resolved": "6.11.1",
|
||||||
|
"contentHash": "plTZ3ariSWQVsFn2mk83SsdmSg1VpgIMTSZpP/eSE/NNQF02p+M9ItxAYeUZBMX+cQ2nFkSwxQRJ0/fkaV9Hbg=="
|
||||||
|
},
|
||||||
"NuGet.Versioning": {
|
"NuGet.Versioning": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
"resolved": "6.10.1",
|
"resolved": "6.11.1",
|
||||||
"contentHash": "tovHZ3OlMVmsTdhv2z5nwnnhoA1ryhfJMyVQ9/+iv6d3h78fp230XaGy3K/iVcLwB50DdfNfIsitW97KSOWDFg=="
|
"contentHash": "YNn3BB71F+guJW42TbAhGcMh3gpyqFMZcPVD9pm5vcvGivTALtRely/VCPWQQ6JQ5PfwIrjPaJMO7VnqyeK3rg=="
|
||||||
},
|
},
|
||||||
"protobuf-net": {
|
"protobuf-net": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
@@ -160,8 +165,8 @@
|
|||||||
},
|
},
|
||||||
"SpaceEngineersDedicated.ReferenceAssemblies": {
|
"SpaceEngineersDedicated.ReferenceAssemblies": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
"resolved": "1.204.18",
|
"resolved": "1.205.23",
|
||||||
"contentHash": "GT7/9CBMx4jjor41zLOOl87YYM/JdJD8xp9ccXyuhP2oUaz25H3ZmCQuGeAuZNENKru1a/7hZrId4PwlMDGoew==",
|
"contentHash": "J7mF5hY39PzzCZps6vhIRzKiq8vD6Af9TgumTJR068vjEi+BzyeEFhqX+cl2Dd1ngOmsBtGWc5m+vxgTfs5YuA==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"SharpDX": "4.2.0-keen-cringe",
|
"SharpDX": "4.2.0-keen-cringe",
|
||||||
"protobuf-net": "1.0.0"
|
"protobuf-net": "1.0.0"
|
||||||
@@ -321,7 +326,11 @@
|
|||||||
"CringeBootstrap.Abstractions": "[1.0.0, )",
|
"CringeBootstrap.Abstractions": "[1.0.0, )",
|
||||||
"CringePlugins": "[1.0.0, )",
|
"CringePlugins": "[1.0.0, )",
|
||||||
"ImGui.NET.DirectX": "[1.91.0.1, )",
|
"ImGui.NET.DirectX": "[1.91.0.1, )",
|
||||||
"PluginLoader": "[1.0.0, )",
|
"Lib.Harmony.Thin": "[2.3.3, )",
|
||||||
|
"Microsoft.CodeAnalysis.CSharp": "[4.11.0, )",
|
||||||
|
"NLog": "[5.3.4, )",
|
||||||
|
"SpaceEngineersDedicated.ReferenceAssemblies": "[1.*, )",
|
||||||
|
"Steamworks.NET": "[20.1.0, )",
|
||||||
"System.Diagnostics.PerformanceCounter": "[8.0.0, )",
|
"System.Diagnostics.PerformanceCounter": "[8.0.0, )",
|
||||||
"System.Management": "[8.0.0, )",
|
"System.Management": "[8.0.0, )",
|
||||||
"System.Private.ServiceModel": "[4.10.3, )",
|
"System.Private.ServiceModel": "[4.10.3, )",
|
||||||
@@ -333,20 +342,26 @@
|
|||||||
"cringeplugins": {
|
"cringeplugins": {
|
||||||
"type": "Project",
|
"type": "Project",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"CringeBootstrap.Abstractions": "[1.0.0, )",
|
|
||||||
"NLog": "[5.3.4, )",
|
"NLog": "[5.3.4, )",
|
||||||
|
"NuGet": "[1.0.0, )",
|
||||||
|
"SharedCringe": "[1.0.0, )",
|
||||||
"SpaceEngineersDedicated.ReferenceAssemblies": "[1.*, )",
|
"SpaceEngineersDedicated.ReferenceAssemblies": "[1.*, )",
|
||||||
"dnlib": "[4.4.0, )"
|
"dnlib": "[4.4.0, )"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"pluginloader": {
|
"nuget": {
|
||||||
"type": "Project",
|
"type": "Project",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"Lib.Harmony.Thin": "[2.3.3, )",
|
"NuGet.Frameworks": "[6.11.1, )",
|
||||||
"Microsoft.CodeAnalysis.CSharp": "[4.11.0, )",
|
"NuGet.Versioning": "[6.11.1, )"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"sharedcringe": {
|
||||||
|
"type": "Project",
|
||||||
|
"dependencies": {
|
||||||
|
"CringeBootstrap.Abstractions": "[1.0.0, )",
|
||||||
"NLog": "[5.3.4, )",
|
"NLog": "[5.3.4, )",
|
||||||
"SpaceEngineersDedicated.ReferenceAssemblies": "[1.*, )",
|
"SpaceEngineersDedicated.ReferenceAssemblies": "[1.*, )"
|
||||||
"Steamworks.NET": "[20.1.0, )"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@@ -12,6 +12,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CringePlugins", "CringePlug
|
|||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestPlugin", "TestPlugin\TestPlugin.csproj", "{C1670878-2301-4AE5-ABD3-5C4D0882CB02}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestPlugin", "TestPlugin\TestPlugin.csproj", "{C1670878-2301-4AE5-ABD3-5C4D0882CB02}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NuGet", "NuGet\NuGet.csproj", "{CC5362CA-881A-4867-9642-033269C1F7D7}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SharedCringe", "SharedCringe\SharedCringe.csproj", "{BDA680D8-D4E3-48A9-8ED4-C4991098B71D}"
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
@@ -42,5 +46,13 @@ Global
|
|||||||
{C1670878-2301-4AE5-ABD3-5C4D0882CB02}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{C1670878-2301-4AE5-ABD3-5C4D0882CB02}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{C1670878-2301-4AE5-ABD3-5C4D0882CB02}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{C1670878-2301-4AE5-ABD3-5C4D0882CB02}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{C1670878-2301-4AE5-ABD3-5C4D0882CB02}.Release|Any CPU.Build.0 = Release|Any CPU
|
{C1670878-2301-4AE5-ABD3-5C4D0882CB02}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{CC5362CA-881A-4867-9642-033269C1F7D7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{CC5362CA-881A-4867-9642-033269C1F7D7}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{CC5362CA-881A-4867-9642-033269C1F7D7}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{CC5362CA-881A-4867-9642-033269C1F7D7}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{BDA680D8-D4E3-48A9-8ED4-C4991098B71D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{BDA680D8-D4E3-48A9-8ED4-C4991098B71D}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{BDA680D8-D4E3-48A9-8ED4-C4991098B71D}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{BDA680D8-D4E3-48A9-8ED4-C4991098B71D}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
EndGlobal
|
EndGlobal
|
||||||
|
@@ -13,6 +13,10 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Publicize Include="VRage:VRage.Plugins.MyPlugins.LoadPlugins" />
|
<Publicize Include="VRage:VRage.Plugins.MyPlugins.LoadPlugins" />
|
||||||
|
<Publicize Include="SpaceEngineers.Game:SpaceEngineers.Game.SpaceEngineersGame.OnRenderInitialized" />
|
||||||
|
<Publicize Include="Sandbox.Game:Sandbox.Engine.Platform.Game.set_DrawThread" />
|
||||||
|
<Publicize Include="Sandbox.Game:Sandbox.MySandboxGame.form" />
|
||||||
|
<Publicize Include="Sandbox.Game:Sandbox.MySandboxGame.RenderThread_SizeChanged" />
|
||||||
<Publicize Include="VRage.Render11;VRage.Platform.Windows" />
|
<Publicize Include="VRage.Render11;VRage.Platform.Windows" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
@@ -32,12 +36,16 @@
|
|||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
|
<PackageReference Include="NLog" Version="5.3.4" />
|
||||||
|
<PackageReference Include="Lib.Harmony.Thin" Version="2.3.3" />
|
||||||
|
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.11.0" />
|
||||||
|
<PackageReference Include="SpaceEngineersDedicated.ReferenceAssemblies" Version="1.*" ExcludeAssets="runtime" />
|
||||||
|
<PackageReference Include="Steamworks.NET" Version="20.1.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\CringeBootstrap.Abstractions\CringeBootstrap.Abstractions.csproj" />
|
<ProjectReference Include="..\CringeBootstrap.Abstractions\CringeBootstrap.Abstractions.csproj" />
|
||||||
<ProjectReference Include="..\CringePlugins\CringePlugins.csproj" />
|
<ProjectReference Include="..\CringePlugins\CringePlugins.csproj" />
|
||||||
<ProjectReference Include="..\PluginLoader\PluginLoader.csproj" />
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@@ -4,6 +4,7 @@ using System.Runtime.Versioning;
|
|||||||
using Windows.Win32;
|
using Windows.Win32;
|
||||||
using Windows.Win32.Foundation;
|
using Windows.Win32.Foundation;
|
||||||
using Windows.Win32.UI.WindowsAndMessaging;
|
using Windows.Win32.UI.WindowsAndMessaging;
|
||||||
|
using CringePlugins.Abstractions;
|
||||||
using CringePlugins.Render;
|
using CringePlugins.Render;
|
||||||
using ImGuiNET;
|
using ImGuiNET;
|
||||||
using SharpDX.Direct3D11;
|
using SharpDX.Direct3D11;
|
||||||
@@ -19,7 +20,7 @@ internal class ImGuiHandler : IDisposable
|
|||||||
public static ImGuiHandler? Instance;
|
public static ImGuiHandler? Instance;
|
||||||
|
|
||||||
public static RenderTargetView? Rtv;
|
public static RenderTargetView? Rtv;
|
||||||
private readonly RenderHandler _renderHandler;
|
private readonly IRootRenderComponent _renderHandler;
|
||||||
|
|
||||||
public ImGuiHandler(nint windowHandle, Device1 device, DeviceContext deviceContext)
|
public ImGuiHandler(nint windowHandle, Device1 device, DeviceContext deviceContext)
|
||||||
{
|
{
|
||||||
|
@@ -1,13 +1,11 @@
|
|||||||
using System.Diagnostics;
|
using System.Reflection;
|
||||||
using System.Reflection;
|
|
||||||
using System.Runtime.Loader;
|
|
||||||
using CringeBootstrap.Abstractions;
|
using CringeBootstrap.Abstractions;
|
||||||
using CringeLauncher.Utils;
|
using CringeLauncher.Utils;
|
||||||
using CringePlugins.Loader;
|
using CringePlugins.Loader;
|
||||||
|
using CringePlugins.Splash;
|
||||||
using HarmonyLib;
|
using HarmonyLib;
|
||||||
using NLog;
|
using NLog;
|
||||||
using Sandbox;
|
using Sandbox;
|
||||||
using Sandbox.Engine.Multiplayer;
|
|
||||||
using Sandbox.Engine.Networking;
|
using Sandbox.Engine.Networking;
|
||||||
using Sandbox.Engine.Platform.VideoMode;
|
using Sandbox.Engine.Platform.VideoMode;
|
||||||
using Sandbox.Engine.Utils;
|
using Sandbox.Engine.Utils;
|
||||||
@@ -15,21 +13,19 @@ using Sandbox.Game;
|
|||||||
using SpaceEngineers.Game;
|
using SpaceEngineers.Game;
|
||||||
using SpaceEngineers.Game.Achievements;
|
using SpaceEngineers.Game.Achievements;
|
||||||
using SpaceEngineers.Game.GUI;
|
using SpaceEngineers.Game.GUI;
|
||||||
using Steamworks;
|
|
||||||
using Velopack;
|
using Velopack;
|
||||||
using VRage;
|
using VRage;
|
||||||
using VRage.Audio;
|
using VRage.Audio;
|
||||||
using VRage.EOS;
|
|
||||||
using VRage.FileSystem;
|
using VRage.FileSystem;
|
||||||
using VRage.Game;
|
using VRage.Game;
|
||||||
using VRage.Game.Localization;
|
using VRage.Game.Localization;
|
||||||
using VRage.GameServices;
|
using VRage.GameServices;
|
||||||
using VRage.Mod.Io;
|
using VRage.Mod.Io;
|
||||||
using VRage.Platform.Windows;
|
using VRage.Platform.Windows;
|
||||||
using VRage.Plugins;
|
|
||||||
using VRage.Steam;
|
using VRage.Steam;
|
||||||
using VRage.UserInterface;
|
using VRage.UserInterface;
|
||||||
using VRageRender;
|
using VRageRender;
|
||||||
|
using VRageRender.ExternalApp;
|
||||||
|
|
||||||
namespace CringeLauncher;
|
namespace CringeLauncher;
|
||||||
|
|
||||||
@@ -40,6 +36,8 @@ public class Launcher : ICorePlugin
|
|||||||
private readonly Harmony _harmony = new("CringeBootstrap");
|
private readonly Harmony _harmony = new("CringeBootstrap");
|
||||||
private PluginsLifetime? _lifetime;
|
private PluginsLifetime? _lifetime;
|
||||||
|
|
||||||
|
private MyGameRenderComponent? _renderComponent;
|
||||||
|
|
||||||
public void Initialize(string[] args)
|
public void Initialize(string[] args)
|
||||||
{
|
{
|
||||||
LogManager.Setup()
|
LogManager.Setup()
|
||||||
@@ -58,32 +56,24 @@ public class Launcher : ICorePlugin
|
|||||||
//environment variable for viktor's plugins
|
//environment variable for viktor's plugins
|
||||||
Environment.SetEnvironmentVariable("SE_PLUGIN_DISABLE_METHOD_VERIFICATION", "True");
|
Environment.SetEnvironmentVariable("SE_PLUGIN_DISABLE_METHOD_VERIFICATION", "True");
|
||||||
|
|
||||||
// early init for plugin loader
|
|
||||||
ProtoBuf.Meta.RuntimeTypeModel.Create(true);
|
|
||||||
_harmony.PatchAll(typeof(Launcher).Assembly);
|
_harmony.PatchAll(typeof(Launcher).Assembly);
|
||||||
SteamAPI.Init();
|
|
||||||
MyPlugins.LoadPlugins([typeof(PluginLoader.Main).Assembly]);
|
|
||||||
|
|
||||||
#if !DEBUG
|
#if !DEBUG
|
||||||
CheckUpdates().GetAwaiter().GetResult();
|
CheckUpdates().GetAwaiter().GetResult();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
PluginLoader.Main.Instance.Splash?.SetText("Initializing plugins...");
|
var splash = new Splash();
|
||||||
PluginLoader.Main.Instance.Splash?.SetBarValue(0);
|
|
||||||
|
|
||||||
_lifetime = new PluginsLifetime();
|
splash.DefineStage(_lifetime = new PluginsLifetime());
|
||||||
|
|
||||||
PluginLoader.Main.Instance.Splash?.SetText("Initializing game...");
|
|
||||||
InitTexts();
|
InitTexts();
|
||||||
SpaceEngineersGame.SetupBasicGameInfo();
|
SpaceEngineersGame.SetupBasicGameInfo();
|
||||||
MyFinalBuildConstants.APP_VERSION = MyPerGameSettings.BasicGameInfo.GameVersion.GetValueOrDefault();
|
MyFinalBuildConstants.APP_VERSION = MyPerGameSettings.BasicGameInfo.GameVersion.GetValueOrDefault();
|
||||||
MyShaderCompiler.Init(MyShaderCompiler.TargetPlatform.PC, false);
|
MyShaderCompiler.Init(MyShaderCompiler.TargetPlatform.PC, false);
|
||||||
PluginLoader.Main.Instance.Splash?.SetBarValue(.25f);
|
|
||||||
MyVRageWindows.Init(MyPerGameSettings.BasicGameInfo.ApplicationName, MySandboxGame.Log,
|
MyVRageWindows.Init(MyPerGameSettings.BasicGameInfo.ApplicationName, MySandboxGame.Log,
|
||||||
Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
|
Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
|
||||||
MyPerGameSettings.BasicGameInfo.ApplicationName),
|
MyPerGameSettings.BasicGameInfo.ApplicationName),
|
||||||
false, false);
|
false, false);
|
||||||
PluginLoader.Main.Instance.Splash?.SetBarValue(.35f);
|
|
||||||
|
|
||||||
MyPlatformGameSettings.SAVE_TO_CLOUD_OPTION_AVAILABLE = true;
|
MyPlatformGameSettings.SAVE_TO_CLOUD_OPTION_AVAILABLE = true;
|
||||||
MyXAudio2.DEVICE_DETAILS_SUPPORTED = false;
|
MyXAudio2.DEVICE_DETAILS_SUPPORTED = false;
|
||||||
@@ -101,39 +91,54 @@ public class Launcher : ICorePlugin
|
|||||||
MyFakes.VOICE_CHAT_MIC_SENSITIVITY = MySandboxGame.Config.MicSensitivity;
|
MyFakes.VOICE_CHAT_MIC_SENSITIVITY = MySandboxGame.Config.MicSensitivity;
|
||||||
MyPlatformGameSettings.VOICE_CHAT_AUTOMATIC_ACTIVATION = MySandboxGame.Config.AutomaticVoiceChatActivation;
|
MyPlatformGameSettings.VOICE_CHAT_AUTOMATIC_ACTIVATION = MySandboxGame.Config.AutomaticVoiceChatActivation;
|
||||||
});
|
});
|
||||||
PluginLoader.Main.Instance.Splash?.SetBarValue(.55f);
|
|
||||||
MyVRage.Platform.Init();
|
MyVRage.Platform.Init();
|
||||||
PluginLoader.Main.Instance.Splash?.SetBarValue(.65f);
|
|
||||||
InitUgc();
|
|
||||||
PluginLoader.Main.Instance.Splash?.SetBarValue(.75f);
|
|
||||||
SpaceEngineersGame.SetupPerGameSettings();
|
SpaceEngineersGame.SetupPerGameSettings();
|
||||||
ConfigureSettings();
|
ConfigureSettings();
|
||||||
// MySandboxGame.InitMultithreading();
|
|
||||||
InitThreadPool();
|
InitThreadPool();
|
||||||
PluginLoader.Main.Instance.Splash?.SetBarValue(.85f);
|
|
||||||
MyVRage.Platform.System.OnThreadpoolInitialized();
|
MyVRage.Platform.System.OnThreadpoolInitialized();
|
||||||
InitRender();
|
InitRender();
|
||||||
PluginLoader.Main.Instance.Splash?.SetBarValue(.95f);
|
|
||||||
|
_renderComponent = new();
|
||||||
|
_renderComponent.Start(new(), InitEarlyWindow, MyVideoSettingsManager.Initialize(), MyPerGameSettings.MaxFrameRate);
|
||||||
|
_renderComponent.RenderThread.BeforeDraw += MyFpsManager.Update;
|
||||||
|
_renderComponent.RenderThread.SizeChanged += RenderThreadOnSizeChanged;
|
||||||
|
|
||||||
|
splash.ExecuteLoadingStages();
|
||||||
|
|
||||||
|
InitUgc();
|
||||||
MyFileSystem.InitUserSpecific(MyGameService.UserId.ToString());
|
MyFileSystem.InitUserSpecific(MyGameService.UserId.ToString());
|
||||||
_game = new(args);
|
_game = new(args)
|
||||||
PluginLoader.Main.Instance.Splash?.SetText("Launching...");
|
{
|
||||||
|
GameRenderComponent = _renderComponent,
|
||||||
|
DrawThread = _renderComponent.RenderThread.SystemThread,
|
||||||
|
form = MyVRage.Platform.Windows.Window
|
||||||
|
};
|
||||||
|
|
||||||
|
_renderComponent.RenderThread.SizeChanged += _game.RenderThread_SizeChanged;
|
||||||
|
_renderComponent.RenderThread.UpdateSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RenderThreadOnSizeChanged(int width, int height, MyViewport viewport)
|
||||||
|
{
|
||||||
|
if (_renderComponent is not null)
|
||||||
|
_renderComponent.RenderThread.SizeChanged -= RenderThreadOnSizeChanged;
|
||||||
|
|
||||||
|
MyVRage.Platform.Windows.Window.ShowAndFocus();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Run() => _game?.Run();
|
public void Run() => _game?.Run();
|
||||||
|
|
||||||
|
private static IVRageWindow InitEarlyWindow()
|
||||||
|
{
|
||||||
|
MyVRage.Platform.Windows.CreateWindow("Cringe Launcher", MyPerGameSettings.GameIcon, null);
|
||||||
|
|
||||||
|
MyVRage.Platform.Windows.Window.OnExit += MySandboxGame.ExitThreadSafe;
|
||||||
|
|
||||||
|
return MyVRage.Platform.Windows.Window;
|
||||||
|
}
|
||||||
|
|
||||||
private async Task CheckUpdates()
|
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");
|
var mgr = new UpdateManager("https://the.place/you-host/updates");
|
||||||
|
|
||||||
// check for new version
|
// check for new version
|
||||||
@@ -142,9 +147,7 @@ public class Launcher : ICorePlugin
|
|||||||
return; // no update available
|
return; // no update available
|
||||||
|
|
||||||
// download new version
|
// download new version
|
||||||
await mgr.DownloadUpdatesAsync(newVersion, i => Report("Downloading update...", i / 100f));
|
await mgr.DownloadUpdatesAsync(newVersion);
|
||||||
|
|
||||||
Report("Restarting for update", 1f);
|
|
||||||
|
|
||||||
// install new version and restart app
|
// install new version and restart app
|
||||||
mgr.ApplyUpdatesAndRestart(newVersion);
|
mgr.ApplyUpdatesAndRestart(newVersion);
|
||||||
@@ -164,8 +167,7 @@ public class Launcher : ICorePlugin
|
|||||||
|
|
||||||
private static void InitTexts()
|
private static void InitTexts()
|
||||||
{
|
{
|
||||||
//MyLanguage.Instance.ObtainCurrentOSCulture();
|
var textsPath = Path.Combine(MyFileSystem.RootPath, @"Content\Data\Localization\CoreTexts");
|
||||||
var textsPath = Path.Combine(MyFileSystem.RootPath, "Content\\Data\\Localization\\CoreTexts");
|
|
||||||
var hashSet = new HashSet<MyLanguagesEnum>();
|
var hashSet = new HashSet<MyLanguagesEnum>();
|
||||||
MyTexts.LoadSupportedLanguages(textsPath, hashSet);
|
MyTexts.LoadSupportedLanguages(textsPath, hashSet);
|
||||||
|
|
||||||
@@ -176,7 +178,7 @@ public class Launcher : ICorePlugin
|
|||||||
MyTexts.LoadTexts(textsPath, description.CultureName, description.SubcultureName);
|
MyTexts.LoadTexts(textsPath, description.CultureName, description.SubcultureName);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void InitUgc()
|
public static void InitUgc()
|
||||||
{
|
{
|
||||||
var steamGameService = MySteamGameService.Create(false, AppId);
|
var steamGameService = MySteamGameService.Create(false, AppId);
|
||||||
MyServiceManager.Instance.AddService(steamGameService);
|
MyServiceManager.Instance.AddService(steamGameService);
|
||||||
|
7
CringeLauncher/Loader/ModAssemblyLoadContext.cs
Normal file
7
CringeLauncher/Loader/ModAssemblyLoadContext.cs
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
using CringeBootstrap.Abstractions;
|
||||||
|
using SharedCringe.Loader;
|
||||||
|
|
||||||
|
namespace CringeLauncher.Loader;
|
||||||
|
|
||||||
|
public class ModAssemblyLoadContext(ICoreLoadContext parentContext)
|
||||||
|
: DerivedAssemblyLoadContext(parentContext, "World Mods Context");
|
@@ -1,15 +1,18 @@
|
|||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Runtime.Loader;
|
using System.Runtime.Loader;
|
||||||
|
using System.Xml.Serialization;
|
||||||
using CringeBootstrap.Abstractions;
|
using CringeBootstrap.Abstractions;
|
||||||
using CringePlugins.Utils;
|
using CringePlugins.Utils;
|
||||||
using HarmonyLib;
|
using HarmonyLib;
|
||||||
|
using Sandbox.Game.World;
|
||||||
using VRage;
|
using VRage;
|
||||||
using VRage.FileSystem;
|
using VRage.FileSystem;
|
||||||
using VRage.Game;
|
using VRage.Game;
|
||||||
using VRage.Game.Common;
|
using VRage.Game.Common;
|
||||||
using VRage.Game.Components;
|
using VRage.Game.Components;
|
||||||
using VRage.Game.Definitions;
|
using VRage.Game.Definitions;
|
||||||
|
using VRage.Game.Entity.UseObject;
|
||||||
using VRage.ObjectBuilders;
|
using VRage.ObjectBuilders;
|
||||||
using VRage.ObjectBuilders.Private;
|
using VRage.ObjectBuilders.Private;
|
||||||
using VRage.Plugins;
|
using VRage.Plugins;
|
||||||
@@ -25,14 +28,30 @@ public static class IntrospectionPatches
|
|||||||
if (AssemblyLoadContext.GetLoadContext(__instance) is ICoreLoadContext || __instance.FullName?.StartsWith("System.") == true)
|
if (AssemblyLoadContext.GetLoadContext(__instance) is ICoreLoadContext || __instance.FullName?.StartsWith("System.") == true)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
#if DEBUG
|
Debug.WriteLine($"Blocking GetTypes for {__instance.FullName}");
|
||||||
Debugger.Break();
|
|
||||||
|
|
||||||
__result = [];
|
__result = [];
|
||||||
return false;
|
return false;
|
||||||
#else
|
}
|
||||||
throw new NotSupportedException($"Getting types from {__instance} is not supported");
|
|
||||||
#endif
|
[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))]
|
[HarmonyPrefix, HarmonyPatch(typeof(MyPlugins), nameof(MyPlugins.LoadPlugins))]
|
||||||
@@ -52,84 +71,25 @@ public static class IntrospectionPatches
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
[HarmonyPrefix, HarmonyPatch(typeof(MyObjectBuilderSerializerKeen), nameof(MyObjectBuilderSerializerKeen.RegisterFromAssembly))]
|
[HarmonyPrefix, HarmonyPatch(typeof(MyXmlSerializerManager), "TryLoadSerializerFrom")]
|
||||||
private static bool RegisterXmlSerializersPrefix(
|
private static bool LoadSerializerPrefix(string assemblyName, string typeName, ref XmlSerializer? __result)
|
||||||
MyObjectFactory<MyObjectBuilderDefinitionAttribute, MyObjectBuilder_Base> ___m_objectFactory, Assembly assembly)
|
|
||||||
{
|
{
|
||||||
Register(___m_objectFactory, assembly);
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
[HarmonyPrefix, HarmonyPatch(typeof(MyComponentFactory), nameof(MyComponentFactory.RegisterFromAssembly))]
|
|
||||||
private static bool RegisterComponentsPrefix(
|
|
||||||
MyObjectFactory<MyComponentBuilderAttribute, MyComponentBase> ___m_objectFactory, Assembly assembly)
|
|
||||||
{
|
|
||||||
Register(___m_objectFactory, assembly);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
[HarmonyTranspiler,
|
|
||||||
HarmonyPatch(typeof(MyDefinitionManagerBase), nameof(MyDefinitionManagerBase.RegisterTypesFromAssembly))]
|
|
||||||
private static IEnumerable<CodeInstruction> RegisterDefinitionTypesTranspiler(
|
|
||||||
IEnumerable<CodeInstruction> 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<MyDefinitionTypeAttribute>(assembly.GetMainModule())
|
|
||||||
.ToArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
[HarmonyTranspiler,
|
|
||||||
HarmonyPatch(typeof(MyObjectBuilderType), nameof(MyObjectBuilderType.RegisterFromAssembly))]
|
|
||||||
private static IEnumerable<CodeInstruction> RegisterObjectBuilderTypesTranspiler(
|
|
||||||
IEnumerable<CodeInstruction> 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<MyObjectBuilder_Base>(assembly.GetMainModule())
|
|
||||||
.ToArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
[HarmonyTranspiler,
|
|
||||||
HarmonyPatch(typeof(MyComponentTypeFactory), nameof(MyComponentTypeFactory.RegisterFromAssembly), typeof(Assembly))]
|
|
||||||
private static IEnumerable<CodeInstruction> RegisterComponentTypesTranspiler(IEnumerable<CodeInstruction> 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<MyComponentBase>(assembly.GetMainModule())
|
|
||||||
.ToArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
[HarmonyPrefix, HarmonyPatch(typeof(MyXmlSerializerManager), nameof(MyXmlSerializerManager.RegisterFromAssembly))]
|
[HarmonyPrefix, HarmonyPatch(typeof(MyXmlSerializerManager), nameof(MyXmlSerializerManager.RegisterFromAssembly))]
|
||||||
private static bool XmlManagerRegisterPrefix(Assembly assembly) => AssemblyLoadContext.GetLoadContext(assembly) is ICoreLoadContext;
|
private static bool XmlManagerRegisterPrefix(Assembly assembly) => AssemblyLoadContext.GetLoadContext(assembly) is ICoreLoadContext;
|
||||||
|
|
||||||
private static void Register<TAttribute, TCreatedObjectBase>(MyObjectFactory<TAttribute, TCreatedObjectBase> factory, Assembly assembly)
|
|
||||||
where TAttribute : MyFactoryTagAttribute where TCreatedObjectBase : class
|
|
||||||
{
|
|
||||||
foreach (var type in IntrospectionContext.Global.CollectAttributedTypes<TAttribute>(assembly.GetMainModule()))
|
|
||||||
{
|
|
||||||
foreach (var attribute in type.GetCustomAttributes<TAttribute>())
|
|
||||||
{
|
|
||||||
factory.RegisterDescriptor(attribute, type);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[HarmonyPatch]
|
[HarmonyPatch]
|
||||||
private static class GameAssembliesPatch
|
private static class GameAssembliesPatch
|
||||||
{
|
{
|
||||||
|
70
CringeLauncher/Patches/ModAssemblyLoadContextPatches.cs
Normal file
70
CringeLauncher/Patches/ModAssemblyLoadContextPatches.cs
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
10
CringeLauncher/Patches/RenderInitPatch.cs
Normal file
10
CringeLauncher/Patches/RenderInitPatch.cs
Normal 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;
|
||||||
|
}
|
@@ -25,6 +25,28 @@
|
|||||||
"resolved": "2.2.1",
|
"resolved": "2.2.1",
|
||||||
"contentHash": "QGI4nMGQbKsuFUUboixVHu4mv3lHB5RejIa7toIlzTmwLkuCYYEpUBJjmy3OpXYyj5dVSZAXVbr4oeMSloE67Q=="
|
"contentHash": "QGI4nMGQbKsuFUUboixVHu4mv3lHB5RejIa7toIlzTmwLkuCYYEpUBJjmy3OpXYyj5dVSZAXVbr4oeMSloE67Q=="
|
||||||
},
|
},
|
||||||
|
"Lib.Harmony.Thin": {
|
||||||
|
"type": "Direct",
|
||||||
|
"requested": "[2.3.3, )",
|
||||||
|
"resolved": "2.3.3",
|
||||||
|
"contentHash": "jsaFv7XnWJnyfyvFbkgIkZtV6tWMteNUcDK3idq+3LwPqpTFNxsOv2eKmj4qqP8QR8UynG1Y9AUaC/+dVruMHg==",
|
||||||
|
"dependencies": {
|
||||||
|
"MonoMod.Core": "1.1.0",
|
||||||
|
"System.Text.Json": "8.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Microsoft.CodeAnalysis.CSharp": {
|
||||||
|
"type": "Direct",
|
||||||
|
"requested": "[4.11.0, )",
|
||||||
|
"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.Windows.CsWin32": {
|
"Microsoft.Windows.CsWin32": {
|
||||||
"type": "Direct",
|
"type": "Direct",
|
||||||
"requested": "[0.3.106, )",
|
"requested": "[0.3.106, )",
|
||||||
@@ -36,6 +58,28 @@
|
|||||||
"Microsoft.Windows.WDK.Win32Metadata": "0.11.4-experimental"
|
"Microsoft.Windows.WDK.Win32Metadata": "0.11.4-experimental"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"NLog": {
|
||||||
|
"type": "Direct",
|
||||||
|
"requested": "[5.3.4, )",
|
||||||
|
"resolved": "5.3.4",
|
||||||
|
"contentHash": "gLy7+O1hEYJXIlcTr1/VWjGXrZTQFZzYNO18IWasD64pNwz0BreV+nHLxWKXWZzERRzoKnsk2XYtwLkTVk7J1A=="
|
||||||
|
},
|
||||||
|
"SpaceEngineersDedicated.ReferenceAssemblies": {
|
||||||
|
"type": "Direct",
|
||||||
|
"requested": "[1.*, )",
|
||||||
|
"resolved": "1.205.23",
|
||||||
|
"contentHash": "J7mF5hY39PzzCZps6vhIRzKiq8vD6Af9TgumTJR068vjEi+BzyeEFhqX+cl2Dd1ngOmsBtGWc5m+vxgTfs5YuA==",
|
||||||
|
"dependencies": {
|
||||||
|
"SharpDX": "4.2.0-keen-cringe",
|
||||||
|
"protobuf-net": "1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Steamworks.NET": {
|
||||||
|
"type": "Direct",
|
||||||
|
"requested": "[20.1.0, )",
|
||||||
|
"resolved": "20.1.0",
|
||||||
|
"contentHash": "+GntwnyJ5tCNvUIaQxv2+ehDvZJzGUqlSB5xRBk1hTj1qqBJ6s4vK/OfGD/jae7aTmXiGSm8wpJORosNtQevJQ=="
|
||||||
|
},
|
||||||
"System.Diagnostics.PerformanceCounter": {
|
"System.Diagnostics.PerformanceCounter": {
|
||||||
"type": "Direct",
|
"type": "Direct",
|
||||||
"requested": "[8.0.0, )",
|
"requested": "[8.0.0, )",
|
||||||
@@ -88,15 +132,6 @@
|
|||||||
"NuGet.Versioning": "6.10.1"
|
"NuGet.Versioning": "6.10.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"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": {
|
"Microsoft.Bcl.AsyncInterfaces": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
"resolved": "5.0.0",
|
"resolved": "5.0.0",
|
||||||
@@ -117,17 +152,6 @@
|
|||||||
"System.Reflection.Metadata": "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": {
|
"Microsoft.Extensions.DependencyInjection.Abstractions": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
"resolved": "8.0.0",
|
"resolved": "8.0.0",
|
||||||
@@ -203,15 +227,15 @@
|
|||||||
"MonoMod.ILHelpers": "1.0.1"
|
"MonoMod.ILHelpers": "1.0.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"NLog": {
|
"NuGet.Frameworks": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
"resolved": "5.3.4",
|
"resolved": "6.11.1",
|
||||||
"contentHash": "gLy7+O1hEYJXIlcTr1/VWjGXrZTQFZzYNO18IWasD64pNwz0BreV+nHLxWKXWZzERRzoKnsk2XYtwLkTVk7J1A=="
|
"contentHash": "plTZ3ariSWQVsFn2mk83SsdmSg1VpgIMTSZpP/eSE/NNQF02p+M9ItxAYeUZBMX+cQ2nFkSwxQRJ0/fkaV9Hbg=="
|
||||||
},
|
},
|
||||||
"NuGet.Versioning": {
|
"NuGet.Versioning": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
"resolved": "6.10.1",
|
"resolved": "6.11.1",
|
||||||
"contentHash": "tovHZ3OlMVmsTdhv2z5nwnnhoA1ryhfJMyVQ9/+iv6d3h78fp230XaGy3K/iVcLwB50DdfNfIsitW97KSOWDFg=="
|
"contentHash": "YNn3BB71F+guJW42TbAhGcMh3gpyqFMZcPVD9pm5vcvGivTALtRely/VCPWQQ6JQ5PfwIrjPaJMO7VnqyeK3rg=="
|
||||||
},
|
},
|
||||||
"protobuf-net": {
|
"protobuf-net": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
@@ -231,20 +255,6 @@
|
|||||||
"System.Runtime.CompilerServices.Unsafe": "4.5.1"
|
"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": {
|
"System.Buffers": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
"resolved": "4.5.1",
|
"resolved": "4.5.1",
|
||||||
@@ -353,20 +363,26 @@
|
|||||||
"cringeplugins": {
|
"cringeplugins": {
|
||||||
"type": "Project",
|
"type": "Project",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"CringeBootstrap.Abstractions": "[1.0.0, )",
|
|
||||||
"NLog": "[5.3.4, )",
|
"NLog": "[5.3.4, )",
|
||||||
|
"NuGet": "[1.0.0, )",
|
||||||
|
"SharedCringe": "[1.0.0, )",
|
||||||
"SpaceEngineersDedicated.ReferenceAssemblies": "[1.*, )",
|
"SpaceEngineersDedicated.ReferenceAssemblies": "[1.*, )",
|
||||||
"dnlib": "[4.4.0, )"
|
"dnlib": "[4.4.0, )"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"pluginloader": {
|
"nuget": {
|
||||||
"type": "Project",
|
"type": "Project",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"Lib.Harmony.Thin": "[2.3.3, )",
|
"NuGet.Frameworks": "[6.11.1, )",
|
||||||
"Microsoft.CodeAnalysis.CSharp": "[4.11.0, )",
|
"NuGet.Versioning": "[6.11.1, )"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"sharedcringe": {
|
||||||
|
"type": "Project",
|
||||||
|
"dependencies": {
|
||||||
|
"CringeBootstrap.Abstractions": "[1.0.0, )",
|
||||||
"NLog": "[5.3.4, )",
|
"NLog": "[5.3.4, )",
|
||||||
"SpaceEngineersDedicated.ReferenceAssemblies": "[1.*, )",
|
"SpaceEngineersDedicated.ReferenceAssemblies": "[1.*, )"
|
||||||
"Steamworks.NET": "[20.1.0, )"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -382,6 +398,12 @@
|
|||||||
"System.Runtime.CompilerServices.Unsafe": "6.0.0"
|
"System.Runtime.CompilerServices.Unsafe": "6.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"Steamworks.NET": {
|
||||||
|
"type": "Direct",
|
||||||
|
"requested": "[20.1.0, )",
|
||||||
|
"resolved": "20.1.0",
|
||||||
|
"contentHash": "+GntwnyJ5tCNvUIaQxv2+ehDvZJzGUqlSB5xRBk1hTj1qqBJ6s4vK/OfGD/jae7aTmXiGSm8wpJORosNtQevJQ=="
|
||||||
|
},
|
||||||
"System.Diagnostics.PerformanceCounter": {
|
"System.Diagnostics.PerformanceCounter": {
|
||||||
"type": "Direct",
|
"type": "Direct",
|
||||||
"requested": "[8.0.0, )",
|
"requested": "[8.0.0, )",
|
||||||
@@ -400,11 +422,6 @@
|
|||||||
"System.CodeDom": "8.0.0"
|
"System.CodeDom": "8.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Steamworks.NET": {
|
|
||||||
"type": "Transitive",
|
|
||||||
"resolved": "20.1.0",
|
|
||||||
"contentHash": "+GntwnyJ5tCNvUIaQxv2+ehDvZJzGUqlSB5xRBk1hTj1qqBJ6s4vK/OfGD/jae7aTmXiGSm8wpJORosNtQevJQ=="
|
|
||||||
},
|
|
||||||
"System.Diagnostics.EventLog": {
|
"System.Diagnostics.EventLog": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
"resolved": "8.0.0",
|
"resolved": "8.0.0",
|
||||||
|
@@ -2,5 +2,10 @@
|
|||||||
|
|
||||||
public interface IRenderComponent
|
public interface IRenderComponent
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets called while the dear ImGui frame is being composed
|
||||||
|
/// </summary>
|
||||||
void OnFrame();
|
void OnFrame();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal interface IRootRenderComponent : IRenderComponent, IDisposable;
|
13
CringePlugins/Config/PackagesConfig.cs
Normal file
13
CringePlugins/Config/PackagesConfig.cs
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
using System.Collections.Immutable;
|
||||||
|
using CringePlugins.Resolver;
|
||||||
|
using NuGet;
|
||||||
|
using NuGet.Models;
|
||||||
|
|
||||||
|
namespace CringePlugins.Config;
|
||||||
|
|
||||||
|
public record PackagesConfig(ImmutableArray<PackageSource> Sources, ImmutableArray<PackageReference> Packages)
|
||||||
|
{
|
||||||
|
public static PackagesConfig Default { get; } = new([
|
||||||
|
new(string.Empty, "https://api.nuget.org/v3/index.json")
|
||||||
|
], []);
|
||||||
|
}
|
@@ -1,14 +1,16 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net8.0</TargetFramework>
|
<TargetFramework>net8.0-windows</TargetFramework>
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
|
<UseWindowsForms>true</UseWindowsForms>
|
||||||
<RestorePackagesWithLockFile>true</RestorePackagesWithLockFile>
|
<RestorePackagesWithLockFile>true</RestorePackagesWithLockFile>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\CringeBootstrap.Abstractions\CringeBootstrap.Abstractions.csproj" />
|
<ProjectReference Include="..\NuGet\NuGet.csproj" />
|
||||||
|
<ProjectReference Include="..\SharedCringe\SharedCringe.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
@@ -26,4 +28,8 @@
|
|||||||
</PackageReference>
|
</PackageReference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<EmbeddedResource Include="splash.gif" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
@@ -1,19 +1,18 @@
|
|||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Runtime.Loader;
|
using System.Runtime.Loader;
|
||||||
using CringeBootstrap.Abstractions;
|
using CringeBootstrap.Abstractions;
|
||||||
|
using SharedCringe.Loader;
|
||||||
|
|
||||||
namespace CringePlugins.Loader;
|
namespace CringePlugins.Loader;
|
||||||
|
|
||||||
internal class PluginAssemblyLoadContext : AssemblyLoadContext
|
internal class PluginAssemblyLoadContext : DerivedAssemblyLoadContext
|
||||||
{
|
{
|
||||||
private readonly ICoreLoadContext _parentContext;
|
|
||||||
private readonly string _entrypointPath;
|
private readonly string _entrypointPath;
|
||||||
private readonly AssemblyDependencyResolver _dependencyResolver;
|
private readonly AssemblyDependencyResolver _dependencyResolver;
|
||||||
private Assembly? _assembly;
|
private Assembly? _assembly;
|
||||||
|
|
||||||
internal PluginAssemblyLoadContext(ICoreLoadContext parentContext, string entrypointPath) : base($"Plugin Context {Path.GetFileNameWithoutExtension(entrypointPath)}", true)
|
internal PluginAssemblyLoadContext(ICoreLoadContext parentContext, string entrypointPath) : base(parentContext, $"Plugin Context {Path.GetFileNameWithoutExtension(entrypointPath)}")
|
||||||
{
|
{
|
||||||
_parentContext = parentContext;
|
|
||||||
_entrypointPath = entrypointPath;
|
_entrypointPath = entrypointPath;
|
||||||
_dependencyResolver = new(entrypointPath);
|
_dependencyResolver = new(entrypointPath);
|
||||||
}
|
}
|
||||||
@@ -25,7 +24,7 @@ internal class PluginAssemblyLoadContext : AssemblyLoadContext
|
|||||||
if (_dependencyResolver.ResolveAssemblyToPath(assemblyName) is { } path)
|
if (_dependencyResolver.ResolveAssemblyToPath(assemblyName) is { } path)
|
||||||
return LoadFromAssemblyPath(path);
|
return LoadFromAssemblyPath(path);
|
||||||
|
|
||||||
return _parentContext.ResolveFromAssemblyName(assemblyName);
|
return base.Load(assemblyName);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override nint LoadUnmanagedDll(string unmanagedDllName)
|
protected override nint LoadUnmanagedDll(string unmanagedDllName)
|
||||||
@@ -33,6 +32,6 @@ internal class PluginAssemblyLoadContext : AssemblyLoadContext
|
|||||||
if (_dependencyResolver.ResolveUnmanagedDllToPath(unmanagedDllName) is { } path)
|
if (_dependencyResolver.ResolveUnmanagedDllToPath(unmanagedDllName) is { } path)
|
||||||
return LoadUnmanagedDllFromPath(path);
|
return LoadUnmanagedDllFromPath(path);
|
||||||
|
|
||||||
return _parentContext.ResolveUnmanagedDll(unmanagedDllName);
|
return base.LoadUnmanagedDll(unmanagedDllName);
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -1,38 +1,71 @@
|
|||||||
using System.Collections.Immutable;
|
using System.Collections.Immutable;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Text.Json;
|
||||||
|
using CringePlugins.Config;
|
||||||
|
using CringePlugins.Resolver;
|
||||||
|
using CringePlugins.Splash;
|
||||||
using NLog;
|
using NLog;
|
||||||
|
using NuGet;
|
||||||
|
using NuGet.Deps;
|
||||||
|
using NuGet.Frameworks;
|
||||||
|
|
||||||
namespace CringePlugins.Loader;
|
namespace CringePlugins.Loader;
|
||||||
|
|
||||||
public class PluginsLifetime
|
public class PluginsLifetime : ILoadingStage
|
||||||
{
|
{
|
||||||
private static readonly Logger Log = LogManager.GetCurrentClassLogger();
|
private static readonly Logger Log = LogManager.GetCurrentClassLogger();
|
||||||
|
|
||||||
private readonly ImmutableArray<PluginInstance> _plugins;
|
public string Name => "Loading Plugins";
|
||||||
|
|
||||||
public PluginsLifetime()
|
private ImmutableArray<PluginInstance> _plugins = [];
|
||||||
|
private readonly DirectoryInfo _dir = Directory.CreateDirectory(Path.Join(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "CringeLauncher"));
|
||||||
|
private readonly NuGetFramework _runtimeFramework = NuGetFramework.ParseFolder("net8.0-windows");
|
||||||
|
|
||||||
|
public async ValueTask Load(ISplashProgress progress)
|
||||||
{
|
{
|
||||||
var dir = Directory.CreateDirectory(Path.Join(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "CringeLauncher", "plugins"));
|
progress.DefineStepsCount(6);
|
||||||
|
|
||||||
var plugins = ImmutableArray<PluginInstance>.Empty.ToBuilder();
|
progress.Report("Discovering local plugins");
|
||||||
|
|
||||||
foreach (var directory in dir.EnumerateDirectories())
|
DiscoverLocalPlugins(_dir.CreateSubdirectory("plugins"));
|
||||||
|
|
||||||
|
progress.Report("Loading config");
|
||||||
|
|
||||||
|
PackagesConfig? packagesConfig = null;
|
||||||
|
var configPath = Path.Join(_dir.FullName, "packages.json");
|
||||||
|
if (File.Exists(configPath))
|
||||||
|
await using (var stream = File.OpenRead(configPath))
|
||||||
|
packagesConfig = JsonSerializer.Deserialize<PackagesConfig>(stream, NuGetClient.SerializerOptions)!;
|
||||||
|
|
||||||
|
if (packagesConfig == null)
|
||||||
{
|
{
|
||||||
var files = directory.GetFiles("*.dll");
|
packagesConfig = PackagesConfig.Default;
|
||||||
|
await using var stream = File.Create(configPath);
|
||||||
if (files.Length != 1) continue;
|
await JsonSerializer.SerializeAsync(stream, packagesConfig, NuGetClient.SerializerOptions);
|
||||||
|
|
||||||
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();
|
progress.Report("Resolving packages");
|
||||||
|
|
||||||
|
var sourceMapping = new PackageSourceMapping(packagesConfig.Sources);
|
||||||
|
var resolver = new PackageResolver(_runtimeFramework, packagesConfig.Packages, sourceMapping);
|
||||||
|
|
||||||
|
var packages = await resolver.ResolveAsync();
|
||||||
|
|
||||||
|
progress.Report("Downloading packages");
|
||||||
|
|
||||||
|
var cachedPackages = await resolver.DownloadPackagesAsync(_dir.CreateSubdirectory("cache"), packages, progress);
|
||||||
|
|
||||||
|
progress.Report("Loading plugins");
|
||||||
|
|
||||||
|
await LoadPlugins(cachedPackages, sourceMapping);
|
||||||
|
|
||||||
|
progress.Report("Registering plugins");
|
||||||
|
|
||||||
|
RegisterLifetime();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RegisterLifetime()
|
||||||
|
{
|
||||||
foreach (var instance in _plugins)
|
foreach (var instance in _plugins)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@@ -46,4 +79,56 @@ public class PluginsLifetime
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task LoadPlugins(IReadOnlySet<CachedPackage> packages, PackageSourceMapping sourceMapping)
|
||||||
|
{
|
||||||
|
var plugins = _plugins.ToBuilder();
|
||||||
|
|
||||||
|
foreach (var package in packages)
|
||||||
|
{
|
||||||
|
var dir = Path.Join(package.Directory.FullName, "lib", package.ResolvedFramework.GetShortFolderName());
|
||||||
|
|
||||||
|
await using (var stream = File.Create(Path.Join(dir, $"{package.Package.Id}.deps.json")))
|
||||||
|
await DependencyManifestUtility.WriteDependencyManifestAsync(stream, package.Entry, _runtimeFramework,
|
||||||
|
sourceMapping,
|
||||||
|
dependency =>
|
||||||
|
packages.First(b => b.Package.Id.Equals(dependency.Id, StringComparison.OrdinalIgnoreCase))
|
||||||
|
.Package
|
||||||
|
.Version);
|
||||||
|
|
||||||
|
LoadComponent(plugins, Path.Join(dir, $"{package.Package.Id}.dll"));
|
||||||
|
}
|
||||||
|
|
||||||
|
_plugins = plugins.ToImmutable();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DiscoverLocalPlugins(DirectoryInfo dir)
|
||||||
|
{
|
||||||
|
var plugins = ImmutableArray<PluginInstance>.Empty.ToBuilder();
|
||||||
|
|
||||||
|
foreach (var directory in dir.EnumerateDirectories())
|
||||||
|
{
|
||||||
|
var files = directory.GetFiles("*.deps.json");
|
||||||
|
|
||||||
|
if (files.Length != 1) continue;
|
||||||
|
|
||||||
|
var path = files[0].FullName[..^".deps.json".Length] + ".dll";
|
||||||
|
|
||||||
|
LoadComponent(plugins, path);
|
||||||
|
}
|
||||||
|
|
||||||
|
_plugins = plugins.ToImmutable();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void LoadComponent(ImmutableArray<PluginInstance>.Builder plugins, string path)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
plugins.Add(new PluginInstance(path));
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Log.Error(e, "Failed to load plugin {PluginPath}", path);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
@@ -4,7 +4,7 @@ using NLog;
|
|||||||
|
|
||||||
namespace CringePlugins.Render;
|
namespace CringePlugins.Render;
|
||||||
|
|
||||||
public sealed class RenderHandler : IDisposable
|
public sealed class RenderHandler : IRootRenderComponent
|
||||||
{
|
{
|
||||||
private static readonly Logger Log = LogManager.GetCurrentClassLogger();
|
private static readonly Logger Log = LogManager.GetCurrentClassLogger();
|
||||||
|
|
||||||
@@ -23,7 +23,7 @@ public sealed class RenderHandler : IDisposable
|
|||||||
_components.Add(new ComponentRegistration(typeof(TComponent), instance));
|
_components.Add(new ComponentRegistration(typeof(TComponent), instance));
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void OnFrame()
|
void IRenderComponent.OnFrame()
|
||||||
{
|
{
|
||||||
foreach (var (instanceType, renderComponent) in _components)
|
foreach (var (instanceType, renderComponent) in _components)
|
||||||
{
|
{
|
||||||
|
148
CringePlugins/Resolver/PackageResolver.cs
Normal file
148
CringePlugins/Resolver/PackageResolver.cs
Normal file
@@ -0,0 +1,148 @@
|
|||||||
|
using System.Collections.Immutable;
|
||||||
|
using System.IO.Compression;
|
||||||
|
using NuGet;
|
||||||
|
using NuGet.Frameworks;
|
||||||
|
using NuGet.Models;
|
||||||
|
using NuGet.Versioning;
|
||||||
|
|
||||||
|
namespace CringePlugins.Resolver;
|
||||||
|
|
||||||
|
public class PackageResolver(NuGetFramework runtimeFramework, ImmutableArray<PackageReference> references, PackageSourceMapping packageSources)
|
||||||
|
{
|
||||||
|
public async Task<ImmutableHashSet<ResolvedPackage>> ResolveAsync()
|
||||||
|
{
|
||||||
|
var order = 0;
|
||||||
|
var packages = new SortedSet<Package>();
|
||||||
|
|
||||||
|
foreach (var reference in references)
|
||||||
|
{
|
||||||
|
var client = await packageSources.GetClientAsync(reference.Id);
|
||||||
|
|
||||||
|
var registrationRoot = await client.GetPackageRegistrationRootAsync(reference.Id);
|
||||||
|
|
||||||
|
NuGetVersion? version = null;
|
||||||
|
foreach (var page in registrationRoot.Items)
|
||||||
|
{
|
||||||
|
version = reference.Range.FindBestMatch(page.Items.Where(b => b.CatalogEntry.PackageTypes is [{ Name: "CringePlugin" }]).Select(b => b.CatalogEntry.Version));
|
||||||
|
if (version is not null)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (version is null)
|
||||||
|
throw new Exception($"Unable to find version for package {reference.Id}");
|
||||||
|
|
||||||
|
var package = new Package(order, reference.Id, version, []); // todo resolve dependencies
|
||||||
|
|
||||||
|
if (packages.Add(package))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!packages.TryGetValue(package, out var existingPackage))
|
||||||
|
throw new Exception($"Duplicate package {package.Id}");
|
||||||
|
|
||||||
|
if (package.Version < existingPackage.Version)
|
||||||
|
throw new Exception($"Package reference {package.Id} has lower version {package.Version} than already resolved {existingPackage.Version}");
|
||||||
|
|
||||||
|
if (package.Version == existingPackage.Version)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
packages.Remove(existingPackage);
|
||||||
|
packages.Add(package with
|
||||||
|
{
|
||||||
|
Order = ++order
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
var set = ImmutableHashSet<ResolvedPackage>.Empty.ToBuilder();
|
||||||
|
foreach (var package in packages)
|
||||||
|
{
|
||||||
|
var client = await packageSources.GetClientAsync(package.Id);
|
||||||
|
|
||||||
|
var (catalogEntryUrl, catalogEntry) = await client.GetPackageRegistrationAsync(package.Id, package.Version);
|
||||||
|
|
||||||
|
catalogEntry ??= await client.GetPackageCatalogEntryAsync(catalogEntryUrl);
|
||||||
|
|
||||||
|
var nearestGroup = NuGetFrameworkUtility.GetNearest(catalogEntry.DependencyGroups, runtimeFramework,
|
||||||
|
g => g.TargetFramework);
|
||||||
|
|
||||||
|
if (nearestGroup is null)
|
||||||
|
throw new Exception($"Unable to find compatible dependency group for package {package.Id}");
|
||||||
|
|
||||||
|
set.Add(new RemotePackage(package, nearestGroup.TargetFramework, client, catalogEntry));
|
||||||
|
}
|
||||||
|
|
||||||
|
return set.ToImmutable();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<ImmutableHashSet<CachedPackage>> DownloadPackagesAsync(DirectoryInfo baseDirectory,
|
||||||
|
IReadOnlySet<ResolvedPackage> resolvedPackages, IProgress<float>? progress = null)
|
||||||
|
{
|
||||||
|
var packages = ImmutableHashSet<CachedPackage>.Empty.ToBuilder();
|
||||||
|
|
||||||
|
var i = 0f;
|
||||||
|
foreach (var package in resolvedPackages)
|
||||||
|
{
|
||||||
|
switch (package)
|
||||||
|
{
|
||||||
|
case RemotePackage remotePackage:
|
||||||
|
{
|
||||||
|
var dir = new DirectoryInfo(Path.Join(baseDirectory.FullName, package.Package.Id, package.Package.Version.ToString()));
|
||||||
|
if (!dir.Exists)
|
||||||
|
{
|
||||||
|
dir.Create();
|
||||||
|
|
||||||
|
await using var stream = await remotePackage.Client.GetPackageContentStreamAsync(remotePackage.Package.Id, remotePackage.Package.Version);
|
||||||
|
using var memStream = new MemoryStream();
|
||||||
|
await stream.CopyToAsync(memStream);
|
||||||
|
memStream.Position = 0;
|
||||||
|
using var archive = new ZipArchive(memStream, ZipArchiveMode.Read);
|
||||||
|
archive.ExtractToDirectory(dir.FullName);
|
||||||
|
}
|
||||||
|
|
||||||
|
packages.Add(new CachedPackage(package.Package, package.ResolvedFramework, dir, package.Entry));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case CachedPackage cachedPackage:
|
||||||
|
packages.Add(cachedPackage);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
progress?.Report(i++ / resolvedPackages.Count);
|
||||||
|
}
|
||||||
|
|
||||||
|
return packages.ToImmutable();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public record CachedPackage(Package Package, NuGetFramework ResolvedFramework, DirectoryInfo Directory, CatalogEntry Entry) : ResolvedPackage(Package, ResolvedFramework, Entry);
|
||||||
|
public record RemotePackage(Package Package, NuGetFramework ResolvedFramework, NuGetClient Client, CatalogEntry Entry) : ResolvedPackage(Package, ResolvedFramework, Entry);
|
||||||
|
|
||||||
|
public abstract record ResolvedPackage(Package Package, NuGetFramework ResolvedFramework, CatalogEntry Entry);
|
||||||
|
|
||||||
|
public record Package(int Order, string Id, NuGetVersion Version, ImmutableArray<string> Dependencies) : IComparable<Package>, IComparable
|
||||||
|
{
|
||||||
|
public int CompareTo(Package? other)
|
||||||
|
{
|
||||||
|
if (ReferenceEquals(this, other)) return 0;
|
||||||
|
if (other is null) return 1;
|
||||||
|
var orderComparison = Order.CompareTo(other.Order);
|
||||||
|
if (orderComparison != 0) return orderComparison;
|
||||||
|
return string.Compare(Id, other.Id, StringComparison.OrdinalIgnoreCase);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int CompareTo(object? obj)
|
||||||
|
{
|
||||||
|
if (obj is null) return 1;
|
||||||
|
if (ReferenceEquals(this, obj)) return 0;
|
||||||
|
return obj is Package other ? CompareTo(other) : throw new ArgumentException($"Object must be of type {nameof(Package)}");
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Id);
|
||||||
|
|
||||||
|
public virtual bool Equals(Package? other)
|
||||||
|
{
|
||||||
|
if (other is null) return false;
|
||||||
|
return Id.Equals(other.Id, StringComparison.OrdinalIgnoreCase);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public record PackageReference(string Id, VersionRange Range);
|
13
CringePlugins/Splash/ISplashProgress.cs
Normal file
13
CringePlugins/Splash/ISplashProgress.cs
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
namespace CringePlugins.Splash;
|
||||||
|
|
||||||
|
public interface ISplashProgress : IProgress<ProgressInfo>, IProgress<float>
|
||||||
|
{
|
||||||
|
void DefineStage(ILoadingStage stage);
|
||||||
|
void DefineStepsCount(int count);
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface ILoadingStage
|
||||||
|
{
|
||||||
|
string Name { get; }
|
||||||
|
ValueTask Load(ISplashProgress progress);
|
||||||
|
}
|
9
CringePlugins/Splash/ProgressInfo.cs
Normal file
9
CringePlugins/Splash/ProgressInfo.cs
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
namespace CringePlugins.Splash;
|
||||||
|
|
||||||
|
public record ProgressInfo(string Text)
|
||||||
|
{
|
||||||
|
public static implicit operator ProgressInfo(string s) => new(s);
|
||||||
|
public static implicit operator ProgressInfo((string, float) s) => new PercentProgressInfo(s.Item1, s.Item2);
|
||||||
|
}
|
||||||
|
|
||||||
|
public record PercentProgressInfo(string Text, float Percent = 0) : ProgressInfo(Text);
|
29
CringePlugins/Splash/Splash.cs
Normal file
29
CringePlugins/Splash/Splash.cs
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
namespace CringePlugins.Splash;
|
||||||
|
|
||||||
|
public class Splash : ISplashProgress
|
||||||
|
{
|
||||||
|
private readonly List<ILoadingStage> _loadingStages = [];
|
||||||
|
|
||||||
|
public void Report(ProgressInfo value)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Report(float value)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public void DefineStage(ILoadingStage stage) => _loadingStages.Add(stage);
|
||||||
|
|
||||||
|
public void DefineStepsCount(int count)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ExecuteLoadingStages()
|
||||||
|
{
|
||||||
|
foreach (var loadingStage in _loadingStages)
|
||||||
|
{
|
||||||
|
// todo sync context
|
||||||
|
loadingStage.Load(this).AsTask().GetAwaiter().GetResult();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"version": 1,
|
"version": 1,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"net8.0": {
|
"net8.0-windows7.0": {
|
||||||
"dnlib": {
|
"dnlib": {
|
||||||
"type": "Direct",
|
"type": "Direct",
|
||||||
"requested": "[4.4.0, )",
|
"requested": "[4.4.0, )",
|
||||||
@@ -23,22 +23,22 @@
|
|||||||
"SpaceEngineersDedicated.ReferenceAssemblies": {
|
"SpaceEngineersDedicated.ReferenceAssemblies": {
|
||||||
"type": "Direct",
|
"type": "Direct",
|
||||||
"requested": "[1.*, )",
|
"requested": "[1.*, )",
|
||||||
"resolved": "1.204.18",
|
"resolved": "1.205.23",
|
||||||
"contentHash": "GT7/9CBMx4jjor41zLOOl87YYM/JdJD8xp9ccXyuhP2oUaz25H3ZmCQuGeAuZNENKru1a/7hZrId4PwlMDGoew==",
|
"contentHash": "J7mF5hY39PzzCZps6vhIRzKiq8vD6Af9TgumTJR068vjEi+BzyeEFhqX+cl2Dd1ngOmsBtGWc5m+vxgTfs5YuA==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"SharpDX": "4.2.0-keen-cringe",
|
"SharpDX": "4.2.0-keen-cringe",
|
||||||
"protobuf-net": "1.0.0"
|
"protobuf-net": "1.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"ImGui.NET.DirectX": {
|
"NuGet.Frameworks": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
"resolved": "1.91.0.1",
|
"resolved": "6.11.1",
|
||||||
"contentHash": "PpW1gQ9g97h6Hm/h/tkSBOmsBYgGwN8wKNmlJomcQFD/zRY1HPkJZz18XRSfRLHPmH2eeh4hhhZv1KHug7dF9g==",
|
"contentHash": "plTZ3ariSWQVsFn2mk83SsdmSg1VpgIMTSZpP/eSE/NNQF02p+M9ItxAYeUZBMX+cQ2nFkSwxQRJ0/fkaV9Hbg=="
|
||||||
"dependencies": {
|
},
|
||||||
"System.Buffers": "4.5.1",
|
"NuGet.Versioning": {
|
||||||
"System.Numerics.Vectors": "4.5.0",
|
"type": "Transitive",
|
||||||
"System.Runtime.CompilerServices.Unsafe": "6.0.0"
|
"resolved": "6.11.1",
|
||||||
}
|
"contentHash": "YNn3BB71F+guJW42TbAhGcMh3gpyqFMZcPVD9pm5vcvGivTALtRely/VCPWQQ6JQ5PfwIrjPaJMO7VnqyeK3rg=="
|
||||||
},
|
},
|
||||||
"protobuf-net": {
|
"protobuf-net": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
@@ -50,28 +50,21 @@
|
|||||||
"resolved": "4.2.0-keen-cringe",
|
"resolved": "4.2.0-keen-cringe",
|
||||||
"contentHash": "LaJN3h1Gi1FWVdef2I5WtOH9gwzKCBniH0CragarbkN2QheYY6Lqm+91PcOfp1w/4wdVb+k8Kjv3sO393Tphtw=="
|
"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": {
|
"cringebootstrap.abstractions": {
|
||||||
"type": "Project"
|
"type": "Project"
|
||||||
},
|
},
|
||||||
"cringerender": {
|
"nuget": {
|
||||||
"type": "Project",
|
"type": "Project",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"ImGui.NET.DirectX": "[1.91.0.1, )",
|
"NuGet.Frameworks": "[6.11.1, )",
|
||||||
|
"NuGet.Versioning": "[6.11.1, )"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"sharedcringe": {
|
||||||
|
"type": "Project",
|
||||||
|
"dependencies": {
|
||||||
|
"CringeBootstrap.Abstractions": "[1.0.0, )",
|
||||||
|
"NLog": "[5.3.4, )",
|
||||||
"SpaceEngineersDedicated.ReferenceAssemblies": "[1.*, )"
|
"SpaceEngineersDedicated.ReferenceAssemblies": "[1.*, )"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
BIN
CringePlugins/splash.gif
Normal file
BIN
CringePlugins/splash.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 515 KiB |
45
NuGet/Converters/FrameworkJsonConverter.cs
Normal file
45
NuGet/Converters/FrameworkJsonConverter.cs
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
using System.Text.Json;
|
||||||
|
using System.Text.Json.Serialization;
|
||||||
|
using NuGet.Frameworks;
|
||||||
|
|
||||||
|
namespace NuGet.Converters;
|
||||||
|
|
||||||
|
public class FrameworkJsonConverter(FrameworkNameFormat format) : JsonConverter<NuGetFramework>
|
||||||
|
{
|
||||||
|
public override NuGetFramework? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
||||||
|
{
|
||||||
|
if (reader.TokenType != JsonTokenType.String)
|
||||||
|
throw new JsonException("Invalid framework string");
|
||||||
|
|
||||||
|
var s = reader.GetString()!;
|
||||||
|
return format switch
|
||||||
|
{
|
||||||
|
FrameworkNameFormat.ShortFolderName => NuGetFramework.ParseFolder(s),
|
||||||
|
FrameworkNameFormat.FrameworkName => NuGetFramework.ParseFrameworkName(s,
|
||||||
|
DefaultFrameworkNameProvider.Instance),
|
||||||
|
_ => throw new ArgumentOutOfRangeException()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Write(Utf8JsonWriter writer, NuGetFramework value, JsonSerializerOptions options)
|
||||||
|
{
|
||||||
|
writer.WriteStringValue(format switch
|
||||||
|
{
|
||||||
|
FrameworkNameFormat.ShortFolderName => value.GetShortFolderName(),
|
||||||
|
FrameworkNameFormat.FrameworkName => value.DotNetFrameworkName,
|
||||||
|
_ => throw new ArgumentOutOfRangeException()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum FrameworkNameFormat
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The short folder name format (net8.0)
|
||||||
|
/// </summary>
|
||||||
|
ShortFolderName,
|
||||||
|
/// <summary>
|
||||||
|
/// Full framework name (.NETCoreApp,Version=v8.0)
|
||||||
|
/// </summary>
|
||||||
|
FrameworkName
|
||||||
|
}
|
27
NuGet/Converters/ManifestPackageKeyJsonConverter.cs
Normal file
27
NuGet/Converters/ManifestPackageKeyJsonConverter.cs
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
using System.Text.Json;
|
||||||
|
using System.Text.Json.Serialization;
|
||||||
|
using NuGet.Deps;
|
||||||
|
|
||||||
|
namespace NuGet.Converters;
|
||||||
|
|
||||||
|
public class ManifestPackageKeyJsonConverter : JsonConverter<ManifestPackageKey>
|
||||||
|
{
|
||||||
|
public override ManifestPackageKey Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
||||||
|
{
|
||||||
|
if (reader.TokenType != JsonTokenType.String)
|
||||||
|
throw new JsonException("Invalid package key string");
|
||||||
|
|
||||||
|
return ManifestPackageKey.Parse(reader.GetString()!);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Write(Utf8JsonWriter writer, ManifestPackageKey value, JsonSerializerOptions options)
|
||||||
|
{
|
||||||
|
writer.WriteStringValue(value.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
public override ManifestPackageKey ReadAsPropertyName(ref Utf8JsonReader reader, Type typeToConvert,
|
||||||
|
JsonSerializerOptions options) => Read(ref reader, typeToConvert, options);
|
||||||
|
|
||||||
|
public override void WriteAsPropertyName(Utf8JsonWriter writer, ManifestPackageKey value,
|
||||||
|
JsonSerializerOptions options) => Write(writer, value, options);
|
||||||
|
}
|
21
NuGet/Converters/ResourceTypeJsonConverter.cs
Normal file
21
NuGet/Converters/ResourceTypeJsonConverter.cs
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
using System.Text.Json;
|
||||||
|
using System.Text.Json.Serialization;
|
||||||
|
using NuGet.Models;
|
||||||
|
|
||||||
|
namespace NuGet.Converters;
|
||||||
|
|
||||||
|
public class ResourceTypeJsonConverter : JsonConverter<ResourceType>
|
||||||
|
{
|
||||||
|
public override ResourceType Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
||||||
|
{
|
||||||
|
if (reader.TokenType != JsonTokenType.String)
|
||||||
|
throw new JsonException("Invalid resource type");
|
||||||
|
|
||||||
|
return ResourceType.Parse(reader.GetString()!);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Write(Utf8JsonWriter writer, ResourceType value, JsonSerializerOptions options)
|
||||||
|
{
|
||||||
|
writer.WriteStringValue(value.ToString());
|
||||||
|
}
|
||||||
|
}
|
21
NuGet/Converters/VersionJsonConverter.cs
Normal file
21
NuGet/Converters/VersionJsonConverter.cs
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
using System.Text.Json;
|
||||||
|
using System.Text.Json.Serialization;
|
||||||
|
using NuGet.Versioning;
|
||||||
|
|
||||||
|
namespace NuGet.Converters;
|
||||||
|
|
||||||
|
public class VersionJsonConverter : JsonConverter<NuGetVersion>
|
||||||
|
{
|
||||||
|
public override NuGetVersion? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
||||||
|
{
|
||||||
|
if (reader.TokenType != JsonTokenType.String)
|
||||||
|
throw new JsonException("Invalid version string");
|
||||||
|
|
||||||
|
return NuGetVersion.Parse(reader.GetString()!);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Write(Utf8JsonWriter writer, NuGetVersion value, JsonSerializerOptions options)
|
||||||
|
{
|
||||||
|
writer.WriteStringValue(value.ToString());
|
||||||
|
}
|
||||||
|
}
|
21
NuGet/Converters/VersionRangeJsonConverter.cs
Normal file
21
NuGet/Converters/VersionRangeJsonConverter.cs
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
using System.Text.Json;
|
||||||
|
using System.Text.Json.Serialization;
|
||||||
|
using NuGet.Versioning;
|
||||||
|
|
||||||
|
namespace NuGet.Converters;
|
||||||
|
|
||||||
|
public class VersionRangeJsonConverter : JsonConverter<VersionRange>
|
||||||
|
{
|
||||||
|
public override VersionRange? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
||||||
|
{
|
||||||
|
if (reader.TokenType != JsonTokenType.String)
|
||||||
|
throw new JsonException("Invalid version range");
|
||||||
|
|
||||||
|
return VersionRange.Parse(reader.GetString()!);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Write(Utf8JsonWriter writer, VersionRange value, JsonSerializerOptions options)
|
||||||
|
{
|
||||||
|
writer.WriteStringValue(value.ToString());
|
||||||
|
}
|
||||||
|
}
|
123
NuGet/Deps/DependenciesManifest.cs
Normal file
123
NuGet/Deps/DependenciesManifest.cs
Normal file
@@ -0,0 +1,123 @@
|
|||||||
|
using System.Collections.Immutable;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Text.Json;
|
||||||
|
using System.Text.Json.Serialization;
|
||||||
|
using NuGet.Converters;
|
||||||
|
using NuGet.Frameworks;
|
||||||
|
using NuGet.Models;
|
||||||
|
using NuGet.Versioning;
|
||||||
|
|
||||||
|
namespace NuGet.Deps;
|
||||||
|
|
||||||
|
public record DependenciesManifest(RuntimeTarget RuntimeTarget,
|
||||||
|
ImmutableDictionary<NuGetFramework, string> CompilationOptions,
|
||||||
|
ImmutableDictionary<NuGetFramework, ImmutableDictionary<ManifestPackageKey, DependencyTarget>> Targets,
|
||||||
|
ImmutableDictionary<ManifestPackageKey, DependencyLibrary> Libraries);
|
||||||
|
|
||||||
|
public record DependencyLibrary(
|
||||||
|
LibraryType Type,
|
||||||
|
string Sha512 = "",
|
||||||
|
bool Serviceable = false,
|
||||||
|
ManifestPackageKey? Path = null,
|
||||||
|
string? HashPath = null);
|
||||||
|
|
||||||
|
[JsonConverter(typeof(JsonStringEnumConverter<LibraryType>))]
|
||||||
|
public enum LibraryType
|
||||||
|
{
|
||||||
|
Project,
|
||||||
|
Package
|
||||||
|
}
|
||||||
|
|
||||||
|
public record DependencyTarget(ImmutableDictionary<string, NuGetVersion>? Dependencies,
|
||||||
|
// key is file path relative to package root
|
||||||
|
ImmutableDictionary<string, RuntimeDependency>? Runtime,
|
||||||
|
// key is file path relative to package root
|
||||||
|
ImmutableDictionary<string, Dependency>? Native);
|
||||||
|
|
||||||
|
public record Dependency(Version? FileVersion = null);
|
||||||
|
|
||||||
|
public record RuntimeDependency(Version? AssemblyVersion = null, Version? FileVersion = null) : Dependency(FileVersion);
|
||||||
|
|
||||||
|
public record RuntimeTarget([property: JsonPropertyName("name")] NuGetFramework Framework, string Signature = "");
|
||||||
|
|
||||||
|
[JsonConverter(typeof(ManifestPackageKeyJsonConverter))]
|
||||||
|
public record ManifestPackageKey(string Id, NuGetVersion Version)
|
||||||
|
{
|
||||||
|
public static ManifestPackageKey Parse(string str)
|
||||||
|
{
|
||||||
|
var index = str.IndexOf('/');
|
||||||
|
if (index < 0)
|
||||||
|
throw new FormatException("Invalid package key: " + str);
|
||||||
|
|
||||||
|
return new ManifestPackageKey(str[..index], NuGetVersion.Parse(str[(index + 1)..]));
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString() => $"{Id}/{Version}";
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class DependencyManifestUtility
|
||||||
|
{
|
||||||
|
private static readonly JsonSerializerOptions SerializerOptions = new(JsonSerializerDefaults.Web)
|
||||||
|
{
|
||||||
|
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
|
||||||
|
WriteIndented = true,
|
||||||
|
Converters =
|
||||||
|
{
|
||||||
|
new FrameworkJsonConverter(FrameworkNameFormat.FrameworkName),
|
||||||
|
new VersionJsonConverter()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public static async ValueTask WriteDependencyManifestAsync(Stream stream, CatalogEntry catalogEntry, NuGetFramework targetFramework,
|
||||||
|
PackageSourceMapping packageSources, Func<Models.Dependency, NuGetVersion> versionResolver)
|
||||||
|
{
|
||||||
|
var runtimeTarget = new RuntimeTarget(targetFramework);
|
||||||
|
|
||||||
|
var targets = ImmutableDictionary<ManifestPackageKey, DependencyTarget>.Empty.ToBuilder();
|
||||||
|
|
||||||
|
await MapCatalogEntry(catalogEntry, targetFramework, packageSources, versionResolver, targets);
|
||||||
|
|
||||||
|
var manifest = new DependenciesManifest(runtimeTarget, ImmutableDictionary<NuGetFramework, string>.Empty,
|
||||||
|
ImmutableDictionary<NuGetFramework, ImmutableDictionary<ManifestPackageKey, DependencyTarget>>.Empty
|
||||||
|
.Add(targetFramework, targets.ToImmutable()),
|
||||||
|
ImmutableDictionary<ManifestPackageKey, DependencyLibrary>.Empty);
|
||||||
|
|
||||||
|
await JsonSerializer.SerializeAsync(stream, manifest, SerializerOptions);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static async Task MapCatalogEntry(CatalogEntry catalogEntry, NuGetFramework targetFramework,
|
||||||
|
PackageSourceMapping packageSources, Func<Models.Dependency, NuGetVersion> versionResolver, ImmutableDictionary<ManifestPackageKey, DependencyTarget>.Builder targets)
|
||||||
|
{
|
||||||
|
if (targets.ContainsKey(new(catalogEntry.Id, catalogEntry.Version)))
|
||||||
|
return;
|
||||||
|
|
||||||
|
var nearest = NuGetFrameworkUtility.GetNearest(catalogEntry.DependencyGroups, targetFramework,
|
||||||
|
group => group.TargetFramework);
|
||||||
|
|
||||||
|
if (nearest is null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
targets.Add(new(catalogEntry.Id, catalogEntry.Version),
|
||||||
|
MapEntry(catalogEntry, nearest, targetFramework, versionResolver));
|
||||||
|
|
||||||
|
foreach (var dependency in nearest.Dependencies)
|
||||||
|
{
|
||||||
|
var client = await packageSources.GetClientAsync(dependency.Id);
|
||||||
|
var (url, entry) = await client.GetPackageRegistrationAsync(dependency.Id, versionResolver(dependency));
|
||||||
|
|
||||||
|
entry ??= await client.GetPackageCatalogEntryAsync(url);
|
||||||
|
|
||||||
|
await MapCatalogEntry(entry, targetFramework, packageSources, versionResolver, targets);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static DependencyTarget MapEntry(CatalogEntry entry, DependencyGroup group, NuGetFramework targetFramework, Func<Models.Dependency, NuGetVersion> versionResolver)
|
||||||
|
{
|
||||||
|
return new(group.Dependencies.ToImmutableDictionary(b => b.Id, versionResolver),
|
||||||
|
entry.PackageEntries.Where(b => b.FullName.StartsWith($"lib/{targetFramework.GetShortFolderName()}/"))
|
||||||
|
.ToImmutableDictionary(b => b.FullName, _ => new RuntimeDependency()),
|
||||||
|
entry.PackageEntries.Where(b =>
|
||||||
|
b.FullName.StartsWith($"runtimes/{RuntimeInformation.RuntimeIdentifier}/native/"))
|
||||||
|
.ToImmutableDictionary(b => b.FullName, _ => new Dependency()));
|
||||||
|
}
|
||||||
|
}
|
9
NuGet/Models/CatalogEntry.cs
Normal file
9
NuGet/Models/CatalogEntry.cs
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
using NuGet.Versioning;
|
||||||
|
|
||||||
|
namespace NuGet.Models;
|
||||||
|
|
||||||
|
public record CatalogEntry(string Id, NuGetVersion Version, DependencyGroup[] DependencyGroups, PackageType[]? PackageTypes,
|
||||||
|
CatalogPackageEntry[] PackageEntries,
|
||||||
|
bool Serviceable = true);
|
||||||
|
|
||||||
|
public record CatalogPackageEntry(string Name, string FullName, long CompressedLength, long Length);
|
5
NuGet/Models/Dependency.cs
Normal file
5
NuGet/Models/Dependency.cs
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
using NuGet.Versioning;
|
||||||
|
|
||||||
|
namespace NuGet.Models;
|
||||||
|
|
||||||
|
public record Dependency(string Id, VersionRange Range);
|
5
NuGet/Models/DependencyGroup.cs
Normal file
5
NuGet/Models/DependencyGroup.cs
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
using NuGet.Frameworks;
|
||||||
|
|
||||||
|
namespace NuGet.Models;
|
||||||
|
|
||||||
|
public record DependencyGroup(NuGetFramework TargetFramework, Dependency[] Dependencies);
|
5
NuGet/Models/NuGetIndex.cs
Normal file
5
NuGet/Models/NuGetIndex.cs
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
using NuGet.Versioning;
|
||||||
|
|
||||||
|
namespace NuGet.Models;
|
||||||
|
|
||||||
|
public record NuGetIndex(NuGetVersion Version, Resource[] Resources);
|
3
NuGet/Models/PackageType.cs
Normal file
3
NuGet/Models/PackageType.cs
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
namespace NuGet.Models;
|
||||||
|
|
||||||
|
public record PackageType(string Name);
|
6
NuGet/Models/Registration.cs
Normal file
6
NuGet/Models/Registration.cs
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
|
namespace NuGet.Models;
|
||||||
|
|
||||||
|
public record Registration([property: JsonPropertyName("catalogEntry")] string CatalogEntryUrl,
|
||||||
|
[property: JsonPropertyName("sleet:catalogEntry")] CatalogEntry? SleetEntry);
|
3
NuGet/Models/RegistrationEntry.cs
Normal file
3
NuGet/Models/RegistrationEntry.cs
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
namespace NuGet.Models;
|
||||||
|
|
||||||
|
public record RegistrationEntry(CatalogEntry CatalogEntry);
|
5
NuGet/Models/RegistrationPage.cs
Normal file
5
NuGet/Models/RegistrationPage.cs
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
using NuGet.Versioning;
|
||||||
|
|
||||||
|
namespace NuGet.Models;
|
||||||
|
|
||||||
|
public record RegistrationPage(int Count, NuGetVersion Lower, NuGetVersion Upper, RegistrationEntry[] Items);
|
3
NuGet/Models/RegistrationRoot.cs
Normal file
3
NuGet/Models/RegistrationRoot.cs
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
namespace NuGet.Models;
|
||||||
|
|
||||||
|
public record RegistrationRoot(int Count, RegistrationPage[] Items);
|
5
NuGet/Models/Resource.cs
Normal file
5
NuGet/Models/Resource.cs
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
|
namespace NuGet.Models;
|
||||||
|
|
||||||
|
public record Resource([property: JsonPropertyName("@id")] string Url, [property: JsonPropertyName("@type")] ResourceType Type, string? Comment);
|
26
NuGet/Models/ResourceType.cs
Normal file
26
NuGet/Models/ResourceType.cs
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
using System.Text.Json.Serialization;
|
||||||
|
using NuGet.Converters;
|
||||||
|
using NuGet.Versioning;
|
||||||
|
|
||||||
|
namespace NuGet.Models;
|
||||||
|
|
||||||
|
[JsonConverter(typeof(ResourceTypeJsonConverter))]
|
||||||
|
public record ResourceType(string Id, NuGetVersion? Version)
|
||||||
|
{
|
||||||
|
public static ResourceType Parse(string typeString)
|
||||||
|
{
|
||||||
|
var slash = typeString.IndexOf('/');
|
||||||
|
|
||||||
|
if (slash < 0)
|
||||||
|
return new ResourceType(typeString, null);
|
||||||
|
|
||||||
|
var id = typeString[..slash];
|
||||||
|
var versionStr = typeString[(slash + 1)..];
|
||||||
|
|
||||||
|
return NuGetVersion.TryParse(versionStr, out var version)
|
||||||
|
? new ResourceType(id, version)
|
||||||
|
: new ResourceType(id, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString() => $"{Id}/{Version}";
|
||||||
|
}
|
14
NuGet/NuGet.csproj
Normal file
14
NuGet/NuGet.csproj
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="NuGet.Frameworks" Version="6.11.1" />
|
||||||
|
<PackageReference Include="NuGet.Versioning" Version="6.11.1" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
73
NuGet/NuGetClient.cs
Normal file
73
NuGet/NuGetClient.cs
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
using System.Net.Http.Json;
|
||||||
|
using System.Text.Json;
|
||||||
|
using NuGet.Converters;
|
||||||
|
using NuGet.Models;
|
||||||
|
using NuGet.Versioning;
|
||||||
|
|
||||||
|
namespace NuGet;
|
||||||
|
|
||||||
|
public class NuGetClient
|
||||||
|
{
|
||||||
|
private readonly HttpClient _client;
|
||||||
|
private readonly Uri _packageBaseAddress;
|
||||||
|
private readonly Uri _registration;
|
||||||
|
|
||||||
|
public static JsonSerializerOptions SerializerOptions { get; } = new(JsonSerializerDefaults.Web)
|
||||||
|
{
|
||||||
|
Converters =
|
||||||
|
{
|
||||||
|
new VersionJsonConverter(),
|
||||||
|
new VersionRangeJsonConverter(),
|
||||||
|
new FrameworkJsonConverter(FrameworkNameFormat.ShortFolderName),
|
||||||
|
},
|
||||||
|
WriteIndented = true
|
||||||
|
};
|
||||||
|
|
||||||
|
private NuGetClient(HttpClient client, Uri packageBaseAddress, Uri registration)
|
||||||
|
{
|
||||||
|
_client = client;
|
||||||
|
_packageBaseAddress = packageBaseAddress;
|
||||||
|
_registration = registration;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<Stream> GetPackageContentStreamAsync(string id, NuGetVersion version)
|
||||||
|
{
|
||||||
|
return _client.GetStreamAsync(new Uri(_packageBaseAddress,
|
||||||
|
new Uri($"{id.ToLower()}/{version}.nupkg", UriKind.Relative)));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<Registration> GetPackageRegistrationAsync(string id, NuGetVersion version)
|
||||||
|
{
|
||||||
|
return _client.GetFromJsonAsync<Registration>(
|
||||||
|
new Uri(_registration,
|
||||||
|
new Uri($"{id.ToLower()}/{version}.json", UriKind.Relative)),
|
||||||
|
SerializerOptions
|
||||||
|
)!;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<RegistrationRoot> GetPackageRegistrationRootAsync(string id)
|
||||||
|
{
|
||||||
|
return _client.GetFromJsonAsync<RegistrationRoot>(
|
||||||
|
new Uri(_registration,
|
||||||
|
new Uri($"{id.ToLower()}/index.json", UriKind.Relative)),
|
||||||
|
SerializerOptions
|
||||||
|
)!;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<CatalogEntry> GetPackageCatalogEntryAsync(string url)
|
||||||
|
{
|
||||||
|
return _client.GetFromJsonAsync<CatalogEntry>(url, SerializerOptions)!;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async Task<NuGetClient> CreateFromIndexUrlAsync(string indexUrl)
|
||||||
|
{
|
||||||
|
var client = new HttpClient();
|
||||||
|
|
||||||
|
var index = await client.GetFromJsonAsync<NuGetIndex>(indexUrl, SerializerOptions);
|
||||||
|
|
||||||
|
var (packageBaseAddress, _, _) = index!.Resources.First(b => b.Type.Id == "PackageBaseAddress");
|
||||||
|
var (registration, _, _) = index!.Resources.First(b => b.Type.Id == "RegistrationsBaseUrl");
|
||||||
|
|
||||||
|
return new NuGetClient(client, new Uri(packageBaseAddress), new Uri(registration));
|
||||||
|
}
|
||||||
|
}
|
16
NuGet/PackageSourceMapping.cs
Normal file
16
NuGet/PackageSourceMapping.cs
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
using System.Collections.Immutable;
|
||||||
|
|
||||||
|
namespace NuGet;
|
||||||
|
|
||||||
|
public class PackageSourceMapping(ImmutableArray<PackageSource> sources)
|
||||||
|
{
|
||||||
|
private readonly ImmutableDictionary<string, Task<NuGetClient>> _clients = sources.Select(b =>
|
||||||
|
new KeyValuePair<string, Task<NuGetClient>>(b.Pattern,
|
||||||
|
NuGetClient.CreateFromIndexUrlAsync(b.Url)))
|
||||||
|
.ToImmutableDictionary();
|
||||||
|
|
||||||
|
public Task<NuGetClient> GetClientAsync(string packageId) =>
|
||||||
|
_clients.FirstOrDefault(b => packageId.StartsWith(b.Key)).Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public record PackageSource(string Pattern, string Url);
|
14
SharedCringe/Loader/DerivedAssemblyLoadContext.cs
Normal file
14
SharedCringe/Loader/DerivedAssemblyLoadContext.cs
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
using System.Reflection;
|
||||||
|
using System.Runtime.Loader;
|
||||||
|
using CringeBootstrap.Abstractions;
|
||||||
|
|
||||||
|
namespace SharedCringe.Loader;
|
||||||
|
|
||||||
|
public abstract class DerivedAssemblyLoadContext(ICoreLoadContext parentContext, string name)
|
||||||
|
: AssemblyLoadContext(name, true)
|
||||||
|
{
|
||||||
|
protected readonly ICoreLoadContext ParentContext = parentContext;
|
||||||
|
|
||||||
|
protected override Assembly? Load(AssemblyName assemblyName) => ParentContext.ResolveFromAssemblyName(assemblyName);
|
||||||
|
protected override nint LoadUnmanagedDll(string unmanagedDllName) => ParentContext.ResolveUnmanagedDll(unmanagedDllName);
|
||||||
|
}
|
19
SharedCringe/SharedCringe.csproj
Normal file
19
SharedCringe/SharedCringe.csproj
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
<RestorePackagesWithLockFile>true</RestorePackagesWithLockFile>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="NLog" Version="5.3.4" />
|
||||||
|
<PackageReference Include="SpaceEngineersDedicated.ReferenceAssemblies" Version="1.*" ExcludeAssets="runtime" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\CringeBootstrap.Abstractions\CringeBootstrap.Abstractions.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
36
SharedCringe/packages.lock.json
Normal file
36
SharedCringe/packages.lock.json
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
{
|
||||||
|
"version": 1,
|
||||||
|
"dependencies": {
|
||||||
|
"net8.0": {
|
||||||
|
"NLog": {
|
||||||
|
"type": "Direct",
|
||||||
|
"requested": "[5.3.4, )",
|
||||||
|
"resolved": "5.3.4",
|
||||||
|
"contentHash": "gLy7+O1hEYJXIlcTr1/VWjGXrZTQFZzYNO18IWasD64pNwz0BreV+nHLxWKXWZzERRzoKnsk2XYtwLkTVk7J1A=="
|
||||||
|
},
|
||||||
|
"SpaceEngineersDedicated.ReferenceAssemblies": {
|
||||||
|
"type": "Direct",
|
||||||
|
"requested": "[1.*, )",
|
||||||
|
"resolved": "1.205.23",
|
||||||
|
"contentHash": "J7mF5hY39PzzCZps6vhIRzKiq8vD6Af9TgumTJR068vjEi+BzyeEFhqX+cl2Dd1ngOmsBtGWc5m+vxgTfs5YuA==",
|
||||||
|
"dependencies": {
|
||||||
|
"SharpDX": "4.2.0-keen-cringe",
|
||||||
|
"protobuf-net": "1.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=="
|
||||||
|
},
|
||||||
|
"cringebootstrap.abstractions": {
|
||||||
|
"type": "Project"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user