public UserInterventionHandlers(MainWindowVM mvm)
 {
     MainWindow = mvm;
 }
Пример #2
0
        public MainWindow()
        {
            try
            {
                // Wire any unhandled crashing exceptions to log before exiting
                AppDomain.CurrentDomain.UnhandledException += (sender, e) =>
                {
                    // Don't do any special logging side effects
                    Utils.LogStraightToFile("Error.");
                    Utils.LogStraightToFile(((Exception)e.ExceptionObject).ToString());
                    Environment.Exit(-1);
                };

                Utils.Log($"Wabbajack Build - {ThisAssembly.Git.Sha}");
                Utils.Log($"Running in {AbsolutePath.EntryPoint}");

                var p = SystemParametersConstructor.Create();

                Utils.Log($"Detected Windows Version: {p.WindowsVersion}");

                if (!(p.WindowsVersion.Major >= 10 && p.WindowsVersion.Minor >= 0))
                {
                    Utils.Log(
                        $"You are not running a recent version of Windows (version 10 or greater), Wabbajack is not supported on OS versions older than Windows 10.");
                }

                Utils.Log(
                    $"System settings - ({p.SystemMemorySize.ToFileSizeString()} RAM) ({p.SystemPageSize.ToFileSizeString()} Page), Display: {p.ScreenWidth} x {p.ScreenHeight} ({p.VideoMemorySize.ToFileSizeString()} VRAM - VideoMemorySizeMb={p.EnbLEVRAMSize})");

                if (p.SystemPageSize == 0)
                {
                    Utils.Log("Pagefile is disabled! Consider increasing to 20000MB. A disabled pagefile can cause crashes and poor in-game performance.");
                }
                else if (p.SystemPageSize < 2e+10)
                {
                    Utils.Log("Pagefile below recommended! Consider increasing to 20000MB. A suboptimal pagefile can cause crashes and poor in-game performance.");
                }

                Warmup();

                var _ = LauncherUpdater.Run();

                var(settings, loadedSettings) = MainSettings.TryLoadTypicalSettings().AsTask().Result;
                // Load settings
                if (CLIArguments.NoSettings || !loadedSettings)
                {
                    _settings = new MainSettings {
                        Version = Consts.SettingsVersion
                    };
                    RunWhenLoaded(DefaultSettings);
                }
                else
                {
                    _settings = settings;
                    RunWhenLoaded(LoadSettings);
                }

                // Set datacontext
                _mwvm       = new MainWindowVM(this, _settings);
                DataContext = _mwvm;

                // Bring window to the front if it isn't already
                this.Initialized += (s, e) =>
                {
                    this.Activate();
                    this.Topmost = true;
                    this.Focus();
                };
                this.ContentRendered += (s, e) =>
                {
                    this.Topmost = false;
                };
            }
            catch (Exception ex)
            {
                Utils.LogStraightToFile("Error");
                Utils.LogStraightToFile(ex.ToString());
                Environment.Exit(-1);
            }
        }
