From d659cc452ac277dd0580f4faecfb8b3d8c46c546 Mon Sep 17 00:00:00 2001
From: fgsfds <4870330+fgsfds@users.noreply.github.com>
Date: Fri, 31 May 2024 10:02:36 +0500
Subject: [PATCH] added support for multiple versions
---
.../Core/Controls/DownloadsControl.axaml | 2 +-
src/Avalonia/Core/ViewModels/ModsViewModel.cs | 4 +-
src/ClientCommon/Config/ConfigProvider.cs | 7 +-
src/ClientCommon/Config/ConfigProviderFake.cs | 5 +-
src/ClientCommon/Config/IConfigProvider.cs | 5 +-
src/Common/AddonVersion.cs | 28 +++
src/Common/Interfaces/IGame.cs | 6 +-
.../Interfaces/IInstalledAddonsProvider.cs | 6 +-
src/Games/Games/BaseGame.cs | 11 +-
src/Games/Games/BloodGame.cs | 9 +-
src/Games/Games/DukeGame.cs | 17 +-
src/Games/Games/FuryGame.cs | 7 +-
src/Games/Games/RedneckGame.cs | 11 +-
src/Games/Games/SlaveGame.cs | 7 +-
src/Games/Games/WangGame.cs | 11 +-
.../Providers/DownloadableAddonsProvider.cs | 221 ++++++++++--------
src/Mods/Providers/InstalledAddonsProvider.cs | 30 +--
src/Ports/Ports/BasePort.cs | 7 +-
18 files changed, 231 insertions(+), 163 deletions(-)
create mode 100644 src/Common/AddonVersion.cs
diff --git a/src/Avalonia/Core/Controls/DownloadsControl.axaml b/src/Avalonia/Core/Controls/DownloadsControl.axaml
index a1230ad9..9cb84766 100644
--- a/src/Avalonia/Core/Controls/DownloadsControl.axaml
+++ b/src/Avalonia/Core/Controls/DownloadsControl.axaml
@@ -59,8 +59,8 @@
-
+
diff --git a/src/Avalonia/Core/ViewModels/ModsViewModel.cs b/src/Avalonia/Core/ViewModels/ModsViewModel.cs
index ef63a821..e76c2bb2 100644
--- a/src/Avalonia/Core/ViewModels/ModsViewModel.cs
+++ b/src/Avalonia/Core/ViewModels/ModsViewModel.cs
@@ -139,11 +139,11 @@ private void ModCheckboxPressed(object? obj)
if (!mod.IsEnabled)
{
- Game.InstalledAddonsProvider.DisableAddon(mod.Id);
+ Game.InstalledAddonsProvider.DisableAddon(new(mod.Id, mod.Version));
}
else if (mod.IsEnabled)
{
- Game.InstalledAddonsProvider.EnableAddon(mod.Id);
+ Game.InstalledAddonsProvider.EnableAddon(new(mod.Id, mod.Version));
}
}
diff --git a/src/ClientCommon/Config/ConfigProvider.cs b/src/ClientCommon/Config/ConfigProvider.cs
index b29e34f0..b22927c3 100644
--- a/src/ClientCommon/Config/ConfigProvider.cs
+++ b/src/ClientCommon/Config/ConfigProvider.cs
@@ -1,4 +1,5 @@
using ClientCommon.Helpers;
+using Common;
using Common.Enums;
using Common.Helpers;
using System.Runtime.CompilerServices;
@@ -106,9 +107,9 @@ public HashSet DisabledAutoloadMods
get => [.. _dbContext.DisabledAddons.Select(x => x.AddonId)];
}
- public void ChangeModState(string addonId, bool isEnabled)
+ public void ChangeModState(AddonVersion addonId, bool isEnabled)
{
- var existing = _dbContext.DisabledAddons.Find([addonId]);
+ var existing = _dbContext.DisabledAddons.Find([addonId.Id]);
if (existing is null)
{
@@ -118,7 +119,7 @@ public void ChangeModState(string addonId, bool isEnabled)
}
else
{
- _dbContext.DisabledAddons.Add(new() { AddonId = addonId });
+ _dbContext.DisabledAddons.Add(new() { AddonId = addonId.Id });
}
}
else
diff --git a/src/ClientCommon/Config/ConfigProviderFake.cs b/src/ClientCommon/Config/ConfigProviderFake.cs
index 318255c2..7b0867e4 100644
--- a/src/ClientCommon/Config/ConfigProviderFake.cs
+++ b/src/ClientCommon/Config/ConfigProviderFake.cs
@@ -1,4 +1,5 @@
-using Common.Enums;
+using Common;
+using Common.Enums;
namespace ClientCommon.Config;
@@ -30,5 +31,5 @@ public sealed class ConfigProviderFake : IConfigProvider
public void AddScore(string addonId, bool isUpvote) => throw new NotImplementedException();
- public void ChangeModState(string addonId, bool isEnabled) => throw new NotImplementedException();
+ public void ChangeModState(AddonVersion addonId, bool isEnabled) => throw new NotImplementedException();
}
diff --git a/src/ClientCommon/Config/IConfigProvider.cs b/src/ClientCommon/Config/IConfigProvider.cs
index 05afe0e4..b037491f 100644
--- a/src/ClientCommon/Config/IConfigProvider.cs
+++ b/src/ClientCommon/Config/IConfigProvider.cs
@@ -1,4 +1,5 @@
-using Common.Enums;
+using Common;
+using Common.Enums;
using static ClientCommon.Config.ConfigProvider;
namespace ClientCommon.Config;
@@ -26,5 +27,5 @@ public interface IConfigProvider
void AddPlaytime(string addonId, TimeSpan playTime);
void AddScore(string addonId, bool isUpvote);
- void ChangeModState(string addonId, bool isEnabled);
+ void ChangeModState(AddonVersion addonId, bool isEnabled);
}
\ No newline at end of file
diff --git a/src/Common/AddonVersion.cs b/src/Common/AddonVersion.cs
new file mode 100644
index 00000000..204aef0c
--- /dev/null
+++ b/src/Common/AddonVersion.cs
@@ -0,0 +1,28 @@
+using System.Diagnostics.CodeAnalysis;
+
+namespace Common;
+
+public readonly struct AddonVersion
+{
+ public required readonly string Id { get; init; }
+ public required readonly string? Version{ get; init; }
+
+ [SetsRequiredMembers]
+ public AddonVersion(
+ string title,
+ string? version
+ )
+ {
+ Id = title;
+ Version = version;
+ }
+
+ [SetsRequiredMembers]
+ public AddonVersion(
+ string title
+ )
+ {
+ Id = title;
+ Version = null;
+ }
+}
diff --git a/src/Common/Interfaces/IGame.cs b/src/Common/Interfaces/IGame.cs
index 10377f32..4e9a67f3 100644
--- a/src/Common/Interfaces/IGame.cs
+++ b/src/Common/Interfaces/IGame.cs
@@ -61,16 +61,16 @@ public interface IGame
///
/// Get list of official addons and custom campaigns
///
- Dictionary GetCampaigns();
+ Dictionary GetCampaigns();
///
/// Get list of custom maps
///
- Dictionary GetSingleMaps();
+ Dictionary GetSingleMaps();
///
/// Get list of autoload mods
///
- Dictionary GetAutoloadMods(bool enabledOnly);
+ Dictionary GetAutoloadMods(bool enabledOnly);
}
}
\ No newline at end of file
diff --git a/src/Common/Interfaces/IInstalledAddonsProvider.cs b/src/Common/Interfaces/IInstalledAddonsProvider.cs
index 18c43e7a..8e1ae085 100644
--- a/src/Common/Interfaces/IInstalledAddonsProvider.cs
+++ b/src/Common/Interfaces/IInstalledAddonsProvider.cs
@@ -24,7 +24,7 @@ public interface IInstalledAddonsProvider
/// Get installed addons
///
/// Addon type
- Dictionary GetInstalledAddons(AddonTypeEnum addonType);
+ Dictionary GetInstalledAddons(AddonTypeEnum addonType);
///
/// Create cache of installed addons
@@ -36,12 +36,12 @@ public interface IInstalledAddonsProvider
/// Disable addon
///
/// Addon id
- void DisableAddon(string id);
+ void DisableAddon(AddonVersion id);
///
/// Enable addon
///
/// Addon id
- void EnableAddon(string id);
+ void EnableAddon(AddonVersion id);
}
}
\ No newline at end of file
diff --git a/src/Games/Games/BaseGame.cs b/src/Games/Games/BaseGame.cs
index 0d322173..5e98e67e 100644
--- a/src/Games/Games/BaseGame.cs
+++ b/src/Games/Games/BaseGame.cs
@@ -1,5 +1,6 @@
using ClientCommon.Helpers;
using ClientCommon.Providers;
+using Common;
using Common.Enums;
using Common.Helpers;
using Common.Interfaces;
@@ -88,7 +89,7 @@ PlaytimeProvider playtimeProvider
///
- public virtual Dictionary GetCampaigns()
+ public virtual Dictionary GetCampaigns()
{
var originalCampaigns = GetOriginalCampaigns();
@@ -112,7 +113,7 @@ public virtual Dictionary GetCampaigns()
///
- public virtual Dictionary GetSingleMaps()
+ public virtual Dictionary GetSingleMaps()
{
var maps = InstalledAddonsProvider.GetInstalledAddons(AddonTypeEnum.Map);
@@ -121,13 +122,13 @@ public virtual Dictionary GetSingleMaps()
///
- public virtual Dictionary GetAutoloadMods(bool enabledOnly)
+ public virtual Dictionary GetAutoloadMods(bool enabledOnly)
{
var mods = InstalledAddonsProvider.GetInstalledAddons(AddonTypeEnum.Mod);
if (enabledOnly)
{
- Dictionary enabled = new(StringComparer.OrdinalIgnoreCase);
+ Dictionary enabled = new();
foreach (var mod in mods)
{
@@ -166,7 +167,7 @@ private void Cleanup()
/// Get list of original campaigns
///
///
- protected abstract Dictionary GetOriginalCampaigns();
+ protected abstract Dictionary GetOriginalCampaigns();
///
diff --git a/src/Games/Games/BloodGame.cs b/src/Games/Games/BloodGame.cs
index cf54afca..d74b0fd5 100644
--- a/src/Games/Games/BloodGame.cs
+++ b/src/Games/Games/BloodGame.cs
@@ -1,4 +1,5 @@
using ClientCommon.Providers;
+using Common;
using Common.Enums;
using Common.Enums.Addons;
using Common.Helpers;
@@ -39,12 +40,12 @@ PlaytimeProvider playtimeProvider
///
- protected override Dictionary GetOriginalCampaigns()
+ protected override Dictionary GetOriginalCampaigns()
{
- Dictionary campaigns = new(2, StringComparer.OrdinalIgnoreCase);
+ Dictionary campaigns = new(2);
var bloodId = nameof(GameEnum.Blood).ToLower();
- campaigns.Add(bloodId, new BloodCampaign()
+ campaigns.Add(new(bloodId), new BloodCampaign()
{
Id = bloodId,
Type = AddonTypeEnum.Official,
@@ -82,7 +83,7 @@ protected override Dictionary GetOriginalCampaigns()
{
var bloodCpId = nameof(BloodAddonEnum.BloodCP).ToLower();
- campaigns.Add(bloodCpId, new BloodCampaign()
+ campaigns.Add(new(bloodCpId), new BloodCampaign()
{
Id = bloodCpId,
Type = AddonTypeEnum.Official,
diff --git a/src/Games/Games/DukeGame.cs b/src/Games/Games/DukeGame.cs
index 0e5d0f8d..c7cdab2b 100644
--- a/src/Games/Games/DukeGame.cs
+++ b/src/Games/Games/DukeGame.cs
@@ -1,4 +1,5 @@
using ClientCommon.Providers;
+using Common;
using Common.Enums;
using Common.Enums.Addons;
using Common.Enums.Versions;
@@ -74,15 +75,15 @@ PlaytimeProvider playtimeProvider
///
- protected override Dictionary GetOriginalCampaigns()
+ protected override Dictionary GetOriginalCampaigns()
{
- Dictionary campaigns = new(6, StringComparer.OrdinalIgnoreCase);
+ Dictionary campaigns = new(6);
if (IsBaseGameInstalled &&
GameInstallFolder != DukeWTInstallPath)
{
var dukeId = nameof(GameEnum.Duke3D).ToLower();
- campaigns.Add(dukeId, new DukeCampaign()
+ campaigns.Add(new(dukeId), new DukeCampaign()
{
Id = dukeId,
Type = AddonTypeEnum.Official,
@@ -115,7 +116,7 @@ Duke Nukem 3D is a first-person shooter developed and published by **3D Realms**
if (IsWorldTourInstalled)
{
var dukeWtId = nameof(DukeVersionEnum.Duke3D_WT).ToLower();
- campaigns.Add(dukeWtId, new DukeCampaign()
+ campaigns.Add(new(dukeWtId), new DukeCampaign()
{
Id = dukeWtId,
Type = AddonTypeEnum.Official,
@@ -150,7 +151,7 @@ Duke Nukem 3D is a first-person shooter developed and published by **3D Realms**
if (IsCaribbeanInstalled)
{
var dukeVacaId = nameof(DukeAddonEnum.DukeVaca).ToLower();
- campaigns.Add(dukeVacaId, new DukeCampaign()
+ campaigns.Add(new(dukeVacaId), new DukeCampaign()
{
Id = dukeVacaId,
Type = AddonTypeEnum.Official,
@@ -183,7 +184,7 @@ Duke Nukem 3D is a first-person shooter developed and published by **3D Realms**
if (IsNuclearWinterInstalled)
{
var dukeNwId = nameof(DukeAddonEnum.DukeNW).ToLower();
- campaigns.Add(dukeNwId, new DukeCampaign()
+ campaigns.Add(new(dukeNwId), new DukeCampaign()
{
Id = dukeNwId,
Type = AddonTypeEnum.Official,
@@ -215,7 +216,7 @@ Duke Nukem must travel to the North Pole in order to stop the brainwashed Santa
if (IsDukeDCInstalled)
{
var dukeDcId = nameof(DukeAddonEnum.DukeDC).ToLower();
- campaigns.Add(dukeDcId, new DukeCampaign()
+ campaigns.Add(new(dukeDcId), new DukeCampaign()
{
Id = dukeDcId,
Type = AddonTypeEnum.Official,
@@ -250,7 +251,7 @@ Duke Nukem must travel to the North Pole in order to stop the brainwashed Santa
if (IsDuke64Installed)
{
var duke64Id = nameof(GameEnum.Duke64).ToLower();
- campaigns.Add(duke64Id, new DukeCampaign()
+ campaigns.Add(new(duke64Id), new DukeCampaign()
{
Id = duke64Id,
Type = AddonTypeEnum.Official,
diff --git a/src/Games/Games/FuryGame.cs b/src/Games/Games/FuryGame.cs
index 4898607f..c43956fb 100644
--- a/src/Games/Games/FuryGame.cs
+++ b/src/Games/Games/FuryGame.cs
@@ -1,4 +1,5 @@
using ClientCommon.Providers;
+using Common;
using Common.Enums;
using Common.Helpers;
using Common.Interfaces;
@@ -28,14 +29,14 @@ PlaytimeProvider playtimeProvider
///
- protected override Dictionary GetOriginalCampaigns()
+ protected override Dictionary GetOriginalCampaigns()
{
- Dictionary campaigns = new(1, StringComparer.OrdinalIgnoreCase);
+ Dictionary campaigns = new(1);
if (IsBaseGameInstalled)
{
var furyId = nameof(GameEnum.Fury).ToLower();
- campaigns.Add(furyId, new FuryCampaign()
+ campaigns.Add(new(furyId), new FuryCampaign()
{
Id = furyId,
Type = AddonTypeEnum.Official,
diff --git a/src/Games/Games/RedneckGame.cs b/src/Games/Games/RedneckGame.cs
index 73222696..aa2bdbe4 100644
--- a/src/Games/Games/RedneckGame.cs
+++ b/src/Games/Games/RedneckGame.cs
@@ -1,4 +1,5 @@
using ClientCommon.Providers;
+using Common;
using Common.Enums;
using Common.Enums.Addons;
using Common.Enums.Versions;
@@ -45,14 +46,14 @@ PlaytimeProvider playtimeProvider
///
- protected override Dictionary GetOriginalCampaigns()
+ protected override Dictionary GetOriginalCampaigns()
{
- Dictionary campaigns = new(3, StringComparer.OrdinalIgnoreCase);
+ Dictionary campaigns = new(3);
if (IsBaseGameInstalled)
{
var redneckId = nameof(GameEnum.Redneck).ToLower();
- campaigns.Add(redneckId, new RedneckCampaign()
+ campaigns.Add(new(redneckId), new RedneckCampaign()
{
Id = redneckId,
Type = AddonTypeEnum.Official,
@@ -86,7 +87,7 @@ protected override Dictionary GetOriginalCampaigns()
if (IsRoute66Installed)
{
var redneckR66Id = nameof(RedneckAddonEnum.Route66).ToLower();
- campaigns.Add(redneckR66Id, new RedneckCampaign()
+ campaigns.Add(new(redneckR66Id), new RedneckCampaign()
{
Id = redneckR66Id,
Type = AddonTypeEnum.Official,
@@ -117,7 +118,7 @@ protected override Dictionary GetOriginalCampaigns()
if (IsAgainInstalled)
{
var redneckRaId = nameof(GameEnum.RidesAgain).ToLower();
- campaigns.Add(redneckRaId, new RedneckCampaign()
+ campaigns.Add(new(redneckRaId), new RedneckCampaign()
{
Id = redneckRaId,
Type = AddonTypeEnum.Official,
diff --git a/src/Games/Games/SlaveGame.cs b/src/Games/Games/SlaveGame.cs
index 8925e0a7..1bb50608 100644
--- a/src/Games/Games/SlaveGame.cs
+++ b/src/Games/Games/SlaveGame.cs
@@ -1,4 +1,5 @@
using ClientCommon.Providers;
+using Common;
using Common.Enums;
using Common.Helpers;
using Common.Interfaces;
@@ -28,14 +29,14 @@ PlaytimeProvider playtimeProvider
///
- protected override Dictionary GetOriginalCampaigns()
+ protected override Dictionary GetOriginalCampaigns()
{
- Dictionary campaigns = new(1, StringComparer.OrdinalIgnoreCase);
+ Dictionary campaigns = new(1);
if (IsBaseGameInstalled)
{
var slaveId = nameof(GameEnum.Exhumed).ToLower();
- campaigns.Add(slaveId, new SlaveCampaign()
+ campaigns.Add(new(slaveId), new SlaveCampaign()
{
Id = slaveId,
Type = AddonTypeEnum.Official,
diff --git a/src/Games/Games/WangGame.cs b/src/Games/Games/WangGame.cs
index 42e321ae..6eee1da5 100644
--- a/src/Games/Games/WangGame.cs
+++ b/src/Games/Games/WangGame.cs
@@ -1,4 +1,5 @@
using ClientCommon.Providers;
+using Common;
using Common.Enums;
using Common.Enums.Addons;
using Common.Helpers;
@@ -41,14 +42,14 @@ PlaytimeProvider playtimeProvider
///
/// Get list of original campaigns
///
- protected override Dictionary GetOriginalCampaigns()
+ protected override Dictionary GetOriginalCampaigns()
{
- Dictionary campaigns = new(3, StringComparer.OrdinalIgnoreCase);
+ Dictionary campaigns = new(3);
if (IsBaseGameInstalled)
{
var wangId = nameof(GameEnum.ShadowWarrior).ToLower();
- campaigns.Add(wangId, new WangCampaign()
+ campaigns.Add(new(wangId), new WangCampaign()
{
Id = wangId,
Type = AddonTypeEnum.Official,
@@ -77,7 +78,7 @@ protected override Dictionary GetOriginalCampaigns()
if (IsWantonInstalled)
{
var wangWdId = nameof(WangAddonEnum.Wanton).ToLower();
- campaigns.Add(wangWdId, new WangCampaign()
+ campaigns.Add(new(wangWdId), new WangCampaign()
{
Id = wangWdId,
Type = AddonTypeEnum.Official,
@@ -109,7 +110,7 @@ protected override Dictionary GetOriginalCampaigns()
if (IsTwinDragonInstalled)
{
var wangTdId = nameof(WangAddonEnum.TwinDragon).ToLower();
- campaigns.Add(wangTdId, new WangCampaign()
+ campaigns.Add(new(wangTdId), new WangCampaign()
{
Id = wangTdId,
Type = AddonTypeEnum.Official,
diff --git a/src/Mods/Providers/DownloadableAddonsProvider.cs b/src/Mods/Providers/DownloadableAddonsProvider.cs
index a1d7d28e..37d9fb45 100644
--- a/src/Mods/Providers/DownloadableAddonsProvider.cs
+++ b/src/Mods/Providers/DownloadableAddonsProvider.cs
@@ -1,154 +1,181 @@
using ClientCommon.API;
using ClientCommon.Helpers;
+using Common;
using Common.Enums;
using Common.Helpers;
using Common.Interfaces;
using Common.Tools;
using System.Collections.Immutable;
-namespace Mods.Providers
+namespace Mods.Providers;
+
+///
+/// Class that provides lists of addons available to download
+///
+public sealed class DownloadableAddonsProvider : IDownloadableAddonsProvider
{
- ///
- /// Class that provides lists of addons available to download
- ///
- public sealed class DownloadableAddonsProvider : IDownloadableAddonsProvider
+ private readonly IGame _game;
+ private readonly ArchiveTools _archiveTools;
+ private readonly ApiInterface _apiInterface;
+
+ private Dictionary>? _cache;
+ private readonly SemaphoreSlim _semaphore = new(1);
+
+ public event AddonChanged AddonDownloadedEvent;
+
+ ///
+ public Progress Progress { get; private set; }
+
+ [Obsolete($"Don't create directly. Use {nameof(DownloadableAddonsProviderFactory)}.")]
+ public DownloadableAddonsProvider(
+ IGame game,
+ ArchiveTools archiveTools,
+ ApiInterface apiInterface
+ )
{
- private readonly IGame _game;
- private readonly ArchiveTools _archiveTools;
- private readonly ApiInterface _apiInterface;
+ _game = game;
+ _archiveTools = archiveTools;
+ _apiInterface = apiInterface;
- private Dictionary>? _cache;
- private readonly SemaphoreSlim _semaphore = new(1);
+ Progress = _archiveTools.Progress;
+ }
- public event AddonChanged AddonDownloadedEvent;
- ///
- public Progress Progress { get; private set; }
+ ///
+ public async Task CreateCacheAsync()
+ {
+ await _semaphore.WaitAsync();
- [Obsolete($"Don't create directly. Use {nameof(DownloadableAddonsProviderFactory)}.")]
- public DownloadableAddonsProvider(
- IGame game,
- ArchiveTools archiveTools,
- ApiInterface apiInterface
- )
+ if (_cache is not null)
{
- _game = game;
- _archiveTools = archiveTools;
- _apiInterface = apiInterface;
-
- Progress = _archiveTools.Progress;
+ _semaphore.Release();
+ return;
}
+ var addons = await _apiInterface.GetAddonsAsync(_game.GameEnum).ConfigureAwait(false);
- ///
- public async Task CreateCacheAsync()
+ if (addons is null || addons.Count == 0)
{
- await _semaphore.WaitAsync();
+ _semaphore.Release();
+ return;
+ }
- if (_cache is not null)
- {
- _semaphore.Release();
- return;
- }
+ _cache = [];
- var addons = await _apiInterface.GetAddonsAsync(_game.GameEnum).ConfigureAwait(false);
+ addons = [.. addons.OrderBy(a => a.Title).OrderBy(a => a.Version)];
- if (addons is null || addons.Count == 0)
- {
- _semaphore.Release();
- return;
- }
+ foreach (var addon in addons)
+ {
+ _cache.TryAdd(addon.AddonType, []);
+ _cache[addon.AddonType].TryAdd(new(addon.Id, addon.Version), addon);
+ }
- _cache = [];
+ _semaphore.Release();
+ }
- foreach (var addon in addons)
- {
- _cache.TryAdd(addon.AddonType, []);
- _cache[addon.AddonType].TryAdd(addon.Id, addon);
- }
- _semaphore.Release();
+ ///
+ public ImmutableList GetDownloadableAddons(AddonTypeEnum addonType)
+ {
+ if (_cache is null)
+ {
+ return [];
+ }
+
+ if (!_cache.TryGetValue(addonType, out var addonTypeCache))
+ {
+ return [];
}
+ var installedAddons = _game.InstalledAddonsProvider.GetInstalledAddons(addonType);
- ///
- public ImmutableList GetDownloadableAddons(AddonTypeEnum addonType)
+ foreach (var downloadableAddon in addonTypeCache)
{
- if (_cache is null)
- {
- return [];
- }
+ var existinsAddons = installedAddons.Where(x => x.Key.Id == downloadableAddon.Key.Id).Select(x => x.Key);
- if (!_cache.TryGetValue(addonType, out var addonTypeCache))
+ downloadableAddon.Value.IsInstalled = true;
+
+ if (!existinsAddons.Any())
{
- return [];
+ downloadableAddon.Value.IsInstalled = false;
+ continue;
}
- var installedAddons = _game.InstalledAddonsProvider.GetInstalledAddons(addonType);
-
- foreach (var downloadableAddon in addonTypeCache)
+ //Death Wish hack
+ if (downloadableAddon.Key.Id.Contains("death-wish", StringComparison.InvariantCultureIgnoreCase) &&
+ downloadableAddon.Key.Version!.StartsWith('1'))
{
- if (installedAddons.TryGetValue(downloadableAddon.Key, out var installedAddon))
+ if (existinsAddons.Contains(downloadableAddon.Key))
{
downloadableAddon.Value.IsInstalled = true;
-
- if (VersionComparer.Compare(downloadableAddon.Value.Version, installedAddon.Version, ">"))
- {
- downloadableAddon.Value.HasNewerVersion = true;
- }
}
else
{
downloadableAddon.Value.IsInstalled = false;
}
+
+ continue;
}
+ else
+ {
+ foreach (var version in existinsAddons.Select(x => x.Version).Where(x => x is not null))
+ {
+ downloadableAddon.Value.HasNewerVersion = true;
- return [.. addonTypeCache.Values];
+ if (VersionComparer.Compare(downloadableAddon.Value.Version, version!, "=="))
+ {
+ downloadableAddon.Value.HasNewerVersion = false;
+ break;
+ }
+ }
+ }
}
+ return [.. addonTypeCache.Values];
+ }
+
- ///
- public async Task DownloadAddonAsync(IDownloadableAddon addon)
+ ///
+ public async Task DownloadAddonAsync(IDownloadableAddon addon)
+ {
+ var url = addon.DownloadUrl;
+ var file = Path.GetFileName(url.ToString());
+ string path;
+
+ if (addon.AddonType is AddonTypeEnum.TC)
+ {
+ path = _game.CampaignsFolderPath;
+ }
+ else if (addon.AddonType is AddonTypeEnum.Map)
+ {
+ path = _game.MapsFolderPath;
+ }
+ else if (addon.AddonType is AddonTypeEnum.Mod)
+ {
+ path = _game.ModsFolderPath;
+ }
+ else
{
- var url = addon.DownloadUrl;
- var file = Path.GetFileName(url.ToString());
- string path;
+ ThrowHelper.NotImplementedException(addon.AddonType.ToString());
+ return;
+ }
- if (addon.AddonType is AddonTypeEnum.TC)
- {
- path = _game.CampaignsFolderPath;
- }
- else if (addon.AddonType is AddonTypeEnum.Map)
- {
- path = _game.MapsFolderPath;
- }
- else if (addon.AddonType is AddonTypeEnum.Mod)
- {
- path = _game.ModsFolderPath;
- }
- else
- {
- ThrowHelper.NotImplementedException(addon.AddonType.ToString());
- return;
- }
+ var pathToFile = Path.Combine(path, file);
- var pathToFile = Path.Combine(path, file);
+ await _archiveTools.DownloadFileAsync(url, pathToFile).ConfigureAwait(false);
- await _archiveTools.DownloadFileAsync(url, pathToFile).ConfigureAwait(false);
+ _game.InstalledAddonsProvider.AddAddon(addon.AddonType, pathToFile);
- _game.InstalledAddonsProvider.AddAddon(addon.AddonType, pathToFile);
+ if (!ClientProperties.IsDevMode)
+ {
+ var result = await _apiInterface.IncreaseNumberOfInstallsAsync(addon.Id);
- if (!ClientProperties.IsDevMode)
+ if (result)
{
- var result = await _apiInterface.IncreaseNumberOfInstallsAsync(addon.Id);
-
- if (result)
- {
- addon.Installs++;
- }
+ addon.Installs++;
}
-
- AddonDownloadedEvent?.Invoke(_game, addon.AddonType);
}
+
+ AddonDownloadedEvent?.Invoke(_game, addon.AddonType);
}
}
diff --git a/src/Mods/Providers/InstalledAddonsProvider.cs b/src/Mods/Providers/InstalledAddonsProvider.cs
index d95719b3..0735bf5e 100644
--- a/src/Mods/Providers/InstalledAddonsProvider.cs
+++ b/src/Mods/Providers/InstalledAddonsProvider.cs
@@ -1,5 +1,6 @@
using ClientCommon.Config;
using ClientCommon.Providers;
+using Common;
using Common.Enums;
using Common.Enums.Versions;
using Common.Helpers;
@@ -20,7 +21,7 @@ public sealed class InstalledAddonsProvider : IInstalledAddonsProvider
private readonly IConfigProvider _config;
private readonly PlaytimeProvider _playtimeProvider;
- private readonly Dictionary> _cache;
+ private readonly Dictionary> _cache;
private static readonly SemaphoreSlim _semaphore = new(1);
private bool _isCacheUpdating = false;
@@ -95,13 +96,13 @@ public void AddAddon(AddonTypeEnum addonType, string pathToFile)
var dict = _cache[addon.Type];
- if (dict.TryGetValue(addon.Id, out _))
+ if (dict.TryGetValue(new(addon.Id, addon.Version), out _))
{
- dict[addon.Id] = addon;
+ dict[new(addon.Id, addon.Version)] = addon;
}
else
{
- dict.Add(addon.Id, addon);
+ dict.Add(new(addon.Id, addon.Version), addon);
}
}
@@ -113,13 +114,13 @@ public void DeleteAddon(IAddon addon)
File.Delete(addon.PathToFile);
- _cache[addon.Type].Remove(addon.Id);
+ _cache[addon.Type].Remove(new(addon.Id, addon.Version));
AddonsChangedEvent?.Invoke(_game, addon.Type);
}
///
- public void EnableAddon(string addonId)
+ public void EnableAddon(AddonVersion addonId)
{
((AutoloadMod)_cache[AddonTypeEnum.Mod][addonId]).IsEnabled = true;
@@ -127,7 +128,7 @@ public void EnableAddon(string addonId)
}
///
- public void DisableAddon(string addonId)
+ public void DisableAddon(AddonVersion addonId)
{
((AutoloadMod)_cache[AddonTypeEnum.Mod][addonId]).IsEnabled = false;
@@ -135,7 +136,7 @@ public void DisableAddon(string addonId)
}
///
- public Dictionary GetInstalledAddons(AddonTypeEnum addonType)
+ public Dictionary GetInstalledAddons(AddonTypeEnum addonType)
{
if (_isCacheUpdating)
{
@@ -161,9 +162,9 @@ public Dictionary GetInstalledAddons(AddonTypeEnum addonType)
///
/// Addon type
/// Paths to addon files
- private Dictionary GetAddonsFromFiles(AddonTypeEnum addonType, IEnumerable files)
+ private Dictionary GetAddonsFromFiles(AddonTypeEnum addonType, IEnumerable files)
{
- Dictionary addedAddons = new(files.Count(), StringComparer.OrdinalIgnoreCase);
+ Dictionary addedAddons = new(files.Count());
foreach (var file in files)
{
@@ -176,25 +177,26 @@ private Dictionary GetAddonsFromFiles(AddonTypeEnum addonType, I
continue;
}
- if (addedAddons.TryGetValue(newAddon.Id, out var existingMod))
+ if (newAddon is AutoloadMod &&
+ addedAddons.TryGetValue(new(newAddon.Id, newAddon.Version), out var existingMod))
{
if (existingMod.Version is null &&
newAddon.Version is not null)
{
//replacing with addon that have version
- addedAddons[newAddon.Id] = newAddon;
+ addedAddons[new(newAddon.Id, newAddon.Version)] = newAddon;
}
else if (existingMod.Version is not null &&
newAddon.Version is not null &&
VersionComparer.Compare(newAddon.Version, existingMod.Version, ">"))
{
//replacing with addon that have higher version
- addedAddons[newAddon.Id] = newAddon;
+ addedAddons[new(newAddon.Id, newAddon.Version)] = newAddon;
}
}
else
{
- addedAddons.Add(newAddon.Id, newAddon);
+ addedAddons.Add(new(newAddon.Id, newAddon.Version), newAddon);
}
}
catch (Exception)
diff --git a/src/Ports/Ports/BasePort.cs b/src/Ports/Ports/BasePort.cs
index 26ed4f31..fa735035 100644
--- a/src/Ports/Ports/BasePort.cs
+++ b/src/Ports/Ports/BasePort.cs
@@ -1,4 +1,5 @@
using ClientCommon.Helpers;
+using Common;
using Common.Enums;
using Common.Enums.Addons;
using Common.Helpers;
@@ -168,7 +169,7 @@ protected void GetMapArgs(StringBuilder sb, IGame game, IAddon camp)
///
/// Autoload mod
/// Campaign
- protected bool ValidateAutoloadMod(AutoloadMod autoloadMod, IAddon campaign, Dictionary addons)
+ protected bool ValidateAutoloadMod(AutoloadMod autoloadMod, IAddon campaign, Dictionary addons)
{
if (!autoloadMod.IsEnabled)
{
@@ -199,7 +200,7 @@ protected bool ValidateAutoloadMod(AutoloadMod autoloadMod, IAddon campaign, Dic
{
foreach (var dep in autoloadMod.DependentAddons)
{
- if (!addons.ContainsKey(dep.Key) &&
+ if (!addons.ContainsKey(new(dep.Key, dep.Value)) &&
!campaign.Id.Equals(dep.Key, StringComparison.OrdinalIgnoreCase))
{
//skipping mod that doesn't have every dependency
@@ -212,7 +213,7 @@ protected bool ValidateAutoloadMod(AutoloadMod autoloadMod, IAddon campaign, Dic
{
foreach (var dep in autoloadMod.IncompatibleAddons)
{
- if (addons.ContainsKey(dep.Key) ||
+ if (addons.ContainsKey(new(dep.Key, dep.Value)) ||
campaign.Id.Equals(dep.Key, StringComparison.OrdinalIgnoreCase))
{
//skipping incompatible mods