diff --git a/Cmdline/Action/GameInstance.cs b/Cmdline/Action/GameInstance.cs
index 849d954703..2690379f85 100644
--- a/Cmdline/Action/GameInstance.cs
+++ b/Cmdline/Action/GameInstance.cs
@@ -558,7 +558,7 @@ int badArgument()
string path = options.path;
GameVersion version;
bool setDefault = options.setDefault;
- IGame game = GameInstanceManager.GameByShortName(options.gameId);
+ IGame game = KnownGames.GameByShortName(options.gameId);
if (game == null)
{
User.RaiseMessage(Properties.Resources.InstanceFakeBadGame, options.gameId);
diff --git a/Cmdline/ConsoleUser.cs b/Cmdline/ConsoleUser.cs
index 2df7feed7d..47bf56d6a9 100644
--- a/Cmdline/ConsoleUser.cs
+++ b/Cmdline/ConsoleUser.cs
@@ -254,11 +254,15 @@ public void RaiseError(string message, params object[] args)
/// Progress in percent
public void RaiseProgress(string message, int percent)
{
- // The percent looks weird on non-download messages.
- // The leading newline makes sure we don't end up with a mess from previous
- // download messages.
- GoToStartOfLine();
- Console.Write("{0}", message);
+ if (message != lastProgressMessage)
+ {
+ // The percent looks weird on non-download messages.
+ // The leading newline makes sure we don't end up with a mess from previous
+ // download messages.
+ GoToStartOfLine();
+ Console.Write("{0}", message);
+ lastProgressMessage = message;
+ }
// This message leaves the cursor at the end of a line of text
atStartOfLine = false;
@@ -286,6 +290,8 @@ public void RaiseProgress(int percent, long bytesPerSecond, long bytesLeft)
///
private int previousPercent = -1;
+ private string lastProgressMessage = null;
+
///
/// Writes a message to the console
///
diff --git a/Core/CKAN-core.csproj b/Core/CKAN-core.csproj
index 4d73dad1d0..ac3d1cd5dd 100644
--- a/Core/CKAN-core.csproj
+++ b/Core/CKAN-core.csproj
@@ -27,6 +27,7 @@
+
diff --git a/Core/CKANPathUtils.cs b/Core/CKANPathUtils.cs
index 1d18a32c68..b0bce16138 100644
--- a/Core/CKANPathUtils.cs
+++ b/Core/CKANPathUtils.cs
@@ -1,6 +1,5 @@
using System;
using System.IO;
-using System.Linq;
using System.Text.RegularExpressions;
using log4net;
@@ -20,48 +19,6 @@ public static class CKANPathUtils
private static readonly ILog log = LogManager.GetLogger(typeof(CKANPathUtils));
- ///
- /// Finds Steam on the current machine.
- ///
- /// The path to Steam, or null if not found
- public static string SteamPath()
- {
- foreach (var steam in SteamPaths.Where(p => !string.IsNullOrEmpty(p)))
- {
- log.DebugFormat("Looking for Steam in {0}", steam);
- if (Directory.Exists(steam))
- {
- log.InfoFormat("Found Steam at {0}", steam);
- return steam;
- }
- }
- log.Info("Steam not found on this system.");
- return null;
- }
-
- private const string steamRegKey = @"HKEY_CURRENT_USER\Software\Valve\Steam";
- private const string steamRegValue = @"SteamPath";
-
- private static string[] SteamPaths
- => Platform.IsWindows ? new string[]
- {
- // First check the registry
- (string)Microsoft.Win32.Registry.GetValue(steamRegKey, steamRegValue, null),
- }
- : Platform.IsUnix ? new string[]
- {
- Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Personal),
- ".local", "share", "Steam"),
- Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Personal),
- ".steam", "steam"),
- }
- : Platform.IsMac ? new string[]
- {
- Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Personal),
- "Library", "Application Support", "Steam"),
- }
- : Array.Empty();
-
///
/// Normalizes the path by replacing all \ with / and removing any trailing slash.
///
diff --git a/Core/Converters/JsonToGamesDictionaryConverter.cs b/Core/Converters/JsonToGamesDictionaryConverter.cs
index 4f8b3ccbd6..0b57f9ca6b 100644
--- a/Core/Converters/JsonToGamesDictionaryConverter.cs
+++ b/Core/Converters/JsonToGamesDictionaryConverter.cs
@@ -4,6 +4,8 @@
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
+using CKAN.Games;
+
namespace CKAN
{
///
@@ -59,7 +61,7 @@ public override object ReadJson(JsonReader reader, Type objectType, object exist
var obj = (IDictionary)Activator.CreateInstance(objectType);
if (!IsTokenEmpty(token))
{
- foreach (var gameName in GameInstanceManager.AllGameShortNames())
+ foreach (var gameName in KnownGames.AllGameShortNames())
{
// Make a new copy of the value for each game
obj.Add(gameName, token.ToObject(valueType));
diff --git a/Core/Extensions/EnumerableExtensions.cs b/Core/Extensions/EnumerableExtensions.cs
index a6d4aef63e..ca57a2aedf 100644
--- a/Core/Extensions/EnumerableExtensions.cs
+++ b/Core/Extensions/EnumerableExtensions.cs
@@ -4,6 +4,7 @@
using System.Collections.Concurrent;
using System.Linq;
using System.Threading;
+using System.Text.RegularExpressions;
namespace CKAN.Extensions
{
@@ -216,6 +217,16 @@ public static void Deconstruct(this KeyValuePair kvp, out T1 key
val = kvp.Value;
}
+ ///
+ /// Try matching a regex against a series of strings and return the Match objects
+ ///
+ /// Sequence of strings to scan
+ /// Pattern to match
+ /// Sequence of Match objects
+ public static IEnumerable WithMatches(this IEnumerable source, Regex pattern)
+ => source.Select(val => pattern.TryMatch(val, out Match match) ? match : null)
+ .Where(m => m != null);
+
}
///
diff --git a/Core/GameInstance.cs b/Core/GameInstance.cs
index 9cea2f3622..1189a68013 100644
--- a/Core/GameInstance.cs
+++ b/Core/GameInstance.cs
@@ -33,6 +33,7 @@ public class GameInstance : IEquatable
public TimeLog playTime;
public string Name { get; set; }
+
///
/// Returns a file system safe version of the instance name that can be used within file names.
///
@@ -240,44 +241,6 @@ public static string PortableDir(IGame game)
return null;
}
- ///
- /// Attempts to automatically find a KSP install on this system.
- /// Returns the path to the install on success.
- /// Throws a DirectoryNotFoundException on failure.
- ///
- public static string FindGameDir(IGame game)
- {
- // See if we can find KSP as part of a Steam install.
- string gameSteamPath = game.SteamPath();
- if (gameSteamPath != null)
- {
- if (game.GameInFolder(new DirectoryInfo(gameSteamPath)))
- {
- return gameSteamPath;
- }
-
- log.DebugFormat("Have Steam, but {0} is not at \"{1}\".",
- game.ShortName, gameSteamPath);
- }
-
- // See if we can find a non-Steam Mac KSP install
- string kspMacPath = game.MacPath();
- if (kspMacPath != null)
- {
- if (game.GameInFolder(new DirectoryInfo(kspMacPath)))
- {
- log.InfoFormat("Found a {0} install at {1}",
- game.ShortName, kspMacPath);
- return kspMacPath;
- }
- log.DebugFormat("Default Mac {0} folder exists at \"{1}\", but {0} is not installed there.",
- game.ShortName, kspMacPath);
- }
-
- // Oh noes! We can't find KSP!
- throw new DirectoryNotFoundException();
- }
-
///
/// Detects the version of a game in a given directory.
///
diff --git a/Core/GameInstanceManager.cs b/Core/GameInstanceManager.cs
index 6e800ff35b..1a6a114a40 100644
--- a/Core/GameInstanceManager.cs
+++ b/Core/GameInstanceManager.cs
@@ -12,7 +12,6 @@
using CKAN.Configuration;
using CKAN.Games;
using CKAN.Games.KerbalSpaceProgram;
-using CKAN.Games.KerbalSpaceProgram2;
using CKAN.Extensions;
using CKAN.Games.KerbalSpaceProgram.GameVersionProviders;
@@ -23,12 +22,6 @@ namespace CKAN
///
public class GameInstanceManager : IDisposable
{
- private static readonly IGame[] knownGames = new IGame[]
- {
- new KerbalSpaceProgram(),
- new KerbalSpaceProgram2(),
- };
-
///
/// An IUser object for user interaction.
/// It is initialized during the startup with a ConsoleUser,
@@ -40,11 +33,13 @@ public class GameInstanceManager : IDisposable
public NetModuleCache Cache { get; private set; }
+ public readonly SteamLibrary SteamLibrary = new SteamLibrary();
+
private static readonly ILog log = LogManager.GetLogger(typeof (GameInstanceManager));
private readonly SortedList instances = new SortedList();
- public string[] AllInstanceAnchorFiles => knownGames
+ public string[] AllInstanceAnchorFiles => KnownGames.knownGames
.SelectMany(g => g.InstanceAnchorFiles)
.Distinct()
.ToArray();
@@ -98,7 +93,7 @@ public GameInstance GetPreferredInstance()
// Actual worker for GetPreferredInstance()
internal GameInstance _GetPreferredInstance()
{
- foreach (IGame game in knownGames)
+ foreach (IGame game in KnownGames.knownGames)
{
// TODO: Check which ones match, prompt user if >1
@@ -135,7 +130,7 @@ internal GameInstance _GetPreferredInstance()
// If we know of no instances, try to find one.
// Otherwise, we know of too many instances!
// We don't know which one to pick, so we return null.
- return !instances.Any() ? FindAndRegisterDefaultInstance() : null;
+ return !instances.Any() ? FindAndRegisterDefaultInstances() : null;
}
///
@@ -145,35 +140,58 @@ internal GameInstance _GetPreferredInstance()
///
/// Returns the resulting game instance if found.
///
- public GameInstance FindAndRegisterDefaultInstance()
+ public GameInstance FindAndRegisterDefaultInstances()
{
if (instances.Any())
{
throw new KSPManagerKraken("Attempted to scan for defaults with instances");
}
- GameInstance val = null;
- foreach (IGame game in knownGames)
+ var found = FindDefaultInstances();
+ foreach (var inst in found)
{
- try
+ log.DebugFormat("Registering {0} at {1}...",
+ inst.Name, inst.GameDir());
+ AddInstance(inst);
+ }
+ return found.FirstOrDefault();
+ }
+
+ public GameInstance[] FindDefaultInstances()
+ {
+ var found = KnownGames.knownGames.SelectMany(g =>
+ SteamLibrary.Games
+ .Select(sg => new { name = sg.Name, dir = sg.GameDir })
+ .Append(new
+ {
+ name = string.Format(Properties.Resources.GameInstanceManagerAuto,
+ g.ShortName),
+ dir = g.MacPath(),
+ })
+ .Where(obj => obj.dir != null && g.GameInFolder(obj.dir))
+ .Select(obj => new GameInstance(g, obj.dir.FullName, obj.name, User)))
+ .Where(inst => inst.Valid)
+ .ToArray();
+ foreach (var group in found.GroupBy(inst => inst.Name))
+ {
+ if (group.Count() > 1)
{
- string gamedir = GameInstance.FindGameDir(game);
- GameInstance foundInst = new GameInstance(
- game, gamedir, string.Format(Properties.Resources.GameInstanceManagerAuto, game.ShortName), User);
- if (foundInst.Valid)
+ // Make sure the names are unique
+ int index = 0;
+ foreach (var inst in group)
{
- var inst = AddInstance(foundInst);
- val = val ?? inst;
+ // Find an unused name
+ string name;
+ do
+ {
+ ++index;
+ name = $"{group.Key} ({++index})";
+ }
+ while (found.Any(other => other.Name == name));
+ inst.Name = name;
}
}
- catch (DirectoryNotFoundException)
- {
- // Thrown if no folder found for a game
- }
- catch (NotKSPDirKraken)
- {
- }
}
- return val;
+ return found;
}
///
@@ -429,7 +447,7 @@ public void SetCurrentInstance(string name)
public void SetCurrentInstanceByPath(string path)
{
- var matchingGames = knownGames
+ var matchingGames = KnownGames.knownGames
.Where(g => g.GameInFolder(new DirectoryInfo(path)))
.ToList();
switch (matchingGames.Count)
@@ -458,7 +476,7 @@ public void SetCurrentInstanceByPath(string path)
public GameInstance InstanceAt(string path)
{
- var matchingGames = knownGames
+ var matchingGames = KnownGames.knownGames
.Where(g => g.GameInFolder(new DirectoryInfo(path)))
.ToList();
switch (matchingGames.Count)
@@ -514,8 +532,8 @@ private void LoadInstances()
var gameName = instance.Item3;
try
{
- var game = knownGames.FirstOrDefault(g => g.ShortName == gameName)
- ?? knownGames[0];
+ var game = KnownGames.knownGames.FirstOrDefault(g => g.ShortName == gameName)
+ ?? KnownGames.knownGames[0];
log.DebugFormat("Loading {0} from {1}", name, path);
// Add unconditionally, sort out invalid instances downstream
instances.Add(name, new GameInstance(game, path, name, User));
@@ -614,7 +632,7 @@ public void Dispose()
}
public static bool IsGameInstanceDir(DirectoryInfo path)
- => knownGames.Any(g => g.GameInFolder(path));
+ => KnownGames.knownGames.Any(g => g.GameInFolder(path));
///
/// Tries to determine the game that is installed at the given path
@@ -625,7 +643,7 @@ public static bool IsGameInstanceDir(DirectoryInfo path)
/// Thrown when no games found
public IGame DetermineGame(DirectoryInfo path, IUser user)
{
- var matchingGames = knownGames.Where(g => g.GameInFolder(path)).ToList();
+ var matchingGames = KnownGames.knownGames.Where(g => g.GameInFolder(path)).ToList();
switch (matchingGames.Count)
{
case 0:
@@ -642,21 +660,5 @@ public IGame DetermineGame(DirectoryInfo path, IUser user)
return selection >= 0 ? matchingGames[selection] : null;
}
}
-
- ///
- /// Return a game object based on its short name
- ///
- /// The short name to find
- /// A game object or null if none found
- public static IGame GameByShortName(string shortName)
- => knownGames.FirstOrDefault(g => g.ShortName == shortName);
-
- ///
- /// Return the short names of all known games
- ///
- /// Sequence of short name strings
- public static IEnumerable AllGameShortNames()
- => knownGames.Select(g => g.ShortName);
-
}
}
diff --git a/Core/Games/IGame.cs b/Core/Games/IGame.cs
index 5af71c556d..58ff2f6a91 100644
--- a/Core/Games/IGame.cs
+++ b/Core/Games/IGame.cs
@@ -13,13 +13,12 @@ public interface IGame
{
// Identification, used for display and saved/loaded in settings JSON
// Must be unique!
- string ShortName { get; }
+ string ShortName { get; }
DateTime FirstReleaseDate { get; }
// Where are we?
- bool GameInFolder(DirectoryInfo where);
- string SteamPath();
- string MacPath();
+ bool GameInFolder(DirectoryInfo where);
+ DirectoryInfo MacPath();
// What do we contain?
string PrimaryModDirectoryRelative { get; }
@@ -32,7 +31,7 @@ public interface IGame
bool IsReservedDirectory(GameInstance inst, string path);
bool AllowInstallationIn(string name, out string path);
void RebuildSubdirectories(string absGameRoot);
- string DefaultCommandLine(string path);
+ string[] DefaultCommandLines(SteamLibrary steamLib, DirectoryInfo path);
string[] AdjustCommandLine(string[] args, GameVersion installedVersion);
IDlcDetector[] DlcDetectors { get; }
diff --git a/Core/Games/KerbalSpaceProgram.cs b/Core/Games/KerbalSpaceProgram.cs
index beaf56edd0..a91f980886 100644
--- a/Core/Games/KerbalSpaceProgram.cs
+++ b/Core/Games/KerbalSpaceProgram.cs
@@ -25,68 +25,13 @@ public bool GameInFolder(DirectoryInfo where)
=> InstanceAnchorFiles.Any(f => File.Exists(Path.Combine(where.FullName, f)))
&& Directory.Exists(Path.Combine(where.FullName, "GameData"));
- ///
- /// Finds the Steam KSP path. Returns null if the folder cannot be located.
- ///
- /// The KSP path.
- public string SteamPath()
- {
- // Attempt to get the Steam path.
- string steamPath = CKANPathUtils.SteamPath();
-
- if (steamPath == null)
- {
- return null;
- }
-
- // Default steam library
- string installPath = KSPDirectory(steamPath);
- if (installPath != null)
- {
- return installPath;
- }
-
- // Attempt to find through config file
- string configPath = Path.Combine(steamPath, "config", "config.vdf");
- if (File.Exists(configPath))
- {
- log.InfoFormat("Found Steam config file at {0}", configPath);
- StreamReader reader = new StreamReader(configPath);
- string line;
- while ((line = reader.ReadLine()) != null)
- {
- // Found Steam library
- if (line.Contains("BaseInstallFolder"))
- {
- // This assumes config file is valid, we just skip it if it looks funny.
- string[] split_line = line.Split('"');
-
- if (split_line.Length > 3)
- {
- log.DebugFormat("Found a Steam Libary Location at {0}", split_line[3]);
-
- installPath = KSPDirectory(split_line[3]);
- if (installPath != null)
- {
- log.InfoFormat("Found a KSP install at {0}", installPath);
- return installPath;
- }
- }
- }
- }
- }
-
- // Could not locate the folder.
- return null;
- }
-
///
/// Get the default non-Steam path to KSP on macOS
///
///
/// "/Applications/Kerbal Space Program" if it exists and we're on a Mac, else null
///
- public string MacPath()
+ public DirectoryInfo MacPath()
{
if (Platform.IsMac)
{
@@ -95,7 +40,8 @@ public string MacPath()
Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles),
"Kerbal Space Program"
);
- return Directory.Exists(installPath) ? installPath : null;
+ return Directory.Exists(installPath) ? new DirectoryInfo(installPath)
+ : null;
}
return null;
}
@@ -175,14 +121,18 @@ public void RebuildSubdirectories(string absGameRoot)
}
}
- public string DefaultCommandLine(string path)
- => Platform.IsMac
- ? "./KSP.app/Contents/MacOS/KSP"
- : string.Format(Platform.IsUnix ? "./{0} -single-instance"
- : "{0} -single-instance",
- InstanceAnchorFiles.FirstOrDefault(f =>
- File.Exists(Path.Combine(path, f)))
- ?? InstanceAnchorFiles.First());
+ public string[] DefaultCommandLines(SteamLibrary steamLib, DirectoryInfo path)
+ => Enumerable.Repeat(Platform.IsMac
+ ? "./KSP.app/Contents/MacOS/KSP"
+ : string.Format(Platform.IsUnix ? "./{0} -single-instance"
+ : "{0} -single-instance",
+ InstanceAnchorFiles.FirstOrDefault(f =>
+ File.Exists(Path.Combine(path.FullName, f)))
+ ?? InstanceAnchorFiles.First()),
+ 1)
+ .Concat(steamLib.GameAppURLs(path)
+ .Select(url => url.ToString()))
+ .ToArray();
public string[] AdjustCommandLine(string[] args, GameVersion installedVersion)
{
@@ -325,28 +275,6 @@ private static string Scenarios(GameInstance inst)
{ "Ships/Script", "Ships/Script" }
};
- ///
- /// Finds the KSP path under a Steam Library. Returns null if the folder cannot be located.
- ///
- /// Steam Library Path
- /// The KSP path.
- private static string KSPDirectory(string steamPath)
- {
- // There are several possibilities for the path under Linux.
- // Try with the uppercase version.
- string installPath = Path.Combine(steamPath, "SteamApps", "common", "Kerbal Space Program");
-
- if (Directory.Exists(installPath))
- {
- return installPath;
- }
-
- // Try with the lowercase version.
- installPath = Path.Combine(steamPath, "steamapps", "common", "Kerbal Space Program");
-
- return Directory.Exists(installPath) ? installPath : null;
- }
-
///
/// If the installed game version is in the given range,
/// return the given array without the given parameter,
diff --git a/Core/Games/KerbalSpaceProgram2.cs b/Core/Games/KerbalSpaceProgram2.cs
index c85c535318..46c3ff14fd 100644
--- a/Core/Games/KerbalSpaceProgram2.cs
+++ b/Core/Games/KerbalSpaceProgram2.cs
@@ -23,68 +23,13 @@ public bool GameInFolder(DirectoryInfo where)
=> InstanceAnchorFiles.Any(f => File.Exists(Path.Combine(where.FullName, f)))
&& Directory.Exists(Path.Combine(where.FullName, "KSP2_x64_Data"));
- ///
- /// Finds the Steam KSP path. Returns null if the folder cannot be located.
- ///
- /// The KSP path.
- public string SteamPath()
- {
- // Attempt to get the Steam path.
- string steamPath = CKANPathUtils.SteamPath();
-
- if (steamPath == null)
- {
- return null;
- }
-
- // Default steam library
- string installPath = GameDirectory(steamPath);
- if (installPath != null)
- {
- return installPath;
- }
-
- // Attempt to find through config file
- string configPath = Path.Combine(steamPath, "config", "config.vdf");
- if (File.Exists(configPath))
- {
- log.InfoFormat("Found Steam config file at {0}", configPath);
- StreamReader reader = new StreamReader(configPath);
- string line;
- while ((line = reader.ReadLine()) != null)
- {
- // Found Steam library
- if (line.Contains("BaseInstallFolder"))
- {
- // This assumes config file is valid, we just skip it if it looks funny.
- string[] split_line = line.Split('"');
-
- if (split_line.Length > 3)
- {
- log.DebugFormat("Found a Steam Libary Location at {0}", split_line[3]);
-
- installPath = GameDirectory(split_line[3]);
- if (installPath != null)
- {
- log.InfoFormat("Found a KSP install at {0}", installPath);
- return installPath;
- }
- }
- }
- }
- }
-
- // Could not locate the folder.
- return null;
- }
-
///
/// Get the default non-Steam path to KSP on macOS
///
///
/// "/Applications/Kerbal Space Program" if it exists and we're on a Mac, else null
///
- public string MacPath()
+ public DirectoryInfo MacPath()
{
if (Platform.IsMac)
{
@@ -93,7 +38,8 @@ public string MacPath()
Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles),
"Kerbal Space Program 2"
);
- return Directory.Exists(installPath) ? installPath : null;
+ return Directory.Exists(installPath) ? new DirectoryInfo(installPath)
+ : null;
}
return null;
}
@@ -146,14 +92,18 @@ public void RebuildSubdirectories(string absGameRoot)
}
}
- public string DefaultCommandLine(string path)
- => Platform.IsMac
- ? "./KSP2.app/Contents/MacOS/KSP2"
- : string.Format(Platform.IsUnix ? "./{0} -single-instance"
- : "{0} -single-instance",
- InstanceAnchorFiles.FirstOrDefault(f =>
- File.Exists(Path.Combine(path, f)))
- ?? InstanceAnchorFiles.First());
+ public string[] DefaultCommandLines(SteamLibrary steamLib, DirectoryInfo path)
+ => Enumerable.Repeat(Platform.IsMac
+ ? "./KSP2.app/Contents/MacOS/KSP2"
+ : string.Format(Platform.IsUnix ? "./{0} -single-instance"
+ : "{0} -single-instance",
+ InstanceAnchorFiles.FirstOrDefault(f =>
+ File.Exists(Path.Combine(path.FullName, f)))
+ ?? InstanceAnchorFiles.First()),
+ 1)
+ .Concat(steamLib.GameAppURLs(path)
+ .Select(url => url.ToString()))
+ .ToArray();
public string[] AdjustCommandLine(string[] args, GameVersion installedVersion)
=> args;
@@ -244,28 +194,6 @@ private GameVersion VersionFromFile(string path)
{ "BepInEx/plugins", "BepInEx/plugins" },
};
- ///
- /// Finds the KSP path under a Steam Library. Returns null if the folder cannot be located.
- ///
- /// Steam Library Path
- /// The KSP path.
- private static string GameDirectory(string steamPath)
- {
- // There are several possibilities for the path under Linux.
- // Try with the uppercase version.
- string installPath = Path.Combine(steamPath, "SteamApps", "common", "Kerbal Space Program 2");
-
- if (Directory.Exists(installPath))
- {
- return installPath;
- }
-
- // Try with the lowercase version.
- installPath = Path.Combine(steamPath, "steamapps", "common", "Kerbal Space Program 2");
-
- return Directory.Exists(installPath) ? installPath : null;
- }
-
private static readonly ILog log = LogManager.GetLogger(typeof(KerbalSpaceProgram2));
}
}
diff --git a/Core/Games/KnownGames.cs b/Core/Games/KnownGames.cs
new file mode 100644
index 0000000000..dc8f1009b6
--- /dev/null
+++ b/Core/Games/KnownGames.cs
@@ -0,0 +1,31 @@
+using System.Collections.Generic;
+using System.Linq;
+
+
+namespace CKAN.Games
+{
+ public static class KnownGames
+ {
+ public static readonly IGame[] knownGames = new IGame[]
+ {
+ new KerbalSpaceProgram.KerbalSpaceProgram(),
+ new KerbalSpaceProgram2.KerbalSpaceProgram2(),
+ };
+
+ ///
+ /// Return a game object based on its short name
+ ///
+ /// The short name to find
+ /// A game object or null if none found
+ public static IGame GameByShortName(string shortName)
+ => knownGames.FirstOrDefault(g => g.ShortName == shortName);
+
+ ///
+ /// Return the short names of all known games
+ ///
+ /// Sequence of short name strings
+ public static IEnumerable AllGameShortNames()
+ => knownGames.Select(g => g.ShortName);
+
+ }
+}
diff --git a/Core/SteamLibrary.cs b/Core/SteamLibrary.cs
new file mode 100644
index 0000000000..137acca7aa
--- /dev/null
+++ b/Core/SteamLibrary.cs
@@ -0,0 +1,149 @@
+using System;
+using System.IO;
+using System.Linq;
+using System.Collections.Generic;
+
+using log4net;
+using ValveKeyValue;
+
+namespace CKAN
+{
+ public class SteamLibrary
+ {
+ public SteamLibrary()
+ {
+ var libraryPath = SteamPaths.Where(p => !string.IsNullOrEmpty(p))
+ .FirstOrDefault(Directory.Exists);
+ if (libraryPath == null)
+ {
+ log.Info("Steam not found");
+ Games = Array.Empty();
+ }
+ else
+ {
+ log.InfoFormat("Found Steam at {0}", libraryPath);
+ var txtParser = KVSerializer.Create(KVSerializationFormat.KeyValues1Text);
+ var appPaths = txtParser.Deserialize>(
+ File.OpenRead(Path.Combine(libraryPath,
+ "config",
+ "libraryfolders.vdf")))
+ .Select(lf => appRelPaths.Select(p => Path.Combine(lf.Path, p))
+ .FirstOrDefault(Directory.Exists))
+ .Where(p => p != null)
+ .ToArray();
+ var steamGames = appPaths.SelectMany(p => LibraryPathGames(txtParser, p));
+ var binParser = KVSerializer.Create(KVSerializationFormat.KeyValues1Binary);
+ var nonSteamGames = Directory.EnumerateDirectories(Path.Combine(libraryPath, "userdata"))
+ .Select(dirName => Path.Combine(dirName, "config"))
+ .Where(Directory.Exists)
+ .Select(dirName => Path.Combine(dirName, "shortcuts.vdf"))
+ .Where(File.Exists)
+ .SelectMany(p => ShortcutsFileGames(binParser, p));
+ Games = steamGames.Concat(nonSteamGames)
+ .ToArray();
+ log.DebugFormat("Games: {0}",
+ string.Join(", ", Games.Select(g => $"{g.LaunchUrl} ({g.GameDir})")));
+ }
+ }
+
+ public IEnumerable GameAppURLs(DirectoryInfo gameDir)
+ => Games.Where(g => gameDir.FullName.Equals(g.GameDir.FullName, compareOpt))
+ .Select(g => g.LaunchUrl);
+
+ public readonly GameBase[] Games;
+
+ private static IEnumerable LibraryPathGames(KVSerializer acfParser,
+ string appPath)
+ => Directory.EnumerateFiles(appPath, "*.acf")
+ .Select(acfFile => acfParser.Deserialize(File.OpenRead(acfFile))
+ .NormalizeDir(Path.Combine(appPath, "common")));
+
+ private static IEnumerable ShortcutsFileGames(KVSerializer vdfParser,
+ string path)
+ => vdfParser.Deserialize>(File.OpenRead(path))
+ .Select(nsg => nsg.NormalizeDir(path));
+
+ private const string registryKey = @"HKEY_CURRENT_USER\Software\Valve\Steam";
+ private const string registryValue = @"SteamPath";
+ private static string[] SteamPaths
+ => Platform.IsWindows ? new string[]
+ {
+ // First check the registry
+ (string)Microsoft.Win32.Registry.GetValue(registryKey, registryValue, null),
+ }
+ : Platform.IsUnix ? new string[]
+ {
+ Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Personal),
+ ".local", "share", "Steam"),
+ Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Personal),
+ ".steam", "steam"),
+ }
+ : Platform.IsMac ? new string[]
+ {
+ Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Personal),
+ "Library", "Application Support", "Steam"),
+ }
+ : Array.Empty();
+
+ private static readonly string[] appRelPaths = new string[] { "SteamApps", "steamapps" };
+
+ private static readonly StringComparison compareOpt
+ = Platform.IsWindows ? StringComparison.InvariantCultureIgnoreCase
+ : StringComparison.InvariantCulture;
+
+ private static readonly ILog log = LogManager.GetLogger(typeof(SteamLibrary));
+ }
+
+ public class LibraryFolder
+ {
+ [KVProperty("path")] public string Path { get; set; }
+ }
+
+ public abstract class GameBase
+ {
+ public abstract string Name { get; set; }
+
+ [KVIgnore] public DirectoryInfo GameDir { get; set; }
+ [KVIgnore] public abstract Uri LaunchUrl { get; }
+
+ public abstract GameBase NormalizeDir(string appPath);
+ }
+
+ public class SteamGame : GameBase
+ {
+ [KVProperty("appid")] public ulong AppId { get; set; }
+ [KVProperty("name")] public override string Name { get; set; }
+ [KVProperty("installdir")] public string InstallDir { get; set; }
+
+ [KVIgnore]
+ public override Uri LaunchUrl => new Uri($"steam://rungameid/{AppId}");
+
+ public override GameBase NormalizeDir(string commonPath)
+ {
+ GameDir = new DirectoryInfo(CKANPathUtils.NormalizePath(Path.Combine(commonPath, InstallDir)));
+ return this;
+ }
+ }
+
+ public class NonSteamGame : GameBase
+ {
+ [KVProperty("appid")]
+ public int AppId { get; set; }
+ [KVProperty("AppName")]
+ public override string Name { get; set; }
+ public string Exe { get; set; }
+ public string StartDir { get; set; }
+
+ [KVIgnore]
+ private ulong UrlId => (unchecked((ulong)AppId) << 32) | 0x02000000;
+
+ [KVIgnore]
+ public override Uri LaunchUrl => new Uri($"steam://rungameid/{UrlId}");
+
+ public override GameBase NormalizeDir(string appPath)
+ {
+ GameDir = new DirectoryInfo(CKANPathUtils.NormalizePath(StartDir.Trim('"')));
+ return this;
+ }
+ }
+}
diff --git a/GUI/Controls/EditModSearchDetails.Designer.cs b/GUI/Controls/EditModSearchDetails.Designer.cs
index b96b377c69..baa13f6216 100644
--- a/GUI/Controls/EditModSearchDetails.Designer.cs
+++ b/GUI/Controls/EditModSearchDetails.Designer.cs
@@ -344,7 +344,7 @@ private void InitializeComponent()
// CompatibleToggle
//
this.CompatibleToggle.Location = new System.Drawing.Point(130, 293);
- this.CompatibleToggle.Changed += TriStateChanged;
+ this.CompatibleToggle.Changed += this.TriStateChanged;
//
// InstalledLabel
//
@@ -360,7 +360,7 @@ private void InitializeComponent()
// InstalledToggle
//
this.InstalledToggle.Location = new System.Drawing.Point(130, 319);
- this.InstalledToggle.Changed += TriStateChanged;
+ this.InstalledToggle.Changed += this.TriStateChanged;
//
// CachedLabel
//
@@ -376,7 +376,7 @@ private void InitializeComponent()
// CachedToggle
//
this.CachedToggle.Location = new System.Drawing.Point(130, 345);
- this.CachedToggle.Changed += TriStateChanged;
+ this.CachedToggle.Changed += this.TriStateChanged;
//
// NewlyCompatibleLabel
//
@@ -392,7 +392,7 @@ private void InitializeComponent()
// NewlyCompatibleToggle
//
this.NewlyCompatibleToggle.Location = new System.Drawing.Point(130, 371);
- this.NewlyCompatibleToggle.Changed += TriStateChanged;
+ this.NewlyCompatibleToggle.Changed += this.TriStateChanged;
//
// UpgradeableLabel
//
@@ -408,7 +408,7 @@ private void InitializeComponent()
// UpgradeableToggle
//
this.UpgradeableToggle.Location = new System.Drawing.Point(130, 397);
- this.UpgradeableToggle.Changed += TriStateChanged;
+ this.UpgradeableToggle.Changed += this.TriStateChanged;
//
// ReplaceableLabel
//
@@ -424,7 +424,7 @@ private void InitializeComponent()
// ReplaceableToggle
//
this.ReplaceableToggle.Location = new System.Drawing.Point(130, 423);
- this.ReplaceableToggle.Changed += TriStateChanged;
+ this.ReplaceableToggle.Changed += this.TriStateChanged;
//
// EditModSearchDetails
//
diff --git a/GUI/Controls/HintTextBox.Designer.cs b/GUI/Controls/HintTextBox.Designer.cs
index 8a203e107e..a3916db255 100644
--- a/GUI/Controls/HintTextBox.Designer.cs
+++ b/GUI/Controls/HintTextBox.Designer.cs
@@ -39,7 +39,7 @@ private void InitializeComponent()
this.ClearIcon.Image = global::CKAN.GUI.EmbeddedImages.textClear;
this.ClearIcon.SizeMode = System.Windows.Forms.PictureBoxSizeMode.CenterImage;
this.ClearIcon.Size = new System.Drawing.Size(18, 18);
- this.ClearIcon.Click += HintClearIcon_Click;
+ this.ClearIcon.Click += this.HintClearIcon_Click;
//
// HintTextBox
//
diff --git a/GUI/Controls/LeftRightRowPanel.cs b/GUI/Controls/LeftRightRowPanel.cs
index 12bdfd5596..297f24086c 100644
--- a/GUI/Controls/LeftRightRowPanel.cs
+++ b/GUI/Controls/LeftRightRowPanel.cs
@@ -1,4 +1,5 @@
using System.Windows.Forms;
+using System.Drawing;
namespace CKAN.GUI
{
@@ -31,6 +32,15 @@ public LeftRightRowPanel()
FlowDirection = FlowDirection.RightToLeft,
};
+ // Let the outer control handle horizontal padding
+ LeftPanel.Margin = new Padding(0, LeftPanel.Margin.Top,
+ 0, LeftPanel.Margin.Bottom);
+ RightPanel.Margin = new Padding(0, RightPanel.Margin.Top,
+ 0, RightPanel.Margin.Bottom);
+
+ // Don't overwrite graphics drawn on parent
+ BackColor = LeftPanel.BackColor = RightPanel.BackColor = Color.Transparent;
+
AutoSize = true;
AutoSizeMode = AutoSizeMode.GrowAndShrink;
// Throw exceptions if the table gets bigger than a 2x1 layout
diff --git a/GUI/Controls/ManageMods.Designer.cs b/GUI/Controls/ManageMods.Designer.cs
index dcb5089a9b..3caf5e9f57 100644
--- a/GUI/Controls/ManageMods.Designer.cs
+++ b/GUI/Controls/ManageMods.Designer.cs
@@ -32,7 +32,9 @@ private void InitializeComponent()
System.ComponentModel.ComponentResourceManager resources = new SingleAssemblyComponentResourceManager(typeof(ManageMods));
this.ToolTip = new System.Windows.Forms.ToolTip();
this.menuStrip2 = new System.Windows.Forms.MenuStrip();
- this.launchGameToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
+ this.LaunchGameToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
+ this.CommandLinesToolStripSeparator = new System.Windows.Forms.ToolStripSeparator();
+ this.EditCommandLinesToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.RefreshToolButton = new System.Windows.Forms.ToolStripMenuItem();
this.UpdateAllToolButton = new System.Windows.Forms.ToolStripMenuItem();
this.ApplyToolButton = new System.Windows.Forms.ToolStripMenuItem();
@@ -101,7 +103,7 @@ private void InitializeComponent()
this.menuStrip2.Dock = System.Windows.Forms.DockStyle.Top;
this.menuStrip2.ImageScalingSize = new System.Drawing.Size(24, 24);
this.menuStrip2.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
- this.launchGameToolStripMenuItem,
+ this.LaunchGameToolStripMenuItem,
this.RefreshToolButton,
this.UpdateAllToolButton,
this.ApplyToolButton,
@@ -117,15 +119,23 @@ private void InitializeComponent()
this.menuStrip2.TabIndex = 4;
this.menuStrip2.Text = "menuStrip2";
//
- // launchGameToolStripMenuItem
+ // LaunchGameToolStripMenuItem
//
- this.launchGameToolStripMenuItem.Image = global::CKAN.GUI.EmbeddedImages.ksp;
- this.launchGameToolStripMenuItem.ImageScaling = System.Windows.Forms.ToolStripItemImageScaling.None;
- this.launchGameToolStripMenuItem.Name = "launchGameToolStripMenuItem";
- this.launchGameToolStripMenuItem.Size = new System.Drawing.Size(146, 56);
- this.launchGameToolStripMenuItem.Overflow = System.Windows.Forms.ToolStripItemOverflow.AsNeeded;
- this.launchGameToolStripMenuItem.Click += new System.EventHandler(this.launchGameToolStripMenuItem_Click);
- resources.ApplyResources(this.launchGameToolStripMenuItem, "launchGameToolStripMenuItem");
+ this.LaunchGameToolStripMenuItem.MouseHover += new System.EventHandler(LaunchGameToolStripMenuItem_MouseHover);
+ this.LaunchGameToolStripMenuItem.Image = global::CKAN.GUI.EmbeddedImages.ksp;
+ this.LaunchGameToolStripMenuItem.ImageScaling = System.Windows.Forms.ToolStripItemImageScaling.None;
+ this.LaunchGameToolStripMenuItem.Name = "LaunchGameToolStripMenuItem";
+ this.LaunchGameToolStripMenuItem.Size = new System.Drawing.Size(146, 56);
+ this.LaunchGameToolStripMenuItem.Overflow = System.Windows.Forms.ToolStripItemOverflow.AsNeeded;
+ this.LaunchGameToolStripMenuItem.Click += new System.EventHandler(this.LaunchGameToolStripMenuItem_Click);
+ resources.ApplyResources(this.LaunchGameToolStripMenuItem, "LaunchGameToolStripMenuItem");
+ //
+ // EditCommandLinesToolStripMenuItem
+ //
+ this.EditCommandLinesToolStripMenuItem.Name = "EditCommandLinesToolStripMenuItem";
+ this.EditCommandLinesToolStripMenuItem.Size = new System.Drawing.Size(179, 22);
+ this.EditCommandLinesToolStripMenuItem.Click += new System.EventHandler(this.EditCommandLinesToolStripMenuItem_Click);
+ resources.ApplyResources(this.EditCommandLinesToolStripMenuItem, "EditCommandLinesToolStripMenuItem");
//
// RefreshToolButton
//
@@ -299,9 +309,9 @@ private void InitializeComponent()
// EditModSearches
//
this.EditModSearches.Dock = System.Windows.Forms.DockStyle.Top;
- this.EditModSearches.ApplySearches += EditModSearches_ApplySearches;
- this.EditModSearches.SurrenderFocus += EditModSearches_SurrenderFocus;
- this.EditModSearches.ShowError += EditModSearches_ShowError;
+ this.EditModSearches.ApplySearches += this.EditModSearches_ApplySearches;
+ this.EditModSearches.SurrenderFocus += this.EditModSearches_SurrenderFocus;
+ this.EditModSearches.ShowError += this.EditModSearches_ShowError;
//
// ModGrid
//
@@ -550,8 +560,8 @@ private void InitializeComponent()
this.hiddenTagsLabelsLinkList.Location = new System.Drawing.Point(0, 0);
this.hiddenTagsLabelsLinkList.Name = "hiddenTagsLabelsLinkList";
this.hiddenTagsLabelsLinkList.Size = new System.Drawing.Size(500, 20);
- this.hiddenTagsLabelsLinkList.TagClicked += hiddenTagsLabelsLinkList_TagClicked;
- this.hiddenTagsLabelsLinkList.LabelClicked += hiddenTagsLabelsLinkList_LabelClicked;
+ this.hiddenTagsLabelsLinkList.TagClicked += this.hiddenTagsLabelsLinkList_TagClicked;
+ this.hiddenTagsLabelsLinkList.LabelClicked += this.hiddenTagsLabelsLinkList_LabelClicked;
resources.ApplyResources(this.hiddenTagsLabelsLinkList, "hiddenTagsLabelsLinkList");
//
// ManageMods
@@ -581,7 +591,9 @@ private void InitializeComponent()
private System.Windows.Forms.ToolTip ToolTip;
private System.Windows.Forms.MenuStrip menuStrip2;
private System.Windows.Forms.CheckBox InstallAllCheckbox;
- private System.Windows.Forms.ToolStripMenuItem launchGameToolStripMenuItem;
+ private System.Windows.Forms.ToolStripMenuItem LaunchGameToolStripMenuItem;
+ private System.Windows.Forms.ToolStripSeparator CommandLinesToolStripSeparator;
+ private System.Windows.Forms.ToolStripMenuItem EditCommandLinesToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem RefreshToolButton;
private System.Windows.Forms.ToolStripMenuItem UpdateAllToolButton;
private System.Windows.Forms.ToolStripMenuItem ApplyToolButton;
diff --git a/GUI/Controls/ManageMods.cs b/GUI/Controls/ManageMods.cs
index 89d8405fc8..e9588dc354 100644
--- a/GUI/Controls/ManageMods.cs
+++ b/GUI/Controls/ManageMods.cs
@@ -40,7 +40,6 @@ public ManageMods()
mainModList = new ModList();
mainModList.ModFiltersUpdated += UpdateFilters;
FilterToolButton.MouseHover += (sender, args) => FilterToolButton.ShowDropDown();
- launchGameToolStripMenuItem.MouseHover += (sender, args) => launchGameToolStripMenuItem.ShowDropDown();
ApplyToolButton.MouseHover += (sender, args) => ApplyToolButton.ShowDropDown();
ApplyToolButton.Enabled = false;
@@ -60,6 +59,7 @@ public ManageMods()
FilterToolButton.DropDown.Renderer = new FlatToolStripRenderer();
FilterTagsToolButton.DropDown.Renderer = new FlatToolStripRenderer();
FilterLabelsToolButton.DropDown.Renderer = new FlatToolStripRenderer();
+ LaunchGameToolStripMenuItem.DropDown.Renderer = new FlatToolStripRenderer();
ModListContextMenuStrip.Renderer = new FlatToolStripRenderer();
ModListHeaderContextMenuStrip.Renderer = new FlatToolStripRenderer();
LabelsContextMenuStrip.Renderer = new FlatToolStripRenderer();
@@ -80,6 +80,8 @@ public ManageMods()
public event Action RaiseMessage;
public event Action RaiseError;
public event Action ClearStatusBar;
+ public event Action LaunchGame;
+ public event Action EditCommandLines;
public readonly ModList mainModList;
private List SortColumns
@@ -549,9 +551,42 @@ private void _MarkModForUpdate(string identifier, bool value)
mod.SetUpgradeChecked(row, UpdateCol, value);
}
- private void launchGameToolStripMenuItem_Click(object sender, EventArgs e)
+ private void LaunchGameToolStripMenuItem_MouseHover(object sender, EventArgs e)
{
- Main.Instance.LaunchGame();
+ var cmdLines = Main.Instance.configuration.CommandLines;
+ LaunchGameToolStripMenuItem.Tag =
+ LaunchGameToolStripMenuItem.ToolTipText = cmdLines.First();
+ LaunchGameToolStripMenuItem.DropDownItems.Clear();
+ LaunchGameToolStripMenuItem.DropDownItems.AddRange(
+ cmdLines.Select(cmdLine => (ToolStripItem)
+ new ToolStripMenuItem(cmdLine, null,
+ LaunchGameToolStripMenuItem_Click)
+ {
+ Tag = cmdLine,
+ ShortcutKeyDisplayString = CmdLineHelp(cmdLine),
+ })
+ .Append(CommandLinesToolStripSeparator)
+ .Append(EditCommandLinesToolStripMenuItem)
+ .ToArray());
+ LaunchGameToolStripMenuItem.ShowDropDown();
+ }
+
+ private string CmdLineHelp(string cmdLine)
+ => Main.Instance.Manager.SteamLibrary.Games.Length > 0
+ ? cmdLine.StartsWith("steam://", StringComparison.InvariantCultureIgnoreCase)
+ ? Properties.Resources.ManageModsSteamPlayTimeYesTooltip
+ : Properties.Resources.ManageModsSteamPlayTimeNoTooltip
+ : "";
+
+ private void LaunchGameToolStripMenuItem_Click(object sender, EventArgs e)
+ {
+ var menuItem = sender as ToolStripMenuItem;
+ LaunchGame?.Invoke(menuItem?.Tag as string);
+ }
+
+ private void EditCommandLinesToolStripMenuItem_Click(object sender, EventArgs e)
+ {
+ EditCommandLines?.Invoke();
}
private void NavBackwardToolButton_Click(object sender, EventArgs e)
@@ -1156,15 +1191,15 @@ private void _UpdateFilters()
GUIMod selected_mod = null;
if (ModGrid.CurrentRow != null)
{
- selected_mod = (GUIMod) ModGrid.CurrentRow.Tag;
+ selected_mod = (GUIMod)ModGrid.CurrentRow.Tag;
}
- var registry = RegistryManager.Instance(Main.Instance.CurrentInstance, repoData).registry;
+ var inst = Main.Instance.CurrentInstance;
+ var registry = RegistryManager.Instance(inst, repoData).registry;
ModGrid.Rows.Clear();
- var instName = Main.Instance.CurrentInstance.Name;
- var instGame = Main.Instance.CurrentInstance.game;
rows.AsParallel().ForAll(row =>
- row.Visible = mainModList.IsVisible((GUIMod)row.Tag, instName, instGame, registry));
+ row.Visible = mainModList.IsVisible((GUIMod)row.Tag,
+ inst.Name, inst.game, registry));
ApplyHeaderGlyphs();
ModGrid.Rows.AddRange(Sort(rows.Where(row => row.Visible)).ToArray());
@@ -1740,6 +1775,7 @@ public void InstanceUpdated()
{
Conflicts = null;
ChangeSet = null;
+ ModGrid.CurrentCell = null;
}
[ForbidGUICalls]
diff --git a/GUI/Controls/ManageMods.resx b/GUI/Controls/ManageMods.resx
index f3e99c918b..d630c3bd40 100644
--- a/GUI/Controls/ManageMods.resx
+++ b/GUI/Controls/ManageMods.resx
@@ -117,7 +117,8 @@
System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
- Play
+ Play
+ Edit command lines...
Refresh
Update all
Apply
diff --git a/GUI/Controls/ModInfo.Designer.cs b/GUI/Controls/ModInfo.Designer.cs
index e5a2d115ad..423855f4e9 100644
--- a/GUI/Controls/ModInfo.Designer.cs
+++ b/GUI/Controls/ModInfo.Designer.cs
@@ -89,8 +89,8 @@ private void InitializeComponent()
this.tagsLabelsLinkList.Location = new System.Drawing.Point(0, 0);
this.tagsLabelsLinkList.Name = "tagsLabelsLinkList";
this.tagsLabelsLinkList.Size = new System.Drawing.Size(500, 20);
- this.tagsLabelsLinkList.TagClicked += tagsLabelsLinkList_TagClicked;
- this.tagsLabelsLinkList.LabelClicked += tagsLabelsLinkList_LabelClicked;
+ this.tagsLabelsLinkList.TagClicked += this.tagsLabelsLinkList_TagClicked;
+ this.tagsLabelsLinkList.LabelClicked += this.tagsLabelsLinkList_LabelClicked;
//
// MetadataModuleAbstractLabel
//
@@ -153,7 +153,7 @@ private void InitializeComponent()
this.Metadata.Margin = new System.Windows.Forms.Padding(2);
this.Metadata.Name = "Metadata";
this.Metadata.TabIndex = 6;
- this.Metadata.OnChangeFilter += Metadata_OnChangeFilter;
+ this.Metadata.OnChangeFilter += this.Metadata_OnChangeFilter;
//
// RelationshipTabPage
//
diff --git a/GUI/Controls/PlayTime.Designer.cs b/GUI/Controls/PlayTime.Designer.cs
index 47015dd913..95d998462e 100755
--- a/GUI/Controls/PlayTime.Designer.cs
+++ b/GUI/Controls/PlayTime.Designer.cs
@@ -80,7 +80,7 @@ private void InitializeComponent()
this.PlayTimeGrid.Size = new System.Drawing.Size(1536, 837);
this.PlayTimeGrid.StandardTab = false;
this.PlayTimeGrid.TabIndex = 1;
- this.PlayTimeGrid.CellValueChanged += PlayTimeGrid_CellValueChanged;
+ this.PlayTimeGrid.CellValueChanged += this.PlayTimeGrid_CellValueChanged;
//
// NameColumn
//
diff --git a/GUI/Dialogs/GameCommandLineOptionsDialog.Designer.cs b/GUI/Dialogs/GameCommandLineOptionsDialog.Designer.cs
index b818ed746f..05da3c7440 100644
--- a/GUI/Dialogs/GameCommandLineOptionsDialog.Designer.cs
+++ b/GUI/Dialogs/GameCommandLineOptionsDialog.Designer.cs
@@ -30,67 +30,138 @@ private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
System.ComponentModel.ComponentResourceManager resources = new SingleAssemblyComponentResourceManager(typeof(GameCommandLineOptionsDialog));
- this.AdditionalArguments = new System.Windows.Forms.TextBox();
- this.label1 = new System.Windows.Forms.Label();
+ this.CmdLineGrid = new System.Windows.Forms.DataGridView();
+ this.CmdLineColumn = new System.Windows.Forms.DataGridViewTextBoxColumn();
+ this.BottomButtonPanel = new CKAN.GUI.LeftRightRowPanel();
+ this.ResetToDefaultsButton = new System.Windows.Forms.Button();
+ this.AddButton = new System.Windows.Forms.Button();
this.AcceptChangesButton = new System.Windows.Forms.Button();
this.CancelChangesButton = new System.Windows.Forms.Button();
this.SuspendLayout();
//
- // AdditionalArguments
+ // CmdLineGrid
//
- this.AdditionalArguments.Location = new System.Drawing.Point(15, 25);
- this.AdditionalArguments.Name = "AdditionalArguments";
- this.AdditionalArguments.Size = new System.Drawing.Size(457, 20);
- this.AdditionalArguments.AutoCompleteMode = System.Windows.Forms.AutoCompleteMode.SuggestAppend;
- this.AdditionalArguments.AutoCompleteSource = System.Windows.Forms.AutoCompleteSource.CustomSource;
- this.AdditionalArguments.TabIndex = 1;
+ this.CmdLineGrid.AutoGenerateColumns = false;
+ this.CmdLineGrid.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D;
+ this.CmdLineGrid.Dock = System.Windows.Forms.DockStyle.Fill;
+ this.CmdLineGrid.EditMode = System.Windows.Forms.DataGridViewEditMode.EditOnKeystrokeOrF2;
+ this.CmdLineGrid.AllowUserToAddRows = true;
+ this.CmdLineGrid.AllowUserToDeleteRows = true;
+ this.CmdLineGrid.AllowUserToResizeRows = false;
+ this.CmdLineGrid.BackgroundColor = System.Drawing.SystemColors.Window;
+ this.CmdLineGrid.EnableHeadersVisualStyles = false;
+ this.CmdLineGrid.ColumnHeadersDefaultCellStyle.Padding = new System.Windows.Forms.Padding(1, 3, 1, 3);
+ this.CmdLineGrid.ColumnHeadersDefaultCellStyle.BackColor = System.Drawing.SystemColors.Control;
+ this.CmdLineGrid.ColumnHeadersDefaultCellStyle.ForeColor = System.Drawing.SystemColors.ControlText;
+ this.CmdLineGrid.ColumnHeadersDefaultCellStyle.SelectionBackColor = System.Drawing.SystemColors.Control;
+ this.CmdLineGrid.DefaultCellStyle.ForeColor = System.Drawing.SystemColors.WindowText;
+ this.CmdLineGrid.CellBorderStyle = System.Windows.Forms.DataGridViewCellBorderStyle.SingleHorizontal;
+ this.CmdLineGrid.ColumnHeadersBorderStyle = System.Windows.Forms.DataGridViewHeaderBorderStyle.Raised;
+ this.CmdLineGrid.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize;
+ this.CmdLineGrid.Columns.AddRange(new System.Windows.Forms.DataGridViewColumn[] {
+ this.CmdLineColumn});
+ this.CmdLineGrid.Location = new System.Drawing.Point(12, 9);
+ this.CmdLineGrid.MultiSelect = false;
+ this.CmdLineGrid.Name = "CmdLineGrid";
+ this.CmdLineGrid.RowHeadersVisible = false;
+ this.CmdLineGrid.SelectionMode = System.Windows.Forms.DataGridViewSelectionMode.FullRowSelect;
+ this.CmdLineGrid.Size = new System.Drawing.Size(457, 20);
+ this.CmdLineGrid.StandardTab = false;
+ this.CmdLineGrid.TabIndex = 1;
+ this.CmdLineGrid.EditingControlShowing += this.CmdLineGrid_EditingControlShowing;
+ this.CmdLineGrid.UserDeletingRow += this.CmdLineGrid_UserDeletingRow;
//
- // label1
+ // CmdLineColumn
//
- this.label1.AutoSize = true;
- this.label1.Location = new System.Drawing.Point(12, 9);
- this.label1.Name = "label1";
- this.label1.Size = new System.Drawing.Size(60, 13);
- this.label1.TabIndex = 2;
- resources.ApplyResources(this.label1, "label1");
+ this.CmdLineColumn.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.Fill;
+ this.CmdLineColumn.Name = "CmdLineColumn";
+ this.CmdLineColumn.DataPropertyName = "CmdLine";
+ this.CmdLineColumn.ReadOnly = false;
+ this.CmdLineColumn.ValueType = typeof(string);
+ this.CmdLineColumn.Width = 250;
+ resources.ApplyResources(this.CmdLineColumn, "CmdLineColumn");
//
- // AcceptChangesButton
+ // BottomButtonPanel
//
- this.AcceptChangesButton.DialogResult = System.Windows.Forms.DialogResult.OK;
- this.AcceptChangesButton.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
- this.AcceptChangesButton.Location = new System.Drawing.Point(397, 51);
- this.AcceptChangesButton.Name = "AcceptChangesButton";
- this.AcceptChangesButton.Size = new System.Drawing.Size(75, 23);
- this.AcceptChangesButton.TabIndex = 3;
- this.AcceptChangesButton.UseVisualStyleBackColor = true;
- resources.ApplyResources(this.AcceptChangesButton, "AcceptChangesButton");
+ this.BottomButtonPanel.LeftControls.Add(this.ResetToDefaultsButton);
+ this.BottomButtonPanel.LeftControls.Add(this.AddButton);
+ this.BottomButtonPanel.RightControls.Add(this.AcceptChangesButton);
+ this.BottomButtonPanel.RightControls.Add(this.CancelChangesButton);
+ this.BottomButtonPanel.Dock = System.Windows.Forms.DockStyle.Bottom;
+ this.BottomButtonPanel.Name = "BottomButtonPanel";
+ //
+ // ResetToDefaultsButton
+ //
+ this.ResetToDefaultsButton.AutoSize = true;
+ this.ResetToDefaultsButton.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowOnly;
+ this.ResetToDefaultsButton.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
+ this.ResetToDefaultsButton.Location = new System.Drawing.Point(316, 51);
+ this.ResetToDefaultsButton.Margin = new System.Windows.Forms.Padding(0, 4, 8, 4);
+ this.ResetToDefaultsButton.Name = "ResetToDefaultsButton";
+ this.ResetToDefaultsButton.Size = new System.Drawing.Size(75, 23);
+ this.ResetToDefaultsButton.TabIndex = 2;
+ this.ResetToDefaultsButton.UseVisualStyleBackColor = true;
+ this.ResetToDefaultsButton.Click += this.ResetToDefaultsButton_Click;
+ resources.ApplyResources(this.ResetToDefaultsButton, "ResetToDefaultsButton");
+ //
+ // AddButton
+ //
+ this.AddButton.AutoSize = true;
+ this.AddButton.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowOnly;
+ this.AddButton.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
+ this.AddButton.Location = new System.Drawing.Point(316, 51);
+ this.AddButton.Margin = new System.Windows.Forms.Padding(0, 4, 8, 4);
+ this.AddButton.Name = "AddButton";
+ this.AddButton.Size = new System.Drawing.Size(75, 23);
+ this.AddButton.TabIndex = 2;
+ this.AddButton.UseVisualStyleBackColor = true;
+ this.AddButton.Visible = false;
+ this.AddButton.Click += this.AddButton_Click;
+ resources.ApplyResources(this.AddButton, "AddButton");
//
// CancelChangesButton
//
+ this.CancelChangesButton.AutoSize = true;
+ this.CancelChangesButton.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowOnly;
this.CancelChangesButton.DialogResult = System.Windows.Forms.DialogResult.Cancel;
this.CancelChangesButton.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
this.CancelChangesButton.Location = new System.Drawing.Point(316, 51);
+ this.CancelChangesButton.Margin = new System.Windows.Forms.Padding(8, 4, 0, 4);
this.CancelChangesButton.Name = "CancelChangesButton";
this.CancelChangesButton.Size = new System.Drawing.Size(75, 23);
- this.CancelChangesButton.TabIndex = 4;
+ this.CancelChangesButton.TabIndex = 2;
this.CancelChangesButton.UseVisualStyleBackColor = true;
resources.ApplyResources(this.CancelChangesButton, "CancelChangesButton");
//
+ // AcceptChangesButton
+ //
+ this.AcceptChangesButton.AutoSize = true;
+ this.AcceptChangesButton.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowOnly;
+ this.AcceptChangesButton.DialogResult = System.Windows.Forms.DialogResult.OK;
+ this.AcceptChangesButton.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
+ this.AcceptChangesButton.Location = new System.Drawing.Point(397, 51);
+ this.AcceptChangesButton.Margin = new System.Windows.Forms.Padding(8, 4, 0, 4);
+ this.AcceptChangesButton.Name = "AcceptChangesButton";
+ this.AcceptChangesButton.Size = new System.Drawing.Size(75, 23);
+ this.AcceptChangesButton.TabIndex = 3;
+ this.AcceptChangesButton.UseVisualStyleBackColor = true;
+ this.AcceptChangesButton.Click += this.AcceptChangesButton_Click;
+ resources.ApplyResources(this.AcceptChangesButton, "AcceptChangesButton");
+ //
// GameCommandLineOptionsDialog
//
- this.AcceptButton = this.AcceptChangesButton;
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
- this.CancelButton = this.CancelChangesButton;
- this.ClientSize = new System.Drawing.Size(481, 112);
+ this.ClientSize = new System.Drawing.Size(320, 180);
this.ControlBox = false;
- this.Controls.Add(this.CancelChangesButton);
- this.Controls.Add(this.AcceptChangesButton);
- this.Controls.Add(this.label1);
- this.Controls.Add(this.AdditionalArguments);
- this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
+ this.Controls.Add(this.CmdLineGrid);
+ this.Controls.Add(this.BottomButtonPanel);
+ this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.SizableToolWindow;
this.Icon = EmbeddedImages.AppIcon;
+ this.MinimumSize = new System.Drawing.Size(320, 180);
this.Name = "GameCommandLineOptionsDialog";
+ this.Padding = new System.Windows.Forms.Padding(8, 8, 8, 0);
+ this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
resources.ApplyResources(this, "$this");
this.ResumeLayout(false);
this.PerformLayout();
@@ -99,9 +170,12 @@ private void InitializeComponent()
#endregion
- private System.Windows.Forms.Label label1;
+ private System.Windows.Forms.DataGridView CmdLineGrid;
+ private System.Windows.Forms.DataGridViewTextBoxColumn CmdLineColumn;
+ private CKAN.GUI.LeftRightRowPanel BottomButtonPanel;
+ private System.Windows.Forms.Button ResetToDefaultsButton;
+ private System.Windows.Forms.Button AddButton;
private System.Windows.Forms.Button AcceptChangesButton;
private System.Windows.Forms.Button CancelChangesButton;
- public System.Windows.Forms.TextBox AdditionalArguments;
}
}
diff --git a/GUI/Dialogs/GameCommandLineOptionsDialog.cs b/GUI/Dialogs/GameCommandLineOptionsDialog.cs
index 0773dc807a..4c8d58c877 100644
--- a/GUI/Dialogs/GameCommandLineOptionsDialog.cs
+++ b/GUI/Dialogs/GameCommandLineOptionsDialog.cs
@@ -1,26 +1,116 @@
+using System;
+using System.ComponentModel;
+using System.Collections.Generic;
+using System.Linq;
using System.Windows.Forms;
namespace CKAN.GUI
{
-
public partial class GameCommandLineOptionsDialog : Form
{
public GameCommandLineOptionsDialog()
{
InitializeComponent();
+ if (Platform.IsMono)
+ {
+ // Mono's DataGridView has showstopper bugs with AllowUserToAddRows,
+ // so use an Add button instead
+ CmdLineGrid.AllowUserToAddRows = false;
+ AddButton.Visible = true;
+ }
+ }
+
+ public DialogResult ShowGameCommandLineOptionsDialog(IWin32Window parent,
+ List cmdLines,
+ string[] defaults)
+ {
+ rows = cmdLines.Select(cmdLine => new CmdLineRow(cmdLine))
+ .ToList();
+ CmdLineGrid.DataSource = new BindingList(rows)
+ {
+ AllowEdit = true,
+ AllowRemove = true,
+ };
+ this.defaults = defaults;
+ return ShowDialog(parent);
+ }
+
+ protected override void OnShown(EventArgs e)
+ {
+ base.OnShown(e);
+ // Edit the top cell immediately for convenience
+ CmdLineGrid.BeginEdit(false);
+ }
+
+ public List Results => rows.Select(row => row.CmdLine)
+ .Where(str => !string.IsNullOrEmpty(str))
+ .ToList();
+
+ private void CmdLineGrid_EditingControlShowing(object sender, DataGridViewEditingControlShowingEventArgs e)
+ {
+ // Don't auto-select the text when the user clicks on it
+ if (e.Control is DataGridViewTextBoxEditingControl tbec)
+ {
+ BeginInvoke(new Action(() =>
+ {
+ tbec.SelectionLength = 0;
+ }));
+ }
+ }
+
+ private void CmdLineGrid_UserDeletingRow(object sender, DataGridViewRowCancelEventArgs e)
+ {
+ // You can't delete the last row
+ if (rows.Count == 1)
+ {
+ e.Cancel = true;
+ }
+ }
- StartPosition = FormStartPosition.CenterScreen;
+ private void ResetToDefaultsButton_Click(object sender, EventArgs e)
+ {
+ rows = defaults.Select(cmdLine => new CmdLineRow(cmdLine))
+ .ToList();
+ CmdLineGrid.DataSource = new BindingList(rows)
+ {
+ AllowEdit = true,
+ AllowRemove = true,
+ };
}
- public DialogResult ShowGameCommandLineOptionsDialog(string arguments)
+ private void AddButton_Click(object sender, EventArgs e)
{
- AdditionalArguments.Text = arguments;
- return ShowDialog();
+ (CmdLineGrid.DataSource as BindingList)?.AddNew();
+ CmdLineGrid.CurrentCell = CmdLineGrid.Rows[CmdLineGrid.RowCount - 1].Cells[0];
+ CmdLineGrid.BeginEdit(false);
}
- public string GetResult()
+ private void AcceptChangesButton_Click(object sender, EventArgs e)
{
- return AdditionalArguments.Text;
+ if (Results.Count < 1)
+ {
+ // Don't accept an empty grid (shouldn't happen because of row deletion limit above)
+ DialogResult = DialogResult.None;
+ }
}
+
+ private string[] defaults;
+ private List rows;
+ }
+
+ public class CmdLineRow
+ {
+ // Called when the user clicks on an empty row
+ public CmdLineRow()
+ {
+ CmdLine = "";
+ }
+
+ public CmdLineRow(string cmdLine)
+ {
+ CmdLine = cmdLine;
+ }
+
+ public string CmdLine { get; set; }
}
}
diff --git a/GUI/Dialogs/GameCommandLineOptionsDialog.resx b/GUI/Dialogs/GameCommandLineOptionsDialog.resx
index 34c8811b97..4892216cea 100644
--- a/GUI/Dialogs/GameCommandLineOptionsDialog.resx
+++ b/GUI/Dialogs/GameCommandLineOptionsDialog.resx
@@ -117,8 +117,10 @@
System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
- Arguments:
- OK
- Cancel
- Command-line arguments
+ Command lines
+ &Reset
+ Add
+ &Accept
+ &Cancel
+ Game command lines
diff --git a/GUI/Dialogs/ManageGameInstancesDialog.Designer.cs b/GUI/Dialogs/ManageGameInstancesDialog.Designer.cs
index fc0e493bc1..98d4efcebb 100644
--- a/GUI/Dialogs/ManageGameInstancesDialog.Designer.cs
+++ b/GUI/Dialogs/ManageGameInstancesDialog.Designer.cs
@@ -46,6 +46,7 @@ private void InitializeComponent()
this.InstanceListContextMenuStrip = new System.Windows.Forms.ContextMenuStrip(this.components);
this.openDirectoryMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.AddToCKANMenuItem = new System.Windows.Forms.ToolStripMenuItem();
+ this.ImportFromSteamMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.CloneGameInstanceMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.RenameButton = new System.Windows.Forms.Button();
this.SetAsDefaultCheckbox = new System.Windows.Forms.CheckBox();
@@ -149,6 +150,7 @@ private void InitializeComponent()
//
this.AddNewMenu.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.AddToCKANMenuItem,
+ this.ImportFromSteamMenuItem,
this.CloneGameInstanceMenuItem});
this.AddNewMenu.Name = "AddNewMenu";
this.AddNewMenu.Size = new System.Drawing.Size(222, 48);
@@ -160,6 +162,13 @@ private void InitializeComponent()
this.AddToCKANMenuItem.Click += new System.EventHandler(this.AddToCKANMenuItem_Click);
resources.ApplyResources(this.AddToCKANMenuItem, "AddToCKANMenuItem");
//
+ // ImportFromSteamMenuItem
+ //
+ this.ImportFromSteamMenuItem.Name = "ImportFromSteamMenuItem";
+ this.ImportFromSteamMenuItem.Size = new System.Drawing.Size(216, 22);
+ this.ImportFromSteamMenuItem.Click += new System.EventHandler(this.ImportFromSteamMenuItem_Click);
+ resources.ApplyResources(this.ImportFromSteamMenuItem, "ImportFromSteamMenuItem");
+ //
// CloneGameInstanceMenuItem
//
this.CloneGameInstanceMenuItem.Name = "CloneGameInstanceMenuItem";
@@ -246,6 +255,7 @@ private void InitializeComponent()
private System.Windows.Forms.ContextMenuStrip InstanceListContextMenuStrip;
private System.Windows.Forms.ToolStripMenuItem openDirectoryMenuItem;
private System.Windows.Forms.ToolStripMenuItem AddToCKANMenuItem;
+ private System.Windows.Forms.ToolStripMenuItem ImportFromSteamMenuItem;
private System.Windows.Forms.ToolStripMenuItem CloneGameInstanceMenuItem;
private System.Windows.Forms.Button RenameButton;
private System.Windows.Forms.CheckBox SetAsDefaultCheckbox;
diff --git a/GUI/Dialogs/ManageGameInstancesDialog.cs b/GUI/Dialogs/ManageGameInstancesDialog.cs
index 1349c800ad..06dcd6fbe4 100644
--- a/GUI/Dialogs/ManageGameInstancesDialog.cs
+++ b/GUI/Dialogs/ManageGameInstancesDialog.cs
@@ -61,7 +61,7 @@ public ManageGameInstancesDialog(bool centerScreen, IUser user)
if (!_manager.Instances.Any())
{
- _manager.FindAndRegisterDefaultInstance();
+ _manager.FindAndRegisterDefaultInstances();
}
// Set the renderer for the AddNewMenu
@@ -195,6 +195,20 @@ private void AddToCKANMenuItem_Click(object sender, EventArgs e)
}
}
+ private void ImportFromSteamMenuItem_Click(object sender, EventArgs e)
+ {
+ var currentDirs = _manager.Instances.Values
+ .Select(inst => inst.GameDir())
+ .ToHashSet();
+ var toAdd = _manager.FindDefaultInstances()
+ .Where(inst => !currentDirs.Contains(inst.GameDir()));
+ foreach (var inst in toAdd)
+ {
+ _manager.AddInstance(inst);
+ }
+ UpdateInstancesList();
+ }
+
private void CloneGameInstanceMenuItem_Click(object sender, EventArgs e)
{
var old_instance = Main.Instance.CurrentInstance;
@@ -343,6 +357,7 @@ private void UpdateButtonState()
{
RenameButton.Enabled = SelectButton.Enabled = SetAsDefaultCheckbox.Enabled = CloneGameInstanceMenuItem.Enabled = HasSelections;
ForgetButton.Enabled = HasSelections && (string)GameInstancesListView.SelectedItems[0].Tag != _manager.CurrentInstance?.Name;
+ ImportFromSteamMenuItem.Enabled = _manager.SteamLibrary.Games.Length > 0;
}
}
}
diff --git a/GUI/Dialogs/ManageGameInstancesDialog.resx b/GUI/Dialogs/ManageGameInstancesDialog.resx
index dce76c9b0c..e69459a1f9 100644
--- a/GUI/Dialogs/ManageGameInstancesDialog.resx
+++ b/GUI/Dialogs/ManageGameInstancesDialog.resx
@@ -115,6 +115,8 @@
Select
New game instance
Add instance to CKAN
+ Import from Steam
+ Scan your Steam library for recognized game directories and add them as instances
Clone instance
Rename
Set as default
diff --git a/GUI/Localization/de-DE/ManageMods.de-DE.resx b/GUI/Localization/de-DE/ManageMods.de-DE.resx
index 295ded3591..81f3764207 100644
--- a/GUI/Localization/de-DE/ManageMods.de-DE.resx
+++ b/GUI/Localization/de-DE/ManageMods.de-DE.resx
@@ -117,7 +117,7 @@
System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
- Spiel starten
+ Spiel starten
Aktualisieren
Verfügbare Updates auswählen
Annehmen
diff --git a/GUI/Localization/fr-FR/ManageMods.fr-FR.resx b/GUI/Localization/fr-FR/ManageMods.fr-FR.resx
index 181ec29574..51145f25f5 100644
--- a/GUI/Localization/fr-FR/ManageMods.fr-FR.resx
+++ b/GUI/Localization/fr-FR/ManageMods.fr-FR.resx
@@ -117,7 +117,7 @@
System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
-
+
Lancer le Jeu
diff --git a/GUI/Localization/it-IT/ManageMods.it-IT.resx b/GUI/Localization/it-IT/ManageMods.it-IT.resx
index 851ea2fa86..f08cd1b96e 100644
--- a/GUI/Localization/it-IT/ManageMods.it-IT.resx
+++ b/GUI/Localization/it-IT/ManageMods.it-IT.resx
@@ -117,7 +117,7 @@
System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
-
+
Avvia Gioco
diff --git a/GUI/Localization/ja-JP/ManageMods.ja-JP.resx b/GUI/Localization/ja-JP/ManageMods.ja-JP.resx
index b21f2e8de9..d2783b6840 100644
--- a/GUI/Localization/ja-JP/ManageMods.ja-JP.resx
+++ b/GUI/Localization/ja-JP/ManageMods.ja-JP.resx
@@ -117,7 +117,7 @@
System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
-
+
ゲームを起動
diff --git a/GUI/Localization/ko-KR/ManageMods.ko-KR.resx b/GUI/Localization/ko-KR/ManageMods.ko-KR.resx
index 651c39dcba..ee77e07035 100644
--- a/GUI/Localization/ko-KR/ManageMods.ko-KR.resx
+++ b/GUI/Localization/ko-KR/ManageMods.ko-KR.resx
@@ -117,7 +117,7 @@
System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
-
+
게임 실행
diff --git a/GUI/Localization/nl-NL/ManageMods.nl-NL.resx b/GUI/Localization/nl-NL/ManageMods.nl-NL.resx
index f0cf79c998..d549f3bd5b 100644
--- a/GUI/Localization/nl-NL/ManageMods.nl-NL.resx
+++ b/GUI/Localization/nl-NL/ManageMods.nl-NL.resx
@@ -117,7 +117,7 @@
System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
-
+
Spel Starten
diff --git a/GUI/Localization/pl-PL/ManageMods.pl-PL.resx b/GUI/Localization/pl-PL/ManageMods.pl-PL.resx
index d426fcfd54..4826171059 100644
--- a/GUI/Localization/pl-PL/ManageMods.pl-PL.resx
+++ b/GUI/Localization/pl-PL/ManageMods.pl-PL.resx
@@ -117,7 +117,7 @@
System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
-
+
Uruchom grę
diff --git a/GUI/Localization/pt-BR/ManageMods.pt-BR.resx b/GUI/Localization/pt-BR/ManageMods.pt-BR.resx
index 3f16ae3841..d7aa0d2ea0 100644
--- a/GUI/Localization/pt-BR/ManageMods.pt-BR.resx
+++ b/GUI/Localization/pt-BR/ManageMods.pt-BR.resx
@@ -117,7 +117,7 @@
System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
-
+
Abrir Jogo
diff --git a/GUI/Localization/ru-RU/ManageMods.ru-RU.resx b/GUI/Localization/ru-RU/ManageMods.ru-RU.resx
index 30ba17c97b..7a77fc2c69 100644
--- a/GUI/Localization/ru-RU/ManageMods.ru-RU.resx
+++ b/GUI/Localization/ru-RU/ManageMods.ru-RU.resx
@@ -117,7 +117,7 @@
System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
-
+
Запустить игру
diff --git a/GUI/Localization/zh-CN/ManageMods.zh-CN.resx b/GUI/Localization/zh-CN/ManageMods.zh-CN.resx
index fb10c1f52d..3d1b8f8082 100644
--- a/GUI/Localization/zh-CN/ManageMods.zh-CN.resx
+++ b/GUI/Localization/zh-CN/ManageMods.zh-CN.resx
@@ -117,7 +117,7 @@
System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
- 启动游戏
+ 启动游戏
刷新
添加可用更新
应用更改
diff --git a/GUI/Main/Main.Designer.cs b/GUI/Main/Main.Designer.cs
index c813a2a20f..8bf05c4aa8 100644
--- a/GUI/Main/Main.Designer.cs
+++ b/GUI/Main/Main.Designer.cs
@@ -400,7 +400,7 @@ private void InitializeComponent()
this.ModInfo.Name = "ModInfo";
this.ModInfo.Size = new System.Drawing.Size(360, 836);
this.ModInfo.TabIndex = 34;
- this.ModInfo.OnDownloadClick += ModInfo_OnDownloadClick;
+ this.ModInfo.OnDownloadClick += this.ModInfo_OnDownloadClick;
//
// StatusLabel
//
@@ -475,14 +475,16 @@ private void InitializeComponent()
this.ManageMods.Name = "ManageMods";
this.ManageMods.Size = new System.Drawing.Size(500, 500);
this.ManageMods.TabIndex = 4;
- this.ManageMods.OnSelectedModuleChanged += ManageMods_OnSelectedModuleChanged;
- this.ManageMods.OnChangeSetChanged += ManageMods_OnChangeSetChanged;
- this.ManageMods.OnRegistryChanged += ManageMods_OnRegistryChanged;
- this.ManageMods.LabelsAfterUpdate += ManageMods_LabelsAfterUpdate;
- this.ManageMods.StartChangeSet += ManageMods_StartChangeSet;
- this.ManageMods.RaiseMessage += ManageMods_RaiseMessage;
- this.ManageMods.RaiseError += ManageMods_RaiseError;
- this.ManageMods.ClearStatusBar += ManageMods_ClearStatusBar;
+ this.ManageMods.OnSelectedModuleChanged += this.ManageMods_OnSelectedModuleChanged;
+ this.ManageMods.OnChangeSetChanged += this.ManageMods_OnChangeSetChanged;
+ this.ManageMods.OnRegistryChanged += this.ManageMods_OnRegistryChanged;
+ this.ManageMods.LabelsAfterUpdate += this.ManageMods_LabelsAfterUpdate;
+ this.ManageMods.StartChangeSet += this.ManageMods_StartChangeSet;
+ this.ManageMods.RaiseMessage += this.ManageMods_RaiseMessage;
+ this.ManageMods.RaiseError += this.ManageMods_RaiseError;
+ this.ManageMods.ClearStatusBar += this.ManageMods_ClearStatusBar;
+ this.ManageMods.LaunchGame += this.LaunchGame;
+ this.ManageMods.EditCommandLines += this.EditCommandLines;
//
// ChangesetTabPage
//
@@ -505,9 +507,9 @@ private void InitializeComponent()
this.Changeset.Name = "Changeset";
this.Changeset.Size = new System.Drawing.Size(500, 500);
this.Changeset.TabIndex = 32;
- this.Changeset.OnSelectedItemsChanged += Changeset_OnSelectedItemsChanged;
- this.Changeset.OnConfirmChanges += Changeset_OnConfirmChanges;
- this.Changeset.OnCancelChanges += Changeset_OnCancelChanges;
+ this.Changeset.OnSelectedItemsChanged += this.Changeset_OnSelectedItemsChanged;
+ this.Changeset.OnConfirmChanges += this.Changeset_OnConfirmChanges;
+ this.Changeset.OnCancelChanges += this.Changeset_OnCancelChanges;
//
// WaitTabPage
//
@@ -530,8 +532,8 @@ private void InitializeComponent()
this.Wait.Name = "Wait";
this.Wait.Size = new System.Drawing.Size(500, 500);
this.Wait.TabIndex = 32;
- this.Wait.OnRetry += Wait_OnRetry;
- this.Wait.OnOk += Wait_OnOk;
+ this.Wait.OnRetry += this.Wait_OnRetry;
+ this.Wait.OnOk += this.Wait_OnOk;
//
// ChooseRecommendedModsTabPage
//
@@ -578,7 +580,7 @@ private void InitializeComponent()
this.PlayTime.Name = "PlayTime";
this.PlayTime.Size = new System.Drawing.Size(500, 500);
this.PlayTime.TabIndex = 32;
- this.PlayTime.Done += PlayTime_Done;
+ this.PlayTime.Done += this.PlayTime_Done;
//
// UnmanagedFilesTabPage
//
@@ -601,7 +603,7 @@ private void InitializeComponent()
this.UnmanagedFiles.Name = "UnmanagedFiles";
this.UnmanagedFiles.Size = new System.Drawing.Size(500, 500);
this.UnmanagedFiles.TabIndex = 32;
- this.UnmanagedFiles.Done += UnmanagedFiles_Done;
+ this.UnmanagedFiles.Done += this.UnmanagedFiles_Done;
//
// InstallationHistoryTabPage
//
@@ -624,9 +626,9 @@ private void InitializeComponent()
this.InstallationHistory.Name = "InstallationHistory";
this.InstallationHistory.Size = new System.Drawing.Size(500, 500);
this.InstallationHistory.TabIndex = 32;
- this.InstallationHistory.OnSelectedModuleChanged += InstallationHistory_OnSelectedModuleChanged;
- this.InstallationHistory.Install += InstallationHistory_Install;
- this.InstallationHistory.Done += InstallationHistory_Done;
+ this.InstallationHistory.OnSelectedModuleChanged += this.InstallationHistory_OnSelectedModuleChanged;
+ this.InstallationHistory.Install += this.InstallationHistory_Install;
+ this.InstallationHistory.Done += this.InstallationHistory_Done;
//
// ChooseProvidedModsTabPage
//
diff --git a/GUI/Main/Main.cs b/GUI/Main/Main.cs
index 6a796a7804..b46430682f 100644
--- a/GUI/Main/Main.cs
+++ b/GUI/Main/Main.cs
@@ -172,6 +172,7 @@ protected override void OnLoad(EventArgs e)
// We need a config object to get the window geometry, but we don't need the registry lock yet
configuration = GUIConfigForInstance(
+ Manager.SteamLibrary,
// Find the most recently used instance if no default instance
CurrentInstance ?? InstanceWithNewestGUIConfig(Manager.Instances.Values));
@@ -203,10 +204,13 @@ protected override void OnLoad(EventArgs e)
private static string GUIConfigPath(GameInstance inst)
=> Path.Combine(inst.CkanDir(), GUIConfigFilename);
- private static GUIConfiguration GUIConfigForInstance(GameInstance inst)
+ private static GUIConfiguration GUIConfigForInstance(SteamLibrary steamLib, GameInstance inst)
=> inst == null ? new GUIConfiguration()
- : GUIConfiguration.LoadOrCreateConfiguration(GUIConfigPath(inst),
- inst.game);
+ : GUIConfiguration.LoadOrCreateConfiguration(
+ GUIConfigPath(inst),
+ inst.game.DefaultCommandLines(steamLib,
+ new DirectoryInfo(inst.GameDir()))
+ .ToList());
private static GameInstance InstanceWithNewestGUIConfig(IEnumerable instances)
=> instances.Where(inst => inst.Valid)
@@ -409,7 +413,7 @@ private void CurrentInstanceUpdated()
}
configuration?.Save();
- configuration = GUIConfigForInstance(CurrentInstance);
+ configuration = GUIConfigForInstance(Manager.SteamLibrary, CurrentInstance);
AutoUpdatePrompts(ServiceLocator.Container
.Resolve(),
@@ -427,6 +431,7 @@ private void CurrentInstanceUpdated()
CurrentInstance.game.RebuildSubdirectories(CurrentInstance.GameDir());
+ ManageMods.InstanceUpdated();
bool repoUpdateNeeded = configuration.RefreshOnStartup;
if (!autoUpdating)
{
@@ -441,7 +446,6 @@ private void CurrentInstanceUpdated()
RefreshModList(registry.Repositories.Count > 0);
}
}
- ManageMods.InstanceUpdated();
}
///
@@ -607,11 +611,18 @@ private void aboutToolStripMenuItem_Click(object sender, EventArgs e)
}
private void GameCommandlineToolStripMenuItem_Click(object sender, EventArgs e)
+ {
+ EditCommandLines();
+ }
+
+ private void EditCommandLines()
{
var dialog = new GameCommandLineOptionsDialog();
- if (dialog.ShowGameCommandLineOptionsDialog(configuration.CommandLineArguments) == DialogResult.OK)
+ var defaults = CurrentInstance.game.DefaultCommandLines(Manager.SteamLibrary,
+ new DirectoryInfo(CurrentInstance.GameDir()));
+ if (dialog.ShowGameCommandLineOptionsDialog(this, configuration.CommandLines, defaults) == DialogResult.OK)
{
- configuration.CommandLineArguments = dialog.GetResult();
+ configuration.CommandLines = dialog.Results;
}
}
@@ -921,12 +932,12 @@ private void openGameDirectoryToolStripMenuItem_Click(object sender, EventArgs e
private void openGameToolStripMenuItem_Click(object sender, EventArgs e)
{
- LaunchGame();
+ LaunchGame(configuration.CommandLines.First());
}
- public void LaunchGame()
+ private void LaunchGame(string command)
{
- var split = configuration.CommandLineArguments.Split(' ');
+ var split = command.Split(' ');
if (split.Length == 0)
{
return;
diff --git a/GUI/Main/Main.resx b/GUI/Main/Main.resx
index aa1f3d90c7..2aa48a35df 100644
--- a/GUI/Main/Main.resx
+++ b/GUI/Main/Main.resx
@@ -134,7 +134,7 @@
CKAN &plugins
Preferred &hosts
Installation &filters
- &Game command-line
+ &Game command lines
&Compatible game versions
&Help
&User guide
diff --git a/GUI/Model/GUIConfiguration.cs b/GUI/Model/GUIConfiguration.cs
index 1fd31c4233..0910132568 100644
--- a/GUI/Model/GUIConfiguration.cs
+++ b/GUI/Model/GUIConfiguration.cs
@@ -1,19 +1,21 @@
using System;
using System.Xml;
using System.Collections.Generic;
+using System.Linq;
using System.Drawing;
using System.IO;
using System.Xml.Serialization;
-using CKAN.Games;
-
namespace CKAN.GUI
{
[XmlRoot("Configuration")]
public class GUIConfiguration
{
- public string CommandLineArguments = "";
- public bool AutoCloseWaitDialog = false;
+ public string CommandLineArguments = null;
+
+ [XmlArray, XmlArrayItem(ElementName = "CommandLine")]
+ public List CommandLines = new List();
+
public bool URLHandlerNoNag = false;
public bool CheckForUpdatesOnLaunch = false;
@@ -25,7 +27,8 @@ public class GUIConfiguration
public bool HideEpochs = true;
public bool HideV = false;
- public bool RefreshOnStartup = true; // Defaults to true, so everyone is forced to refresh on first start
+ // Defaults to true, so everyone is forced to refresh on first start
+ public bool RefreshOnStartup = true;
public bool RefreshOnStartupNoNag = false;
public bool RefreshPaused = false;
@@ -107,25 +110,27 @@ public void Save()
}
}
- public static GUIConfiguration LoadOrCreateConfiguration(string path, IGame game)
+ public static GUIConfiguration LoadOrCreateConfiguration(string path,
+ List defaultCommandLines)
{
if (!File.Exists(path) || new FileInfo(path).Length == 0)
{
var configuration = new GUIConfiguration
{
- path = path,
- CommandLineArguments = game.DefaultCommandLine(path),
+ path = path,
+ CommandLines = defaultCommandLines,
};
SaveConfiguration(configuration);
}
- return LoadConfiguration(path);
+ return LoadConfiguration(path, defaultCommandLines);
}
- private static GUIConfiguration LoadConfiguration(string path)
+ private static GUIConfiguration LoadConfiguration(string path,
+ List defaultCommandLines)
{
- var serializer = new XmlSerializer(typeof (GUIConfiguration));
+ var serializer = new XmlSerializer(typeof(GUIConfiguration));
GUIConfiguration configuration;
using (var stream = new StreamReader(path))
@@ -163,7 +168,7 @@ private static GUIConfiguration LoadConfiguration(string path)
}
configuration.path = path;
- if (DeserializationFixes(configuration))
+ if (DeserializationFixes(configuration, defaultCommandLines))
{
SaveConfiguration(configuration);
}
@@ -175,7 +180,8 @@ private static GUIConfiguration LoadConfiguration(string path)
///
/// The current configuration to apply the fixes on
/// A bool indicating whether something changed and the configuration should be saved to disk
- private static bool DeserializationFixes(GUIConfiguration configuration)
+ private static bool DeserializationFixes(GUIConfiguration configuration,
+ List defaultCommandLines)
{
bool needsSave = false;
@@ -187,6 +193,16 @@ private static bool DeserializationFixes(GUIConfiguration configuration)
needsSave = FixColumnName(configuration.SortColumns, "SizeCol", "DownloadSize") || needsSave;
needsSave = FixColumnName(configuration.HiddenColumnNames, "SizeCol", "DownloadSize") || needsSave;
+ if (!string.IsNullOrEmpty(configuration.CommandLineArguments))
+ {
+ configuration.CommandLines.AddRange(
+ Enumerable.Repeat(configuration.CommandLineArguments, 1)
+ .Concat(defaultCommandLines)
+ .Distinct());
+ configuration.CommandLineArguments = null;
+ needsSave = true;
+ }
+
return needsSave;
}
diff --git a/GUI/Properties/Resources.resx b/GUI/Properties/Resources.resx
index e8fde203ac..869ca7a985 100644
--- a/GUI/Properties/Resources.resx
+++ b/GUI/Properties/Resources.resx
@@ -432,6 +432,8 @@ Do you want to allow CKAN to do this? If you click no you won't see this message
replaceable
Expand or collapse the detailed search fields (Ctrl-Shift-F)
Combine a new search with your current searches
+ (will count play time in Steam)
+ (will NOT count play time in Steam)
Uncheck to uninstall all mods, check to clear change set
Hidden labels:
Hidden tags:
diff --git a/Netkan/Processors/Inflator.cs b/Netkan/Processors/Inflator.cs
index 6991e612da..87aa6288a4 100644
--- a/Netkan/Processors/Inflator.cs
+++ b/Netkan/Processors/Inflator.cs
@@ -20,7 +20,6 @@ public Inflator(string cacheDir, bool overwriteCache, string githubToken, string
{
log.Debug("Initializing inflator");
cache = FindCache(
- new GameInstanceManager(new ConsoleUser(false)),
ServiceLocator.Container.Resolve(),
cacheDir);
@@ -80,7 +79,7 @@ internal void ValidateCkan(Metadata ckan)
ckanValidator.Validate(ckan);
}
- private static NetFileCache FindCache(GameInstanceManager kspManager, IConfiguration cfg, string cacheDir)
+ private static NetFileCache FindCache(IConfiguration cfg, string cacheDir)
{
if (cacheDir != null)
{
@@ -92,7 +91,7 @@ private static NetFileCache FindCache(GameInstanceManager kspManager, IConfigura
{
log.InfoFormat("Using main CKAN meta-cache at {0}", cfg.DownloadCacheDir);
// Create a new file cache in the same location so NetKAN can download pure URLs not sourced from CkanModules
- return new NetFileCache(kspManager, cfg.DownloadCacheDir);
+ return new NetFileCache(null, cfg.DownloadCacheDir);
}
catch
{
diff --git a/Netkan/Program.cs b/Netkan/Program.cs
index 84144c1ab1..c63b32434c 100644
--- a/Netkan/Program.cs
+++ b/Netkan/Program.cs
@@ -11,6 +11,7 @@
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
+using CKAN.Games;
using CKAN.Versioning;
using CKAN.NetKAN.Model;
using CKAN.NetKAN.Processors;
@@ -48,7 +49,7 @@ public static int Main(string[] args)
return ExitOk;
}
- var game = GameInstanceManager.GameByShortName(Options.Game);
+ var game = KnownGames.GameByShortName(Options.Game);
if (!string.IsNullOrEmpty(Options.ValidateCkan))
{
diff --git a/Tests/GUI/GUIConfiguration.cs b/Tests/GUI/GUIConfiguration.cs
index c5a11c77d4..9c474c0d8d 100644
--- a/Tests/GUI/GUIConfiguration.cs
+++ b/Tests/GUI/GUIConfiguration.cs
@@ -1,10 +1,10 @@
using System.IO;
+using System.Collections.Generic;
using NUnit.Framework;
using CKAN;
using CKAN.GUI;
-using CKAN.Games.KerbalSpaceProgram;
using Tests.Data;
@@ -37,7 +37,7 @@ public void LoadOrCreateConfiguration_MalformedXMLFile_ThrowsKraken()
stream.Write("This is not a valid XML file.");
}
- Assert.Throws(() => GUIConfiguration.LoadOrCreateConfiguration(tempFile, new KerbalSpaceProgram()));
+ Assert.Throws(() => GUIConfiguration.LoadOrCreateConfiguration(tempFile, new List()));
}
[Test]
@@ -50,7 +50,7 @@ public void LoadOrCreateConfiguration_CorrectConfigurationFile_Loaded()
stream.Write(TestData.ConfigurationFile());
}
- var result = GUIConfiguration.LoadOrCreateConfiguration(tempFile, new KerbalSpaceProgram());
+ var result = GUIConfiguration.LoadOrCreateConfiguration(tempFile, new List());
Assert.IsNotNull(result);
}
diff --git a/build.cake b/build.cake
index 33ea649416..350ac4e99b 100644
--- a/build.cake
+++ b/build.cake
@@ -16,6 +16,8 @@ var solution = Argument("solution", "CKAN.sln");
var rootDirectory = Context.Environment.WorkingDirectory;
var buildDirectory = rootDirectory.Combine("_build");
+var nugetDirectory = buildDirectory.Combine("lib")
+ .Combine("nuget");
var outDirectory = buildDirectory.Combine("out");
var repackDirectory = buildDirectory.Combine("repack");
var ckanFile = repackDirectory.Combine(configuration)
@@ -188,8 +190,6 @@ Task("Restore")
.Description("Intermediate - Download dependencies")
.Does(() =>
{
- var nugetDirectory = buildDirectory.Combine("lib")
- .Combine("nuget");
if (IsRunningOnWindows())
{
DotNetRestore(solution, new DotNetRestoreSettings
@@ -305,7 +305,8 @@ Task("Repack-Ckan")
assemblyPaths,
new ILRepackSettings
{
- Libs = new List { cmdLineBinDirectory.FullPath },
+ Libs = new List { cmdLineBinDirectory,
+ netstandardRefDirectory() },
TargetPlatform = TargetPlatformVersion.v4,
Parallel = true,
Verbose = false,
@@ -329,7 +330,7 @@ Task("Repack-Ckan")
autoupdateBinDirectory)),
new ILRepackSettings
{
- Libs = new List { autoupdateBinDirectory.FullPath },
+ Libs = new List { autoupdateBinDirectory },
TargetPlatform = TargetPlatformVersion.v4,
Parallel = true,
Verbose = false,
@@ -352,15 +353,16 @@ Task("Repack-Netkan")
.Combine(buildNetFramework);
var netkanLogFile = repackDirectory.Combine(configuration)
.CombineWithFilePath($"netkan.log");
+ var assemblyPaths = GetFiles(string.Format("{0}/*.dll", netkanBinDirectory));
ReportRepacking(netkanFile, netkanLogFile);
ILRepack(
netkanFile,
netkanBinDirectory.CombineWithFilePath("CKAN-NetKAN.exe"),
- GetFiles(string.Format("{0}/*.dll",
- netkanBinDirectory)),
+ assemblyPaths,
new ILRepackSettings
{
- Libs = new List { netkanBinDirectory.FullPath },
+ Libs = new List { netkanBinDirectory,
+ netstandardRefDirectory() },
TargetPlatform = TargetPlatformVersion.v4,
Parallel = true,
Verbose = false,
@@ -520,6 +522,23 @@ Teardown(context =>
RunTarget(target);
+private DirectoryPath netstandardRefDirectory()
+{
+ // We need to tell ILRepack where to find netstandard.dll (on Linux),
+ // which doesn't get copied to the output folder
+ var netstandardDirectory = nugetDirectory.Combine("netstandard.library");
+ var netstandardVersion = System.IO.Directory
+ .EnumerateDirectories(netstandardDirectory.ToString())
+ .Select(p => System.IO.Path.GetFileName(p))
+ .OrderBy(p => ParseSemVer(p))
+ .Last();
+ return netstandardDirectory.Combine(netstandardVersion)
+ .Combine("build")
+ .Combine("netstandard2.0")
+ .Combine("ref");
+}
+
+
private Semver.SemVersion GetVersion()
{
var pattern = new Regex(@"^\s*##\s+v(?\S+)\s?.*$");