Пример #3
0
        public ModListGalleryVM(MainWindowVM mainWindowVM)
            : base(mainWindowVM)
        {
            MWVM = mainWindowVM;

            // load persistent filter settings
            if (settings.IsPersistent)
            {
                GameType         = !string.IsNullOrEmpty(settings.Game) ? settings.Game : ALL_GAME_TYPE;
                ShowNSFW         = settings.ShowNSFW;
                ShowUtilityLists = settings.ShowUtilityLists;
                OnlyInstalled    = settings.OnlyInstalled;
                Search           = settings.Search;
            }
            else
            {
                GameType = ALL_GAME_TYPE;
            }

            // subscribe to save signal
            MWVM.Settings.SaveSignal
            .Subscribe(_ => UpdateFiltersSettings())
            .DisposeWith(this.CompositeDisposable);

            ClearFiltersCommand = ReactiveCommand.Create(
                () =>
            {
                OnlyInstalled    = false;
                ShowNSFW         = false;
                ShowUtilityLists = false;
                Search           = string.Empty;
                GameType         = ALL_GAME_TYPE;
            });


            this.WhenAny(x => x.OnlyInstalled)
            .Subscribe(val =>
            {
                if (val)
                {
                    GameType = ALL_GAME_TYPE;
                }
            })
            .DisposeWith(CompositeDisposable);

            var sourceList = Observable.Return(Unit.Default)
                             .ObserveOn(RxApp.TaskpoolScheduler)
                             .SelectTask(async _ =>
            {
                try
                {
                    Error    = null;
                    var list = await ModlistMetadata.LoadFromGithub();
                    Error    = ErrorResponse.Success;
                    return(list
                           .AsObservableChangeSet(x => x.DownloadMetadata?.Hash ?? Hash.Empty));
                }
                catch (Exception ex)
                {
                    Utils.Error(ex);
                    Error = ErrorResponse.Fail(ex);
                    return(Observable.Empty <IChangeSet <ModlistMetadata, Hash> >());
                }
            })
                             // Unsubscribe and release when not active
                             .FlowSwitch(
                this.WhenAny(x => x.IsActive),
                valueWhenOff: Observable.Return(ChangeSet <ModlistMetadata, Hash> .Empty))
                             .Switch()
                             .RefCount();

            _Loaded = sourceList.CollectionCount()
                      .Select(c => c > 0)
                      .ToProperty(this, nameof(Loaded));

            // Convert to VM and bind to resulting list
            sourceList
            .ObserveOnGuiThread()
            .Transform(m => new ModListMetadataVM(this, m))
            .DisposeMany()
            // Filter only installed
            .Filter(this.WhenAny(x => x.OnlyInstalled)
                    .Select <bool, Func <ModListMetadataVM, bool> >(onlyInstalled => (vm) =>
            {
                if (!onlyInstalled)
                {
                    return(true);
                }
                if (!GameRegistry.Games.TryGetValue(vm.Metadata.Game, out var gameMeta))
                {
                    return(false);
                }
                return(gameMeta.IsInstalled);
            }))
            // Filter on search box
            .Filter(this.WhenAny(x => x.Search)
                    .Debounce(TimeSpan.FromMilliseconds(150), RxApp.MainThreadScheduler)
                    .Select <string, Func <ModListMetadataVM, bool> >(search => (vm) =>
            {
                if (string.IsNullOrWhiteSpace(search))
                {
                    return(true);
                }
                return(vm.Metadata.Title.ContainsCaseInsensitive(search));
            }))
            .Filter(this.WhenAny(x => x.ShowNSFW)
                    .Select <bool, Func <ModListMetadataVM, bool> >(showNSFW => vm =>
            {
                if (!vm.Metadata.NSFW)
                {
                    return(true);
                }
                return(vm.Metadata.NSFW && showNSFW);
            }))
            .Filter(this.WhenAny(x => x.ShowUtilityLists)
                    .Select <bool, Func <ModListMetadataVM, bool> >(showUtilityLists => vm => showUtilityLists ? vm.Metadata.UtilityList : !vm.Metadata.UtilityList))
            // Filter by Game
            .Filter(this.WhenAny(x => x.GameType)
                    .Debounce(TimeSpan.FromMilliseconds(150), RxApp.MainThreadScheduler)
                    .Select <string, Func <ModListMetadataVM, bool> >(GameType => (vm) =>
            {
                if (GameType == ALL_GAME_TYPE)
                {
                    return(true);
                }
                if (string.IsNullOrEmpty(GameType))
                {
                    return(false);
                }

                return(GameType == vm.Metadata.Game.GetDescription <Game>().ToString());
            }))
            .Bind(ModLists)
            .Subscribe()
            .DisposeWith(CompositeDisposable);

            // Extra GC when navigating away, just to immediately clean up modlist metadata
            this.WhenAny(x => x.IsActive)
            .Where(x => !x)
            .Skip(1)
            .Delay(TimeSpan.FromMilliseconds(50), RxApp.MainThreadScheduler)
            .Subscribe(_ =>
            {
                GC.Collect();
            })
            .DisposeWith(CompositeDisposable);
        }
