Skip to content

Commit

Permalink
Merge pull request #2233 from erri120/game-features
Browse files Browse the repository at this point in the history
Add game support and feature tracking
  • Loading branch information
erri120 authored Nov 14, 2024
2 parents af6c9ba + abb64a1 commit ec18f4d
Show file tree
Hide file tree
Showing 11 changed files with 172 additions and 4 deletions.
8 changes: 7 additions & 1 deletion src/Abstractions/NexusMods.Abstractions.Games/AGame.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,13 @@ protected virtual ILoadoutSynchronizer MakeSynchronizer(IServiceProvider provide

/// <inheritdoc />
public abstract string Name { get; }


/// <inheritdoc />
public abstract SupportType SupportType { get; }

/// <inheritdoc />
public virtual HashSet<FeatureStatus> Features { get; } = [];

/// <inheritdoc />
public abstract GameId GameId { get; }

Expand Down
77 changes: 77 additions & 0 deletions src/Abstractions/NexusMods.Abstractions.Games/Feature.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
using JetBrains.Annotations;

namespace NexusMods.Abstractions.Games;

/// <summary>
/// Represents a feature a game can support.
/// </summary>
/// <param name="Description">Description</param>
[PublicAPI]
public readonly record struct Feature(string Description)
{
/// <summary>
/// Identifier.
/// </summary>
public readonly Guid Id = Guid.NewGuid();

/// <inheritdoc/>
public override int GetHashCode() => Id.GetHashCode();

/// <summary>
/// Equality.
/// </summary>
public bool Equals(Feature? other) => other is not null && Id.Equals(other.Value.Id);
}

/// <summary>
/// Status of a feature.
/// </summary>
/// <param name="Feature">The feature.</param>
/// <param name="IsImplemented">Whether the feature is implemented or not.</param>
[PublicAPI]
public readonly record struct FeatureStatus(Feature Feature, bool IsImplemented);

/// <summary>
/// Status of all game features.
/// </summary>
[PublicAPI]
public enum GameFeatureStatus
{
/// <summary>
/// Default value.
/// </summary>
None = 0,

/// <summary>
/// The minimum amount of features is implemented.
/// </summary>
Minimal = 1,

/// <summary>
/// All features are implemented.
/// </summary>
Full = 2,
}

/// <summary>
/// Extension methods.
/// </summary>
[PublicAPI]
public static class FeatureExtensions
{
/// <summary>
///
/// </summary>
public static GameFeatureStatus ToStatus(this HashSet<FeatureStatus> features)
{
var implemented = features.Count(status => status.IsImplemented);
var total = features.Count;
if (implemented == total) return GameFeatureStatus.Full;

return implemented switch
{
0 => GameFeatureStatus.None,
_ => GameFeatureStatus.Minimal,
};
}
}
19 changes: 19 additions & 0 deletions src/Abstractions/NexusMods.Abstractions.Games/Features.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
using JetBrains.Annotations;
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member

namespace NexusMods.Abstractions.Games;

/// <summary>
/// List of features.
/// </summary>
[PublicAPI]
public static class BaseFeatures
{
public static readonly Feature GameLocatable = new(Description: "The game can be located.");

public static readonly Feature HasInstallers = new(Description: "The extension provides mod installers.");

public static readonly Feature HasDiagnostics = new(Description: "The extension provides diagnostics.");

public static readonly Feature HasLoadOrder = new(Description: "The extension provides load-order support.");
}
4 changes: 4 additions & 0 deletions src/Abstractions/NexusMods.Abstractions.Games/IGame.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ namespace NexusMods.Abstractions.Games;
/// </summary>
public interface IGame : ILocatableGame
{
SupportType SupportType { get; }
HashSet<FeatureStatus> Features { get; }
GameFeatureStatus FeatureStatus => Features.ToStatus();

/// <summary>
/// Stream factory for the game's icon, must be square but need not be small.
/// </summary>
Expand Down
25 changes: 25 additions & 0 deletions src/Abstractions/NexusMods.Abstractions.Games/SupportLevel.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
using JetBrains.Annotations;

namespace NexusMods.Abstractions.Games;

/// <summary>
/// Game support type.
/// </summary>
[PublicAPI]
public enum SupportType
{
/// <summary>
/// The game is unsupported.
/// </summary>
Unsupported = 0,

/// <summary>
/// The game is officially supported and the extension maintained by Nexus Mods.
/// </summary>
Official = 1,

/// <summary>
/// The game is supported and the extension is maintained by the community.
/// </summary>
Community = 2,
}
9 changes: 9 additions & 0 deletions src/Games/NexusMods.Games.Larian/BaldursGate3/BaldursGate3.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,15 @@ public class BaldursGate3 : AGame, ISteamGame, IGogGame
public IEnumerable<uint> SteamIds => [1086940u];
public IEnumerable<long> GogIds => [1456460669];
public override GameId GameId => GameId.From(3474);
public override SupportType SupportType => SupportType.Official;

public override HashSet<FeatureStatus> Features { get; } =
[
new(BaseFeatures.GameLocatable, IsImplemented: true),
new(BaseFeatures.HasInstallers, IsImplemented: true),
new(BaseFeatures.HasDiagnostics, IsImplemented: true),
new(BaseFeatures.HasLoadOrder, IsImplemented: false),
];

public BaldursGate3(IServiceProvider provider) : base(provider)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,16 @@ public sealed class MountAndBlade2Bannerlord : AGame, ISteamGame, IGogGame, IEpi

public override string Name => DisplayName;
public override GameId GameId => GameIdStatic;

public override SupportType SupportType => SupportType.Official;

public override HashSet<FeatureStatus> Features { get; } =
[
new(BaseFeatures.GameLocatable, IsImplemented: true),
new(BaseFeatures.HasInstallers, IsImplemented: true),
new(BaseFeatures.HasDiagnostics, IsImplemented: false),
new(BaseFeatures.HasLoadOrder, IsImplemented: false),
];

public IEnumerable<uint> SteamIds => [261550u];
public IEnumerable<long> GogIds => [1802539526, 1564781494];
public IEnumerable<string> EpicCatalogItemId => ["Chickadee"];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,16 @@ protected override ILoadoutSynchronizer MakeSynchronizer(IServiceProvider provid

public override string Name => "Cyberpunk 2077";
public override GameId GameId => GameIdStatic;
public override SupportType SupportType => SupportType.Official;

public override HashSet<FeatureStatus> Features { get; } =
[
new(BaseFeatures.GameLocatable, IsImplemented: true),
new(BaseFeatures.HasInstallers, IsImplemented: true),
new(BaseFeatures.HasDiagnostics, IsImplemented: true),
new(BaseFeatures.HasLoadOrder, IsImplemented: false),
];

public override GamePath GetPrimaryFile(GameStore store) => new(LocationId.Game, "bin/x64/Cyberpunk2077.exe");
protected override IReadOnlyDictionary<LocationId, AbsolutePath> GetLocations(IFileSystem fileSystem,
GameLocatorResult installation)
Expand Down
9 changes: 9 additions & 0 deletions src/Games/NexusMods.Games.StardewValley/StardewValley.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,15 @@ public class StardewValley : AGame, ISteamGame, IGogGame, IXboxGame
public override string Name => "Stardew Valley";
public override GameId GameId => GameId.From(1303);

public override SupportType SupportType => SupportType.Official;

public override HashSet<FeatureStatus> Features { get; } =
[
new(BaseFeatures.GameLocatable, IsImplemented: true),
new(BaseFeatures.HasInstallers, IsImplemented: true),
new(BaseFeatures.HasDiagnostics, IsImplemented: true),
];

public StardewValley(
IOSInformation osInformation,
IEnumerable<IGameLocator> gameLocators,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,6 @@ protected override ValueTask MoveNewFilesToMods(Loadout.ReadOnly loadout, IEnume

foreach (var newFile in newFiles)
{
GamePath gamePath;

if (!IsModFile(newFile.LoadoutItemWithTargetPath.TargetPath, out var modDirectoryName))
{
continue;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ public class StubbedGame : AGame, IEADesktopGame, IEpicGame, IOriginGame, ISteam
public override string Name => "Stubbed Game";
public override GameId GameId => GameId.From(uint.MaxValue);

public override SupportType SupportType => SupportType.Unsupported;

private readonly IServiceProvider _serviceProvider;
public StubbedGame(ILogger<StubbedGame> logger, IEnumerable<IGameLocator> locators,
IFileSystem fileSystem, IServiceProvider provider) : base(provider)
Expand Down

0 comments on commit ec18f4d

Please sign in to comment.