diff --git a/CringeLauncher/Patches/ModAssemblyLoadContextPatches.cs b/CringeLauncher/Patches/ModAssemblyLoadContextPatches.cs index 3769f81..7410998 100644 --- a/CringeLauncher/Patches/ModAssemblyLoadContextPatches.cs +++ b/CringeLauncher/Patches/ModAssemblyLoadContextPatches.cs @@ -12,7 +12,7 @@ using VRage.Scripting; namespace CringeLauncher.Patches; [HarmonyPatch] -public static class ModAssemblyLoadContextPatches +public static class ModAssemblyLoadContextPatches //todo: use ModScriptCompilerPatch { private static ModAssemblyLoadContext? _currentSessionContext; private static readonly MyConcurrentHashSet AssemblyNames = []; @@ -30,7 +30,7 @@ public static class ModAssemblyLoadContextPatches .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); + //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)); })) @@ -39,7 +39,7 @@ public static class ModAssemblyLoadContextPatches .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); + //if (target is not MyApiTarget.Mod) return Assembly.Load(assembly); ArgumentNullException.ThrowIfNull(_currentSessionContext, "No session context"); return _currentSessionContext.LoadFromStream(new MemoryStream(assembly)); })) diff --git a/CringePlugins/Compatability/PluginLoaderConfig.cs b/CringePlugins/Compatability/PluginLoaderConfig.cs index c65f373..d3d5925 100644 --- a/CringePlugins/Compatability/PluginLoaderConfig.cs +++ b/CringePlugins/Compatability/PluginLoaderConfig.cs @@ -9,24 +9,39 @@ namespace CringePlugins.Compatability; [XmlType("PluginConfig")] public class PluginLoaderConfig { - [XmlArrayItem("Id")] - public string[] Plugins { get; set; } = []; + /// + /// Raw plugin and mod ids + /// + [XmlArrayItem("Id")] public string[] Plugins { get; set; } = []; - [XmlArrayItem("Profile")] - public PluginLoaderProfile[] Profiles { get; set; } = []; + /// + /// Raw profiles + /// + [XmlArrayItem("Profile")] public PluginLoaderProfile[] Profiles { get; set; } = []; - public PackagesConfig Migrate(PackagesConfig old) + public PackagesConfig MigratePlugins(PackagesConfig old) { + //ensure defaults are installed + var defaultConfig = PackagesConfig.Default; + var sources = old.Sources.ToBuilder(); + foreach (var source in defaultConfig.Sources) + { + if (!sources.Contains(source)) + sources.Add(source); + } + var pluginsBuilder = ImmutableArray.CreateBuilder(); var defaultVersion = new NuGetVersion(1, 0, 0); - foreach (var plugin in Plugins) + foreach (var plugin in GetPlugins()) { - if (!IsValidId(plugin)) - continue; - pluginsBuilder.Add(new PackageReference($"Plugin.{plugin.Replace('/', '.')}", new(defaultVersion))); } + foreach (var package in defaultConfig.Packages) + { + if (!pluginsBuilder.Any(x => x.Id == package.Id)) + pluginsBuilder.Add(package); + } var profiles = new Dictionary>(); foreach (var profile in Profiles) @@ -34,24 +49,85 @@ public class PluginLoaderConfig var builder = ImmutableArray.CreateBuilder(); foreach (var plugin in profile.Plugins) { - if (!IsValidId(plugin)) + if (!IsValidPluginId(plugin)) continue; builder.Add(new PackageReference($"Plugin.{plugin.Replace('/', '.')}", new(defaultVersion))); } + foreach (var package in defaultConfig.Packages) + { + if (!builder.Any(x => x.Id == package.Id)) + builder.Add(package); + } + profiles[profile.Name] = builder.ToImmutable(); } return old with { - Packages = pluginsBuilder.ToImmutableArray(), - Profiles = profiles + Packages = pluginsBuilder.ToImmutable(), + Profiles = profiles, + Sources = sources.ToImmutable() }; } - private static bool IsValidId(string pluginId) + public HashSet GetPlugins() => GetPlugins(Plugins); + public HashSet GetMods() => GetMods(Plugins); + public Dictionary> GetPluginProfiles() + { + var dict = new Dictionary>(Profiles.Length); + + foreach (var profile in Profiles) + { + dict[profile.Name] = GetPlugins(profile.Plugins); + } + + return dict; + } + public Dictionary> GetModProfiles() + { + var dict = new Dictionary>(Profiles.Length); + + foreach (var profile in Profiles) + { + dict[profile.Name] = GetMods(profile.Plugins); + } + + return dict; + } + + + private static HashSet GetPlugins(string[] mixed) + { + var plugins = new HashSet(); + foreach (var plugin in mixed) + { + if (!IsValidPluginId(plugin)) + continue; + + plugins.Add(plugin); + } + + return plugins; + } + + private static HashSet GetMods(string[] mixed) + { + var mods = new HashSet(); + foreach (var plugin in mixed) + { + if (!ulong.TryParse(plugin, out var modId)) + continue; + + mods.Add(modId); + } + + return mods; + } + + private static bool IsValidPluginId(string pluginId) { var count = 0; foreach (var c in pluginId) diff --git a/CringePlugins/Config/PackagesConfig.cs b/CringePlugins/Config/PackagesConfig.cs index 0488aa5..d3d9a77 100644 --- a/CringePlugins/Config/PackagesConfig.cs +++ b/CringePlugins/Config/PackagesConfig.cs @@ -10,5 +10,9 @@ public record PackagesConfig(ImmutableArray Sources, ImmutableArr 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("nuget.org", string.Empty, "https://api.nuget.org/v3/index.json") - ], [], []); //todo: default profile with recommended plugins? + ], + [ + new PackageReference("Plugin.ClientModLoader", new(new(0,0,0))) + ], + []); //todo: default profile with recommended plugins? } \ No newline at end of file diff --git a/CringePlugins/Ui/PluginListComponent.cs b/CringePlugins/Ui/PluginListComponent.cs index e0663a2..c085914 100644 --- a/CringePlugins/Ui/PluginListComponent.cs +++ b/CringePlugins/Ui/PluginListComponent.cs @@ -33,6 +33,7 @@ internal class PluginListComponent : IRenderComponent private bool _open = true; private PackagesConfig _packagesConfig; private readonly PackageSourceMapping _sourceMapping; + private readonly JsonSerializerOptions _serializerOptions = new(JsonSerializerDefaults.Web); private ImmutableHashSet? _selectedSources; private readonly string _configPath; private readonly string _gameFolder; @@ -255,17 +256,50 @@ internal class PluginListComponent : IRenderComponent if (BeginTabItem("Settings")) { var oldConfigPath = Path.Join(_gameFolder, "Plugins", "config.xml"); - if (File.Exists(oldConfigPath) && Button("Migrate PluginLoader Config")) + if (File.Exists(oldConfigPath)) { - var configSerializer = new XmlSerializer(typeof(PluginLoaderConfig)); - using var fs = File.OpenRead(oldConfigPath); - - if (configSerializer.Deserialize(fs) is PluginLoaderConfig oldConfig) + if (Button("Migrate PluginLoader Plugins")) { - _packagesConfig = oldConfig.Migrate(_packagesConfig); + var configSerializer = new XmlSerializer(typeof(PluginLoaderConfig)); + using var fs = File.OpenRead(oldConfigPath); + if (configSerializer.Deserialize(fs) is PluginLoaderConfig oldConfig) + { + _packagesConfig = oldConfig.MigratePlugins(_packagesConfig); - Save(false); + Save(false); + + _packages = _packagesConfig.Packages.ToImmutableDictionary(b => b.Id, b => b.Range, StringComparer.OrdinalIgnoreCase); + } + } + + var hasModLodaer = _packages.ContainsKey("Plugin.ClientModLoader"); + + if (!hasModLodaer) + BeginDisabled(); + + if (Button("Migrate Pluginloader Mods")) + { + var configSerializer = new XmlSerializer(typeof(PluginLoaderConfig)); + using var fs = File.OpenRead(oldConfigPath); + + if (configSerializer.Deserialize(fs) is PluginLoaderConfig plConfig) + { + var dir = new DirectoryInfo(Path.Join(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), + "CringeLauncher")); + var file = Path.Join(dir.FullName, "mods.json"); + + using var modsFile = File.Create(file); + JsonSerializer.Serialize(modsFile, plConfig.GetMods(), _serializerOptions); + } + } + + if (!hasModLodaer) + { + if (IsItemHovered()) + SetTooltip("Requires Plugin.ClientModLoader"); + + EndDisabled(); } } EndTabItem();