Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .github/workflows/build-and-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ jobs:
run: dotnet build --no-restore
- name: Test Unit
run: dotnet test ./src/Tests.Unit/Tests.Unit.csproj --no-build --verbosity normal
- name: Test External
run: dotnet test ./src/Tests.External/Tests.External.csproj --no-build --verbosity normal

build-and-test-linux:
runs-on: ubuntu-latest
Expand All @@ -32,3 +34,5 @@ jobs:
run: dotnet build --no-restore
- name: Test Unit
run: dotnet test ./src/Tests.Unit/Tests.Unit.csproj --no-build --verbosity normal
- name: Test External
run: dotnet test ./src/Tests.External/Tests.External.csproj --no-build --verbosity normal
1 change: 1 addition & 0 deletions BuildLauncher.slnx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
</Folder>
<Folder Name="/Tests/">
<Project Path="src/Tests.Database/Tests.Database.csproj" />
<Project Path="src/Tests.External/Tests.External.csproj" />
<Project Path="src/Tests.Unit/Tests.Unit.csproj" />
</Folder>
<Project Path="src/Benchmarks/Benchmarks.csproj" Id="8645d9f4-dce1-455b-b334-d988acd75e72" />
Expand Down
25 changes: 8 additions & 17 deletions src/Addons/Addons/BaseAddon.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using Core.All;
using Core.All.Enums;
using Core.All.Interfaces;
using Core.Client.Helpers;

namespace Addons.Addons;

Expand All @@ -16,15 +17,20 @@ public abstract class BaseAddon
/// </summary>
public required AddonId AddonId { get; init; }

/// <summary>
/// Addon file information.
/// </summary>
public required AddonFilePathWrapper? FileInfo { get; init; }

/// <summary>
/// Type of the addon
/// </summary>
public required AddonTypeEnum Type { get; init; }

/// <summary>
/// List of supported games
/// Supported game
/// </summary>
public required GameStruct SupportedGame { get; init; }
public required GameInfo SupportedGame { get; init; }

/// <summary>
/// Name of the addon
Expand Down Expand Up @@ -61,11 +67,6 @@ public abstract class BaseAddon
/// </summary>
public required IReadOnlyDictionary<string, string?>? IncompatibleAddons { get; init; }

/// <summary>
/// Path to addon file
/// </summary>
public required string? PathToFile { get; init; }

/// <summary>
/// Cover image hash
/// </summary>
Expand All @@ -91,11 +92,6 @@ public abstract class BaseAddon
/// </summary>
public required IStartMap? StartMap { get; init; }

/// <summary>
/// Is addon unpacked to a folder
/// </summary>
public required bool IsUnpacked { get; init; }

/// <summary>
/// Is the item marked as a favorite.
/// </summary>
Expand All @@ -116,11 +112,6 @@ public abstract class BaseAddon
/// </summary>
public required Dictionary<string, Dictionary<string, OptionalParameterTypeEnum>>? Options { get; init; }

/// <summary>
/// Name of the addon file
/// </summary>
public string? FileName => PathToFile is null ? null : Path.GetFileName(PathToFile);

/// <inheritdoc/>
public override string ToString() => Title;

Expand Down
38 changes: 23 additions & 15 deletions src/Addons/Helpers/AddonDropHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
using Microsoft.Extensions.Logging;
using SharpCompress.Archives;

namespace Addons.Helpers;

