Added options to disable launcher/plugin auto updates
All checks were successful
Build / Compute Version (push) Successful in 6s
Build / Build Nuget package (CringeBootstrap.Abstractions) (push) Successful in 4m4s
Build / Build Nuget package (NuGet) (push) Successful in 4m7s
Build / Build Nuget package (SharedCringe) (push) Successful in 4m5s
Build / Build Nuget package (CringePlugins) (push) Successful in 4m25s
Build / Build Launcher (push) Successful in 5m12s

Also ran cleanup
This commit is contained in:
2025-06-06 01:35:09 -04:00
parent bc88f0c28a
commit 94fc8a55c0
48 changed files with 381 additions and 267 deletions

View File

@@ -51,9 +51,9 @@ public class GameDirectoryAssemblyLoadContext : AssemblyLoadContext, ICoreLoadCo
AddOverride(new(name), Path.Join(AppContext.BaseDirectory, name + ".dll")); AddOverride(new(name), Path.Join(AppContext.BaseDirectory, name + ".dll"));
} }
protected override Assembly? Load(AssemblyName name) protected override Assembly? Load(AssemblyName assemblyName)
{ {
var key = name.Name ?? name.FullName[..',']; var key = assemblyName.Name ?? assemblyName.FullName[..','];
try try
{ {

View File

@@ -1,9 +1,4 @@
using System.Net; using CringeBootstrap.Abstractions;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Loader;
using CringeBootstrap.Abstractions;
using CringeLauncher.Utils; using CringeLauncher.Utils;
using CringePlugins.Config; using CringePlugins.Config;
using CringePlugins.Loader; using CringePlugins.Loader;
@@ -25,6 +20,12 @@ 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 System.Net;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Loader;
using System.Text.Json;
using Velopack; using Velopack;
using VRage; using VRage;
using VRage.Audio; using VRage.Audio;
@@ -81,6 +82,8 @@ public class Launcher : ICorePlugin
#if !DEBUG #if !DEBUG
CheckUpdates(args, logger).GetAwaiter().GetResult(); CheckUpdates(args, logger).GetAwaiter().GetResult();
#else
logger.Info("Updates disabled: {Flag}", CheckUpdatesDisabledAsync(logger).GetAwaiter().GetResult());
#endif #endif
// hook up steam as we ship it inside base context as an override // hook up steam as we ship it inside base context as an override
@@ -222,9 +225,39 @@ public class Launcher : ICorePlugin
return MyVRage.Platform.Windows.Window; return MyVRage.Platform.Windows.Window;
} }
private async Task<bool> CheckUpdatesDisabledAsync(Logger logger)
{
var path = Path.Join(_configDir.FullName, "launcher.json");
if (!File.Exists(path))
return false;
try
{
await using var stream = File.OpenRead(path);
var conf = await JsonSerializer.DeserializeAsync<LauncherConfig>(stream, ConfigHandler.SerializerOptions);
return conf?.DisableLauncherUpdates ?? false;
}
catch (Exception ex)
{
logger.Error(ex, "Error reading launcher config");
}
return false;
}
private async Task CheckUpdates(string[] args, Logger logger) private async Task CheckUpdates(string[] args, Logger logger)
{ {
if (await CheckUpdatesDisabledAsync(logger))
{
logger.Warn("Updates Disabled (may break from keen update)");
return;
}
logger.Info("Checking for updates..."); logger.Info("Checking for updates...");
var mgr = new UpdateManager("https://dl.zznty.ru/CringeLauncher/"); var mgr = new UpdateManager("https://dl.zznty.ru/CringeLauncher/");
// check for new version // check for new version
@@ -297,7 +330,7 @@ public class Launcher : ICorePlugin
"AKGM16qoFtct0IIIA8RCqEIYG4d4gXPPDNpzGuvlhLA", "24b1cd652a18461fa9b3d533ac8d6b5b", "AKGM16qoFtct0IIIA8RCqEIYG4d4gXPPDNpzGuvlhLA", "24b1cd652a18461fa9b3d533ac8d6b5b",
"1958fe26c66d4151a327ec162e4d49c8", "07c169b3b641401496d352cad1c905d6", "1958fe26c66d4151a327ec162e4d49c8", "07c169b3b641401496d352cad1c905d6",
"https://retail.epicgames.com/", EosService.CreatePlatform(), "https://retail.epicgames.com/", EosService.CreatePlatform(),
MyPlatformGameSettings.VERBOSE_NETWORK_LOGGING, ArraySegment<string>.Empty, aggregator, MyPlatformGameSettings.VERBOSE_NETWORK_LOGGING, [], aggregator,
MyMultiplayer.Channels); MyMultiplayer.Channels);
MyServiceManager.Instance.AddService<IMyServerDiscovery>(aggregator); MyServiceManager.Instance.AddService<IMyServerDiscovery>(aggregator);

View File

@@ -17,13 +17,13 @@ public static class EosInitPatch
var stIndex = ins.FindIndex(b => b.opcode == OpCodes.Stloc_1); var stIndex = ins.FindIndex(b => b.opcode == OpCodes.Stloc_1);
ins.InsertRange(stIndex, new [] ins.InsertRange(stIndex,
{ [
new CodeInstruction(OpCodes.Dup), new CodeInstruction(OpCodes.Dup),
new(OpCodes.Ldc_I4_2), // PlatformFlags.DisableOverlay new(OpCodes.Ldc_I4_2), // PlatformFlags.DisableOverlay
new(OpCodes.Conv_I8), new(OpCodes.Conv_I8),
CodeInstruction.Call("Epic.OnlineServices.Platform.Options:set_Flags"), CodeInstruction.Call("Epic.OnlineServices.Platform.Options:set_Flags"),
}); ]);
return ins; return ins;
} }

