2019-11-03 16:43:43 +00:00
using System ;
using System.Collections.Generic ;
using System.IO ;
using System.Linq ;
2019-11-04 16:04:37 +00:00
using System.Security.Cryptography ;
2019-11-03 16:43:43 +00:00
using System.Text ;
2019-12-04 12:36:56 +00:00
using DynamicData ;
2019-11-09 20:35:08 +00:00
using Microsoft.WindowsAPICodePack.Shell ;
2019-11-17 16:26:04 +00:00
using Newtonsoft.Json ;
2019-11-03 16:43:43 +00:00
using Wabbajack.Common ;
using Wabbajack.Lib.CompilationSteps ;
2019-11-04 16:04:37 +00:00
using Wabbajack.Lib.NexusApi ;
2019-11-09 15:10:31 +00:00
using File = Alphaleonis . Win32 . Filesystem . File ;
2019-11-03 16:43:43 +00:00
namespace Wabbajack.Lib
{
public class VortexCompiler : ACompiler
{
2019-11-17 16:26:04 +00:00
/ * vortex creates a vortex . deployment . json file that contains information
about all deployed files , parsing that file , we can get a list of all ' active '
archives so we don ' t force the user to install all archives found in the downloads folder .
Similar to how IgnoreDisabledMods for MO2 works
* /
public VortexDeployment VortexDeployment ;
public List < string > ActiveArchives ;
2019-11-09 14:10:28 +00:00
public Game Game { get ; }
2019-11-03 16:43:43 +00:00
public string GameName { get ; }
2019-11-12 17:54:48 +00:00
public string VortexFolder { get ; set ; }
public string StagingFolder { get ; set ; }
public string DownloadsFolder { get ; set ; }
2019-11-03 16:43:43 +00:00
public bool IgnoreMissingFiles { get ; set ; }
2019-11-24 00:30:51 +00:00
public override ModManager ModManager = > ModManager . Vortex ;
public override string GamePath { get ; }
public override string ModListOutputFolder { get ; }
public override string ModListOutputFile { get ; }
2019-11-17 03:09:46 +00:00
public const string StagingMarkerName = "__vortex_staging_folder" ;
public const string DownloadMarkerName = "__vortex_downloads_folder" ;
2019-12-02 16:44:24 +00:00
private bool _isSteamGame ;
private SteamGame _steamGame ;
private bool _hasSteamWorkshopItems ;
2019-11-24 00:30:51 +00:00
public VortexCompiler ( Game game , string gamePath , string vortexFolder , string downloadsFolder , string stagingFolder , string outputFile )
2019-11-03 16:43:43 +00:00
{
2019-11-17 13:51:28 +00:00
Game = game ;
2019-11-03 16:43:43 +00:00
GamePath = gamePath ;
2019-11-16 22:10:13 +00:00
GameName = GameRegistry . Games [ game ] . NexusName ;
2019-11-17 13:51:28 +00:00
VortexFolder = vortexFolder ;
DownloadsFolder = downloadsFolder ;
StagingFolder = stagingFolder ;
2019-11-03 16:43:43 +00:00
ModListOutputFolder = "output_folder" ;
2019-11-24 00:30:51 +00:00
ModListOutputFile = outputFile ;
2019-11-17 16:26:04 +00:00
2019-12-02 16:44:24 +00:00
// there can be max one game after filtering
SteamHandler . Instance . Games . Where ( g = > g . Game ! = null & & g . Game = = game ) . Do ( g = >
{
_isSteamGame = true ;
_steamGame = g ;
SteamHandler . Instance . LoadWorkshopItems ( _steamGame ) ;
_hasSteamWorkshopItems = _steamGame . WorkshopItems . Count > 0 ;
} ) ;
2019-11-17 16:26:04 +00:00
ActiveArchives = new List < string > ( ) ;
2019-11-03 16:43:43 +00:00
}
2019-11-17 23:48:32 +00:00
protected override bool _Begin ( )
2019-11-03 16:43:43 +00:00
{
2019-11-17 23:48:32 +00:00
ConfigureProcessor ( 10 ) ;
2019-11-17 14:54:04 +00:00
if ( string . IsNullOrEmpty ( ModListName ) )
ModListName = $"Vortex ModList for {Game.ToString()}" ;
2019-11-17 14:30:06 +00:00
2019-11-03 16:43:43 +00:00
Info ( $"Starting Vortex compilation for {GameName} at {GamePath} with staging folder at {StagingFolder} and downloads folder at {DownloadsFolder}." ) ;
2019-11-17 16:26:04 +00:00
ParseDeploymentFile ( ) ;
2019-11-04 16:04:37 +00:00
Info ( "Starting pre-compilation steps" ) ;
CreateMetaFiles ( ) ;
Info ( $"Indexing {StagingFolder}" ) ;
2019-11-16 00:01:37 +00:00
VFS . AddRoot ( StagingFolder ) ;
2019-11-04 16:04:37 +00:00
2019-11-03 16:43:43 +00:00
Info ( $"Indexing {GamePath}" ) ;
2019-11-16 00:01:37 +00:00
VFS . AddRoot ( GamePath ) ;
2019-11-03 16:43:43 +00:00
Info ( $"Indexing {DownloadsFolder}" ) ;
2019-11-16 00:01:37 +00:00
VFS . AddRoot ( DownloadsFolder ) ;
2019-11-03 16:43:43 +00:00
2019-11-09 20:35:08 +00:00
AddExternalFolder ( ) ;
2019-11-03 16:43:43 +00:00
Info ( "Cleaning output folder" ) ;
2019-11-23 17:37:24 +00:00
if ( Directory . Exists ( ModListOutputFolder ) ) Utils . DeleteDirectory ( ModListOutputFolder ) ;
2019-11-03 16:43:43 +00:00
Directory . CreateDirectory ( ModListOutputFolder ) ;
2019-11-04 16:04:37 +00:00
2019-12-01 14:59:08 +00:00
var vortexStagingFiles = Directory . EnumerateFiles ( StagingFolder , "*" , SearchOption . AllDirectories )
2019-11-17 03:09:46 +00:00
. Where ( p = > p . FileExists ( ) & & p ! = StagingMarkerName )
2019-11-15 13:06:34 +00:00
. Select ( p = > new RawSourceFile ( VFS . Index . ByRootPath [ p ] )
2019-11-04 16:04:37 +00:00
{ Path = p . RelativeTo ( StagingFolder ) } ) ;
2019-12-01 14:59:08 +00:00
var vortexDownloads = Directory . EnumerateFiles ( DownloadsFolder , "*" , SearchOption . AllDirectories )
2019-11-04 16:04:37 +00:00
. Where ( p = > p . FileExists ( ) )
2019-11-15 13:06:34 +00:00
. Select ( p = > new RawSourceFile ( VFS . Index . ByRootPath [ p ] )
2019-11-04 16:04:37 +00:00
{ Path = p . RelativeTo ( DownloadsFolder ) } ) ;
2019-11-03 16:43:43 +00:00
2019-12-01 14:59:08 +00:00
var gameFiles = Directory . EnumerateFiles ( GamePath , "*" , SearchOption . AllDirectories )
2019-11-03 16:43:43 +00:00
. Where ( p = > p . FileExists ( ) )
2019-11-15 13:06:34 +00:00
. Select ( p = > new RawSourceFile ( VFS . Index . ByRootPath [ p ] )
2019-11-04 12:30:02 +00:00
{ Path = Path . Combine ( Consts . GameFolderFilesDir , p . RelativeTo ( GamePath ) ) } ) ;
2019-11-03 16:43:43 +00:00
Info ( "Indexing Archives" ) ;
IndexedArchives = Directory . EnumerateFiles ( DownloadsFolder )
2019-11-15 13:06:34 +00:00
. Where ( f = > File . Exists ( f + ".meta" ) )
2019-11-03 16:43:43 +00:00
. Select ( f = > new IndexedArchive
{
2019-11-15 13:06:34 +00:00
File = VFS . Index . ByRootPath [ f ] ,
2019-11-04 12:30:02 +00:00
Name = Path . GetFileName ( f ) ,
2019-11-15 13:06:34 +00:00
IniData = ( f + ".meta" ) . LoadIniFile ( ) ,
Meta = File . ReadAllText ( f + ".meta" )
2019-11-03 16:43:43 +00:00
} )
. ToList ( ) ;
Info ( "Indexing Files" ) ;
2019-11-15 13:06:34 +00:00
IndexedFiles = IndexedArchives . SelectMany ( f = > f . File . ThisAndAllChildren )
. OrderBy ( f = > f . NestingFactor )
2019-11-03 16:43:43 +00:00
. GroupBy ( f = > f . Hash )
. ToDictionary ( f = > f . Key , f = > f . AsEnumerable ( ) ) ;
Info ( "Searching for mod files" ) ;
2019-11-04 16:04:37 +00:00
AllFiles = vortexStagingFiles . Concat ( vortexDownloads )
. Concat ( gameFiles )
. DistinctBy ( f = > f . Path )
. ToList ( ) ;
2019-11-03 16:43:43 +00:00
Info ( $"Found {AllFiles.Count} files to build into mod list" ) ;
Info ( "Verifying destinations" ) ;
2019-12-01 14:59:08 +00:00
var duplicates = AllFiles . GroupBy ( f = > f . Path )
2019-11-03 16:43:43 +00:00
. Where ( fs = > fs . Count ( ) > 1 )
. Select ( fs = >
{
2019-11-04 12:30:02 +00:00
Utils . Log ( $"Duplicate files installed to {fs.Key} from : {string.Join(" , ", fs.Select(f => f.AbsolutePath))}" ) ;
2019-11-03 16:43:43 +00:00
return fs ;
} ) . ToList ( ) ;
2019-12-01 14:59:08 +00:00
if ( duplicates . Count > 0 )
2019-11-03 16:43:43 +00:00
{
2019-12-01 14:59:08 +00:00
Error ( $"Found {duplicates.Count} duplicates, exiting" ) ;
2019-11-03 16:43:43 +00:00
}
2019-12-04 12:36:56 +00:00
for ( var i = 0 ; i < AllFiles . Count ; i + + )
{
var f = AllFiles [ i ] ;
if ( ! f . Path . StartsWith ( Consts . GameFolderFilesDir ) | | ! IndexedFiles . ContainsKey ( f . Hash ) )
continue ;
if ( ! IndexedFiles . TryGetValue ( f . Hash , out var value ) )
continue ;
var element = value . ElementAt ( 0 ) ;
if ( ! f . Path . Contains ( element . Name ) )
continue ;
IndexedArchive targetArchive = null ;
IndexedArchives . Where ( a = > a . File . Children . Contains ( element ) ) . Do ( a = > targetArchive = a ) ;
if ( targetArchive = = null )
continue ;
if ( targetArchive . IniData ? . General ? . tag = = null | | targetArchive . IniData ? . General ? . tag ! = Consts . WABBAJACK_VORTEX_MANUAL )
continue ;
#if DEBUG
Utils . Log ( $"Double hash for: {f.AbsolutePath}" ) ;
#endif
var replace = f ;
replace . Path = Path . Combine ( "Manual Game Files" , element . FullPath . Substring ( DownloadsFolder . Length + 1 ) . Replace ( '|' , '\\' ) ) ;
AllFiles . RemoveAt ( i ) ;
AllFiles . Insert ( i , replace ) ;
//AllFiles.Replace(f, replace);
}
2019-12-01 14:59:08 +00:00
var stack = MakeStack ( ) ;
2019-11-03 16:43:43 +00:00
Info ( "Running Compilation Stack" ) ;
2019-12-01 14:59:08 +00:00
var results = AllFiles . PMap ( Queue , f = > RunStack ( stack . Where ( s = > s ! = null ) , f ) ) . ToList ( ) ;
2019-11-03 16:43:43 +00:00
IEnumerable < NoMatch > noMatch = results . OfType < NoMatch > ( ) . ToList ( ) ;
Info ( $"No match for {noMatch.Count()} files" ) ;
foreach ( var file in noMatch )
Info ( $" {file.To}" ) ;
if ( noMatch . Any ( ) )
{
if ( IgnoreMissingFiles )
{
Info ( "Continuing even though files were missing at the request of the user." ) ;
}
else
{
Info ( "Exiting due to no way to compile these files" ) ;
return false ;
}
}
InstallDirectives = results . Where ( i = > ! ( i is IgnoredDirectly ) ) . ToList ( ) ;
// TODO: nexus stuff
/ * Info ( "Getting Nexus api_key, please click authorize if a browser window appears" ) ;
if ( IndexedArchives . Any ( a = > a . IniData ? . General ? . gameName ! = null ) )
{
var nexusClient = new NexusApiClient ( ) ;
if ( ! nexusClient . IsPremium ) Error ( $"User {nexusClient.Username} is not a premium Nexus user, so we cannot access the necessary API calls, cannot continue" ) ;
}
* /
GatherArchives ( ) ;
ModList = new ModList
{
2019-11-17 14:54:04 +00:00
Name = ModListName ? ? "" ,
2019-11-17 14:30:06 +00:00
Author = ModListAuthor ? ? "" ,
Description = ModListDescription ? ? "" ,
Readme = ModListReadme ? ? "" ,
Image = ModListImage ? ? "" ,
Website = ModListWebsite ? ? "" ,
2019-12-03 21:13:29 +00:00
Archives = SelectedArchives . ToList ( ) ,
2019-11-03 16:43:43 +00:00
ModManager = ModManager . Vortex ,
2019-11-09 15:10:31 +00:00
Directives = InstallDirectives ,
GameType = Game
2019-11-03 16:43:43 +00:00
} ;
2019-11-17 14:54:04 +00:00
GenerateReport ( ) ;
2019-11-03 16:43:43 +00:00
ExportModList ( ) ;
Info ( "Done Building ModList" ) ;
2019-11-17 14:54:04 +00:00
ShowReport ( ) ;
2019-11-03 16:43:43 +00:00
return true ;
}
2019-11-17 16:26:04 +00:00
private void ParseDeploymentFile ( )
{
Info ( "Searching for vortex.deployment.json..." ) ;
var deploymentFile = "" ;
Directory . EnumerateFiles ( GamePath , "vortex.deployment.json" , SearchOption . AllDirectories )
. Where ( File . Exists )
. Do ( f = > deploymentFile = f ) ;
var currentGame = GameRegistry . Games [ Game ] ;
if ( currentGame . AdditionalFolders ! = null & & currentGame . AdditionalFolders . Count ! = 0 )
currentGame . AdditionalFolders . Do ( f = > Directory . EnumerateFiles ( f , "vortex.deployment.json" , SearchOption . AllDirectories )
. Where ( File . Exists )
. Do ( d = > deploymentFile = d ) ) ;
if ( string . IsNullOrEmpty ( deploymentFile ) )
{
Info ( "vortex.deployment.json not found!" ) ;
return ;
}
Info ( "vortex.deployment.json found at " + deploymentFile ) ;
Info ( "Parsing vortex.deployment.json..." ) ;
try
{
VortexDeployment = deploymentFile . FromJSON < VortexDeployment > ( ) ;
}
catch ( JsonSerializationException e )
{
Info ( "Failed to parse vortex.deployment.json!" ) ;
Utils . LogToFile ( e . Message ) ;
Utils . LogToFile ( e . StackTrace ) ;
}
VortexDeployment . files . Do ( f = >
{
var archive = f . source ;
2019-12-04 12:36:56 +00:00
if ( ActiveArchives . Contains ( archive ) )
return ;
Utils . Log ( $"Adding Archive {archive} to ActiveArchives" ) ;
ActiveArchives . Add ( archive ) ;
2019-11-17 16:26:04 +00:00
} ) ;
}
2019-11-09 20:35:08 +00:00
/// <summary>
/// Some have mods outside their game folder located
/// </summary>
private void AddExternalFolder ( )
{
var currentGame = GameRegistry . Games [ Game ] ;
if ( currentGame . AdditionalFolders = = null | | currentGame . AdditionalFolders . Count = = 0 ) return ;
currentGame . AdditionalFolders . Do ( f = >
{
var path = f . Replace ( "%documents%" , KnownFolders . Documents . Path ) ;
if ( ! Directory . Exists ( path ) ) return ;
Info ( $"Indexing {path}" ) ;
VFS . AddRoot ( path ) ;
} ) ;
}
2019-11-04 16:04:37 +00:00
private void CreateMetaFiles ( )
{
2019-11-11 13:03:48 +00:00
Utils . Log ( "Getting Nexus api_key, please click authorize if a browser window appears" ) ;
var nexusClient = new NexusApiClient ( ) ;
2019-11-04 16:04:37 +00:00
Directory . EnumerateFiles ( DownloadsFolder , "*" , SearchOption . TopDirectoryOnly )
2019-12-01 15:08:19 +00:00
. Where ( File . Exists )
2019-11-04 16:04:37 +00:00
. Do ( f = >
{
2019-12-01 15:08:19 +00:00
if ( Path . GetExtension ( f ) ! = ".meta" & & ! File . Exists ( $"{f}.meta" ) & & ActiveArchives . Contains ( Path . GetFileNameWithoutExtension ( f ) ) )
2019-11-09 15:19:08 +00:00
{
2019-12-01 15:08:19 +00:00
Utils . Log ( $"Trying to create meta file for {Path.GetFileName(f)}" ) ;
var metaString = "[General]\n" +
"repository=Nexus\n" +
"installed=true\n" +
"uninstalled=false\n" +
"paused=false\n" +
"removed=false\n" +
$"gameName={GameName}\n" ;
string hash ;
using ( var md5 = MD5 . Create ( ) )
using ( var stream = File . OpenRead ( f ) )
{
Utils . Log ( $"Calculating hash for {Path.GetFileName(f)}" ) ;
var cH = md5 . ComputeHash ( stream ) ;
hash = BitConverter . ToString ( cH ) . Replace ( "-" , "" ) . ToLowerInvariant ( ) ;
Utils . Log ( $"Hash is {hash}" ) ;
}
var md5Response = nexusClient . GetModInfoFromMD5 ( Game , hash ) ;
if ( md5Response . Count > = 1 )
{
var modInfo = md5Response [ 0 ] . mod ;
metaString + = $"modID={modInfo.mod_id}\n" +
$"modName={modInfo.name}\nfileID={md5Response[0].file_details.file_id}" ;
File . WriteAllText ( f + ".meta" , metaString , Encoding . UTF8 ) ;
}
else
{
Error ( "Error while getting information from NexusMods via MD5 hash!" ) ;
}
2019-11-09 15:19:08 +00:00
}
else
{
2019-12-01 15:08:19 +00:00
if ( Path . GetExtension ( f ) ! = ".meta" | |
ActiveArchives . Contains ( Path . GetFileNameWithoutExtension ( f ) ) )
return ;
2019-12-04 12:36:56 +00:00
Utils . Log ( $"File {f} is not in ActiveArchives" ) ;
2019-12-01 15:08:19 +00:00
var lines = File . ReadAllLines ( f ) ;
if ( lines . Length = = 0 | | ! lines . Any ( line = > line . Contains ( "directURL=" ) ) )
2019-12-04 12:36:56 +00:00
{
if ( lines . Length = = 0 )
return ;
2019-12-01 15:08:19 +00:00
2019-12-04 12:36:56 +00:00
lines . Do ( line = >
{
var tag = "" ;
if ( line . Contains ( "tag=" ) )
tag = line . Substring ( "tag=" . Length ) ;
if ( tag ! = Consts . WABBAJACK_VORTEX_MANUAL )
return ;
Utils . Log ( $"File {f} contains the {Consts.WABBAJACK_VORTEX_MANUAL} tag, adding to ActiveArchives" ) ;
ActiveArchives . Add ( Path . GetFileNameWithoutExtension ( f ) ) ;
} ) ;
}
else
{
Utils . Log ( $"File {f} appears to not come from the Nexus, adding to ActiveArchives" ) ;
ActiveArchives . Add ( Path . GetFileNameWithoutExtension ( f ) ) ;
}
2019-11-09 15:19:08 +00:00
}
2019-11-04 16:04:37 +00:00
} ) ;
2019-12-02 16:44:24 +00:00
Utils . Log ( $"Checking for Steam Workshop Items..." ) ;
if ( ! _isSteamGame | | _steamGame = = null | | _steamGame . WorkshopItems . Count < = 0 )
return ;
_steamGame . WorkshopItems . Do ( item = >
{
2019-12-04 12:36:56 +00:00
var filePath = Path . Combine ( DownloadsFolder , $"steamWorkshopItem_{item.ItemID}.meta" ) ;
if ( File . Exists ( filePath ) )
{
Utils . Log ( $"File {filePath} already exists, skipping..." ) ;
return ;
}
2019-12-02 16:44:24 +00:00
Utils . Log ( $"Creating meta file for {item.ItemID}" ) ;
var metaString = "[General]\n" +
"repository=Steam\n" +
"installed=true\n" +
$"gameName={GameName}\n" +
$"steamID={_steamGame.AppId}\n" +
$"itemID={item.ItemID}\n" +
$"itemSize={item.Size}\n" ;
try
{
File . WriteAllText ( filePath , metaString ) ;
}
catch ( Exception e )
{
Utils . LogToFile ( $"Exception while writing to disk at {filePath}\n{e}" ) ;
}
} ) ;
2019-11-04 16:04:37 +00:00
}
2019-11-03 16:43:43 +00:00
public override IEnumerable < ICompilationStep > GetStack ( )
{
2019-11-14 19:20:08 +00:00
var s = Consts . TestMode ? DownloadsFolder : VortexFolder ;
var userConfig = Path . Combine ( s , "compilation_stack.yml" ) ;
2019-11-03 16:43:43 +00:00
if ( File . Exists ( userConfig ) )
return Serialization . Deserialize ( File . ReadAllText ( userConfig ) , this ) ;
2019-12-01 14:59:08 +00:00
var stack = MakeStack ( ) ;
2019-11-03 16:43:43 +00:00
2019-11-14 19:20:08 +00:00
File . WriteAllText ( Path . Combine ( s , "_current_compilation_stack.yml" ) ,
2019-11-03 16:43:43 +00:00
Serialization . Serialize ( stack ) ) ;
return stack ;
}
public override IEnumerable < ICompilationStep > MakeStack ( )
{
Utils . Log ( "Generating compilation stack" ) ;
return new List < ICompilationStep >
{
2019-11-17 14:30:06 +00:00
new IncludePropertyFiles ( this ) ,
2019-12-02 16:44:24 +00:00
new IncludeSteamWorkshopItems ( this , _steamGame ) ,
_hasSteamWorkshopItems ? new IncludeRegex ( this , "^steamWorkshopItem_\\d*\\.meta$" ) : null ,
2019-11-17 16:26:04 +00:00
new IgnoreDisabledVortexMods ( this ) ,
2019-11-04 12:47:41 +00:00
new IncludeVortexDeployment ( this ) ,
2019-11-11 13:03:48 +00:00
new IgnoreVortex ( this ) ,
2019-12-03 02:38:33 +00:00
new IgnoreRegex ( this , $"^*{StagingMarkerName}$" ) ,
2019-11-09 18:57:29 +00:00
Game = = Game . DarkestDungeon ? new IncludeRegex ( this , "project\\.xml$" ) : null ,
2019-11-17 03:09:46 +00:00
new IgnoreStartsWith ( this , StagingFolder ) ,
new IgnoreEndsWith ( this , StagingFolder ) ,
2019-11-03 16:43:43 +00:00
2019-11-04 12:47:41 +00:00
new IgnoreGameFiles ( this ) ,
2019-11-03 16:43:43 +00:00
new DirectMatch ( this ) ,
new IgnoreGameFiles ( this ) ,
new IgnoreWabbajackInstallCruft ( this ) ,
new DropAll ( this )
} ;
}
2019-11-16 22:10:13 +00:00
public static string TypicalVortexFolder ( )
{
return Path . Combine ( Environment . GetFolderPath ( Environment . SpecialFolder . ApplicationData ) , "Vortex" ) ;
}
2019-11-17 03:09:46 +00:00
public static string RetrieveDownloadLocation ( Game game , string vortexFolderPath = null )
2019-11-16 22:10:13 +00:00
{
vortexFolderPath = vortexFolderPath ? ? TypicalVortexFolder ( ) ;
2019-11-17 03:09:46 +00:00
return Path . Combine ( vortexFolderPath , "downloads" , GameRegistry . Games [ game ] . NexusName ) ;
2019-11-16 22:10:13 +00:00
}
2019-11-17 03:09:46 +00:00
public static string RetrieveStagingLocation ( Game game , string vortexFolderPath = null )
2019-11-16 22:10:13 +00:00
{
2019-11-17 03:09:46 +00:00
vortexFolderPath = vortexFolderPath ? ? TypicalVortexFolder ( ) ;
var gameName = GameRegistry . Games [ game ] . NexusName ;
return Path . Combine ( vortexFolderPath , gameName , "mods" ) ;
2019-11-16 22:10:13 +00:00
}
2019-11-17 03:09:46 +00:00
public static IErrorResponse IsValidBaseDownloadsFolder ( string path )
2019-11-16 22:10:13 +00:00
{
2019-11-17 03:09:46 +00:00
if ( ! Directory . Exists ( path ) ) return ErrorResponse . Fail ( $"Path does not exist: {path}" ) ;
if ( Directory . EnumerateFiles ( path , DownloadMarkerName , SearchOption . TopDirectoryOnly ) . Any ( ) ) return ErrorResponse . Success ;
return ErrorResponse . Fail ( $"Folder must contain {DownloadMarkerName} file" ) ;
2019-11-16 22:10:13 +00:00
}
2019-11-17 03:09:46 +00:00
public static IErrorResponse IsValidDownloadsFolder ( string path )
2019-11-16 22:10:13 +00:00
{
2019-11-17 03:09:46 +00:00
return IsValidBaseDownloadsFolder ( Path . GetDirectoryName ( path ) ) ;
}
public static IErrorResponse IsValidBaseStagingFolder ( string path )
{
if ( ! Directory . Exists ( path ) ) return ErrorResponse . Fail ( $"Path does not exist: {path}" ) ;
if ( Directory . EnumerateFiles ( path , StagingMarkerName , SearchOption . TopDirectoryOnly ) . Any ( ) ) return ErrorResponse . Success ;
return ErrorResponse . Fail ( $"Folder must contain {StagingMarkerName} file" ) ;
}
public static IErrorResponse IsValidStagingFolder ( string path )
{
return IsValidBaseStagingFolder ( Path . GetDirectoryName ( path ) ) ;
2019-11-16 22:10:13 +00:00
}
2019-12-03 02:38:33 +00:00
public static bool IsActiveVortexGame ( Game g )
{
return GameRegistry . Games [ g ] . SupportedModManager = = ModManager . Vortex & & ! GameRegistry . Games [ g ] . Disabled ;
}
2019-11-03 16:43:43 +00:00
}
2019-11-17 16:26:04 +00:00
public class VortexDeployment
{
public string instance ;
public int version ;
public string deploymentMethod ;
public List < VortexFile > files ;
}
public class VortexFile
{
public string relPath ;
public string source ;
public string target ;
}
2019-11-03 16:43:43 +00:00
}