public interface IAddonDropHelper
{
/// <summary>
Expand All @@ -18,12 +20,15 @@ public interface IAddonDropHelper

public sealed class AddonDropHelper : IAddonDropHelper
{
private readonly InstalledAddonsProviderFactory _installedAddonsProvider;
private readonly LocalFilesProvider _addonScanner;
private readonly ILogger<AddonDropHelper> _logger;

public AddonDropHelper(InstalledAddonsProviderFactory installedAddonsProvider, ILogger<AddonDropHelper> logger)
public AddonDropHelper(
LocalFilesProvider addonScanner,
ILogger<AddonDropHelper> logger
)
{
_installedAddonsProvider = installedAddonsProvider;
_addonScanner = addonScanner;
_logger = logger;
}

Expand All @@ -35,21 +40,19 @@ public AddonDropHelper(InstalledAddonsProviderFactory installedAddonsProvider, I
return null;
}

List<string> failedInstalls = [];
List<string>? failedInstalls = null;

foreach (var file in filePaths)
{
var isAdded = await AddAddonAsync(file, game).ConfigureAwait(false);

if (!isAdded)
if (isAdded)
{
failedInstalls.Add(Path.GetFileName(file));
continue;
}
}

if (failedInstalls.Count == 0)
{
return null;
failedInstalls ??= [];
failedInstalls.Add(Path.GetFileName(file));
}

return failedInstalls;
Expand All @@ -71,7 +74,7 @@ private async Task<bool> AddAddonAsync(string pathToFile, BaseGame game)
return false;
}

var addon = await GetGameAndTypeFromFileAsync(pathToFile, game).ConfigureAwait(false);
var addon = await GetGameAndTypeFromFileAsync(pathToFile, game.GameEnum).ConfigureAwait(false);

if (addon is null)
{
Expand Down Expand Up @@ -109,8 +112,12 @@ private async Task<bool> AddAddonAsync(string pathToFile, BaseGame game)

File.Copy(pathToFile, newPathToFile, true);

using var installer = _installedAddonsProvider.Get(game);
await installer.AddAddonAsync(newPathToFile).ConfigureAwait(false);
var parsedFiles = await _addonScanner.TryAddFileToCacheAsync(newPathToFile, game.GameEnum).ConfigureAwait(false);

if (parsedFiles is null)
{
return false;
}

return true;
}
Expand All @@ -119,7 +126,8 @@ private async Task<bool> AddAddonAsync(string pathToFile, BaseGame game)
/// Get game enum and addon type enum from a file.
/// </summary>
/// <param name="pathToFile">Path to file.</param>
private async Task<Tuple<GameEnum, AddonTypeEnum>?> GetGameAndTypeFromFileAsync(string pathToFile, BaseGame game)
/// <param name="gameEnum">The game to associate with standalone .map files.</param>
private async Task<Tuple<GameEnum, AddonTypeEnum>?> GetGameAndTypeFromFileAsync(string pathToFile, GameEnum gameEnum)
{
if (ArchiveFactory.IsArchive(pathToFile, out _))
{
Expand All @@ -138,7 +146,7 @@ private async Task<bool> AddAddonAsync(string pathToFile, BaseGame game)

if (pathToFile.EndsWith(".map", StringComparison.OrdinalIgnoreCase))
{
return new(game.GameEnum, AddonTypeEnum.Map);
return new(gameEnum, AddonTypeEnum.Map);
}

return null;
Expand Down
103 changes: 52 additions & 51 deletions src/Addons/Helpers/AutoloadModsValidator.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using Addons.Addons;
using Core.All;
using Core.All.Enums;
using Core.All.Helpers;

Expand All @@ -14,7 +13,7 @@ public static class AutoloadModsValidator
/// <param name="campaign">Campaign</param>
/// <param name="mods">Autoload mods</param>
/// <param name="features">Features supported by the port</param>
public static bool ValidateAutoloadMod(AutoloadMod autoloadMod, BaseAddon campaign, IReadOnlyDictionary<AddonId, BaseAddon> mods, List<FeatureEnum> features)
public static bool ValidateAutoloadMod(AutoloadMod autoloadMod, BaseAddon campaign, IReadOnlyList<BaseAddon> mods, List<FeatureEnum> features)
{
if (!autoloadMod.IsEnabled)
{
Expand All @@ -41,7 +40,7 @@ public static bool ValidateAutoloadMod(AutoloadMod autoloadMod, BaseAddon campai
return false;
}

//check if campaign is incomatible with this or all addons
//check if campaign is incompatible with this or all addons
if (campaign.IncompatibleAddons is not null)
{
foreach (var incompatibleAddon in campaign.IncompatibleAddons)
Expand Down Expand Up @@ -84,52 +83,49 @@ public static bool ValidateAutoloadMod(AutoloadMod autoloadMod, BaseAddon campai
private static bool CheckDependencies(
AutoloadMod autoloadMod,
BaseAddon campaign,
IReadOnlyDictionary<AddonId, BaseAddon> mods)
IReadOnlyList<BaseAddon> mods
)
{
if (autoloadMod.DependentAddons is not null)
if (autoloadMod.DependentAddons is null)
{
byte passedDependenciesCount = 0;
return true;
}

foreach (var dependentAddon in autoloadMod.DependentAddons)
byte passedDependenciesCount = 0;

foreach (var dependentAddon in autoloadMod.DependentAddons)
{
if (campaign.AddonId.Id.Equals(dependentAddon.Key, StringComparison.OrdinalIgnoreCase) &&
(dependentAddon.Value is null || VersionComparer.Compare(campaign.AddonId.Version, dependentAddon.Value)))
{
if (campaign.AddonId.Id.Equals(dependentAddon.Key, StringComparison.OrdinalIgnoreCase) &&
(dependentAddon.Value is null || VersionComparer.Compare(campaign.AddonId.Version, dependentAddon.Value)))
{
passedDependenciesCount++;
continue;
}
passedDependenciesCount++;
continue;
}

if (campaign.DependentAddons is not null &&
campaign.DependentAddons.TryGetValue(dependentAddon.Key, out var dependentAddonVersion) &&
(dependentAddon.Value is null || VersionComparer.Compare(dependentAddonVersion, dependentAddon.Value)))
{
passedDependenciesCount++;
continue;
}

if (campaign.DependentAddons?.TryGetValue(dependentAddon.Key, out var dependentAddonVersion) ?? false &&
(dependentAddon.Value is null || VersionComparer.Compare(dependentAddonVersion, dependentAddon.Value)))
foreach (var addon in mods)
{
if (!dependentAddon.Key.Equals(addon.AddonId.Id, StringComparison.InvariantCultureIgnoreCase))
{
passedDependenciesCount++;
continue;
}

foreach (var addon in mods)
if (dependentAddon.Value is null || VersionComparer.Compare(addon.AddonId.Version, dependentAddon.Value))
{
if (!dependentAddon.Key.Equals(addon.Key.Id, StringComparison.OrdinalIgnoreCase))
{
continue;
}

if (dependentAddon.Value is null)
{
passedDependenciesCount++;
}
else if (VersionComparer.Compare(addon.Key.Version, dependentAddon.Value))
{
passedDependenciesCount++;
}
passedDependenciesCount++;
}
}

return autoloadMod.DependentAddons.Count == passedDependenciesCount;
}
else
{
return true;
}

return autoloadMod.DependentAddons.Count == passedDependenciesCount;

}

/// <summary>
Expand All @@ -138,30 +134,35 @@ private static bool CheckDependencies(
private static bool CheckIncompatibles(
AutoloadMod autoloadMod,
BaseAddon campaign,
IReadOnlyDictionary<AddonId, BaseAddon> mods
IReadOnlyList<BaseAddon> mods
)
{
if (autoloadMod.IncompatibleAddons is null)
{
return true;
}

var campaignIncompatibles = campaign.IncompatibleAddons?.ToDictionary() ?? [];
campaignIncompatibles.Add(campaign.AddonId.Id, campaign.AddonId.Version);
campaignIncompatibles.AddRange(mods.Where(x => x.Value is AutoloadMod { IsEnabled: true }).ToDictionary(x => x.Key.Id, x => x.Key.Version));
campaignIncompatibles.TryAdd(campaign.AddonId.Id, campaign.AddonId.Version);
foreach (var addon in mods.Where(x => x is AutoloadMod { IsEnabled: true }))
{
campaignIncompatibles.TryAdd(addon.AddonId.Id, addon.AddonId.Version);
}

if (autoloadMod.IncompatibleAddons is not null)
foreach (var a in campaignIncompatibles)
{
foreach (var a in campaignIncompatibles)
foreach (var b in autoloadMod.IncompatibleAddons)
{
foreach (var b in autoloadMod.IncompatibleAddons)
if (!a.Key.Equals(b.Key, StringComparison.OrdinalIgnoreCase))
{
if (!a.Key.Equals(b.Key, StringComparison.OrdinalIgnoreCase))
{
continue;
}
continue;
}

var areEqual = VersionComparer.Compare(a.Value, b.Value);
var areEqual = VersionComparer.Compare(a.Value, b.Value);

if (areEqual)
{
return false;
}
if (areEqual)
{
return false;
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/Addons/Helpers/DiHelper.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using Addons.Providers;
using Core.Client.Providers;
using Microsoft.Extensions.DependencyInjection;

namespace Addons.Helpers;
Expand All @@ -15,6 +14,7 @@ public static IServiceCollection WithAddons(this IServiceCollection container)
_ = container.AddSingleton<DownloadableAddonsProviderFactory>();
_ = container.AddSingleton<OriginalCampaignsProvider>();
_ = container.AddSingleton<MetadataProvider>();
_ = container.AddSingleton<LocalFilesProvider>();

return container.AddTransient<IAddonDropHelper, AddonDropHelper>();
}
Expand Down
Loading
Loading