Skip to content

Commit

Permalink
Merge #3891 Alternate mod dirs for validation and manual installs
Browse files Browse the repository at this point in the history
  • Loading branch information
HebaruSan committed Aug 30, 2023
2 parents 5d1b8b8 + adf3156 commit 2950cbb
Show file tree
Hide file tree
Showing 6 changed files with 43 additions and 30 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ All notable changes to this project will be documented in this file.
- [Multiple] Caching and changeset fixes (#3881 by: HebaruSan; reviewed: techman83)
- [GUI] Mod list fixes and improvements (#3883 by: HebaruSan; reviewed: techman83)
- [Multiple] Multi-game labels (#3885 by: HebaruSan; reviewed: techman83)
- [Multiple] Alternate mod dirs for validation and manual installs (#3891 by: HebaruSan; reviewed: techman83)

### Internal

Expand Down
44 changes: 25 additions & 19 deletions Core/GameInstance.cs
Original file line number Diff line number Diff line change
Expand Up @@ -355,28 +355,32 @@ public bool Scan()
var manager = RegistryManager.Instance(this);
using (TransactionScope tx = CkanTransaction.CreateTransactionScope())
{
log.DebugFormat("Scanning for DLLs in {0}",
game.PrimaryModDirectory(this));
var oldDlls = manager.registry.InstalledDlls.ToHashSet();
manager.registry.ClearDlls();

if (Directory.Exists(game.PrimaryModDirectory(this)))
foreach (var dir in Enumerable.Repeat<string>(game.PrimaryModDirectoryRelative, 1)
.Concat(game.AlternateModDirectoriesRelative)
.Select(d => ToAbsoluteGameDir(d)))
{
// EnumerateFiles is *case-sensitive* in its pattern, which causes
// DLL files to be missed under Linux; we have to pick .dll, .DLL, or scanning
// GameData *twice*.
//
// The least evil is to walk it once, and filter it ourselves.
var files = Directory
.EnumerateFiles(game.PrimaryModDirectory(this), "*", SearchOption.AllDirectories)
.Where(file => file.EndsWith(".dll", StringComparison.CurrentCultureIgnoreCase))
.Select(CKANPathUtils.NormalizePath)
.Where(absPath => !game.StockFolders.Any(f =>
ToRelativeGameDir(absPath).StartsWith($"{f}/")));
log.DebugFormat("Scanning for DLLs in {0}", dir);

foreach (string dll in files)
if (Directory.Exists(dir))
{
manager.registry.RegisterDll(this, dll);
// EnumerateFiles is *case-sensitive* in its pattern, which causes
// DLL files to be missed under Linux; we have to pick .dll, .DLL, or scanning
// GameData *twice*.
//
// The least evil is to walk it once, and filter it ourselves.
var files = Directory
.EnumerateFiles(dir, "*", SearchOption.AllDirectories)
.Where(file => file.EndsWith(".dll", StringComparison.CurrentCultureIgnoreCase))
.Select(CKANPathUtils.NormalizePath)
.Where(absPath => !game.StockFolders.Any(f =>
ToRelativeGameDir(absPath).StartsWith($"{f}/")));

foreach (string dll in files)
{
manager.registry.RegisterDll(this, dll);
}
}
}
var newDlls = manager.registry.InstalledDlls.ToHashSet();
Expand Down Expand Up @@ -432,9 +436,11 @@ public string ToAbsoluteGameDir(string path)
/// </returns>
public string DllPathToIdentifier(string relative_path)
{
if (!relative_path.StartsWith($"{game.PrimaryModDirectoryRelative}/", StringComparison.CurrentCultureIgnoreCase))
var paths = Enumerable.Repeat<string>(game.PrimaryModDirectoryRelative, 1)
.Concat(game.AlternateModDirectoriesRelative);
if (!paths.Any(p => relative_path.StartsWith($"{p}/", StringComparison.CurrentCultureIgnoreCase)))
{
// DLLs only live in the primary mod directory
// DLLs only live in the primary or alternate mod directories
return null;
}
Match match = dllPattern.Match(relative_path);
Expand Down
3 changes: 2 additions & 1 deletion Core/Games/IGame.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ public interface IGame
string MacPath();

// What do we contain?
string PrimaryModDirectoryRelative { get; }
string PrimaryModDirectoryRelative { get; }
string[] AlternateModDirectoriesRelative { get; }
string PrimaryModDirectory(GameInstance inst);
string[] StockFolders { get; }
string[] ReservedPaths { get; }
Expand Down
1 change: 1 addition & 0 deletions Core/Games/KerbalSpaceProgram.cs
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ public string MacPath()
}

public string PrimaryModDirectoryRelative => "GameData";
public string[] AlternateModDirectoriesRelative => new string[] { };

public string PrimaryModDirectory(GameInstance inst)
=> CKANPathUtils.NormalizePath(
Expand Down
1 change: 1 addition & 0 deletions Core/Games/KerbalSpaceProgram2.cs
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ public string MacPath()
}

public string PrimaryModDirectoryRelative => "GameData/Mods";
public string[] AlternateModDirectoriesRelative => new string[] { "BepInEx/plugins" };

public string PrimaryModDirectory(GameInstance inst)
=> CKANPathUtils.NormalizePath(
Expand Down
23 changes: 13 additions & 10 deletions Netkan/Validators/InstallsFilesValidator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,23 +35,26 @@ public void Validate(Metadata metadata)
{
throw new Kraken(string.Format(
"Module contains no files matching: {0}",
mod.DescribeInstallStanzas(_game)
));
mod.DescribeInstallStanzas(_game)));
}

// Get the files the module will install
var allFiles = _moduleService.FileDestinations(mod, file).Memoize();

// Make sure no paths include GameData other than at the start
var gamedatas = allFiles
.Where(p => p.StartsWith("GameData", StringComparison.InvariantCultureIgnoreCase)
&& p.LastIndexOf("/GameData/", StringComparison.InvariantCultureIgnoreCase) > 0)
.OrderBy(f => f)
.ToList();
if (gamedatas.Any())
foreach (var dir in Enumerable.Repeat<string>(_game.PrimaryModDirectoryRelative, 1)
.Concat(_game.AlternateModDirectoriesRelative))
{
var badPaths = string.Join("\r\n", gamedatas);
throw new Kraken($"GameData directory found within GameData:\r\n{badPaths}");
var gamedatas = allFiles
.Where(p => p.StartsWith(dir, StringComparison.InvariantCultureIgnoreCase)
&& p.LastIndexOf($"/{dir}/", StringComparison.InvariantCultureIgnoreCase) > 0)
.OrderBy(f => f)
.ToList();
if (gamedatas.Any())
{
var badPaths = string.Join("\r\n", gamedatas);
throw new Kraken($"{dir} directory found within {dir}:\r\n{badPaths}");
}
}

// Make sure we won't try to overwrite our own files
Expand Down

0 comments on commit 2950cbb

Please sign in to comment.