diff --git a/CringeBootstrap/packages.lock.json b/CringeBootstrap/packages.lock.json
index 572e75b..9e8d188 100644
--- a/CringeBootstrap/packages.lock.json
+++ b/CringeBootstrap/packages.lock.json
@@ -337,7 +337,6 @@
"Microsoft.CodeAnalysis.CSharp": "[4.13.0, )",
"NLog": "[5.4.0, )",
"SpaceEngineersDedicated.ReferenceAssemblies": "[1.*, )",
- "Steamworks.NET": "[20.1.0, )",
"System.Diagnostics.PerformanceCounter": "[9.0.4, )",
"System.Management": "[9.0.4, )",
"System.Private.ServiceModel": "[4.10.3, )",
@@ -355,6 +354,7 @@
"NuGet": "[1.0.0, )",
"SharedCringe": "[1.0.0, )",
"SpaceEngineersDedicated.ReferenceAssemblies": "[1.*, )",
+ "Steamworks.NET": "[20.1.0, 20.1.0]",
"dnlib": "[4.4.0, )"
}
},
diff --git a/CringeLauncher/CringeLauncher.csproj b/CringeLauncher/CringeLauncher.csproj
index 2a407c1..b0c6efe 100644
--- a/CringeLauncher/CringeLauncher.csproj
+++ b/CringeLauncher/CringeLauncher.csproj
@@ -40,7 +40,6 @@
-
diff --git a/CringeLauncher/packages.lock.json b/CringeLauncher/packages.lock.json
index 79a2ec5..f36cf41 100644
--- a/CringeLauncher/packages.lock.json
+++ b/CringeLauncher/packages.lock.json
@@ -62,12 +62,6 @@
"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": {
"type": "Direct",
"requested": "[9.0.4, )",
@@ -262,6 +256,11 @@
"System.Runtime.CompilerServices.Unsafe": "4.5.1"
}
},
+ "Steamworks.NET": {
+ "type": "Transitive",
+ "resolved": "20.1.0",
+ "contentHash": "+GntwnyJ5tCNvUIaQxv2+ehDvZJzGUqlSB5xRBk1hTj1qqBJ6s4vK/OfGD/jae7aTmXiGSm8wpJORosNtQevJQ=="
+ },
"System.Buffers": {
"type": "Transitive",
"resolved": "4.5.1",
@@ -376,6 +375,7 @@
"NuGet": "[1.0.0, )",
"SharedCringe": "[1.0.0, )",
"SpaceEngineersDedicated.ReferenceAssemblies": "[1.*, )",
+ "Steamworks.NET": "[20.1.0, 20.1.0]",
"dnlib": "[4.4.0, )"
}
},
@@ -397,12 +397,6 @@
}
},
"net9.0-windows10.0.19041/win-x64": {
- "Steamworks.NET": {
- "type": "Direct",
- "requested": "[20.1.0, )",
- "resolved": "20.1.0",
- "contentHash": "+GntwnyJ5tCNvUIaQxv2+ehDvZJzGUqlSB5xRBk1hTj1qqBJ6s4vK/OfGD/jae7aTmXiGSm8wpJORosNtQevJQ=="
- },
"System.Diagnostics.PerformanceCounter": {
"type": "Direct",
"requested": "[9.0.4, )",
@@ -431,6 +425,11 @@
"System.Runtime.CompilerServices.Unsafe": "6.0.0"
}
},
+ "Steamworks.NET": {
+ "type": "Transitive",
+ "resolved": "20.1.0",
+ "contentHash": "+GntwnyJ5tCNvUIaQxv2+ehDvZJzGUqlSB5xRBk1hTj1qqBJ6s4vK/OfGD/jae7aTmXiGSm8wpJORosNtQevJQ=="
+ },
"System.Diagnostics.EventLog": {
"type": "Transitive",
"resolved": "9.0.4",
diff --git a/CringePlugins/CringePlugins.csproj b/CringePlugins/CringePlugins.csproj
index ad87dea..8034bdf 100644
--- a/CringePlugins/CringePlugins.csproj
+++ b/CringePlugins/CringePlugins.csproj
@@ -28,6 +28,7 @@
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
diff --git a/CringePlugins/Loader/PluginsLifetime.cs b/CringePlugins/Loader/PluginsLifetime.cs
index df47271..3fc27c9 100644
--- a/CringePlugins/Loader/PluginsLifetime.cs
+++ b/CringePlugins/Loader/PluginsLifetime.cs
@@ -59,15 +59,16 @@ public class PluginsLifetime(string gameFolder) : ILoadingStage
var packages = await resolver.ResolveAsync();
progress.Report("Downloading packages");
-
- var cachedPackages = await resolver.DownloadPackagesAsync(_dir.CreateSubdirectory("cache"), packages, progress);
+
+ var builtInPackages = BuiltInPackages.GetPackages(_runtimeFramework).ToImmutableDictionary(package => package.Package.Id);
+ var cachedPackages = await resolver.DownloadPackagesAsync(_dir.CreateSubdirectory("cache"), packages, builtInPackages.Keys.ToHashSet(), progress);
progress.Report("Loading plugins");
//we can move this, but it should be before plugin init
RenderHandler.Current.RegisterComponent(new NotificationsComponent());
- await LoadPlugins(cachedPackages, sourceMapping, packagesConfig);
+ await LoadPlugins(cachedPackages, sourceMapping, packagesConfig, builtInPackages);
RenderHandler.Current.RegisterComponent(new PluginListComponent(packagesConfig, sourceMapping, configPath, gameFolder, _plugins));
}
@@ -91,12 +92,9 @@ public class PluginsLifetime(string gameFolder) : ILoadingStage
}
private async Task LoadPlugins(IReadOnlyCollection packages, PackageSourceMapping sourceMapping,
- PackagesConfig packagesConfig)
+ PackagesConfig packagesConfig, ImmutableDictionary builtInPackages)
{
var plugins = _plugins.ToBuilder();
-
- var builtInPackages = BuiltInPackages.GetPackages(_runtimeFramework)
- .ToImmutableDictionary(package => package.Package.Id);
var resolvedPackages = builtInPackages.ToDictionary();
foreach (var package in packages)
@@ -120,8 +118,17 @@ public class PluginsLifetime(string gameFolder) : ILoadingStage
var path = Path.Join(dir, $"{package.Package.Id}.deps.json");
if (!File.Exists(path))
{
- await using var stream = File.Create(path);
- await manifestBuilder.WriteDependencyManifestAsync(stream, package.Entry, _runtimeFramework);
+ try
+ {
+ await using var stream = File.Create(path);
+ await manifestBuilder.WriteDependencyManifestAsync(stream, package.Entry, _runtimeFramework);
+ }
+ catch (Exception ex)
+ {
+ Log.Error(ex, $"Failed to write dependency manifest for {path}");
+ File.Delete(path); //delete file to avoid breaking cache
+ throw;
+ }
}
var client = await sourceMapping.GetClientAsync(package.Package.Id);
diff --git a/CringePlugins/Resolver/BuiltInPackages.cs b/CringePlugins/Resolver/BuiltInPackages.cs
index b16e498..32d12af 100644
--- a/CringePlugins/Resolver/BuiltInPackages.cs
+++ b/CringePlugins/Resolver/BuiltInPackages.cs
@@ -21,6 +21,7 @@ public static class BuiltInPackages
private const string SeReferenceAssemblies = "SpaceEngineersDedicated.ReferenceAssemblies";
private const string ImGui = "ImGui.NET.DirectX";
private const string Harmony = "Lib.Harmony.Thin";
+ private const string Steamworks = "Steamworks.NET";
public static ImmutableArray GetPackages(NuGetFramework runtimeFramework)
{
@@ -32,6 +33,7 @@ public static class BuiltInPackages
], SeReferenceAssemblies, new(seVersion));
var imGui = FromAssembly(runtimeFramework, id: ImGui);
var harmony = FromAssembly(runtimeFramework, id: Harmony);
+ var steam = FromAssembly(runtimeFramework, id: Steamworks);
BuiltInSdkPackage MapSdkPackage(
(string FileName, byte[] ImageBytes, PortableExecutableReference Reference, Guid Mvid) r)
@@ -53,6 +55,7 @@ public static class BuiltInPackages
se,
imGui,
harmony,
+ steam,
FromAssembly(runtimeFramework,
[se.AsDependency(), imGui.AsDependency(), harmony.AsDependency()]
#if DEBUG
diff --git a/CringePlugins/Resolver/PackageResolver.cs b/CringePlugins/Resolver/PackageResolver.cs
index 7bcfb10..667a356 100644
--- a/CringePlugins/Resolver/PackageResolver.cs
+++ b/CringePlugins/Resolver/PackageResolver.cs
@@ -14,7 +14,7 @@ public class PackageResolver(NuGetFramework runtimeFramework, ImmutableArray> ResolveAsync()
{
var order = 0;
- var packages = new SortedDictionary();
+ var packages = new Dictionary();
foreach (var reference in references)
{
@@ -39,7 +39,7 @@ public class PackageResolver(NuGetFramework runtimeFramework, ImmutableArray b.CatalogEntry.Version).OrderDescending().First(b => reference.Range.Satisfies(b));
if (version is null)
- throw new Exception($"Unable to find version for package {reference.Id}");
+ throw new NotSupportedException($"Unable to find version for package {reference.Id}");
var catalogEntry = items[version].CatalogEntry;
@@ -48,22 +48,18 @@ public class PackageResolver(NuGetFramework runtimeFramework, ImmutableArray b.Version == package.Version && b.Id == 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)
+ if (package.Version < existingEntry.Version)
+ throw new NotSupportedException($"Package reference {package.Id} has lower version {package.Version} than already resolved {existingEntry.Version}");
+
+ if (package.Version == existingEntry.Version)
continue;
- packages.Remove(existingPackage);
- packages.Add(package with
- {
- Order = ++order
- }, catalogEntry);
+ packages[package with { Order = ++order }] = catalogEntry;
}
var set = ImmutableSortedSet.Empty.ToBuilder();
@@ -78,11 +74,13 @@ public class PackageResolver(NuGetFramework runtimeFramework, ImmutableArray g.TargetFramework);
if (nearestGroup is null)
- throw new Exception($"Unable to find compatible dependency group for package {package.Id}");
+ throw new NotSupportedException($"Unable to find compatible dependency group for package {package.Id}");
set.Add(new RemotePackage(package, nearestGroup.TargetFramework, client, catalogEntry));
}
-
+
+ var dependencyVersions = new Dictionary();
+ var dependencyPackages = new HashSet();
for (var i = 0; i < set.Count; i++)
{
if (set[i] is not RemotePackage package) continue;
@@ -103,79 +101,105 @@ public class PackageResolver(NuGetFramework runtimeFramework, ImmutableArray page.Items!)
.ToImmutableDictionary(b => b.CatalogEntry.Version);
- var version = items.Values.Select(b => b.CatalogEntry.Version).OrderDescending().FirstOrDefault(b => versionRange.Satisfies(b));
+ var version = items.Values.Select(b => b.CatalogEntry.Version).OrderDescending().FirstOrDefault(versionRange.Satisfies);
if (version is null)
- throw new Exception($"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}");
var catalogEntry = items[version].CatalogEntry;
var dependencyPackage = new Package(i, id, version);
- if (packages.TryGetValue(dependencyPackage, out var existingPackage))
+ if (packages.TryGetValue(dependencyPackage, out var existingCatalog))
{
- if (dependencyPackage.Version < existingPackage.Version)
- {
- // dependency has lower version than already resolved
- // need to check if existing fits the version range
- // and reorder existing to ensure it's ordered before requesting package
+ if (dependencyPackage.Version == existingCatalog.Version)
+ continue; //a dependency with this version has already been resolved
- if (!versionRange.Satisfies(existingPackage.Version))
- throw new Exception(
- $"Incompatible package version {dependencyPackage} (required by {package.Package}) from {existingPackage}");
-
- if (dependencyPackage.CompareTo(existingPackage) < 0)
- {
- packages.Remove(dependencyPackage);
- packages.Add(dependencyPackage, existingPackage);
- }
-
- continue;
+ //does the existing version support our package?
+ if (versionRange.Satisfies(existingCatalog.Version))
+ continue; //keep the old one
+
+ if (!dependencyVersions.TryGetValue(dependencyPackage, out var minimalVersionRange))
+ throw new InvalidOperationException("Missing minimal version range");
+
+ minimalVersionRange = VersionRange.CommonSubSet([minimalVersionRange, versionRange]);
+
+ if (!minimalVersionRange.Satisfies(version))
+ {
+ //do one last check for a matching version
+ version = items.Values.Select(b => b.CatalogEntry.Version).OrderDescending().FirstOrDefault(minimalVersionRange.Satisfies);
+
+ if (version is null)
+ throw new NotSupportedException($"Unable to find version for package {id} as dependency of {package.Package} (and others) that satisfies {minimalVersionRange}");
+
+ catalogEntry = items[version].CatalogEntry;
+
+ dependencyPackage = dependencyPackage with { Version = version };
}
-
- throw new Exception($"Detected package downgrade from {existingPackage} to {dependencyPackage} as dependency of {package.Package}");
+
+ //swap to this version
+ packages[dependencyPackage] = catalogEntry;
+ dependencyVersions[dependencyPackage] = minimalVersionRange;
+
+ var replacementGroup = NuGetFrameworkUtility.GetNearest(catalogEntry.DependencyGroups ?? [], runtimeFramework, g => g.TargetFramework)
+ ?? throw new NotSupportedException($"Unable to find compatible dependency group for {dependencyPackage} as dependency of {package.Package}");
+
+ var replacement = new RemoteDependencyPackage(dependencyPackage, replacementGroup.TargetFramework, client, package, catalogEntry);
+
+ if (!dependencyPackages.Remove(replacement))
+ throw new InvalidOperationException("Replaced dependency wasn't there");
+
+ dependencyPackages.Add(replacement);
+
+ continue;
}
- if (!packages.TryAdd(dependencyPackage, catalogEntry))
- throw new Exception($"Duplicate package {dependencyPackage.Id}");
+ if (!packages.TryAdd(dependencyPackage, catalogEntry) || !dependencyVersions.TryAdd(dependencyPackage, versionRange))
+ throw new InvalidOperationException($"Duplicate package {dependencyPackage.Id}");
var nearestGroup = NuGetFrameworkUtility.GetNearest(catalogEntry.DependencyGroups ?? [], runtimeFramework,
- g => g.TargetFramework);
-
- if (nearestGroup is null)
- throw new Exception($"Unable to find compatible dependency group for {dependencyPackage} as dependency of {package.Package}");
-
- set.Add(new RemoteDependencyPackage(dependencyPackage, nearestGroup.TargetFramework, client, package, catalogEntry));
+ g => g.TargetFramework) ?? throw new NotSupportedException($"Unable to find compatible dependency group for {dependencyPackage} as dependency of {package.Package}");
+
+ dependencyPackages.Add(new RemoteDependencyPackage(dependencyPackage, nearestGroup.TargetFramework, client, package, catalogEntry));
}
}
+ foreach (var item in dependencyPackages)
+ set.Add(item);
+
return set.ToImmutable();
}
public async Task> DownloadPackagesAsync(DirectoryInfo baseDirectory,
- IReadOnlySet resolvedPackages, IProgress? progress = null)
+ IReadOnlySet resolvedPackages, IReadOnlySet? ignorePackages = null, IProgress? progress = null)
{
var packages = ImmutableHashSet.Empty.ToBuilder();
var i = 0f;
foreach (var package in resolvedPackages)
{
+ if (ignorePackages?.Contains(package.Package.Id) == true)
+ continue;
+
switch (package)
{
- case RemotePackage remotePackage:
+ case RemoteDependencyPackage:
+ case 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);
+ var client = (package as RemoteDependencyPackage)?.Client ?? ((RemotePackage)package).Client;
+
+ await using var stream = await client.GetPackageContentStreamAsync(package.Package.Id, package.Package.Version);
using var memStream = new MemoryStream();
await stream.CopyToAsync(memStream);
memStream.Position = 0;
@@ -189,6 +213,8 @@ public class PackageResolver(NuGetFramework runtimeFramework, ImmutableArray