-
Notifications
You must be signed in to change notification settings - Fork 52
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #667 from Nexus-Mods/suggestions-for-advancedinsta…
…ller Added: Basic Suggesions for AdvancedInstaller
- Loading branch information
Showing
14 changed files
with
290 additions
and
12 deletions.
There are no files selected for viewing
78 changes: 78 additions & 0 deletions
78
docs/decisions/backend/0010-basic-advanced-installer-suggestions.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
# Advanced Installer: Suggestions | ||
|
||
This document describes the design of the 'Suggestions' system within Advanced Installer, pictured | ||
in the following mockup below: | ||
|
||
![There is an image here, once it's in the ADRs folder, I promise >w<](./images/0009-advanced-installer-location.png) | ||
|
||
## Context Statement | ||
|
||
When using the Advanced Installer, the user should be provided with 'hints' dictating where a file might | ||
require to be placed based on a number of heuristics. | ||
|
||
This is part of the UX effort to 'Make Modding Easy' and a general requirement of our [Advanced Installer Design](./0009-advanced-installer-design.md). | ||
|
||
## Considered Options (Suggestions) | ||
|
||
- Reusing the Deployment System (`InstallFolderTarget`) for suggestions. | ||
- Creating a Suggestion System from scratch. | ||
|
||
## Decision Outcome | ||
|
||
Rather than splitting the metadata in two, we can leverage the existing | ||
`InstallFolderTarget` system in order to implement Advanced Installer suggestions; | ||
as that system already has required metadata. | ||
|
||
### Consequences | ||
|
||
- [Good] Strong code reuse as `InstallFolderTarget` already has required metadata to support this functionality. | ||
- [Neutral] Each `InstallFolderTarget` folder will now need a description. | ||
- [Neutral] All games will need to be converted to new `InstallFolderTarget` system. | ||
- [Negative] The `InstallFolderTarget` list may not contain all folders that the user may want to drop their files manually to. | ||
|
||
## Implementation: Reuse of `InstallFolderTarget` | ||
|
||
The parts of `InstallFolderTarget` which are usable by the suggestion system will be lifted out into a new interface, | ||
shown below: | ||
|
||
```csharp | ||
/// <summary> | ||
/// Represents a target used for suggestions for installing mods within the Advanced Installer. | ||
/// </summary> | ||
public interface IModInstallDestination | ||
{ | ||
/// <summary> | ||
/// GamePath to which the relative mod file paths should appended to. | ||
/// </summary> | ||
public GamePath DestinationGamePath { get; init; } | ||
|
||
/// <summary> | ||
/// List of known recognizable file extensions for direct children of the target <see cref="DestinationGamePath"/>. | ||
/// NOTE: Only include file extensions that are only likely to appear at this level of the folder hierarchy. | ||
/// </summary> | ||
public IEnumerable<Extension> KnownValidFileExtensions { get; init; } | ||
|
||
/// <summary> | ||
/// List of file extensions to discard when installing to this target. | ||
/// </summary> | ||
public IEnumerable<Extension> FileExtensionsToDiscard { get; init; } | ||
} | ||
``` | ||
|
||
## Acquiring `IModInstallDestination`(s) During Deploy Step (a.k.a. `GetModsAsync`) | ||
|
||
Extend the `GameInstallation` abstract class to expose a property which returns `IModInstallDestination`(s) for the game's most common directories. | ||
To do this, we will add an abstract method into `AGame`, to accompany the existing `GetLocations()` method. | ||
|
||
This property is populated with the following elements: | ||
- All `GamePath` entries (i.e. Game folder, Save folder, Config folder, etc.) | ||
- All `InstallFolderTarget` entries (e.g. `Data` folder for Skyrim.), as `IModInstallDestination`. | ||
- Custom `IModInstallDestination`(s) defined on a per game basis. | ||
- Remove duplicates. | ||
- Apply the filtering steps detailed below. (Detailed in future ADR/Issue) | ||
|
||
This interface can be accessed during the deploy step under `GameInstallation` structure. | ||
|
||
Note: Currently we don't auto fetch, `InstallFolderTarget`(s) [as in, auto add targets with 0 code] for the following reason(s): | ||
- We might potentially one day have directories that `GenericFolderMatchInstaller` might use, but we don't want to display to user. | ||
- We can only pull locations from `GenericFolderMatchInstaller` in current code, but that lives in an inaccessible package/project from `AGame`. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
89 changes: 89 additions & 0 deletions
89
...DataModel/Games/GameCapabilities/FolderMatchInstallerCapability/IModInstallDestination.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
using NexusMods.Paths; | ||
|
||
namespace NexusMods.DataModel.Games.GameCapabilities.FolderMatchInstallerCapability; | ||
|
||
/// <summary> | ||
/// Represents a target used for where user mods may be manually installed when using human assisted installers | ||
/// such as the Advanced Installer. | ||
/// </summary> | ||
public interface IModInstallDestination | ||
{ | ||
/// <summary> | ||
/// GamePath to which the relative mod file paths should appended to. | ||
/// </summary> | ||
public GamePath DestinationGamePath { get; } | ||
} | ||
|
||
/// <summary> | ||
/// Helper methods for <see cref="IModInstallDestination"/>. | ||
/// </summary> | ||
public static class ModInstallDestinationHelpers | ||
{ | ||
/// <summary> | ||
/// Converts a list of <see cref="InstallFolderTarget"/>(s) into <see cref="IModInstallDestination"/>. | ||
/// </summary> | ||
/// <param name="target">The target to create a mod install destination from.</param> | ||
/// <param name="accumulator">List to return the results into.</param> | ||
public static void AddInstallFolderTarget(InstallFolderTarget target, List<IModInstallDestination> accumulator) | ||
{ | ||
accumulator.Add(target); | ||
foreach (var subTarget in target.SubTargets) | ||
AddInstallFolderTarget(subTarget, accumulator); | ||
} | ||
|
||
/// <summary> | ||
/// Converts a list of <see cref="InstallFolderTarget"/>(s) into <see cref="IModInstallDestination"/>. | ||
/// </summary> | ||
/// <param name="targets">Collection of targets to get destinations from.</param> | ||
/// <param name="accumulator">List to return the results into.</param> | ||
public static void AddInstallFolderTargets(IEnumerable<InstallFolderTarget> targets, List<IModInstallDestination> accumulator) | ||
{ | ||
foreach (var target in targets) | ||
AddInstallFolderTarget(target, accumulator); | ||
} | ||
|
||
/// <summary> | ||
/// Adds a list of common locations (passed via parameter) to accumulator of <see cref="IModInstallDestination"/>. | ||
/// </summary> | ||
/// <param name="locations">Locations to add to the accumulator.</param> | ||
/// <param name="accumulator">List to return the results into.</param> | ||
public static void AddCommonLocations(IReadOnlyDictionary<LocationId, AbsolutePath> locations, List<IModInstallDestination> accumulator) | ||
{ | ||
foreach (var location in locations) | ||
{ | ||
accumulator.Add(new InstallFolderTarget() | ||
{ | ||
// Locations has | ||
DestinationGamePath = new GamePath(location.Key, ""), | ||
KnownSourceFolderNames = Array.Empty<string>(), | ||
KnownValidSubfolders = Array.Empty<string>(), | ||
KnownValidFileExtensions = Array.Empty<Extension>(), | ||
FileExtensionsToDiscard = Array.Empty<Extension>(), | ||
SubPathsToDiscard = Array.Empty<RelativePath>() | ||
}); | ||
} | ||
} | ||
|
||
/// <summary> | ||
/// Converts a list of common locations (passed via parameter) to <see cref="IModInstallDestination"/>. | ||
/// </summary> | ||
/// <param name="locations">Locations to add to the accumulator.</param> | ||
public static List<IModInstallDestination> GetCommonLocations(IReadOnlyDictionary<LocationId, AbsolutePath> locations) | ||
{ | ||
var result = new List<IModInstallDestination>(); | ||
AddCommonLocations(locations, result); | ||
return result; | ||
} | ||
|
||
/// <summary> | ||
/// Converts a list of <see cref="InstallFolderTarget"/>(s) into <see cref="IModInstallDestination"/>. | ||
/// </summary> | ||
/// <param name="targets">Collection of targets to get destinations from.</param> | ||
/// <returns>Collection of destinations.</returns> | ||
public static List<IModInstallDestination> FromInstallFolderTargets(IEnumerable<InstallFolderTarget> targets) | ||
{ | ||
var result = new List<IModInstallDestination>(); | ||
AddInstallFolderTargets(targets, result); | ||
return result; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.