Пример #4
0
 public void Init(MainWindowVM vm, MainSettings settings)
 {
     DataContext = vm;
     _mwvm       = vm;
     _settings   = settings;
 }
Пример #5
0
        public CompilerVM(MainWindowVM mainWindowVM)
        {
            MWVM = mainWindowVM;

            OutputLocation = new FilePickerVM()
            {
                ExistCheckOption = FilePickerVM.CheckOptions.IfPathNotEmpty,
                PathType         = FilePickerVM.PathTypeOptions.Folder,
                PromptTitle      = "Select the folder to place the resulting modlist.wabbajack file",
            };

            // Load settings
            CompilerSettings settings = MWVM.Settings.Compiler;

            SelectedCompilerType      = settings.LastCompiledModManager;
            OutputLocation.TargetPath = settings.OutputLocation;
            MWVM.Settings.SaveSignal
            .Subscribe(_ =>
            {
                settings.LastCompiledModManager = SelectedCompilerType;
                settings.OutputLocation         = OutputLocation.TargetPath;
            })
            .DisposeWith(CompositeDisposable);

            // Swap to proper sub VM based on selected type
            _compiler = this.WhenAny(x => x.SelectedCompilerType)
                        // Delay so the initial VM swap comes in immediately, subVM comes right after
                        .DelayInitial(TimeSpan.FromMilliseconds(50), RxApp.MainThreadScheduler)
                        .Select <ModManager, ISubCompilerVM>(type =>
            {
                switch (type)
                {
                case ModManager.MO2:
                    return(new MO2CompilerVM(this));

                case ModManager.Vortex:
                    return(new VortexCompilerVM(this));

                default:
                    return(null);
                }
            })
                        // Unload old VM
                        .Pairwise()
                        .Do(pair =>
            {
                pair.Previous?.Unload();
            })
                        .Select(p => p.Current)
                        .ToProperty(this, nameof(Compiler));

            // Let sub VM determine what settings we're displaying and when
            _currentModlistSettings = this.WhenAny(x => x.Compiler.ModlistSettings)
                                      .ToProperty(this, nameof(CurrentModlistSettings));

            _image = this.WhenAny(x => x.CurrentModlistSettings.ImagePath.TargetPath)
                     // Throttle so that it only loads image after any sets of swaps have completed
                     .Throttle(TimeSpan.FromMilliseconds(50), RxApp.MainThreadScheduler)
                     .DistinctUntilChanged()
                     .Select(path =>
            {
                if (string.IsNullOrWhiteSpace(path))
                {
                    return(UIUtils.BitmapImageFromResource("Resources/Wabba_Mouth_No_Text.png"));
                }
                if (UIUtils.TryGetBitmapImageFromFile(path, out var image))
                {
                    return(image);
                }
                return(null);
            })
                     .ToProperty(this, nameof(Image));

            _compiling = this.WhenAny(x => x.Compiler.ActiveCompilation)
                         .Select(compilation => compilation != null)
                         .ObserveOnGuiThread()
                         .ToProperty(this, nameof(Compiling));

            BackCommand = ReactiveCommand.Create(
                execute: () =>
            {
                mainWindowVM.ActivePane = mainWindowVM.ModeSelectionVM;
                StartedCompilation      = false;
                Completed = null;
            },
                canExecute: this.WhenAny(x => x.Compiling)
                .Select(x => !x));

            // Compile progress updates and populate ObservableCollection
            Dictionary <int, CPUDisplayVM> cpuDisplays = new Dictionary <int, CPUDisplayVM>();

            this.WhenAny(x => x.Compiler.ActiveCompilation)
            .SelectMany(c => c?.QueueStatus ?? Observable.Empty <CPUStatus>())
            .ObserveOn(RxApp.TaskpoolScheduler)
            // Attach start times to incoming CPU items
            .Scan(
                new CPUDisplayVM(),
                (_, cpu) =>
            {
                var ret = cpuDisplays.TryCreate(cpu.ID);
                ret.AbsorbStatus(cpu);
                return(ret);
            })
            .ToObservableChangeSet(x => x.Status.ID)
            .Batch(TimeSpan.FromMilliseconds(250), RxApp.TaskpoolScheduler)
            .EnsureUniqueChanges()
            .Filter(i => i.Status.IsWorking && i.Status.ID != WorkQueue.UnassignedCpuId)
            .ObserveOn(RxApp.MainThreadScheduler)
            .Sort(SortExpressionComparer <CPUDisplayVM> .Ascending(s => s.StartTime))
            .Bind(StatusList)
            .Subscribe()
            .DisposeWith(CompositeDisposable);

            _percentCompleted = this.WhenAny(x => x.Compiler.ActiveCompilation)
                                .StartWith(default(ACompiler))
                                .CombineLatest(
                this.WhenAny(x => x.Completed),
                (compiler, completed) =>
            {
                if (compiler == null)
                {
                    return(Observable.Return <float>(completed != null ? 1f : 0f));
                }
                return(compiler.PercentCompleted.StartWith(0));
            })
                                .Switch()
                                .Debounce(TimeSpan.FromMilliseconds(25))
                                .ToProperty(this, nameof(PercentCompleted));

            BeginCommand = ReactiveCommand.CreateFromTask(
                canExecute: this.WhenAny(x => x.Compiler.CanCompile)
                .Switch(),
                execute: async() =>
            {
                try
                {
                    await this.Compiler.Compile();
                    Completed = ErrorResponse.Success;
                }
                catch (Exception ex)
                {
                    Completed = ErrorResponse.Fail(ex);
                    while (ex.InnerException != null)
                    {
                        ex = ex.InnerException;
                    }
                    Utils.Error(ex, $"Compiler error");
                }
            });

            // When sub compiler begins a compile, mark state variable
            BeginCommand.StartingExecution()
            .Subscribe(_ =>
            {
                StartedCompilation = true;
            })
            .DisposeWith(CompositeDisposable);

            // Listen for user interventions, and compile a dynamic list of all unhandled ones
            var activeInterventions = this.WhenAny(x => x.Compiler.ActiveCompilation)
                                      .SelectMany(c => c?.LogMessages ?? Observable.Empty <IStatusMessage>())
                                      .WhereCastable <IStatusMessage, IUserIntervention>()
                                      .ToObservableChangeSet()
                                      .AutoRefresh(i => i.Handled)
                                      .Filter(i => !i.Handled)
                                      .AsObservableList();

            // Find the top intervention /w no CPU ID to be marked as "global"
            _ActiveGlobalUserIntervention = activeInterventions.Connect()
                                            .Filter(x => x.CpuID == WorkQueue.UnassignedCpuId)
                                            .QueryWhenChanged(query => query.FirstOrDefault())
                                            .ObserveOnGuiThread()
                                            .ToProperty(this, nameof(ActiveGlobalUserIntervention));

            CloseWhenCompleteCommand = ReactiveCommand.Create(
                canExecute: this.WhenAny(x => x.Completed)
                .Select(x => x != null),
                execute: () =>
            {
                MWVM.ShutdownApplication();
            });

            GoToModlistCommand = ReactiveCommand.Create(
                canExecute: this.WhenAny(x => x.Completed)
                .Select(x => x != null),
                execute: () =>
            {
                if (string.IsNullOrWhiteSpace(OutputLocation.TargetPath))
                {
                    Process.Start("explorer.exe", Path.GetDirectoryName(System.Reflection.Assembly.GetEntryAssembly().Location));
                }
                else
                {
                    Process.Start("explorer.exe", OutputLocation.TargetPath);
                }
            });
        }