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 ;
2019-12-19 01:14:21 +00:00
using System.Threading.Tasks ;
2019-11-14 05:28:27 +00:00
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
2020-03-28 20:04:22 +00:00
private readonly ObservableAsPropertyHelper < AbsolutePath > _mo2Folder ;
public AbsolutePath 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 ; }
2019-12-14 22:13:31 +00:00
public FilePickerVM ModListLocation { get ; }
2019-11-14 05:28:27 +00:00
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-12-19 01:14:21 +00:00
public IObservable < bool > CanCompile { get ; }
2019-11-14 05:28:27 +00:00
public MO2CompilerVM ( CompilerVM parent )
{
2019-11-24 00:53:04 +00:00
Parent = parent ;
2019-12-14 22:13:31 +00:00
ModListLocation = new FilePickerVM ( )
2019-11-14 05:28:27 +00:00
{
2019-12-14 20:11:39 +00:00
ExistCheckOption = FilePickerVM . CheckOptions . On ,
2019-11-14 05:28:27 +00:00
PathType = FilePickerVM . PathTypeOptions . File ,
2020-01-13 21:11:07 +00:00
PromptTitle = "Select a 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-12-14 20:11:39 +00:00
ExistCheckOption = FilePickerVM . CheckOptions . On ,
2019-11-14 05:28:27 +00:00
PathType = FilePickerVM . PathTypeOptions . Folder ,
2020-01-13 21:11:07 +00:00
PromptTitle = "Select a downloads location" ,
2019-11-24 00:53:04 +00:00
} ;
2019-11-14 05:28:27 +00:00
2019-12-14 22:13:31 +00:00
_mo2Folder = this . WhenAny ( x = > x . ModListLocation . TargetPath )
2019-11-14 05:28:27 +00:00
. Select ( loc = >
{
try
{
2020-03-28 20:04:22 +00:00
var profileFolder = loc . Parent ;
return profileFolder . Parent . Parent ;
2019-11-14 05:28:27 +00:00
}
catch ( Exception )
{
2020-03-28 20:04:22 +00:00
return default ;
2019-11-14 05:28:27 +00:00
}
} )
2020-01-17 04:48:54 +00:00
. ToGuiProperty ( this , nameof ( Mo2Folder ) ) ;
2019-12-14 22:13:31 +00:00
_moProfile = this . WhenAny ( x = > x . ModListLocation . TargetPath )
2019-11-14 05:28:27 +00:00
. Select ( loc = >
{
try
{
2020-03-28 20:04:22 +00:00
return ( string ) loc . Parent . FileName ;
2019-11-14 05:28:27 +00:00
}
catch ( Exception )
{
return null ;
}
} )
2020-01-17 04:48:54 +00:00
. ToGuiProperty ( this , nameof ( MOProfile ) ) ;
2019-11-14 05:28:27 +00:00
2020-01-13 21:11:07 +00:00
// Wire missing Mo2Folder to signal error state for ModList Location
2019-12-14 22:13:31 +00:00
ModListLocation . AdditionalError = this . WhenAny ( x = > x . Mo2Folder )
2020-03-28 20:04:22 +00:00
. Select < AbsolutePath , IErrorResponse > ( moFolder = >
2019-11-14 05:28:27 +00:00
{
2020-03-28 20:04:22 +00:00
if ( moFolder . IsDirectory ) return ErrorResponse . Success ;
2020-01-13 21:11:07 +00:00
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." ) ;
2019-11-14 05:28:27 +00:00
} ) ;
2020-01-13 21:11:07 +00:00
// Load custom ModList settings per MO2 profile
2019-12-14 20:11:39 +00:00
_modlistSettings = Observable . CombineLatest (
2019-12-19 01:14:21 +00:00
( this ) . WhenAny ( x = > x . ModListLocation . ErrorState ) ,
( this ) . WhenAny ( x = > x . ModListLocation . TargetPath ) ,
2019-12-14 20:11:39 +00:00
resultSelector : ( state , path ) = > ( State : state , Path : path ) )
// A short throttle is a quick hack to make the above changes "atomic"
2020-01-17 04:52:29 +00:00
. Throttle ( TimeSpan . FromMilliseconds ( 25 ) , RxApp . MainThreadScheduler )
2019-12-14 20:11:39 +00:00
. Select ( u = >
{
if ( u . State . Failed ) return null ;
var modlistSettings = _settings . ModlistSettings . TryCreate ( u . Path ) ;
return new ModlistSettingsEditorVM ( modlistSettings )
{
ModListName = MOProfile
} ;
} )
// Interject and save old while loading new
. Pairwise ( )
. Do ( pair = >
{
pair . Previous ? . Save ( ) ;
pair . Current ? . Init ( ) ;
} )
. Select ( x = > x . Current )
2020-01-17 04:48:54 +00:00
. ToGuiProperty ( this , nameof ( ModlistSettings ) ) ;
2019-12-14 20:11:39 +00:00
2019-12-19 01:14:21 +00:00
CanCompile = Observable . CombineLatest (
this . WhenAny ( x = > x . ModListLocation . InError ) ,
this . WhenAny ( x = > x . DownloadLocation . InError ) ,
parent . WhenAny ( x = > x . OutputLocation . InError ) ,
this . WhenAny ( x = > x . ModlistSettings )
. Select ( x = > x ? . InError ? ? Observable . Return ( false ) )
. Switch ( ) ,
resultSelector : ( ml , down , output , modlistSettings ) = > ! ml & & ! down & & ! output & & ! modlistSettings )
. Publish ( )
. RefCount ( ) ;
2019-11-14 05:28:27 +00:00
// Load settings
2019-11-21 15:45:00 +00:00
_settings = parent . MWVM . Settings . Compiler . MO2Compilation ;
2019-12-14 22:13:31 +00:00
ModListLocation . TargetPath = _settings . LastCompiledProfileLocation ;
2020-03-28 20:04:22 +00:00
if ( _settings . DownloadLocation ! = default )
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
}
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
2019-11-15 04:54:34 +00:00
// If Mo2 folder changes and download location is empty, set it for convenience
2020-01-16 03:54:06 +00:00
this . WhenAny ( x = > x . Mo2Folder )
2020-01-17 04:52:29 +00:00
. DelayInitial ( TimeSpan . FromMilliseconds ( 100 ) , RxApp . MainThreadScheduler )
2020-03-28 20:04:22 +00:00
. Where ( x = > x . IsDirectory )
2020-01-14 05:17:54 +00:00
. FlowSwitch (
2019-12-19 01:14:21 +00:00
( this ) . WhenAny ( x = > x . DownloadLocation . Exists )
2019-11-15 04:54:34 +00:00
. 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 ;
2019-12-14 22:13:31 +00:00
_settings . LastCompiledProfileLocation = ModListLocation . TargetPath ;
2019-11-21 15:04:33 +00:00
ModlistSettings ? . Save ( ) ;
2019-11-14 05:28:27 +00:00
}
2019-12-19 01:14:21 +00:00
2020-01-26 03:21:41 +00:00
public async Task < GetResponse < ModList > > Compile ( )
2019-12-19 01:14:21 +00:00
{
2020-03-28 20:04:22 +00:00
AbsolutePath outputFile ;
if ( Parent . OutputLocation . TargetPath = = default )
2019-12-19 01:14:21 +00:00
{
2020-03-28 20:04:22 +00:00
outputFile = ( MOProfile + Consts . ModListExtension ) . RelativeTo ( AbsolutePath . EntryPoint ) ;
2019-12-19 01:14:21 +00:00
}
else
{
2020-03-28 20:04:22 +00:00
outputFile = Parent . OutputLocation . TargetPath . Combine ( MOProfile + Consts . ModListExtension ) ;
2019-12-19 01:14:21 +00:00
}
try
{
2020-01-10 04:55:57 +00:00
using ( ActiveCompilation = new MO2Compiler (
2019-12-19 01:14:21 +00:00
mo2Folder : Mo2Folder ,
mo2Profile : MOProfile ,
outputFile : outputFile )
{
ModListName = ModlistSettings . ModListName ,
ModListAuthor = ModlistSettings . AuthorText ,
ModListDescription = ModlistSettings . Description ,
ModListImage = ModlistSettings . ImagePath . TargetPath ,
ModListWebsite = ModlistSettings . Website ,
2020-04-15 17:40:41 +00:00
ModlistReadme = ModlistSettings . Readme ,
2020-01-20 02:05:05 +00:00
MO2DownloadsFolder = DownloadLocation . TargetPath ,
2020-05-05 14:38:06 +00:00
ModlistVersion = ModlistSettings . Version ,
ModlistIsNSFW = ModlistSettings . IsNSFW
2020-01-10 04:55:57 +00:00
} )
{
Parent . MWVM . Settings . Performance . AttachToBatchProcessor ( ActiveCompilation ) ;
2020-01-26 03:21:41 +00:00
var success = await ActiveCompilation . Begin ( ) ;
return GetResponse < ModList > . Create ( success , ActiveCompilation . ModList ) ;
2020-01-10 04:55:57 +00:00
}
2019-12-19 01:14:21 +00:00
}
finally
{
StatusTracker = null ;
ActiveCompilation = null ;
}
}
2019-11-14 05:28:27 +00:00
}
}