Exemple #1
0
        public AllModsMissingErrorVm(
            IProfileDataFolderVm dataFolderVm,
            OpenProfileSettings openProfileSettings,
            IImplicitListingModKeyProvider implicitListingsProvider,
            IProfileLoadOrder profileLoadOrder)
        {
            var nonImplicit = profileLoadOrder.LoadOrder.Connect()
                              .Filter(x => !implicitListingsProvider.Listings.Contains(x.ModKey))
                              .ObserveOn(RxApp.MainThreadScheduler)
                              .AsObservableList();

            _InError = nonImplicit.CountChanged
                       .Select(x => x > 0)
                       .CombineLatest(
                nonImplicit.Connect()
                .FilterOnObservable(i => i.WhenAnyValue(x => x.Exists))
                .QueryWhenChanged(q => q.Count > 0),
                (hasAny, anyExist) => hasAny && !anyExist)
                       .ToGuiProperty(this, nameof(InError), deferSubscription: true);

            _ErrorString = nonImplicit.CountChanged
                           .Select(count =>
            {
                return($"Load order listed {count} mods, but none were found in the game's data folder");
            })
                           .ToGuiProperty(this, nameof(ErrorString), default(string?), deferSubscription: true);

            _DataFolderPath = dataFolderVm.WhenAnyValue(x => x.Path)
                              .Select(x => x.Path)
                              .ToGuiProperty(this, nameof(DataFolderPath), string.Empty, deferSubscription: true);

            GoToProfileSettingsCommand = openProfileSettings.OpenCommand;
        }
Exemple #2
0
 public MissingMods(
     IProfileLoadOrder loadOrder,
     IPatcherConfigurationWatcher configurationWatcher)
 {
     Missing = configurationWatcher.Customization
               .Select(conf =>
     {
         if (conf == null)
         {
             return(Enumerable.Empty <ModKey>());
         }
         return(conf.RequiredMods
                .SelectWhere(x => TryGet <ModKey> .Create(ModKey.TryFromNameAndExtension(x, out var modKey), modKey)));
     })
               .Select(x => x.AsObservableChangeSet())
               .Switch()
               .Except(loadOrder.LoadOrder.Connect()
                       .Transform(x => x.ModKey))
               .RefCount();
 }