View File

@@ -42,16 +42,19 @@ public static class IntrospectionPatches
//mods need to look for specific derived types //mods need to look for specific derived types
Debug.WriteLine($"Getting special types for {__instance.FullName}"); Debug.WriteLine($"Getting special types for {__instance.FullName}");
var module = __instance.GetMainModule(); var module = __instance.GetMainModule();
__result = IntrospectionContext.Global.CollectDerivedTypes<MyObjectBuilder_Base>(module) __result =
.Concat(IntrospectionContext.Global.CollectDerivedTypes<MyStatLogic>(module)) [
.Concat(IntrospectionContext.Global.CollectAttributedTypes<MyObjectBuilderDefinitionAttribute>(module)) .. IntrospectionContext.Global.CollectDerivedTypes<MyObjectBuilder_Base>(module)
.Concat(IntrospectionContext.Global.CollectDerivedTypes<MyComponentBase>(module)) ,
.Concat(IntrospectionContext.Global.CollectAttributedTypes<MyComponentBuilderAttribute>(module)) .. IntrospectionContext.Global.CollectDerivedTypes<MyStatLogic>(module),
.Concat(IntrospectionContext.Global.CollectDerivedTypes<IMyTextSurfaceScript>(module)) .. IntrospectionContext.Global.CollectAttributedTypes<MyObjectBuilderDefinitionAttribute>(module),
.Concat(IntrospectionContext.Global.CollectDerivedTypes<IMyUseObject>(module)) .. IntrospectionContext.Global.CollectDerivedTypes<MyComponentBase>(module),
.Concat(IntrospectionContext.Global.CollectDerivedTypes<IMyHudStat>(module)) .. IntrospectionContext.Global.CollectAttributedTypes<MyComponentBuilderAttribute>(module),
.Concat(IntrospectionContext.Global.CollectAttributedTypes<MySessionComponentDescriptor>(module)) .. IntrospectionContext.Global.CollectDerivedTypes<IMyTextSurfaceScript>(module),
.ToArray(); .. IntrospectionContext.Global.CollectDerivedTypes<IMyUseObject>(module),
.. IntrospectionContext.Global.CollectDerivedTypes<IMyHudStat>(module),
.. IntrospectionContext.Global.CollectAttributedTypes<MySessionComponentDescriptor>(module),
];
return false; return false;
@@ -76,8 +79,7 @@ public static class IntrospectionPatches
} }
// static classes are abstract // static classes are abstract
__result = IntrospectionContext.Global.CollectAttributedTypes<HarmonyAttribute>(assembly.GetMainModule(), true) __result = [.. IntrospectionContext.Global.CollectAttributedTypes<HarmonyAttribute>(assembly.GetMainModule(), true)];
.ToArray();
return false; return false;
} }

