Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Alternate mod dirs for validation and manual installs #3891

Merged
Merged
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
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
Loading