Implement Migration of PluginLoader configs (UI is temporary atm)
All checks were successful
Build / Compute Version (push) Successful in 5s
Build / Build Nuget package (CringeBootstrap.Abstractions) (push) Successful in 1m24s
Build / Build Nuget package (NuGet) (push) Successful in 2m8s
Build / Build Nuget package (CringePlugins) (push) Successful in 3m21s
Build / Build Nuget package (SharedCringe) (push) Successful in 2m32s
Build / Build Launcher (push) Successful in 3m31s

Add profiles to Config
Error handling for package resolution
Remove debug code from wndproc hook
This commit is contained in:
2024-11-09 18:23:40 -05:00
parent 2e4c7f5e15
commit c25bf3bb3d
9 changed files with 126 additions and 16 deletions

View File

@@ -45,7 +45,7 @@ internal class ImGuiHandler : IDisposable
_init = true; _init = true;
} }
public void HookWindow(HWND windowHandle) public static void HookWindow(HWND windowHandle)
{ {
_wndproc = PInvoke.GetWindowLongPtr(windowHandle, WINDOW_LONG_PTR_INDEX.GWL_WNDPROC); _wndproc = PInvoke.GetWindowLongPtr(windowHandle, WINDOW_LONG_PTR_INDEX.GWL_WNDPROC);
@@ -96,8 +96,8 @@ internal class ImGuiHandler : IDisposable
var blockMessage = (msg is >= 256 and <= 265 && io.WantTextInput) var blockMessage = (msg is >= 256 and <= 265 && io.WantTextInput)
|| (msg is >= 512 and <= 526 && io.WantCaptureMouse); || (msg is >= 512 and <= 526 && io.WantCaptureMouse);
if (!blockMessage) /*if (!blockMessage)
Console.WriteLine($"{msg} - M:{io.WantCaptureMouse}, K:{io.WantTextInput}"); Console.WriteLine($"{msg} - M:{io.WantCaptureMouse}, K:{io.WantTextInput}");*/
return blockMessage ? hookResult : CallWindowProc(_wndproc, hWnd, msg, wParam, lParam); return blockMessage ? hookResult : CallWindowProc(_wndproc, hWnd, msg, wParam, lParam);
} }

View File

@@ -73,7 +73,7 @@ public class Launcher : ICorePlugin
var splash = new Splash(); var splash = new Splash();
splash.DefineStage(_lifetime = new PluginsLifetime()); splash.DefineStage(_lifetime = new PluginsLifetime(Path.GetDirectoryName(args[0])!));
InitTexts(); InitTexts();
SpaceEngineersGame.SetupBasicGameInfo(); SpaceEngineersGame.SetupBasicGameInfo();

View File

@@ -19,6 +19,6 @@ public class RenderHookPatch
[HarmonyPostfix, HarmonyPatch(typeof(MyGameForm), "OnLoad")] [HarmonyPostfix, HarmonyPatch(typeof(MyGameForm), "OnLoad")]
private static void LoadPostfix(MyGameForm __instance) private static void LoadPostfix(MyGameForm __instance)
{ {
ImGuiHandler.Instance?.HookWindow((HWND)__instance.Handle); ImGuiHandler.HookWindow((HWND)__instance.Handle);
} }
} }

View File

@@ -0,0 +1,70 @@
using CringePlugins.Config;
using CringePlugins.Resolver;
using NuGet.Versioning;
using System.Collections.Immutable;
using System.Xml.Serialization;
namespace CringePlugins.Compatability;
[XmlType("PluginConfig")]
public class PluginLoaderConfig
{
[XmlArrayItem("Id")]
public string[] Plugins { get; set; } = [];
[XmlArrayItem("Profile")]
public PluginLoaderProfile[] Profiles { get; set; } = [];
public PackagesConfig Migrate(PackagesConfig old)
{
var pluginsBuilder = ImmutableArray.CreateBuilder<PackageReference>();
var defaultVersion = new NuGetVersion(1, 0, 0);
foreach (var plugin in Plugins)
{
if (!IsValidId(plugin))
continue;
pluginsBuilder.Add(new PackageReference($"Plugin.{plugin.Replace('/', '.')}",
new(defaultVersion)));
}
var profiles = new Dictionary<string, ImmutableArray<PackageReference>>();
foreach (var profile in Profiles)
{
var builder = ImmutableArray.CreateBuilder<PackageReference>();
foreach (var plugin in profile.Plugins)
{
if (!IsValidId(plugin))
continue;
builder.Add(new PackageReference($"Plugin.{plugin.Replace('/', '.')}",
new(defaultVersion)));
}
profiles[profile.Name] = builder.ToImmutable();
}
return old with
{
Packages = pluginsBuilder.ToImmutableArray(),
Profiles = profiles
};
}
private static bool IsValidId(string pluginId)
{
var count = 0;
foreach (var c in pluginId)
{
if (c != '/')
continue;
count++;
if (count > 1)
return false;
}
return count == 1;
}
}