View File

@@ -10,7 +10,7 @@ public static class WhitelistAllowPatch
private static void Prefix(ref MemberInfo[] members) private static void Prefix(ref MemberInfo[] members)
{ {
if (members.Any(b => b is null)) if (members.Any(b => b is null))
members = members.Where(b => b is { }).ToArray(); members = [.. members.Where(b => b is { })];
} }
private static Exception? Finalizer(Exception __exception) private static Exception? Finalizer(Exception __exception)

View File

@@ -16,20 +16,20 @@ public static class XmlRootWriterPatch
b.opcode == OpCodes.Ldstr && b.operand is "xsi:type"); b.opcode == OpCodes.Ldstr && b.operand is "xsi:type");
ins[index].operand = "xsi"; ins[index].operand = "xsi";
ins.InsertRange(index + 1, new[] ins.InsertRange(index + 1,
{ [
new CodeInstruction(OpCodes.Ldstr, "type"), new CodeInstruction(OpCodes.Ldstr, "type"),
new CodeInstruction(OpCodes.Ldstr, "http://www.w3.org/2001/XMLSchema-instance") new CodeInstruction(OpCodes.Ldstr, "http://www.w3.org/2001/XMLSchema-instance")
}); ]);
var instruction = ins[ins.FindIndex(b => b.opcode == OpCodes.Callvirt)]; var instruction = ins[ins.FindIndex(b => b.opcode == OpCodes.Callvirt)];
instruction.operand = AccessTools.Method(typeof(XmlWriter), "WriteAttributeString", new[] instruction.operand = AccessTools.Method(typeof(XmlWriter), "WriteAttributeString",
{ [
typeof(string), typeof(string),
typeof(string), typeof(string),
typeof(string), typeof(string),
typeof(string) typeof(string)
}); ]);
return ins; return ins;
} }

View File

