diff --git a/SS14.Launcher/ConfigConstants.cs b/SS14.Launcher/ConfigConstants.cs index 1010f48..cf1125f 100644 --- a/SS14.Launcher/ConfigConstants.cs +++ b/SS14.Launcher/ConfigConstants.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using SS14.Launcher.Utility; namespace SS14.Launcher; @@ -48,18 +49,46 @@ public static class ConfigConstants public const string NewsFeedUrl = "https://spacestation14.com/post/index.xml"; public const string TranslateUrl = "https://docs.spacestation14.com/en/general-development/contributing-translations.html"; - private static readonly UrlFallbackSet RobustBuildsBaseUrl = new([ - "https://robust-builds.cdn.spacestation14.com/", - "https://robust-builds.fallback.cdn.spacestation14.com/", - ]); + public static readonly Dictionary EngineBuildsUrl = new() + { + { + "Robust", + new UrlFallbackSet([ + "https://robust-builds.cdn.spacestation14.com/manifest.json", + "https://robust-builds.fallback.cdn.spacestation14.com/manifest.json", + ]) + }, + { + "Multiverse", + new UrlFallbackSet([ + "https://cdn.spacestationmultiverse.com/ssmv-engine-manifest", + ]) + }, + }; + + public static readonly Dictionary EngineModulesUrl = new() + { + { + "Robust", + new UrlFallbackSet([ + "https://robust-builds.cdn.spacestation14.com/modules.json", + "https://robust-builds.fallback.cdn.spacestation14.com/modules.json", + ]) + }, + { + "Multiverse", + new UrlFallbackSet([ + // Same as Robust for now + "https://robust-builds.cdn.spacestation14.com/modules.json", + "https://robust-builds.fallback.cdn.spacestation14.com/modules.json", + ]) + }, + }; private static readonly UrlFallbackSet LauncherDataBaseUrl = new([ "http://assets.simplestation.org/launcher/", ]); - public static readonly UrlFallbackSet RobustBuildsManifest = RobustBuildsBaseUrl + "manifest.json"; - public static readonly UrlFallbackSet RobustModulesManifest = RobustBuildsBaseUrl + "modules.json"; - // How long to keep cached copies of Robust manifests. // TODO: Take this from Cache-Control header responses instead. public static readonly TimeSpan RobustManifestCacheTime = TimeSpan.FromMinutes(15); diff --git a/SS14.Launcher/LauncherPaths.cs b/SS14.Launcher/LauncherPaths.cs index 297537c..0b94bd3 100644 --- a/SS14.Launcher/LauncherPaths.cs +++ b/SS14.Launcher/LauncherPaths.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.IO; using System.Runtime.InteropServices; @@ -31,7 +32,12 @@ public static class LauncherPaths public static readonly string PathClientMacLog = Path.Combine(DirLogs, ClientMacLogName); public static readonly string PathClientStdoutLog = Path.Combine(DirLogs, ClientStdoutLogName); public static readonly string PathClientStderrLog = Path.Combine(DirLogs, ClientStderrLogName); - public static readonly string PathPublicKey = Path.Combine(DirLauncherInstall, "signing_key"); + public static readonly string PathPublicKey = Path.Combine(DirLauncherInstall, "signing_key_Robust"); // Used as a fallback + public static readonly Dictionary PathPublicKeys = new() + { + { "Robust", PathPublicKey }, + { "Multiverse", Path.Combine(DirLauncherInstall, "signing_key_Multiverse") }, + }; public static readonly string PathContentDb = Path.Combine(DirLocalData, "content.db"); public static readonly string PathOverrideAssetsDb = Path.Combine(DirLocalData, "override_assets.db"); diff --git a/SS14.Launcher/Models/Connector.cs b/SS14.Launcher/Models/Connector.cs index b9109cb..5dfe0cd 100644 --- a/SS14.Launcher/Models/Connector.cs +++ b/SS14.Launcher/Models/Connector.cs @@ -218,7 +218,8 @@ private async Task LaunchClientWrap( Status = ConnectionStatus.ClientExited; } - private async Task ConnectLaunchClient(ContentLaunchInfo launchInfo, + private async Task ConnectLaunchClient( + ContentLaunchInfo launchInfo, ServerInfo? info, ServerBuildInformation? serverBuildInformation, Uri? connectAddress, @@ -297,7 +298,7 @@ void BuildCVar(string name, string? value) } // Launch client. - return await LaunchClient(launchInfo, args, cVars); + return await LaunchClient(launchInfo, serverBuildInformation?.EngineType ?? "Robust", args, cVars); } catch (Exception e) { @@ -410,11 +411,15 @@ private async Task InstallContentBundleAsync( private async Task LaunchClient( ContentLaunchInfo launchInfo, + string engine, IEnumerable extraArgs, List<(string, string)> env) { - var pubKey = LauncherPaths.PathPublicKey; - var engineVersion = launchInfo.ModuleInfo.Single(x => x.Module == "Robust").Version; + Log.Information("Launching client with engine {Engine}", engine); + Log.Debug($"Engine has modules {string.Join(", ", launchInfo.ModuleInfo)}"); + + var pubKey = LauncherPaths.PathPublicKeys!.GetValueOrDefault(engine, null) ?? LauncherPaths.PathPublicKey; + var engineVersion = launchInfo.ModuleInfo.Single(x => x.Module == engine).Version; var binPath = _engineManager.GetEnginePath(engineVersion); var sig = _engineManager.GetEngineSignature(engineVersion); @@ -433,17 +438,15 @@ private async Task InstallContentBundleAsync( EnvVar("SS14_LOADER_CONTENT_VERSION", launchInfo.Version.ToString()); // Env vars for engine modules. + foreach (var (moduleName, moduleVersion) in launchInfo.ModuleInfo) { - foreach (var (moduleName, moduleVersion) in launchInfo.ModuleInfo) - { - if (moduleName == "Robust") - continue; + if (moduleName == engine) + continue; - var modulePath = _engineManager.GetEngineModule(moduleName, moduleVersion); + var modulePath = _engineManager.GetEngineModule(moduleName, moduleVersion); - var envVar = $"ROBUST_MODULE_{moduleName.ToUpperInvariant().Replace('.', '_')}"; - EnvVar(envVar, modulePath); - } + var envVar = $"ROBUST_MODULE_{moduleName.ToUpperInvariant().Replace('.', '_')}"; + EnvVar(envVar, modulePath); } if (_cfg.GetCVar(CVars.DisableSigning)) @@ -696,7 +699,8 @@ public ConnectException(ConnectionStatus status, Exception inner) public sealed record ContentBundleMetadata( [property: JsonPropertyName("server_gc")] bool? ServerGC, [property: JsonPropertyName("engine_version")] string EngineVersion, - [property: JsonPropertyName("base_build")] ContentBundleBaseBuild? BaseBuild + [property: JsonPropertyName("base_build")] ContentBundleBaseBuild? BaseBuild, + [property: JsonPropertyName("engine")] string Engine = "Robust" ); public sealed record ContentBundleBaseBuild( diff --git a/SS14.Launcher/Models/ContentLaunchInfo.cs b/SS14.Launcher/Models/ContentLaunchInfo.cs index 5019506..899a229 100644 --- a/SS14.Launcher/Models/ContentLaunchInfo.cs +++ b/SS14.Launcher/Models/ContentLaunchInfo.cs @@ -4,4 +4,3 @@ /// Information loaded by the updater that we need to launch the game. /// public sealed record ContentLaunchInfo(long Version, (string Module, string Version)[] ModuleInfo, bool ServerGC = false); - diff --git a/SS14.Launcher/Models/EngineManager/EngineManagerDynamic.Manifest.cs b/SS14.Launcher/Models/EngineManager/EngineManagerDynamic.Manifest.cs index 7b217fd..a0c57a1 100644 --- a/SS14.Launcher/Models/EngineManager/EngineManagerDynamic.Manifest.cs +++ b/SS14.Launcher/Models/EngineManager/EngineManagerDynamic.Manifest.cs @@ -6,6 +6,7 @@ using System.Threading; using System.Threading.Tasks; using Serilog; +using SS14.Launcher.Utility; namespace SS14.Launcher.Models.EngineManager; @@ -16,7 +17,7 @@ public sealed partial class EngineManagerDynamic private readonly SemaphoreSlim _manifestSemaphore = new(1); private readonly Stopwatch _manifestStopwatch = Stopwatch.StartNew(); - private Dictionary? _cachedRobustVersionInfo; + private readonly Dictionary?> _cachedEngineVersionInfo = new(); private TimeSpan _robustCacheValidUntil; /// @@ -31,13 +32,14 @@ public sealed partial class EngineManagerDynamic /// private async ValueTask GetVersionInfo( string version, + string engine, bool followRedirects = true, CancellationToken cancel = default) { await _manifestSemaphore.WaitAsync(cancel); try { - return await GetVersionInfoCore(version, followRedirects, cancel); + return await GetVersionInfoCore(version, followRedirects, cancel, engine); } finally { @@ -48,51 +50,59 @@ public sealed partial class EngineManagerDynamic private async ValueTask GetVersionInfoCore( string version, bool followRedirects, - CancellationToken cancel) + CancellationToken cancel, + string engine) { - // If we have a cached copy, and it's not expired, we check it. - if (_cachedRobustVersionInfo != null && _robustCacheValidUntil > _manifestStopwatch.Elapsed) - { - // Check the version. If this fails, we immediately re-request the manifest as it may have changed. - // (Connecting to a freshly-updated server with a new Robust version, within the cache window.) - if (FindVersionInfoInCached(version, followRedirects) is { } foundVersionInfo) - return foundVersionInfo; - } - - await UpdateBuildManifest(cancel); - - return FindVersionInfoInCached(version, followRedirects); + // First, check if we have a cached copy of the manifest. + if (_cachedEngineVersionInfo.TryGetValue(engine, out var versionInfo) + && versionInfo != null + && _robustCacheValidUntil > _manifestStopwatch.Elapsed) + return FindVersionInfoInCached(version, followRedirects, engine); + + // If we don't have a cached copy, or it's expired, we re-request the manifest. + await UpdateBuildManifest(cancel, engine); + return FindVersionInfoInCached(version, followRedirects, engine); } - private async Task UpdateBuildManifest(CancellationToken cancel) + private async Task UpdateBuildManifest(CancellationToken cancel, string name) { // TODO: If-Modified-Since and If-None-Match request conditions. - Log.Debug("Loading manifest from {manifestUrl}...", ConfigConstants.RobustBuildsManifest); - _cachedRobustVersionInfo = - await ConfigConstants.RobustBuildsManifest.GetFromJsonAsync>( - _http, cancel); + if (ConfigConstants.EngineBuildsUrl.TryGetValue(name, out var urlSet)) + foreach (var url in urlSet.Urls) + { + try + { + _cachedEngineVersionInfo.Remove(name); + _cachedEngineVersionInfo.Add(name, await new UrlFallbackSet([url]).GetFromJsonAsync>(_http, cancel)); + break; + } + catch (Exception e) + { + Log.Error(e, "Failed to download manifest from {url}", url); + } + } _robustCacheValidUntil = _manifestStopwatch.Elapsed + ConfigConstants.RobustManifestCacheTime; } - private FoundVersionInfo? FindVersionInfoInCached(string version, bool followRedirects) + private FoundVersionInfo? FindVersionInfoInCached(string version, bool followRedirects, string name) { - Debug.Assert(_cachedRobustVersionInfo != null); - - if (!_cachedRobustVersionInfo.TryGetValue(version, out var versionInfo)) + if (!_cachedEngineVersionInfo.TryGetValue(name, out var versionInfo)) + Debug.Assert(false); + if (versionInfo == null || !versionInfo.TryGetValue(version, out var info)) return null; if (followRedirects) { - while (versionInfo.RedirectVersion != null) + while (info.RedirectVersion != null) { - version = versionInfo.RedirectVersion; - versionInfo = _cachedRobustVersionInfo[versionInfo.RedirectVersion]; + if (!versionInfo.TryGetValue(info.RedirectVersion, out info)) + return null; } } - return new FoundVersionInfo(version, versionInfo); + return new FoundVersionInfo(version, info); } private sealed record FoundVersionInfo(string Version, VersionInfo Info); diff --git a/SS14.Launcher/Models/EngineManager/EngineManagerDynamic.cs b/SS14.Launcher/Models/EngineManager/EngineManagerDynamic.cs index cdef9f0..f36484f 100644 --- a/SS14.Launcher/Models/EngineManager/EngineManagerDynamic.cs +++ b/SS14.Launcher/Models/EngineManager/EngineManagerDynamic.cs @@ -25,14 +25,8 @@ public sealed partial class EngineManagerDynamic : IEngineManager { public const string OverrideVersionName = "_OVERRIDE_"; - private readonly DataManager _cfg; - private readonly HttpClient _http; - - public EngineManagerDynamic() - { - _cfg = Locator.Current.GetRequiredService(); - _http = Locator.Current.GetRequiredService(); - } + private readonly DataManager _cfg = Locator.Current.GetRequiredService(); + private readonly HttpClient _http = Locator.Current.GetRequiredService(); public string GetEnginePath(string engineVersion) { @@ -72,7 +66,8 @@ public string GetEngineSignature(string engineVersion) } public async Task DownloadEngineIfNecessary( - string engineVersion, + string version, + string engine, Helpers.DownloadProgressCallback? progress = null, CancellationToken cancel = default) { @@ -81,21 +76,18 @@ public async Task DownloadEngineIfNecessary( { // Engine override means we don't need to download anything, we have it locally! // At least, if we don't, we'll just blame the developer that enabled it. - return new EngineInstallationResult(engineVersion, false); + return new EngineInstallationResult(version, false); } #endif - var foundVersion = await GetVersionInfo(engineVersion, cancel: cancel); + var foundVersion = await GetVersionInfo(version, engine, true, cancel); if (foundVersion == null) throw new UpdateException("Unable to find engine version in manifest!"); if (foundVersion.Info.Insecure) throw new UpdateException("Specified engine version is insecure!"); - Log.Debug( - "Requested engine version was {RequestedEngien}, redirected to {FoundVersion}", - engineVersion, - foundVersion.Version); + Log.Debug($"Requested engine version was {version}, redirected to {foundVersion.Version}"); if (_cfg.EngineInstallations.Lookup(foundVersion.Version).HasValue) { @@ -203,7 +195,7 @@ public async Task DownloadModuleIfNecessary( // Verify signature. tempFile.Seek(0, SeekOrigin.Begin); - if (!VerifyModuleSignature(tempFile, platformData.Sig)) + if (!VerifyModuleSignature(tempFile, moduleName, platformData.Sig)) { #if DEBUG if (_cfg.GetCVar(CVars.DisableSigning)) @@ -291,7 +283,7 @@ private static void ExtractModule(string moduleName, string moduleVersionDiskPat } } - private static unsafe bool VerifyModuleSignature(FileStream stream, string signature) + private static unsafe bool VerifyModuleSignature(FileStream stream, string module, string signature) { if (stream.Length > int.MaxValue) throw new InvalidOperationException("Unable to handle files larger than 2 GiB"); @@ -315,7 +307,7 @@ private static unsafe bool VerifyModuleSignature(FileStream stream, string signa var pubKey = PublicKey.Import( SignatureAlgorithm.Ed25519, - File.ReadAllBytes(LauncherPaths.PathPublicKey), + File.ReadAllBytes(LauncherPaths.PathPublicKeys!.GetValueOrDefault(module, null) ?? LauncherPaths.PathPublicKey), KeyBlobFormat.PkixPublicKeyText); var sigBytes = Convert.FromHexString(signature); @@ -328,10 +320,15 @@ private static unsafe bool VerifyModuleSignature(FileStream stream, string signa } } - public async Task GetEngineModuleManifest(CancellationToken cancel = default) + public async Task GetEngineModuleManifest(string engine, CancellationToken cancel = default) { - return await ConfigConstants.RobustModulesManifest.GetFromJsonAsync(_http, cancel) ?? - throw new InvalidDataException(); + if (!ConfigConstants.EngineBuildsUrl.TryGetValue(engine, out var urls)) + throw new InvalidOperationException("No manifest URL for engine module"); + + if (await urls.GetFromJsonAsync(_http, cancel) is { } manifest) + return manifest; + + throw new InvalidOperationException("Failed to download engine module manifest"); } public async Task DoEngineCullMaybeAsync(SqliteConnection contenCon) @@ -350,7 +347,7 @@ public async Task DoEngineCullMaybeAsync(SqliteConnection contenCon) var modulesUsed = new HashSet<(string, string)>(); foreach (var (name, version) in origModulesUsed) { - if (name == "Robust" && await GetVersionInfo(version) is { } redirect) + if (name == "Robust" && await GetVersionInfo(version, name) is { } redirect) { modulesUsed.Add(("Robust", redirect.Version)); } @@ -360,7 +357,7 @@ public async Task DoEngineCullMaybeAsync(SqliteConnection contenCon) } } - var toCull = _cfg.EngineInstallations.Items.Where(i => !modulesUsed.Contains(("Robust", i.Version))).ToArray(); + var toCull = _cfg.EngineInstallations.Items.Where(i => !modulesUsed.Any(m => m.Item2 == i.Version)).ToArray(); foreach (var installation in toCull) { diff --git a/SS14.Launcher/Models/EngineManager/IEngineManager.cs b/SS14.Launcher/Models/EngineManager/IEngineManager.cs index 2de8250..c19f0fd 100644 --- a/SS14.Launcher/Models/EngineManager/IEngineManager.cs +++ b/SS14.Launcher/Models/EngineManager/IEngineManager.cs @@ -17,10 +17,11 @@ public interface IEngineManager string GetEnginePath(string engineVersion); string GetEngineSignature(string engineVersion); - Task GetEngineModuleManifest(CancellationToken cancel = default); + Task GetEngineModuleManifest(string engine, CancellationToken cancel = default); Task DownloadEngineIfNecessary( - string engineVersion, + string version, + string engine, Helpers.DownloadProgressCallback? progress = null, CancellationToken cancel = default); diff --git a/SS14.Launcher/Models/ServerInfo.cs b/SS14.Launcher/Models/ServerInfo.cs index f0470ad..8af9b1c 100644 --- a/SS14.Launcher/Models/ServerInfo.cs +++ b/SS14.Launcher/Models/ServerInfo.cs @@ -38,6 +38,9 @@ public class ServerBuildInformation [JsonInclude, JsonPropertyName("manifest_download_url")] public string? ManifestDownloadUrl; + [JsonInclude, JsonPropertyName("engine_type")] + public string EngineType = "Robust"; + [JsonInclude, JsonPropertyName("engine_version")] public string EngineVersion = default!; diff --git a/SS14.Launcher/Models/Updater.cs b/SS14.Launcher/Models/Updater.cs index 50d6b96..6ae0746 100644 --- a/SS14.Launcher/Models/Updater.cs +++ b/SS14.Launcher/Models/Updater.cs @@ -124,7 +124,7 @@ private async Task RunUpdate( // Both content downloading and engine downloading MAY need the manifest. // So use a Lazy> to avoid loading it twice. var moduleManifest = - new Lazy>(() => _engineManager.GetEngineModuleManifest(cancel)); + new Lazy>(() => _engineManager.GetEngineModuleManifest(buildInfo.EngineType, cancel)); // ReSharper disable once UseAwaitUsing using var con = ContentManager.GetSqliteConnection(); @@ -136,7 +136,7 @@ private async Task RunUpdate( await Task.Run(() => { CullOldContentVersions(con); }, CancellationToken.None); - return await InstallEnginesForVersion(con, moduleManifest, versionRowId, cancel); + return await InstallEnginesForVersion(con, versionRowId, buildInfo.EngineType, cancel); } private async Task InstallContentBundle( @@ -153,7 +153,7 @@ private async Task InstallContentBundle( // Both content downloading and engine downloading MAY need the manifest. // So use a Lazy> to avoid loading it twice. var moduleManifest = new Lazy>( - () => _engineManager.GetEngineModuleManifest(cancel) + () => _engineManager.GetEngineModuleManifest(metadata.Engine, cancel) ); var versionId = await Task.Run(async () => @@ -247,7 +247,7 @@ FROM ContentManifest Log.Debug("Resolving content dependencies..."); // TODO: This could copy from base build modules in certain cases. - await ResolveContentDependencies(con, versionId, metadata.EngineVersion, moduleManifest); + await ResolveContentDependencies(con, versionId, metadata.Engine, metadata.EngineVersion, moduleManifest); } else { @@ -268,45 +268,32 @@ FROM ContentManifest return versionId; }, CancellationToken.None); - return await InstallEnginesForVersion(con, moduleManifest, versionId, cancel); + return await InstallEnginesForVersion(con, versionId, metadata.Engine, cancel); } private async Task InstallEnginesForVersion( SqliteConnection con, - Lazy> moduleManifest, long versionRowId, + string engine, CancellationToken cancel) { - (string, string)[] modules; + Status = UpdateStatus.CheckingClientUpdate; + var modules = con.Query<(string, string)>( + "SELECT ModuleName, moduleVersion FROM ContentEngineDependency WHERE ModuleName = @Engine AND VersionId = @Version", + new { Engine = engine, Version = versionRowId }).ToArray(); + for (var index = 0; index < modules.Length; index++) { - Status = UpdateStatus.CheckingClientUpdate; - modules = con.Query<(string, string)>( - "SELECT ModuleName, moduleVersion FROM ContentEngineDependency WHERE VersionId = @Version", - new { Version = versionRowId }).ToArray(); + var (name, version) = modules[index]; - for (var index = 0; index < modules.Length; index++) + if (!ConfigConstants.EngineBuildsUrl.TryGetValue(name, out _)) { - var (name, version) = modules[index]; - if (name == "Robust") - { - // Engine version may change here due to manifest version redirects. - var newEngineVersion = await InstallEngineVersionIfMissing(version, cancel); - modules[index] = (name, newEngineVersion); - } - else - { - Status = UpdateStatus.DownloadingEngineModules; - - var manifest = await moduleManifest.Value; - await _engineManager.DownloadModuleIfNecessary( - name, - version, - manifest, - DownloadProgressCallback, - cancel); - } + Log.Error($"No engine URL set for module {name}"); + continue; } + + var newEngineVersion = await InstallEngineVersionIfMissing(version, name, cancel); + modules[index] = (name, newEngineVersion); } Status = UpdateStatus.CullingEngine; @@ -386,9 +373,9 @@ private void CullOldContentVersions(SqliteConnection con) "WHERE Hash = @Hash " + "ORDER BY ForkVersion = @ForkVersion " + "AND ForkId = @ForkId " + - "AND (SELECT ModuleVersion FROM ContentEngineDependency ced WHERE ced.VersionId = cv.Id AND ModuleName = 'Robust') = @EngineVersion " + + "AND (SELECT ModuleVersion FROM ContentEngineDependency ced WHERE ced.VersionId = cv.Id AND ModuleName = @Engine) = @EngineVersion " + "DESC", - new { Hash = hash, ForkVersion = buildInfo.Version, buildInfo.ForkId, buildInfo.EngineVersion }); + new { Hash = hash, ForkVersion = buildInfo.Version, buildInfo.ForkId, Engine = buildInfo.EngineType, buildInfo.EngineVersion }); } else if (buildInfo.Hash is { } hashHex) { @@ -399,9 +386,9 @@ private void CullOldContentVersions(SqliteConnection con) "SELECT * FROM ContentVersion cv WHERE ZipHash = @ZipHash " + "ORDER BY ForkVersion = @ForkVersion " + "AND ForkId = @ForkId " + - "AND (SELECT ModuleVersion FROM ContentEngineDependency ced WHERE ced.VersionId = cv.Id AND ModuleName = 'Robust') = @EngineVersion " + + "AND (SELECT ModuleVersion FROM ContentEngineDependency ced WHERE ced.VersionId = cv.Id AND ModuleName = @Engine) = @EngineVersion " + "DESC", - new { ZipHash = hash, ForkVersion = buildInfo.Version, buildInfo.ForkId, buildInfo.EngineVersion }); + new { ZipHash = hash, ForkVersion = buildInfo.Version, buildInfo.ForkId, Engine = buildInfo.EngineType, buildInfo.EngineVersion }); } else { @@ -411,9 +398,9 @@ private void CullOldContentVersions(SqliteConnection con) found = con.QueryFirstOrDefault( "SELECT * FROM ContentVersion cv WHERE ForkId = @ForkId AND ForkVersion = @Version " + - "ORDER BY (SELECT ModuleVersion FROM ContentEngineDependency ced WHERE ced.VersionId = cv.Id AND ModuleName = 'Robust') = @EngineVersion " + + "ORDER BY (SELECT ModuleVersion FROM ContentEngineDependency ced WHERE ced.VersionId = cv.Id AND ModuleName = @Engine) = @EngineVersion " + "DESC", - new { buildInfo.ForkId, buildInfo.Version, buildInfo.EngineVersion }); + new { buildInfo.ForkId, buildInfo.Version, Engine = buildInfo.EngineType, buildInfo.EngineVersion }); } @@ -487,8 +474,8 @@ private static async Task DuplicateExistingVersion( var curEngineVersion = con.ExecuteScalar( - "SELECT ModuleVersion FROM ContentEngineDependency WHERE ModuleName = 'Robust' AND VersionId = @Version", - new { Version = existingVersion.Id }); + "SELECT ModuleVersion FROM ContentEngineDependency WHERE ModuleName = @Engine AND VersionId = @Version", + new { Engine = buildInfo.EngineType, Version = existingVersion.Id }); var changedFork = buildInfo.ForkId != existingVersion.ForkId || buildInfo.Version != existingVersion.ForkVersion; @@ -525,9 +512,10 @@ FROM ContentManifest { con.Execute(@" INSERT INTO ContentEngineDependency (VersionId, ModuleName, ModuleVersion) - VALUES (@VersionId, 'Robust', @EngineVersion)", + VALUES (@VersionId, @Engine, @EngineVersion)", new { + Engine = buildInfo.EngineType, EngineVersion = engineVersion, VersionId = versionId }); @@ -536,9 +524,9 @@ INSERT INTO ContentEngineDependency (VersionId, ModuleName, ModuleVersion) var oldDependencies = con.Query(@" SELECT ModuleName FROM ContentEngineDependency - WHERE VersionId = @OldVersion AND ModuleName != 'Robust'", new + WHERE VersionId = @OldVersion AND ModuleName != @Engine", new { - OldVersion = existingVersion.Id + OldVersion = existingVersion.Id, Engine = buildInfo.EngineType, }).ToArray(); if (oldDependencies.Length > 0) @@ -640,7 +628,7 @@ private async Task DownloadNewVersion( // Insert engine dependencies. - await ResolveContentDependencies(con, versionId, engineVersion, moduleManifest); + await ResolveContentDependencies(con, versionId, buildInfo.EngineType, engineVersion, moduleManifest); return versionId; } @@ -648,19 +636,22 @@ private async Task DownloadNewVersion( private static async Task ResolveContentDependencies( SqliteConnection con, long versionId, + string engine, string engineVersion, Lazy> moduleManifest) { // Engine version. con.Execute( @"INSERT INTO ContentEngineDependency(VersionId, ModuleName, ModuleVersion) - VALUES (@Version, 'Robust', @EngineVersion)", + VALUES (@Version, @Engine, @EngineVersion)", new { - Version = versionId, EngineVersion = engineVersion + Version = versionId, + Engine = engine, + EngineVersion = engineVersion }); - Log.Debug("Inserting dependency: {ModuleName} {ModuleVersion}", "Robust", engineVersion); + Log.Debug("Inserting dependency: {ModuleName} {ModuleVersion}", engine, engineVersion); // If we have a manifest file, load module dependencies from manifest file. if (LoadManifestData(con, versionId) is not { } manifestData) @@ -1397,10 +1388,10 @@ private async Task CullEngineVersionsMaybe(SqliteConnection contentConnection) await _engineManager.DoEngineCullMaybeAsync(contentConnection); } - private async Task InstallEngineVersionIfMissing(string engineVer, CancellationToken cancel) + private async Task InstallEngineVersionIfMissing(string engineVer, string engine, CancellationToken cancel) { Status = UpdateStatus.DownloadingEngineVersion; - var (changedVersion, _) = await _engineManager.DownloadEngineIfNecessary(engineVer, DownloadProgressCallback, cancel); + var (changedVersion, _) = await _engineManager.DownloadEngineIfNecessary(engineVer, engine, DownloadProgressCallback, cancel); Progress = null; return changedVersion; diff --git a/SS14.Launcher/SS14.Launcher.csproj b/SS14.Launcher/SS14.Launcher.csproj index d95c288..938e06d 100644 --- a/SS14.Launcher/SS14.Launcher.csproj +++ b/SS14.Launcher/SS14.Launcher.csproj @@ -83,8 +83,12 @@ - - + + + PreserveNewest + + + PreserveNewest diff --git a/SS14.Launcher/signing_key_Multiverse b/SS14.Launcher/signing_key_Multiverse new file mode 100644 index 0000000..ed53547 --- /dev/null +++ b/SS14.Launcher/signing_key_Multiverse @@ -0,0 +1,3 @@ +-----BEGIN PUBLIC KEY----- +MCowBQYDK2VwAyEAM2YE9eSPVh+Z6yWGseQ8HdK4qLbwjfMd/CxlsjfQitM= +-----END PUBLIC KEY----- diff --git a/SS14.Launcher/signing_key b/SS14.Launcher/signing_key_Robust similarity index 99% rename from SS14.Launcher/signing_key rename to SS14.Launcher/signing_key_Robust index 60875c6..0a6067b 100644 --- a/SS14.Launcher/signing_key +++ b/SS14.Launcher/signing_key_Robust @@ -1,4 +1,3 @@ -----BEGIN PUBLIC KEY----- MCowBQYDK2VwAyEApQ9mAhMLbmhQqRH7itgNo75S5rCSMsMXvVRmMv1d9NQ= -----END PUBLIC KEY----- -