Exemple #3
0
 public ProfileSimpleLinkCacheVm(
     ILogger logger,
     IProfileLoadOrder loadOrder,
     IProfileDataFolderVm dataFolder,
     IProfileIdentifier ident)
 {
     _simpleLinkCache = Observable.CombineLatest(
         dataFolder.WhenAnyValue(x => x.Path),
         loadOrder.LoadOrder.Connect()
         .QueryWhenChanged()
         .Select(q => q.Where(x => x.Enabled).Select(x => x.ModKey).ToArray())
         .StartWithEmpty(),
         (dataFolder, loadOrder) => (dataFolder, loadOrder))
                        .Throttle(TimeSpan.FromMilliseconds(100), RxApp.TaskpoolScheduler)
                        .Select(x =>
     {
         return(Observable.Create <(ILinkCache?Cache, IDisposable Disposable)>(obs =>
         {
             try
             {
                 var loadOrder = Mutagen.Bethesda.Plugins.Order.LoadOrder.Import(
                     x.dataFolder,
                     x.loadOrder,
                     factory: (modPath) => ModInstantiator.Importer(modPath, ident.Release));
                 obs.OnNext(
                     (loadOrder.ToUntypedImmutableLinkCache(LinkCachePreferences.OnlyIdentifiers()),
                      loadOrder));
                 obs.OnCompleted();
                 // ToDo
                 // Figure out why returning this is disposing too early.
                 // Gets disposed undesirably, which makes formlink pickers fail
                 // return loadOrder;
             }
             catch (Exception ex)
             {
                 logger.Error(ex, "Error creating simple link cache for GUI lookups");
                 obs.OnNext((default, Disposable.Empty));
Exemple #4
0
        public PatcherUserSettingsVm(
            ILogger logger,
            IProfileLoadOrder loadOrder,
            IProfileSimpleLinkCacheVm linkCacheVm,
            IObservable <Inputs> source,
            bool needBuild,
            IInitRepository initRepository,
            IProvideAutogeneratedSettings autoGenSettingsProvider,
            IProvideRepositoryCheckouts repoCheckouts,
            IGetSettingsStyle getSettingsStyle,
            IExecuteOpenForSettings executeOpenForSettings,
            IOpenSettingsHost openSettingsHost)
        {
            _logger                = logger;
            _initRepository        = initRepository;
            _repoCheckouts         = repoCheckouts;
            _settingsConfiguration = source
                                     .Select(i =>
            {
                return(Observable.Create <SettingsConfiguration>(async(observer, cancel) =>
                {
                    observer.OnNext(new SettingsConfiguration(SettingsStyle.None, Array.Empty <ReflectionSettingsConfig
                                                                                               >()));
                    if (i.ProjPath.Failed)
                    {
                        return;
                    }

                    try
                    {
                        var result = await getSettingsStyle.Get(
                            i.ProjPath.Value,
                            directExe: false,
                            cancel: cancel,
                            buildMetaPath: i.MetaPath,
                            build: needBuild).ConfigureAwait(false);
                        logger.Information($"Settings type: {result}");
                        observer.OnNext(result);
                    }
                    catch (Exception ex)
                    {
                        logger.Error($"Error checking if patcher can open settings: {ex}");
                    }
                    observer.OnCompleted();
                }));
            })
                                     .Switch()
                                     .ToGuiProperty(this, nameof(SettingsConfiguration), new SettingsConfiguration(SettingsStyle.None, Array.Empty <ReflectionSettingsConfig>()), deferSubscription: true);

            OpenSettingsCommand = NoggogCommand.CreateFromObject(
                objectSource: Observable.CombineLatest(
                    source.Select(x => x.ProjPath),
                    this.WhenAnyValue(x => x.SettingsConfiguration),
                    (Proj, Conf) => (Proj, Conf)),
                canExecute: x => x.Proj.Succeeded &&
                (x.Conf.Style == SettingsStyle.Open || x.Conf.Style == SettingsStyle.Host),
                execute: async(o) =>
            {
                if (o.Conf.Style == SettingsStyle.Open)
                {
                    await executeOpenForSettings.Open(
                        o.Proj.Value,
                        directExe: false,
                        cancel: CancellationToken.None,
                        loadOrder: loadOrder.LoadOrder.Items.Select <ReadOnlyModListingVM, IModListingGetter>(lvm => lvm)).ConfigureAwait(false);
                }
                else
                {
                    await openSettingsHost.Open(
                        path: o.Proj.Value,
                        cancel: CancellationToken.None,
                        loadOrder: loadOrder.LoadOrder.Items.Select <ReadOnlyModListingVM, IModListingGetter>(lvm => lvm)).ConfigureAwait(false);
                }
            },
                disposable: this);

            _settingsOpen = OpenSettingsCommand.IsExecuting
                            .ToGuiProperty(this, nameof(SettingsOpen), deferSubscription: true);

            _reflectionSettings = Observable.CombineLatest(
                this.WhenAnyValue(x => x.SettingsConfiguration),
                source.Select(x => x.ProjPath),
                (SettingsConfig, ProjPath) => (SettingsConfig, ProjPath))
                                  .Select(x =>
            {
                if (x.ProjPath.Failed ||
                    x.SettingsConfig.Style != SettingsStyle.SpecifiedClass ||
                    x.SettingsConfig.Targets.Length == 0)
                {
                    return(default(AutogeneratedSettingsVm?));
                }
                return(autoGenSettingsProvider.Get(x.SettingsConfig,
                                                   projPath: x.ProjPath.Value,
                                                   loadOrder: loadOrder.LoadOrder.Connect().Transform <ReadOnlyModListingVM, IModListingGetter>(x => x),
                                                   linkCache: linkCacheVm.WhenAnyValue(x => x.SimpleLinkCache)));
            })
                                  .ToGuiProperty <AutogeneratedSettingsVm?>(this, nameof(ReflectionSettings), initialValue: null, deferSubscription: true);
        }
Exemple #5
0
        public ProfileVm(
            ILifetimeScope scope,
            IPatcherInitializationVm initVm,
            IProfileDataFolderVm dataFolder,
            IProfileIdentifier ident,
            IProfileNameVm nameProvider,
            IProfileLoadOrder loadOrder,
            IProfileDirectories dirs,
            IProfileVersioning versioning,
            IProfileDisplayControllerVm profileDisplay,
            ILockToCurrentVersioning lockSetting,
            ISelectedProfileControllerVm selProfile,
            IProfileExporter exporter,
            IProfileGroupsList groupsList,
            IEnvironmentErrorsVm environmentErrors,
            OverallErrorVm overallErrorVm,
            StartRun startRun,
            ILogger logger)
        {
            Scope              = scope;
            Init               = initVm;
            OverallErrorVm     = overallErrorVm;
            NameVm             = nameProvider;
            Groups             = groupsList.Groups;
            DataFolderOverride = dataFolder;
            Versioning         = versioning;
            LockSetting        = lockSetting;
            Exporter           = exporter;
            DisplayController  = profileDisplay;
            _startRun          = startRun;
            _logger            = logger;
            ID      = ident.ID;
            Release = ident.Release;

            GroupsDisplay = new SourceListUiFunnel <GroupVm>(Groups, this);

            ProfileDirectory = dirs.ProfileDirectory;
            WorkingDirectory = dirs.WorkingDirectory;

            EnvironmentErrors = environmentErrors;

            _dataFolder = dataFolder.WhenAnyValue(x => x.Path)
                          .ToGuiProperty <DirectoryPath>(this, nameof(DataFolder), string.Empty, deferSubscription: true);

            LoadOrder = loadOrder.LoadOrder;

            var enabledGroups = Groups.Connect()
                                .ObserveOnGui()
                                .FilterOnObservable(p => p.WhenAnyValue(x => x.IsOn), scheduler: RxApp.MainThreadScheduler)
                                .RefCount();

            var enabledGroupModKeys = enabledGroups
                                      .Transform(x => x.ModKey)
                                      .QueryWhenChanged(q => q.ToHashSet())
                                      .Replay(1).RefCount();

            _blockingError = Observable.CombineLatest(
                dataFolder.WhenAnyValue(x => x.DataFolderResult),
                loadOrder.WhenAnyValue(x => x.State),
                enabledGroups
                .QueryWhenChanged(q => q)
                .StartWith(Noggog.ListExt.Empty <GroupVm>()),
                enabledGroups
                .FilterOnObservable(g => g.WhenAnyValue(x => x.State).Select(x => x.IsHaltingError))
                .QueryWhenChanged(q => q)
                .StartWith(Noggog.ListExt.Empty <GroupVm>()),
                LoadOrder.Connect()
                .FilterOnObservable(
                    x =>
            {
                return(Observable.CombineLatest(
                           x.WhenAnyValue(y => y.Exists)
                           .DistinctUntilChanged(),
                           enabledGroupModKeys
                           .Select(groupModKeys => groupModKeys.Contains(x.ModKey)),
                           (exists, isEnabledGroupKey) => !exists && !isEnabledGroupKey));
            },
                    scheduler: RxApp.MainThreadScheduler)
                .QueryWhenChanged(q => q)
                .StartWith(Noggog.ListExt.Empty <ReadOnlyModListingVM>())
                .Throttle(TimeSpan.FromMilliseconds(200), RxApp.MainThreadScheduler),
                this.WhenAnyValue(x => x.IgnoreMissingMods),
                (dataFolder, loadOrder, enabledGroups, erroredEnabledGroups, missingMods, ignoreMissingMods) =>
            {
                if (enabledGroups.Count == 0)
                {
                    return(GetResponse <ViewModel> .Fail("There are no enabled groups to run."));
                }
                if (!dataFolder.Succeeded)
                {
                    return(dataFolder.BubbleFailure <ViewModel>());
                }
                if (!loadOrder.Succeeded)
                {
                    return(loadOrder.BubbleFailure <ViewModel>());
                }
                if (!ignoreMissingMods && missingMods.Count > 0)
                {
                    return(GetResponse <ViewModel> .Fail($"Load order had mods that were missing:{Environment.NewLine}{string.Join(Environment.NewLine, missingMods.Select(x => x.ModKey))}"));
                }
                if (erroredEnabledGroups.Count > 0)
                {
                    var errGroup = erroredEnabledGroups.First();
                    return(GetResponse <ViewModel> .Fail(errGroup, $"\"{errGroup.Name}\" has a blocking error: {errGroup.State}"));
                }
                return(GetResponse <ViewModel> .Succeed(null !));
            })
        public PatcherRunnabilityCliState(
            ICompilationProvider compilationProvider,
            IProfileDataFolderVm dataFolder,
            IProfileLoadOrder loadOrder,
            IExecuteRunnabilityCheck checkRunnability,
            ITemporaryLoadOrderProvider temporaryLoadOrderProvider,
            ILogger logger)
        {
            Runnable = Observable.CombineLatest(
                compilationProvider.State,
                dataFolder.WhenAnyValue(x => x.Path),
                loadOrder.LoadOrder.Connect()
                .QueryWhenChanged()
                .StartWith(ListExt.Empty <ReadOnlyModListingVM>()),
                (comp, data, loadOrder) => (comp, data, loadOrder))
                       .Select(i =>
            {
                return(Observable.Create <ConfigurationState <RunnerRepoInfo> >(async(observer, cancel) =>
                {
                    if (i.comp.RunnableState.Failed)
                    {
                        observer.OnNext(i.comp);
                        return;
                    }

                    logger.Information("Checking runnability");
                    // Return early with the values, but mark not complete
                    observer.OnNext(new ConfigurationState <RunnerRepoInfo>(i.comp.Item)
                    {
                        IsHaltingError = false,
                        RunnableState = ErrorResponse.Fail("Checking runnability")
                    });

                    try
                    {
                        using var tmpLoadOrder = temporaryLoadOrderProvider.Get(
                                  i.loadOrder.Select <ReadOnlyModListingVM, IModListingGetter>(lvm => lvm));
                        var runnability = await checkRunnability.Check(
                            path: i.comp.Item.ProjPath,
                            directExe: false,
                            cancel: cancel,
                            buildMetaPath: i.comp.Item.MetaPath,
                            loadOrderPath: tmpLoadOrder.File).ConfigureAwait(false);
                        if (runnability.Failed)
                        {
                            logger.Information($"Checking runnability failed: {runnability.Reason}");
                            observer.OnNext(runnability.BubbleFailure <RunnerRepoInfo>());
                            return;
                        }

                        // Return things again, without error
                        logger.Information("Checking runnability succeeded");
                        observer.OnNext(i.comp);
                    }
                    catch (Exception ex)
                    {
                        var str = $"Error checking runnability on runner repository: {ex}";
                        logger.Error(str);
                        observer.OnNext(ErrorResponse.Fail(str).BubbleFailure <RunnerRepoInfo>());
                    }

                    observer.OnCompleted();
                }));
            })
                       .Switch()
                       .Replay(1)
                       .RefCount();
        }