@@ -9,16 +9,18 @@ namespace CringePlugins.Config;
public sealed class ConfigHandler public sealed class ConfigHandler
{ {
private static readonly Logger Log = LogManager.GetCurrentClassLogger(); public static readonly JsonSerializerOptions SerializerOptions = new(NuGetClient.SerializerOptions)
private readonly DirectoryInfo _configDirectory;
private readonly JsonSerializerOptions _serializerOptions = new(NuGetClient.SerializerOptions)
{ {
WriteIndented = true, WriteIndented = true,
AllowTrailingCommas = true, AllowTrailingCommas = true,
ReadCommentHandling = JsonCommentHandling.Skip ReadCommentHandling = JsonCommentHandling.Skip
}; };
private static readonly Logger Log = LogManager.GetCurrentClassLogger();
private readonly DirectoryInfo _configDirectory;
private readonly EvaluationOptions _evaluationOptions = new() private readonly EvaluationOptions _evaluationOptions = new()
{ {
OutputFormat = OutputFormat.List, OutputFormat = OutputFormat.List,
@@ -67,7 +69,7 @@ public sealed class ConfigHandler
T instance; T instance;
try try
{ {
instance = jsonNode.Deserialize<T>(_serializerOptions)!; instance = jsonNode.Deserialize<T>(SerializerOptions)!;
} }
catch (JsonException e) catch (JsonException e)
{ {
@@ -84,7 +86,7 @@ public sealed class ConfigHandler
{ {
var spec = IConfigurationSpecProvider.FromType(typeof(T)); var spec = IConfigurationSpecProvider.FromType(typeof(T));
var jsonNode = JsonSerializer.SerializeToNode(newValue, _serializerOptions)!; var jsonNode = JsonSerializer.SerializeToNode(newValue, SerializerOptions)!;
if (spec != null && !TryValidate(name, spec, jsonNode)) if (spec != null && !TryValidate(name, spec, jsonNode))
throw new JsonException($"Supplied config value for {name} is invalid"); throw new JsonException($"Supplied config value for {name} is invalid");
@@ -96,7 +98,7 @@ public sealed class ConfigHandler
{ {
Indented = true Indented = true
}); });
jsonNode.WriteTo(writer, _serializerOptions); jsonNode.WriteTo(writer, SerializerOptions);
ConfigReloaded?.Invoke(this, new ConfigValue<T>(name, newValue)); ConfigReloaded?.Invoke(this, new ConfigValue<T>(name, newValue));
} }

View File

@@ -0,0 +1,5 @@
namespace CringePlugins.Config;
public sealed record LauncherConfig(bool DisableLauncherUpdates, bool DisablePluginUpdates)
{
public static LauncherConfig Default => new(false, false);
}

View File

@@ -28,6 +28,7 @@ internal class PluginsLifetime(ConfigHandler configHandler, HttpClient client) :
private readonly NuGetRuntimeFramework _runtimeFramework = new(NuGetFramework.ParseFolder("net9.0-windows10.0.19041.0"), RuntimeInformation.RuntimeIdentifier); private readonly NuGetRuntimeFramework _runtimeFramework = new(NuGetFramework.ParseFolder("net9.0-windows10.0.19041.0"), RuntimeInformation.RuntimeIdentifier);
private ConfigReference<PackagesConfig>? _configReference; private ConfigReference<PackagesConfig>? _configReference;
private ConfigReference<LauncherConfig>? _launcherConfig;
public async ValueTask Load(ISplashProgress progress) public async ValueTask Load(ISplashProgress progress)
{ {
@@ -40,7 +41,9 @@ internal class PluginsLifetime(ConfigHandler configHandler, HttpClient client) :
progress.Report("Loading config"); progress.Report("Loading config");
_configReference = configHandler.RegisterConfig("packages", PackagesConfig.Default); _configReference = configHandler.RegisterConfig("packages", PackagesConfig.Default);
_launcherConfig = configHandler.RegisterConfig("launcher", LauncherConfig.Default);
var packagesConfig = _configReference.Value; var packagesConfig = _configReference.Value;
var launcherConfig = _launcherConfig.Value;
progress.Report("Resolving packages"); progress.Report("Resolving packages");
@@ -48,12 +51,14 @@ internal class PluginsLifetime(ConfigHandler configHandler, HttpClient client) :
// TODO take into account the target framework runtime identifier // TODO take into account the target framework runtime identifier
var resolver = new PackageResolver(_runtimeFramework.Framework, packagesConfig.Packages, sourceMapping); var resolver = new PackageResolver(_runtimeFramework.Framework, packagesConfig.Packages, sourceMapping);
var packages = await resolver.ResolveAsync(); var cacheDir = _dir.CreateSubdirectory("cache");
var packages = await resolver.ResolveAsync(cacheDir, launcherConfig.DisablePluginUpdates);
progress.Report("Downloading packages"); progress.Report("Downloading packages");
var builtInPackages = await BuiltInPackages.GetPackagesAsync(_runtimeFramework); var builtInPackages = await BuiltInPackages.GetPackagesAsync(_runtimeFramework);
var cachedPackages = await resolver.DownloadPackagesAsync(_dir.CreateSubdirectory("cache"), packages, builtInPackages.Keys.ToHashSet(), progress); var cachedPackages = await PackageResolver.DownloadPackagesAsync(cacheDir, packages, builtInPackages.Keys.ToHashSet(), progress);
progress.Report("Loading plugins"); progress.Report("Loading plugins");
@@ -62,7 +67,7 @@ internal class PluginsLifetime(ConfigHandler configHandler, HttpClient client) :
await LoadPlugins(cachedPackages, sourceMapping, packagesConfig, builtInPackages); await LoadPlugins(cachedPackages, sourceMapping, packagesConfig, builtInPackages);
RenderHandler.Current.RegisterComponent(new PluginListComponent(_configReference, sourceMapping, MyFileSystem.ExePath, _plugins)); RenderHandler.Current.RegisterComponent(new PluginListComponent(_configReference, _launcherConfig, sourceMapping, MyFileSystem.ExePath, _plugins));
} }
public void RegisterLifetime() public void RegisterLifetime()
@@ -105,9 +110,9 @@ internal class PluginsLifetime(ConfigHandler configHandler, HttpClient client) :
{ {
if (builtInPackages.ContainsKey(package.Package.Id)) continue; if (builtInPackages.ContainsKey(package.Package.Id)) continue;
var client = await sourceMapping.GetClientAsync(package.Package.Id); var packageClient = await sourceMapping.GetClientAsync(package.Package.Id);
if (client == null) if (packageClient == null)
{ {
Log.Warn("Client not found for {Package}", package.Package.Id); Log.Warn("Client not found for {Package}", package.Package.Id);
continue; continue;
@@ -133,7 +138,7 @@ internal class PluginsLifetime(ConfigHandler configHandler, HttpClient client) :
} }
} }
var sourceName = packagesConfig.Sources.First(b => b.Url == client.ToString()).Name; var sourceName = packagesConfig.Sources.First(b => b.Url == packageClient.ToString()).Name;
LoadComponent(plugins, Path.Join(dir, $"{package.Package.Id}.dll"), LoadComponent(plugins, Path.Join(dir, $"{package.Package.Id}.dll"),
new(package.Package.Id, package.Package.Version, sourceName)); new(package.Package.Id, package.Package.Version, sourceName));
} }

View File

@@ -1,17 +1,17 @@
using System.Collections.Immutable; using NLog;
using System.IO.Compression;
using NLog;
using NuGet; using NuGet;
using NuGet.Frameworks; using NuGet.Frameworks;
using NuGet.Models; using NuGet.Models;
using NuGet.Versioning; using NuGet.Versioning;
using System.Collections.Immutable;
using System.IO.Compression;
namespace CringePlugins.Resolver; 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(); private static readonly ILogger Log = LogManager.GetCurrentClassLogger();
public async Task<ImmutableSortedSet<ResolvedPackage>> ResolveAsync() public async Task<ImmutableSortedSet<ResolvedPackage>> ResolveAsync(DirectoryInfo baseDir, bool disableUpdates)
{ {
var order = 0; var order = 0;
var packages = new Dictionary<Package, CatalogEntry>(); var packages = new Dictionary<Package, CatalogEntry>();
@@ -39,7 +39,24 @@ public class PackageResolver(NuGetFramework runtimeFramework, ImmutableArray<Pac
page.Items!.Where(b => b.CatalogEntry.PackageTypes is ["CringePlugin"])) page.Items!.Where(b => b.CatalogEntry.PackageTypes is ["CringePlugin"]))
.ToImmutableDictionary(b => b.CatalogEntry.Version); .ToImmutableDictionary(b => b.CatalogEntry.Version);
var version = items.Values.Select(b => b.CatalogEntry.Version).OrderDescending().First(b => reference.Range.Satisfies(b)); var version = items.Values.Select(b => b.CatalogEntry.Version).OrderDescending().First(reference.Range.Satisfies);
if (disableUpdates)
{
if (GetLatestInstalledVersion(baseDir, reference.Id, reference.Range) is { } installedVersion && items.ContainsKey(installedVersion))
{
if (installedVersion < version)
{
Log.Warn("Using outdated version of package {Package} {InstalledVersion} instead of {AvailableVersion} due to updates being disabled",
reference.Id, installedVersion, version);
}
version = installedVersion;
}
else
{
Log.Warn("No valid installed version found for package {Package}", reference.Id);
}
}
if (version is null) if (version is null)
throw new NotSupportedException($"Unable to find version for package {reference.Id}"); throw new NotSupportedException($"Unable to find version for package {reference.Id}");
@@ -118,6 +135,20 @@ public class PackageResolver(NuGetFramework runtimeFramework, ImmutableArray<Pac
if (version is null) if (version is null)
throw new NotSupportedException($"Unable to find version for package {id} as dependency of {package.Package}"); throw new NotSupportedException($"Unable to find version for package {id} as dependency of {package.Package}");
if (disableUpdates)
{
if (GetLatestInstalledVersion(baseDir, id, versionRange) is { } installedVersion && items.ContainsKey(installedVersion))
{
if (installedVersion < version)
{
Log.Warn("Using outdated version of dependency package {Package} {InstalledVersion} instead of {AvailableVersion} due to updates being disabled",
id, installedVersion, version);
}
version = installedVersion;
}
//todo: warnings here? we'd need to check against builtin packages
}
var catalogEntry = items[version].CatalogEntry; var catalogEntry = items[version].CatalogEntry;
var dependencyPackage = new Package(i, id, version); var dependencyPackage = new Package(i, id, version);
@@ -182,7 +213,26 @@ public class PackageResolver(NuGetFramework runtimeFramework, ImmutableArray<Pac
return set.ToImmutable(); return set.ToImmutable();
} }
public async Task<ImmutableHashSet<CachedPackage>> DownloadPackagesAsync(DirectoryInfo baseDirectory, private static NuGetVersion? GetLatestInstalledVersion(DirectoryInfo baseDirectory, string id, VersionRange range)
{
var dir = new DirectoryInfo(Path.Join(baseDirectory.FullName, id));
if (!dir.Exists)
return null;
NuGetVersion? maxVersion = null;
foreach (var subdir in dir.GetDirectories())
{
if (NuGetVersion.TryParse(subdir.Name, out var version) && range.Satisfies(version) && (maxVersion == null || version > maxVersion))
{
maxVersion = version;
}
}
return maxVersion;
}
public static async Task<ImmutableHashSet<CachedPackage>> DownloadPackagesAsync(DirectoryInfo baseDirectory,
IReadOnlySet<ResolvedPackage> resolvedPackages, IReadOnlySet<string>? ignorePackages = null, IProgress<float>? progress = null) IReadOnlySet<ResolvedPackage> resolvedPackages, IReadOnlySet<string>? ignorePackages = null, IProgress<float>? progress = null)
{ {
var packages = ImmutableHashSet<CachedPackage>.Empty.ToBuilder(); var packages = ImmutableHashSet<CachedPackage>.Empty.ToBuilder();
@@ -206,7 +256,7 @@ public class PackageResolver(NuGetFramework runtimeFramework, ImmutableArray<Pac
var client = (package as RemoteDependencyPackage)?.Client ?? ((RemotePackage)package).Client; var client = (package as RemoteDependencyPackage)?.Client ?? ((RemotePackage)package).Client;
await using var stream = await client.GetPackageContentStreamAsync(package.Package.Id, package.Package.Version); await using var stream = await client.GetPackageContentStreamAsync(package.Package.Id, package.Package.Version);
using var memStream = new MemoryStream(); await using var memStream = new MemoryStream();
await stream.CopyToAsync(memStream); await stream.CopyToAsync(memStream);
memStream.Position = 0; memStream.Position = 0;
using var archive = new ZipArchive(memStream, ZipArchiveMode.Read); using var archive = new ZipArchive(memStream, ZipArchiveMode.Read);

View File

@@ -25,7 +25,6 @@ public sealed class NotificationsComponent : IRenderComponent
var lastY = _notificationSize.Y; var lastY = _notificationSize.Y;
var viewportPos = ImGui.GetMainViewport().Pos; var viewportPos = ImGui.GetMainViewport().Pos;
//todo: consider adding a limit to the number of messages that can be displayed at once //todo: consider adding a limit to the number of messages that can be displayed at once
for (var i = Notifications.Count; i-- > 0;) for (var i = Notifications.Count; i-- > 0;)
{ {

View File

@@ -38,10 +38,13 @@ internal class PluginListComponent : IRenderComponent
private int _selectedProfile = -1; private int _selectedProfile = -1;
private ImmutableArray<Profile> _profiles; private ImmutableArray<Profile> _profiles;
private bool _disableUpdates;
private bool _disablePluginUpdates;
private bool _changed; private bool _restartRequired;
private bool _open = true; private bool _open = true;
private readonly ConfigReference<PackagesConfig> _packagesConfig; private readonly ConfigReference<PackagesConfig> _packagesConfig;
private readonly ConfigReference<LauncherConfig> _launcherConfig;
private readonly PackageSourceMapping _sourceMapping; private readonly PackageSourceMapping _sourceMapping;
private readonly JsonSerializerOptions _serializerOptions = new(JsonSerializerDefaults.Web); private readonly JsonSerializerOptions _serializerOptions = new(JsonSerializerDefaults.Web);
private ImmutableHashSet<PackageSource>? _selectedSources; private ImmutableHashSet<PackageSource>? _selectedSources;
@@ -51,10 +54,11 @@ internal class PluginListComponent : IRenderComponent
private (PackageSource source, int index)? _selectedSource; private (PackageSource source, int index)? _selectedSource;
private readonly IImGuiImageService _imageService = GameServicesExtension.GameServices.GetRequiredService<IImGuiImageService>(); private readonly IImGuiImageService _imageService = GameServicesExtension.GameServices.GetRequiredService<IImGuiImageService>();
public PluginListComponent(ConfigReference<PackagesConfig> packagesConfig, PackageSourceMapping sourceMapping, string gameFolder, public PluginListComponent(ConfigReference<PackagesConfig> packagesConfig, ConfigReference<LauncherConfig> launcherConfig,
ImmutableArray<PluginInstance> plugins) PackageSourceMapping sourceMapping, string gameFolder, ImmutableArray<PluginInstance> plugins)
{ {
_packagesConfig = packagesConfig; _packagesConfig = packagesConfig;
_launcherConfig = launcherConfig;
_sourceMapping = sourceMapping; _sourceMapping = sourceMapping;
_gameFolder = gameFolder; _gameFolder = gameFolder;
_plugins = plugins; _plugins = plugins;
@@ -62,6 +66,9 @@ internal class PluginListComponent : IRenderComponent
StringComparer.OrdinalIgnoreCase); StringComparer.OrdinalIgnoreCase);
_profiles = packagesConfig.Value.Profiles; _profiles = packagesConfig.Value.Profiles;
_disablePluginUpdates = _launcherConfig.Value.DisablePluginUpdates;
_disableUpdates = _launcherConfig.Value.DisableLauncherUpdates;
MyScreenManager.ScreenAdded += ScreenChanged; MyScreenManager.ScreenAdded += ScreenChanged;
MyScreenManager.ScreenRemoved += ScreenChanged; MyScreenManager.ScreenRemoved += ScreenChanged;
} }
@@ -83,9 +90,9 @@ internal class PluginListComponent : IRenderComponent
return; return;
} }
if (_changed) if (_restartRequired)
{ {
TextDisabled("Changes would be applied on the next restart"); TextDisabled("Changes will be applied on the next restart");
SameLine(); SameLine();
if (Button("Restart Now")) if (Button("Restart Now"))
{ {
@@ -279,6 +286,14 @@ internal class PluginListComponent : IRenderComponent
if (BeginTabItem("Settings")) if (BeginTabItem("Settings"))
{ {
if (Checkbox("Disable Plugin Updates", ref _disablePluginUpdates))
{
_launcherConfig.Value = _launcherConfig.Value with { DisablePluginUpdates = _disablePluginUpdates };
}
if (Checkbox("Disable Launcher Updates", ref _disableUpdates))
{
_launcherConfig.Value = _launcherConfig.Value with { DisableLauncherUpdates = _disableUpdates };
}
var oldConfigPath = Path.Join(_gameFolder, "Plugins", "config.xml"); var oldConfigPath = Path.Join(_gameFolder, "Plugins", "config.xml");
if (File.Exists(oldConfigPath)) if (File.Exists(oldConfigPath))
{ {
@@ -299,6 +314,8 @@ internal class PluginListComponent : IRenderComponent
var hasModLodaer = _packages.ContainsKey("Plugin.ClientModLoader"); var hasModLodaer = _packages.ContainsKey("Plugin.ClientModLoader");
SameLine();
if (!hasModLodaer) if (!hasModLodaer)
BeginDisabled(); BeginDisabled();
@@ -310,11 +327,12 @@ internal class PluginListComponent : IRenderComponent
if (configSerializer.Deserialize(fs) is PluginLoaderConfig plConfig) if (configSerializer.Deserialize(fs) is PluginLoaderConfig plConfig)
{ {
var dir = new DirectoryInfo(Path.Join(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), var dir = new DirectoryInfo(Path.Join(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
"CringeLauncher")); "config", "CringeLauncher"));
var file = Path.Join(dir.FullName, "mods.json"); var file = Path.Join(dir.FullName, "mods.json");
using var modsFile = File.Create(file); using var modsFile = File.Create(file);
JsonSerializer.Serialize(modsFile, plConfig.GetMods(), _serializerOptions); JsonSerializer.Serialize(modsFile, plConfig.GetMods(), _serializerOptions);
_restartRequired = true;
} }
} }
@@ -535,7 +553,7 @@ internal class PluginListComponent : IRenderComponent
{ {
_selectedSources = selected _selectedSources = selected
? (_selectedSources?.Count ?? 0) + 1 == _packagesConfig.Value.Sources.Length ? null : _selectedSources?.Add(source) ? (_selectedSources?.Count ?? 0) + 1 == _packagesConfig.Value.Sources.Length ? null : _selectedSources?.Add(source)
: (_selectedSources ?? _packagesConfig.Value.Sources.ToImmutableHashSet()).Remove(source); : (_selectedSources ?? [.. _packagesConfig.Value.Sources]).Remove(source);
_searchTask = RefreshAsync(); _searchTask = RefreshAsync();
EndCombo(); EndCombo();
@@ -733,7 +751,7 @@ internal class PluginListComponent : IRenderComponent
await foreach (var source in _sourceMapping) await foreach (var source in _sourceMapping)
{ {
if (source == null || _selectedSources is not null && _selectedSources.All(b => b.Url != source.ToString())) if (source == null || _selectedSources?.All(b => b.Url != source.ToString()) == true)
continue; continue;
try try
@@ -758,7 +776,7 @@ internal class PluginListComponent : IRenderComponent
Packages = [.. _packages.Select(b => new PackageReference(b.Key, b.Value))] Packages = [.. _packages.Select(b => new PackageReference(b.Key, b.Value))]
} : _packagesConfig; } : _packagesConfig;
_changed = true; _restartRequired = true;
} }
private static unsafe int ComparePlugins(PluginInstance x, PluginInstance y, ImGuiTableSortSpecsPtr specs) private static unsafe int ComparePlugins(PluginInstance x, PluginInstance y, ImGuiTableSortSpecsPtr specs)

View File

@@ -156,7 +156,7 @@ public class DependencyManifestBuilder(DirectoryInfo cacheDirectory, PackageSour
{ {
await using var stream = await client.GetPackageContentStreamAsync(entry.Id, entry.Version); await using var stream = await client.GetPackageContentStreamAsync(entry.Id, entry.Version);
using var memStream = new MemoryStream(); await using var memStream = new MemoryStream();
await stream.CopyToAsync(memStream); await stream.CopyToAsync(memStream);
memStream.Position = 0; memStream.Position = 0;
using var archive = new ZipArchive(memStream, ZipArchiveMode.Read); using var archive = new ZipArchive(memStream, ZipArchiveMode.Read);

View File

@@ -7,7 +7,7 @@ using NuGet.Versioning;
namespace NuGet; namespace NuGet;
public class NuGetClient public sealed class NuGetClient
{ {
private readonly Uri _index; private readonly Uri _index;
private readonly HttpClient _client; private readonly HttpClient _client;