View File

@@ -0,0 +1,12 @@
using System.Xml.Serialization;
namespace CringePlugins.Compatability;
//https://github.com/sepluginloader/PluginLoader/blob/main/PluginLoader/Profile.cs
[XmlType("Profile")]
public class PluginLoaderProfile
{
public string Key { get; set; } = "";
public string Name { get; set; } = "";
public string[] Plugins { get; set; } = [];
}

View File

@@ -5,10 +5,10 @@ using NuGet.Models;
namespace CringePlugins.Config; namespace CringePlugins.Config;
public record PackagesConfig(ImmutableArray<PackageSource> Sources, ImmutableArray<PackageReference> Packages) public record PackagesConfig(ImmutableArray<PackageSource> Sources, ImmutableArray<PackageReference> Packages, Dictionary<string, ImmutableArray<PackageReference>> Profiles)
{ {
public static PackagesConfig Default { get; } = new([ public static PackagesConfig Default { get; } = new([
new("zznty", @"^SpaceEngineersDedicated\.ReferenceAssemblies$|^ImGui\.NET\.DirectX$|^NuGet$|^Cringe.+$|^SharedCringe$|^Plugin.+$", "https://ng.zznty.ru/v3/index.json"), new("zznty", @"^SpaceEngineersDedicated\.ReferenceAssemblies$|^ImGui\.NET\.DirectX$|^NuGet$|^Cringe.+$|^SharedCringe$|^Plugin.+$", "https://ng.zznty.ru/v3/index.json"),
new("nuget.org", string.Empty, "https://api.nuget.org/v3/index.json") new("nuget.org", string.Empty, "https://api.nuget.org/v3/index.json")
], []); ], [], []); //todo: default profile with recommended plugins?
} }

View File

@@ -15,7 +15,7 @@ using SharedCringe.Loader;
namespace CringePlugins.Loader; namespace CringePlugins.Loader;
public class PluginsLifetime : ILoadingStage public class PluginsLifetime(string gameFolder) : ILoadingStage
{ {
public static ImmutableArray<DerivedAssemblyLoadContext> Contexts { get; private set; } = []; public static ImmutableArray<DerivedAssemblyLoadContext> Contexts { get; private set; } = [];
@@ -65,7 +65,7 @@ public class PluginsLifetime : ILoadingStage
await LoadPlugins(cachedPackages, sourceMapping, packagesConfig); await LoadPlugins(cachedPackages, sourceMapping, packagesConfig);
RenderHandler.Current.RegisterComponent(new PluginListComponent(packagesConfig, sourceMapping, configPath, _plugins)); RenderHandler.Current.RegisterComponent(new PluginListComponent(packagesConfig, sourceMapping, configPath, gameFolder, _plugins));
} }
public void RegisterLifetime() public void RegisterLifetime()

View File

