2019-11-24 00:53:04 +00:00
using Microsoft.WindowsAPICodePack.Dialogs ;
using ReactiveUI ;
2019-11-14 05:28:27 +00:00
using ReactiveUI.Fody.Helpers ;
using System ;
using System.IO ;
using System.Linq ;
using System.Reactive.Disposables ;
using System.Reactive.Linq ;
using Wabbajack.Common ;
using Wabbajack.Lib ;
namespace Wabbajack
{
public class MO2CompilerVM : ViewModel , ISubCompilerVM
{
2019-11-24 00:53:04 +00:00
public CompilerVM Parent { get ; }
2019-11-21 15:45:00 +00:00
private readonly MO2CompilationSettings _settings ;
2019-11-16 23:09:13 +00:00
2019-11-21 15:45:00 +00:00
private readonly ObservableAsPropertyHelper < string > _mo2Folder ;
public string Mo2Folder = > _mo2Folder . Value ;
2019-11-14 05:28:27 +00:00
2019-11-21 15:45:00 +00:00
private readonly ObservableAsPropertyHelper < string > _moProfile ;
public string MOProfile = > _moProfile . Value ;
2019-11-14 05:28:27 +00:00
public FilePickerVM DownloadLocation { get ; }
public FilePickerVM ModlistLocation { get ; }
2019-11-24 00:53:04 +00:00
public FilePickerVM OutputLocation { get ; }
2019-11-14 05:28:27 +00:00
public IReactiveCommand BeginCommand { get ; }
2019-11-21 05:15:47 +00:00
[Reactive]
public ACompiler ActiveCompilation { get ; private set ; }
2019-11-14 05:28:27 +00:00
2019-11-21 15:45:00 +00:00
private readonly ObservableAsPropertyHelper < ModlistSettingsEditorVM > _modlistSettings ;
public ModlistSettingsEditorVM ModlistSettings = > _modlistSettings . Value ;
2019-11-14 05:28:27 +00:00
2019-11-17 07:59:00 +00:00
[Reactive]
public StatusUpdateTracker StatusTracker { get ; private set ; }
2019-11-14 05:28:27 +00:00
public MO2CompilerVM ( CompilerVM parent )
{
2019-11-24 00:53:04 +00:00
Parent = parent ;
2019-11-21 15:04:33 +00:00
ModlistLocation = new FilePickerVM ( )
2019-11-14 05:28:27 +00:00
{
2019-11-17 07:04:53 +00:00
ExistCheckOption = FilePickerVM . ExistCheckOptions . On ,
2019-11-14 05:28:27 +00:00
PathType = FilePickerVM . PathTypeOptions . File ,
2019-11-24 00:53:04 +00:00
PromptTitle = "Select modlist"
2019-11-14 05:28:27 +00:00
} ;
2019-11-21 15:04:33 +00:00
DownloadLocation = new FilePickerVM ( )
2019-11-14 05:28:27 +00:00
{
2019-11-17 07:04:53 +00:00
ExistCheckOption = FilePickerVM . ExistCheckOptions . On ,
2019-11-14 05:28:27 +00:00
PathType = FilePickerVM . PathTypeOptions . Folder ,
2019-11-24 00:53:04 +00:00
PromptTitle = "Select download location" ,
} ;
OutputLocation = new FilePickerVM ( )
{
ExistCheckOption = FilePickerVM . ExistCheckOptions . IfNotEmpty ,
PathType = FilePickerVM . PathTypeOptions . Folder ,
PromptTitle = "Select the folder to place the resulting modlist.wabbajack file" ,
2019-11-14 05:28:27 +00:00
} ;
2019-11-21 15:45:00 +00:00
_mo2Folder = this . WhenAny ( x = > x . ModlistLocation . TargetPath )
2019-11-14 05:28:27 +00:00
. Select ( loc = >
{
try
{
2019-11-21 15:45:00 +00:00
var profileFolder = Path . GetDirectoryName ( loc ) ;
return Path . GetDirectoryName ( Path . GetDirectoryName ( profileFolder ) ) ;
2019-11-14 05:28:27 +00:00
}
catch ( Exception )
{
return null ;
}
} )
2019-11-21 15:04:33 +00:00
. ToProperty ( this , nameof ( Mo2Folder ) ) ;
2019-11-21 15:45:00 +00:00
_moProfile = this . WhenAny ( x = > x . ModlistLocation . TargetPath )
2019-11-14 05:28:27 +00:00
. Select ( loc = >
{
try
{
2019-11-21 15:45:00 +00:00
var profileFolder = Path . GetDirectoryName ( loc ) ;
return Path . GetFileName ( profileFolder ) ;
2019-11-14 05:28:27 +00:00
}
catch ( Exception )
{
return null ;
}
} )
2019-11-21 15:04:33 +00:00
. ToProperty ( this , nameof ( MOProfile ) ) ;
2019-11-14 05:28:27 +00:00
// Wire missing Mo2Folder to signal error state for Modlist Location
2019-11-21 15:04:33 +00:00
ModlistLocation . AdditionalError = this . WhenAny ( x = > x . Mo2Folder )
2019-11-14 05:28:27 +00:00
. Select < string , IErrorResponse > ( moFolder = >
{
if ( Directory . Exists ( moFolder ) ) return ErrorResponse . Success ;
return ErrorResponse . Fail ( $"MO2 Folder could not be located from the given modlist location.{Environment.NewLine}Make sure your modlist is inside a valid MO2 distribution." ) ;
} ) ;
// Wire start command
2019-11-21 15:04:33 +00:00
BeginCommand = ReactiveCommand . CreateFromTask (
2019-11-14 05:28:27 +00:00
canExecute : Observable . CombineLatest (
this . WhenAny ( x = > x . ModlistLocation . InError ) ,
this . WhenAny ( x = > x . DownloadLocation . InError ) ,
2019-11-24 00:53:04 +00:00
this . WhenAny ( x = > x . OutputLocation . InError ) ,
resultSelector : ( ml , down , output ) = > ! ml & & ! down & & ! output )
2019-11-14 05:28:27 +00:00
. ObserveOnGuiThread ( ) ,
execute : async ( ) = >
{
try
{
2019-11-24 00:53:04 +00:00
string outputFile ;
if ( string . IsNullOrWhiteSpace ( OutputLocation . TargetPath ) )
{
outputFile = MOProfile + ExtensionManager . Extension ;
}
else
{
outputFile = Path . Combine ( OutputLocation . TargetPath , MOProfile + ExtensionManager . Extension ) ;
}
2019-11-24 00:30:51 +00:00
ActiveCompilation = new MO2Compiler (
mo2Folder : Mo2Folder ,
mo2Profile : MOProfile ,
2019-11-24 00:53:04 +00:00
outputFile : outputFile )
2019-11-14 05:28:27 +00:00
{
2019-11-21 15:04:33 +00:00
ModListName = ModlistSettings . ModListName ,
ModListAuthor = ModlistSettings . AuthorText ,
ModListDescription = ModlistSettings . Description ,
ModListImage = ModlistSettings . ImagePath . TargetPath ,
ModListWebsite = ModlistSettings . Website ,
ModListReadme = ModlistSettings . ReadMeText . TargetPath ,
2019-11-14 05:28:27 +00:00
} ;
}
catch ( Exception ex )
{
while ( ex . InnerException ! = null ) ex = ex . InnerException ;
Utils . Log ( $"Compiler error: {ex.ExceptionToString()}" ) ;
return ;
}
2019-11-18 00:17:06 +00:00
try
2019-11-14 05:28:27 +00:00
{
2019-11-21 15:04:33 +00:00
await ActiveCompilation . Begin ( ) ;
2019-11-18 00:17:06 +00:00
}
catch ( Exception ex )
{
while ( ex . InnerException ! = null ) ex = ex . InnerException ;
Utils . Log ( $"Compiler error: {ex.ExceptionToString()}" ) ;
}
finally
{
2019-11-21 15:04:33 +00:00
StatusTracker = null ;
ActiveCompilation . Dispose ( ) ;
ActiveCompilation = null ;
2019-11-18 00:17:06 +00:00
}
2019-11-14 05:28:27 +00:00
} ) ;
// Load settings
2019-11-21 15:45:00 +00:00
_settings = parent . MWVM . Settings . Compiler . MO2Compilation ;
ModlistLocation . TargetPath = _settings . LastCompiledProfileLocation ;
if ( ! string . IsNullOrWhiteSpace ( _settings . DownloadLocation ) )
2019-11-14 05:28:27 +00:00
{
2019-11-21 15:45:00 +00:00
DownloadLocation . TargetPath = _settings . DownloadLocation ;
2019-11-14 05:28:27 +00:00
}
2019-11-24 00:53:04 +00:00
OutputLocation . TargetPath = parent . MWVM . Settings . Compiler . OutputLocation ;
2019-11-14 05:28:27 +00:00
parent . MWVM . Settings . SaveSignal
2019-11-16 23:09:13 +00:00
. Subscribe ( _ = > Unload ( ) )
2019-11-21 15:04:33 +00:00
. DisposeWith ( CompositeDisposable ) ;
2019-11-14 05:28:27 +00:00
// Load custom modlist settings per MO2 profile
2019-11-21 15:45:00 +00:00
_modlistSettings = Observable . CombineLatest (
2019-11-14 05:28:27 +00:00
this . WhenAny ( x = > x . ModlistLocation . ErrorState ) ,
this . WhenAny ( x = > x . ModlistLocation . TargetPath ) ,
2019-11-21 15:45:00 +00:00
resultSelector : ( state , path ) = > ( State : state , Path : path ) )
2019-11-14 05:28:27 +00:00
// A short throttle is a quick hack to make the above changes "atomic"
. Throttle ( TimeSpan . FromMilliseconds ( 25 ) )
. Select ( u = >
{
if ( u . State . Failed ) return null ;
2019-11-21 15:45:00 +00:00
var modlistSettings = _settings . ModlistSettings . TryCreate ( u . Path ) ;
2019-11-16 22:33:32 +00:00
return new ModlistSettingsEditorVM ( modlistSettings )
{
2019-11-21 15:04:33 +00:00
ModListName = MOProfile
2019-11-16 22:33:32 +00:00
} ;
2019-11-14 05:28:27 +00:00
} )
// Interject and save old while loading new
. Pairwise ( )
. Do ( pair = >
{
pair . Previous ? . Save ( ) ;
pair . Current ? . Init ( ) ;
} )
. Select ( x = > x . Current )
// Save to property
. ObserveOnGuiThread ( )
2019-11-21 15:04:33 +00:00
. ToProperty ( this , nameof ( ModlistSettings ) ) ;
2019-11-15 04:54:34 +00:00
// If Mo2 folder changes and download location is empty, set it for convenience
this . WhenAny ( x = > x . Mo2Folder )
. DelayInitial ( TimeSpan . FromMilliseconds ( 100 ) )
. Where ( x = > Directory . Exists ( x ) )
. FilterSwitch (
this . WhenAny ( x = > x . DownloadLocation . Exists )
. Invert ( ) )
2019-11-24 00:40:18 +00:00
// A skip is needed to ignore the initial signal when the FilterSwitch turns on
. Skip ( 1 )
2019-11-24 00:36:57 +00:00
. Subscribe ( _ = >
2019-11-15 04:54:34 +00:00
{
2019-11-24 00:36:57 +00:00
DownloadLocation . TargetPath = MO2Compiler . GetTypicalDownloadsFolder ( Mo2Folder ) ;
2019-11-15 04:54:34 +00:00
} )
2019-11-21 15:04:33 +00:00
. DisposeWith ( CompositeDisposable ) ;
2019-11-16 23:09:13 +00:00
}
2019-11-15 04:54:34 +00:00
2019-11-16 23:09:13 +00:00
public void Unload ( )
{
2019-11-21 15:45:00 +00:00
_settings . DownloadLocation = DownloadLocation . TargetPath ;
_settings . LastCompiledProfileLocation = ModlistLocation . TargetPath ;
2019-11-24 00:53:04 +00:00
Parent . MWVM . Settings . Compiler . OutputLocation = OutputLocation . TargetPath ;
2019-11-21 15:04:33 +00:00
ModlistSettings ? . Save ( ) ;
2019-11-14 05:28:27 +00:00
}
}
}