@@ -1,5 +1,6 @@
using System.Collections.Immutable; using System.Collections.Immutable;
using System.IO.Compression; using System.IO.Compression;
using NLog;
using NuGet; using NuGet;
using NuGet.Frameworks; using NuGet.Frameworks;
using NuGet.Models; using NuGet.Models;
@@ -9,6 +10,7 @@ namespace CringePlugins.Resolver;
public class PackageResolver(NuGetFramework runtimeFramework, ImmutableArray<PackageReference> references, PackageSourceMapping packageSources) public class PackageResolver(NuGetFramework runtimeFramework, ImmutableArray<PackageReference> references, PackageSourceMapping packageSources)
{ {
private static readonly ILogger Log = LogManager.GetCurrentClassLogger();
public async Task<ImmutableHashSet<ResolvedPackage>> ResolveAsync() public async Task<ImmutableHashSet<ResolvedPackage>> ResolveAsync()
{ {
var order = 0; var order = 0;
@@ -18,7 +20,17 @@ public class PackageResolver(NuGetFramework runtimeFramework, ImmutableArray<Pac
{ {
var client = await packageSources.GetClientAsync(reference.Id); var client = await packageSources.GetClientAsync(reference.Id);
var registrationRoot = await client.GetPackageRegistrationRootAsync(reference.Id); RegistrationRoot? registrationRoot;
try
{
registrationRoot = await client.GetPackageRegistrationRootAsync(reference.Id);
}
catch (HttpRequestException ex)
{
Log.Warn("Failed to resolve package {Package}: {Message}", reference.Id, ex.Message);
continue;
}
var items = registrationRoot.Items.SelectMany(page => var items = registrationRoot.Items.SelectMany(page =>
page.Items!.Where(b => b.CatalogEntry.PackageTypes is ["CringePlugin"])) page.Items!.Where(b => b.CatalogEntry.PackageTypes is ["CringePlugin"]))

View File

@@ -1,7 +1,9 @@
using System.Collections.Immutable; using System.Collections.Immutable;
using System.Diagnostics; using System.Diagnostics;
using System.Text.Json; using System.Text.Json;
using System.Xml.Serialization;
using CringePlugins.Abstractions; using CringePlugins.Abstractions;
using CringePlugins.Compatability;
using CringePlugins.Config; using CringePlugins.Config;
using CringePlugins.Loader; using CringePlugins.Loader;
using CringePlugins.Resolver; using CringePlugins.Resolver;
@@ -33,16 +35,18 @@ internal class PluginListComponent : IRenderComponent
private readonly PackageSourceMapping _sourceMapping; private readonly PackageSourceMapping _sourceMapping;
private ImmutableHashSet<PackageSource>? _selectedSources; private ImmutableHashSet<PackageSource>? _selectedSources;
private readonly string _configPath; private readonly string _configPath;
private readonly string _gameFolder;
private readonly ImmutableArray<PluginInstance> _plugins; private readonly ImmutableArray<PluginInstance> _plugins;
private (SearchResultEntry entry, NuGetClient client)? _selected; private (SearchResultEntry entry, NuGetClient client)? _selected;
private (PackageSource source, int index)? _selectedSource; private (PackageSource source, int index)? _selectedSource;
public PluginListComponent(PackagesConfig packagesConfig, PackageSourceMapping sourceMapping, string configPath, public PluginListComponent(PackagesConfig packagesConfig, PackageSourceMapping sourceMapping, string configPath, string gameFolder,
ImmutableArray<PluginInstance> plugins) ImmutableArray<PluginInstance> plugins)
{ {
_packagesConfig = packagesConfig; _packagesConfig = packagesConfig;
_sourceMapping = sourceMapping; _sourceMapping = sourceMapping;
_configPath = configPath; _configPath = configPath;
_gameFolder = gameFolder;
_plugins = plugins; _plugins = plugins;
_packages = packagesConfig.Packages.ToImmutableDictionary(b => b.Id, b => b.Range, _packages = packagesConfig.Packages.ToImmutableDictionary(b => b.Id, b => b.Range,
StringComparer.OrdinalIgnoreCase); StringComparer.OrdinalIgnoreCase);
@@ -251,8 +255,20 @@ internal class PluginListComponent : IRenderComponent
if (BeginTabItem("Settings")) if (BeginTabItem("Settings"))
{ {
//todo var oldConfigPath = Path.Join(_gameFolder, "Plugins", "config.xml");
Text("Todo"); if (File.Exists(oldConfigPath) && Button("Migrate PluginLoader Config"))
{
var configSerializer = new XmlSerializer(typeof(PluginLoaderConfig));
using var fs = File.OpenRead(oldConfigPath);
if (configSerializer.Deserialize(fs) is PluginLoaderConfig oldConfig)
{
_packagesConfig = oldConfig.Migrate(_packagesConfig);
Save(false);
}
}
EndTabItem(); EndTabItem();
} }
@@ -481,15 +497,15 @@ internal class PluginListComponent : IRenderComponent
_searchResults = builder.ToImmutable(); _searchResults = builder.ToImmutable();
} }
private void Save() private void Save(bool keepPackages = true)
{ {
_changed = true; _changed = true;
using var stream = File.Create(_configPath); using var stream = File.Create(_configPath);
JsonSerializer.Serialize(stream, _packagesConfig with JsonSerializer.Serialize(stream, keepPackages ? _packagesConfig with
{ {
Packages = [.._packages.Select(b => new PackageReference(b.Key, b.Value))] Packages = [.._packages.Select(b => new PackageReference(b.Key, b.Value))]
}, NuGetClient.SerializerOptions); } : _packagesConfig, NuGetClient.SerializerOptions);
} }
} }