Merge remote-tracking branch 'origin/main'

This commit is contained in:
Timothy Baldridge 2023-10-12 14:19:57 -06:00
commit 7a706fdd64
107 changed files with 580 additions and 903 deletions

View File

@ -1,21 +1,32 @@
### Changelog ### Changelog
#### Version - 3.3.0.0 - TBA
* Fixed some UI issues arising from 3.2.0.0 changes - more informative error text, wiki link button
* Added optional JSON flag for `DisplayVersionOnlyInInstallerView` to enable the installer image to only show version number.
* Fixed manual downloader downloading in the OS's "Downloads" folder
* Added RAM Limit setting for downloads
* This fixes the High RAM usage (and sometimes app crashes) on some Hardware + Very High Speed Internet Connection Systems
* Added Fallout 4 (GOG) to the index
* Updated App to .NET 7.0
* Should fix random crashes on some systems
* Updated GameFinder to 4.0.0
#### Version - 3.2.0.1 - 7/23/2023 #### Version - 3.2.0.1 - 7/23/2023
* Code cleanup: re-added some network and diagnostic code missing since 2.5 * Code cleanup: re-added some network and diagnostic code missing since 2.5
#### Version - 3.2.0.0 - 7/16/2023 #### Version - 3.2.0.0 - 7/16/2023
* Fixed issues related to high RAM usage * Fixed issues related to high RAM usage
* The resumable downloads now reserve drive space to write to in advance instead of being managed in system RAM * The resumable downloads now reserve drive space to write to in advance instead of being managed in system RAM
* remove LoversLab from the "Logins" Setting because it is deprecated for ages now and only causes confusion, * remove LoversLab from the "Logins" Setting because it is deprecated for ages now and only causes confusion,
just for the unlikely probability that LL will fix their proper API. just for the unlikely probability that LL will fix their proper API.
* Added safety to install path selection, to ensure that no files are deleted that are not intended to be. * Added safety to install path selection, to ensure that no files are deleted that are not intended to be.
* Fixed allowing back button during install which can result in multiple install processes * Fixed allowing back button during install which can result in multiple install processes
* fixed search filter not applying when pressing back button and reaccessing gallery * fixed search filter not applying when pressing back button and reaccessing gallery
* Added more robust checking for protected location paths and subfolders for the launcher exe and install and download paths * Added more robust checking for protected location paths and subfolders for the launcher exe and install and download paths
* Fixed readme double opening when modlist details are prepoulated * Fixed readme double opening when modlist details are prepoulated
* Added a check if Downloadpath is alongside Wabbajack.exe location, to match the install path check that already exists * Added a check if Downloadpath is alongside Wabbajack.exe location, to match the install path check that already exists
* Added check for identical download and install paths * Added check for identical download and install paths
* Fixed No Delete and NoDelete being handled by stripping whitespace before the regex, to idiotproof things a bit * Fixed No Delete and NoDelete being handled by stripping whitespace before the regex, to idiotproof things a bit
#### Version - 3.1.0.0 - 5/7/2023 #### Version - 3.1.0.0 - 5/7/2023
* Fixed Readme opening twice * Fixed Readme opening twice

View File

@ -3,7 +3,6 @@ using System.Reactive.Concurrency;
using System.Reactive.Disposables; using System.Reactive.Disposables;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Security.Principal; using System.Security.Principal;
using System.Threading.Tasks;
using System.Windows; using System.Windows;
using System.Windows.Threading; using System.Windows.Threading;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
@ -166,7 +165,6 @@ namespace Wabbajack
services.AddSingleton<LauncherUpdater>(); services.AddSingleton<LauncherUpdater>();
services.AddSingleton<ResourceMonitor>(); services.AddSingleton<ResourceMonitor>();
services.AddSingleton<MainSettings>();
services.AddTransient<CompilerVM>(); services.AddTransient<CompilerVM>();
services.AddTransient<InstallerVM>(); services.AddTransient<InstallerVM>();
services.AddTransient<ModeSelectionVM>(); services.AddTransient<ModeSelectionVM>();

View File

@ -8,6 +8,7 @@ using System.Threading.Tasks;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Microsoft.VisualBasic.CompilerServices; using Microsoft.VisualBasic.CompilerServices;
using Newtonsoft.Json; using Newtonsoft.Json;
using Wabbajack.Common;
using Wabbajack.Downloaders; using Wabbajack.Downloaders;
using Wabbajack.DTOs; using Wabbajack.DTOs;
using Wabbajack.DTOs.DownloadStates; using Wabbajack.DTOs.DownloadStates;
@ -146,7 +147,7 @@ namespace Wabbajack
private HttpRequestMessage MakeMessage(Uri uri) private HttpRequestMessage MakeMessage(Uri uri)
{ {
var msg = new HttpRequestMessage(HttpMethod.Get, uri); var msg = new HttpRequestMessage(HttpMethod.Get, uri);
msg.UseChromeUserAgent(); msg.AddChromeAgent();
return msg; return msg;
} }

View File

@ -1,84 +1,11 @@
using System; using Wabbajack.Downloaders;
using System.Collections.Generic;
using System.Reactive;
using System.Reactive.Subjects;
using System.Threading.Tasks;
using Newtonsoft.Json;
using Wabbajack.Compiler;
using Wabbajack.DTOs.JsonConverters; using Wabbajack.DTOs.JsonConverters;
using Wabbajack;
using Wabbajack.Paths; using Wabbajack.Paths;
using Consts = Wabbajack.Consts; using Wabbajack.RateLimiter;
using Wabbajack.Util;
namespace Wabbajack namespace Wabbajack
{ {
[JsonName("MainSettings")]
[JsonObject(MemberSerialization.OptOut)]
public class MainSettings
{
public byte Version { get; set; } = Consts.SettingsVersion;
public double PosX { get; set; }
public double PosY { get; set; }
public double Height { get; set; }
public double Width { get; set; }
public InstallerSettings Installer { get; set; } = new();
public FiltersSettings Filters { get; set; } = new();
public CompilerSettings Compiler { get; set; } = new();
public PerformanceSettings Performance { get; set; } = new();
private Subject<Unit> _saveSignal = new();
[JsonIgnore]
public IObservable<Unit> SaveSignal => _saveSignal;
public static async ValueTask<(MainSettings settings, bool loaded)> TryLoadTypicalSettings()
{
/*
if (!Consts.SettingsFile.Exists)
{
return default;
}
// Version check
try
{
var settings = Consts.SettingsFile.FromJson<MainSettings>();
if (settings.Version == Consts.SettingsVersion)
return (settings, true);
}
catch (Exception ex)
{
Utils.Error(ex, "Error loading settings");
}
var backup = Consts.SettingsFile.AppendToName("-backup");
await backup.DeleteAsync();
await Consts.SettingsFile.CopyToAsync(backup);
await Consts.SettingsFile.DeleteAsync();
*/
return default;
}
public static async ValueTask SaveSettings(MainSettings settings)
{
settings._saveSignal.OnNext(Unit.Default);
// Might add this if people are putting save work on other threads or other
// things that delay the operation.
//settings._saveSignal.OnCompleted();
//await settings._saveSignal;
//await settings.ToJsonAsync(Consts.SettingsFile);
}
}
[JsonName("InstallerSettings")]
public class InstallerSettings
{
public AbsolutePath LastInstalledListLocation { get; set; }
public Dictionary<AbsolutePath, Mo2ModlistInstallationSettings> Mo2ModlistSettings { get; } = new Dictionary<AbsolutePath, Mo2ModlistInstallationSettings>();
}
[JsonName("Mo2ModListInstallerSettings")] [JsonName("Mo2ModListInstallerSettings")]
public class Mo2ModlistInstallationSettings public class Mo2ModlistInstallationSettings
{ {
@ -87,105 +14,41 @@ namespace Wabbajack
public bool AutomaticallyOverrideExistingInstall { get; set; } public bool AutomaticallyOverrideExistingInstall { get; set; }
} }
[JsonName("FiltersSettings")]
[JsonObject(MemberSerialization.OptOut)]
public class FiltersSettings : ViewModel
{
public bool ShowNSFW { get; set; }
public bool OnlyInstalled { get; set; }
public string Game { get; set; }
public string Search { get; set; }
private bool _isPersistent = true;
public bool IsPersistent { get => _isPersistent; set => RaiseAndSetIfChanged(ref _isPersistent, value); }
private bool _useCompression = false;
public bool UseCompression { get => _useCompression; set => RaiseAndSetIfChanged(ref _useCompression, value); }
public bool ShowUtilityLists { get; set; }
}
[JsonName("PerformanceSettings")]
[JsonObject(MemberSerialization.OptOut)]
public class PerformanceSettings : ViewModel public class PerformanceSettings : ViewModel
{ {
public PerformanceSettings() private readonly Configuration.MainSettings _settings;
private readonly int _defaultMaximumMemoryPerDownloadThreadMb;
public PerformanceSettings(Configuration.MainSettings settings, IResource<DownloadDispatcher> downloadResources, SystemParametersConstructor systemParams)
{ {
_reduceHDDThreads = true; var p = systemParams.Create();
_favorPerfOverRam = false;
_diskThreads = Environment.ProcessorCount; _settings = settings;
_downloadThreads = Environment.ProcessorCount <= 8 ? Environment.ProcessorCount : 8; // Split half of available memory among download threads
_defaultMaximumMemoryPerDownloadThreadMb = (int)(p.SystemMemorySize / downloadResources.MaxTasks / 1024 / 1024) / 2;
_maximumMemoryPerDownloadThreadMb = settings.PerformanceSettings.MaximumMemoryPerDownloadThreadMb;
if (MaximumMemoryPerDownloadThreadMb < 0)
{
ResetMaximumMemoryPerDownloadThreadMb();
}
} }
private int _downloadThreads; private int _maximumMemoryPerDownloadThreadMb;
public int DownloadThreads { get => _downloadThreads; set => RaiseAndSetIfChanged(ref _downloadThreads, value); }
private int _diskThreads; public int MaximumMemoryPerDownloadThreadMb
public int DiskThreads { get => _diskThreads; set => RaiseAndSetIfChanged(ref _diskThreads, value); }
private bool _reduceHDDThreads;
public bool ReduceHDDThreads { get => _reduceHDDThreads; set => RaiseAndSetIfChanged(ref _reduceHDDThreads, value); }
private bool _favorPerfOverRam;
public bool FavorPerfOverRam { get => _favorPerfOverRam; set => RaiseAndSetIfChanged(ref _favorPerfOverRam, value); }
private bool _networkWorkaroundMode;
public bool NetworkWorkaroundMode
{ {
get => _networkWorkaroundMode; get => _maximumMemoryPerDownloadThreadMb;
set set
{ {
Consts.UseNetworkWorkaroundMode = value; RaiseAndSetIfChanged(ref _maximumMemoryPerDownloadThreadMb, value);
RaiseAndSetIfChanged(ref _networkWorkaroundMode, value); _settings.PerformanceSettings.MaximumMemoryPerDownloadThreadMb = value;
} }
} }
public void ResetMaximumMemoryPerDownloadThreadMb()
private bool _disableTextureResizing;
public bool DisableTextureResizing
{ {
get => _disableTextureResizing; MaximumMemoryPerDownloadThreadMb = _defaultMaximumMemoryPerDownloadThreadMb;
set
{
RaiseAndSetIfChanged(ref _disableTextureResizing, value);
} }
} }
/*
public void SetProcessorSettings(ABatchProcessor processor)
{
processor.DownloadThreads = DownloadThreads;
processor.DiskThreads = DiskThreads;
processor.ReduceHDDThreads = ReduceHDDThreads;
processor.FavorPerfOverRam = FavorPerfOverRam;
if (processor is MO2Compiler mo2c)
mo2c.DisableTextureResizing = DisableTextureResizing;
}*/
}
[JsonName("CompilationModlistSettings")]
public class CompilationModlistSettings
{
public string ModListName { get; set; }
public string Version { get; set; }
public string Author { get; set; }
public string Description { get; set; }
public string Website { get; set; }
public string Readme { get; set; }
public bool IsNSFW { get; set; }
public string MachineUrl { get; set; }
public AbsolutePath SplashScreen { get; set; }
public bool Publish { get; set; }
}
[JsonName("MO2CompilationSettings")]
public class MO2CompilationSettings
{
public AbsolutePath DownloadLocation { get; set; }
public AbsolutePath LastCompiledProfileLocation { get; set; }
public Dictionary<AbsolutePath, CompilationModlistSettings> ModlistSettings { get; } = new Dictionary<AbsolutePath, CompilationModlistSettings>();
}
} }

View File

@ -1,10 +1,7 @@
using System.Security.Policy;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Wabbajack.DTOs;
using Wabbajack.DTOs.DownloadStates; using Wabbajack.DTOs.DownloadStates;
using Wabbajack.DTOs.Interventions; using Wabbajack.DTOs.Interventions;
using Wabbajack.Paths;
namespace Wabbajack.UserIntervention; namespace Wabbajack.UserIntervention;
@ -21,13 +18,13 @@ public class ManualDownloadHandler : BrowserWindowViewModel
HeaderText = $"Manual download ({md.Url.Host})"; HeaderText = $"Manual download ({md.Url.Host})";
Instructions = string.IsNullOrWhiteSpace(md.Prompt) ? $"Please download {archive.Name}" : md.Prompt; Instructions = string.IsNullOrWhiteSpace(md.Prompt) ? $"Please download {archive.Name}" : md.Prompt;
await NavigateTo(md.Url);
var task = WaitForDownloadUri(token, async () =>
var uri = await WaitForDownloadUri(token, async () =>
{ {
await RunJavaScript("Array.from(document.getElementsByTagName(\"iframe\")).forEach(f => f.remove())"); await RunJavaScript("Array.from(document.getElementsByTagName(\"iframe\")).forEach(f => f.remove())");
}); });
await NavigateTo(md.Url);
var uri = await task;
Intervention.Finish(uri); Intervention.Finish(uri);
} }

View File

@ -8,6 +8,7 @@ using System.Threading.Tasks;
using System.Web; using System.Web;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using ReactiveUI; using ReactiveUI;
using Wabbajack.Common;
using Wabbajack.DTOs.Interventions; using Wabbajack.DTOs.Interventions;
using Wabbajack.DTOs.Logins; using Wabbajack.DTOs.Logins;
using Wabbajack.Messages; using Wabbajack.Messages;
@ -88,8 +89,7 @@ public abstract class OAuth2LoginHandler<TLoginType> : BrowserWindowViewModel
var msg = new HttpRequestMessage(); var msg = new HttpRequestMessage();
msg.Method = HttpMethod.Post; msg.Method = HttpMethod.Post;
msg.RequestUri = tlogin.TokenEndpoint; msg.RequestUri = tlogin.TokenEndpoint;
msg.Headers.Add("User-Agent", msg.AddChromeAgent();
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Safari/537.36");
msg.Headers.Add("Cookie", string.Join(";", cookies.Select(c => $"{c.Name}={c.Value}"))); msg.Headers.Add("Cookie", string.Join(";", cookies.Select(c => $"{c.Name}={c.Value}")));
msg.Content = new FormUrlEncodedContent(formData.ToList()); msg.Content = new FormUrlEncodedContent(formData.ToList());

View File

@ -83,6 +83,11 @@ public abstract class BrowserWindowViewModel : ViewModel
public async Task<Cookie[]> GetCookies(string domainEnding, CancellationToken token) public async Task<Cookie[]> GetCookies(string domainEnding, CancellationToken token)
{ {
// Strip www. before searching for cookies on a domain to handle websites saving their cookies like .example.org
if (domainEnding.StartsWith("www."))
{
domainEnding = domainEnding[4..];
}
var cookies = (await _browser.CoreWebView2.CookieManager.GetCookiesAsync("")) var cookies = (await _browser.CoreWebView2.CookieManager.GetCookiesAsync(""))
.Where(c => c.Domain.EndsWith(domainEnding)); .Where(c => c.Domain.EndsWith(domainEnding));
return cookies.Select(c => new Cookie return cookies.Select(c => new Cookie
@ -112,11 +117,13 @@ public abstract class BrowserWindowViewModel : ViewModel
{ {
var source = new TaskCompletionSource<Uri>(); var source = new TaskCompletionSource<Uri>();
var referer = _browser.Source; var referer = _browser.Source;
while (_browser.CoreWebView2 == null)
await Task.Delay(10, token);
_browser.CoreWebView2.DownloadStarting += (sender, args) => _browser.CoreWebView2.DownloadStarting += (sender, args) =>
{ {
try try
{ {
source.SetResult(new Uri(args.DownloadOperation.Uri)); source.SetResult(new Uri(args.DownloadOperation.Uri));
} }
catch (Exception) catch (Exception)
@ -144,10 +151,14 @@ public abstract class BrowserWindowViewModel : ViewModel
} }
var cookies = await GetCookies(uri.Host, token); var cookies = await GetCookies(uri.Host, token);
return new ManualDownload.BrowserDownloadState(uri, cookies, new[] return new ManualDownload.BrowserDownloadState(
uri,
cookies,
new[]
{ {
("Referer", referer.ToString()) ("Referer", referer?.ToString() ?? uri.ToString())
}); },
_browser.CoreWebView2.Settings.UserAgent);
} }
public async Task<Hash> WaitForDownload(AbsolutePath path, CancellationToken token) public async Task<Hash> WaitForDownload(AbsolutePath path, CancellationToken token)

View File

@ -1,109 +0,0 @@
using System;
using System.Reactive.Linq;
using System.Windows.Input;
using DynamicData;
using Microsoft.WindowsAPICodePack.Dialogs;
using ReactiveUI;
using ReactiveUI.Fody.Helpers;
using Wabbajack.Common;
using Wabbajack;
namespace Wabbajack
{
public class ModlistSettingsEditorVM : ViewModel
{
private readonly CompilationModlistSettings _settings;
[Reactive]
public string ModListName { get; set; }
[Reactive]
public string VersionText { get; set; }
private readonly ObservableAsPropertyHelper<Version> _version;
public Version Version => _version.Value;
[Reactive]
public string AuthorText { get; set; }
[Reactive]
public string Description { get; set; }
public FilePickerVM ImagePath { get; }
[Reactive]
public string Readme { get; set; }
[Reactive] public string MachineUrl { get; set; } = "";
[Reactive] public bool Publish { get; set; } = false;
[Reactive]
public string Website { get; set; }
[Reactive]
public bool IsNSFW { get; set; }
public IObservable<bool> InError { get; }
public ModlistSettingsEditorVM(CompilationModlistSettings settings)
{
_settings = settings;
ImagePath = new FilePickerVM
{
ExistCheckOption = FilePickerVM.CheckOptions.IfPathNotEmpty,
PathType = FilePickerVM.PathTypeOptions.File,
};
ImagePath.Filters.Add(new CommonFileDialogFilter("Banner image", "*.png"));
_version = this.WhenAny(x => x.VersionText)
.Select(x =>
{
if (string.IsNullOrWhiteSpace(x))
return new Version(0, 0);
return !Version.TryParse(x, out var version) ? new Version(0, 0) : version;
}).ObserveOnGuiThread()
.ToProperty(this, x => x.Version);
InError = this.WhenAny(x => x.ImagePath.ErrorState)
.Select(err => err.Failed)
.CombineLatest(
this.WhenAny(x => x.VersionText)
.Select(x => Version.TryParse(x, out _)),
(image, version) => !image && !version)
.Publish()
.RefCount();
}
public void Init()
{
AuthorText = _settings.Author;
if (!string.IsNullOrWhiteSpace(_settings.ModListName))
{
ModListName = _settings.ModListName;
}
Description = _settings.Description;
Readme = _settings.Readme;
ImagePath.TargetPath = _settings.SplashScreen;
Website = _settings.Website;
VersionText = _settings.Version;
IsNSFW = _settings.IsNSFW;
MachineUrl = _settings.MachineUrl;
Publish = _settings.Publish;
}
public void Save()
{
_settings.Version = VersionText;
_settings.Author = AuthorText;
_settings.ModListName = ModListName;
_settings.Description = Description;
_settings.Readme = Readme;
_settings.SplashScreen = ImagePath.TargetPath;
_settings.Website = Website;
_settings.IsNSFW = IsNSFW;
_settings.MachineUrl = MachineUrl;
_settings.Publish = Publish;
}
}
}

View File

@ -80,7 +80,6 @@ namespace Wabbajack
private readonly SettingsManager _settingsManager; private readonly SettingsManager _settingsManager;
private readonly CancellationToken _cancellationToken; private readonly CancellationToken _cancellationToken;
private FiltersSettings settings { get; set; } = new();
public ICommand ClearFiltersCommand { get; set; } public ICommand ClearFiltersCommand { get; set; }
public ModListGalleryVM(ILogger<ModListGalleryVM> logger, Client wjClient, GameLocator locator, public ModListGalleryVM(ILogger<ModListGalleryVM> logger, Client wjClient, GameLocator locator,

View File

@ -82,6 +82,13 @@ namespace Wabbajack
[Reactive] [Reactive]
public string VersionText { get; private set; } public string VersionText { get; private set; }
[Reactive]
public bool ImageContainsTitle { get; private set; }
[Reactive]
public bool DisplayVersionOnlyInInstallerView { get; private set; }
[Reactive] [Reactive]
public IErrorResponse Error { get; private set; } public IErrorResponse Error { get; private set; }
@ -123,6 +130,8 @@ namespace Wabbajack
Metadata.DownloadMetadata.SizeOfArchives + Metadata.DownloadMetadata.SizeOfInstalledFiles Metadata.DownloadMetadata.SizeOfArchives + Metadata.DownloadMetadata.SizeOfInstalledFiles
); );
VersionText = "Modlist version : " + Metadata.Version; VersionText = "Modlist version : " + Metadata.Version;
ImageContainsTitle = Metadata.ImageContainsTitle;
DisplayVersionOnlyInInstallerView = Metadata.DisplayVersionOnlyInInstallerView;
IsBroken = metadata.ValidationSummary.HasFailures || metadata.ForceDown; IsBroken = metadata.ValidationSummary.HasFailures || metadata.ForceDown;
// https://www.wabbajack.org/modlist/wj-featured/aldrnari // https://www.wabbajack.org/modlist/wj-featured/aldrnari
OpenWebsiteCommand = ReactiveCommand.Create(() => UIUtils.OpenWebsite(new Uri($"https://www.wabbajack.org/modlist/{Metadata.NamespacedName}"))); OpenWebsiteCommand = ReactiveCommand.Create(() => UIUtils.OpenWebsite(new Uri($"https://www.wabbajack.org/modlist/{Metadata.NamespacedName}")));

View File

@ -136,10 +136,13 @@ public class InstallerVM : BackNavigatingVM, IBackNavigatingVM, ICpuStatusVM
private AbsolutePath LastInstallPath { get; set; } private AbsolutePath LastInstallPath { get; set; }
[Reactive] public bool OverwriteFiles { get; set; }
// Command properties // Command properties
public ReactiveCommand<Unit, Unit> ShowManifestCommand { get; } public ReactiveCommand<Unit, Unit> ShowManifestCommand { get; }
public ReactiveCommand<Unit, Unit> OpenReadmeCommand { get; } public ReactiveCommand<Unit, Unit> OpenReadmeCommand { get; }
public ReactiveCommand<Unit, Unit> OpenWikiCommand { get; }
public ReactiveCommand<Unit, Unit> OpenDiscordButton { get; } public ReactiveCommand<Unit, Unit> OpenDiscordButton { get; }
public ReactiveCommand<Unit, Unit> VisitModListWebsiteCommand { get; } public ReactiveCommand<Unit, Unit> VisitModListWebsiteCommand { get; }
@ -178,6 +181,11 @@ public class InstallerVM : BackNavigatingVM, IBackNavigatingVM, ICpuStatusVM
UIUtils.OpenWebsite(new Uri(ModList!.Readme)); UIUtils.OpenWebsite(new Uri(ModList!.Readme));
}, this.WhenAnyValue(vm => vm.LoadingLock.IsNotLoading, vm => vm.ModList.Readme, (isNotLoading, readme) => isNotLoading && !string.IsNullOrWhiteSpace(readme))); }, this.WhenAnyValue(vm => vm.LoadingLock.IsNotLoading, vm => vm.ModList.Readme, (isNotLoading, readme) => isNotLoading && !string.IsNullOrWhiteSpace(readme)));
OpenWikiCommand = ReactiveCommand.Create(() =>
{
UIUtils.OpenWebsite(new Uri("https://wiki.wabbajack.org/index.html"));
}, this.WhenAnyValue(vm => vm.LoadingLock.IsNotLoading));
VisitModListWebsiteCommand = ReactiveCommand.Create(() => VisitModListWebsiteCommand = ReactiveCommand.Create(() =>
{ {
UIUtils.OpenWebsite(ModList!.Website); UIUtils.OpenWebsite(ModList!.Website);
@ -220,6 +228,9 @@ public class InstallerVM : BackNavigatingVM, IBackNavigatingVM, ICpuStatusVM
UIUtils.OpenFolder(Installer.Location.TargetPath); UIUtils.OpenFolder(Installer.Location.TargetPath);
}); });
this.WhenAnyValue(x => x.OverwriteFiles)
.Subscribe(x => ConfirmOverwrite());
MessageBus.Current.Listen<LoadModlistForInstalling>() MessageBus.Current.Listen<LoadModlistForInstalling>()
.Subscribe(msg => LoadModlistFromGallery(msg.Path, msg.Metadata).FireAndForget()) .Subscribe(msg => LoadModlistFromGallery(msg.Path, msg.Metadata).FireAndForget())
.DisposeWith(CompositeDisposable); .DisposeWith(CompositeDisposable);
@ -280,6 +291,10 @@ public class InstallerVM : BackNavigatingVM, IBackNavigatingVM, ICpuStatusVM
{ {
yield return ErrorResponse.Fail("Can't have identical install and download folders"); yield return ErrorResponse.Fail("Can't have identical install and download folders");
} }
if (installPath.ToString().Length > 0 && downloadPath.ToString().Length > 0 && KnownFolders.IsSubDirectoryOf(installPath.ToString(), downloadPath.ToString()))
{
yield return ErrorResponse.Fail("Can't put the install folder inside the download folder");
}
foreach (var game in GameRegistry.Games) foreach (var game in GameRegistry.Games)
{ {
if (!_gameLocator.TryFindLocation(game.Key, out var location)) if (!_gameLocator.TryFindLocation(game.Key, out var location))
@ -304,30 +319,52 @@ public class InstallerVM : BackNavigatingVM, IBackNavigatingVM, ICpuStatusVM
yield return ErrorResponse.Fail("Installing in this folder may overwrite Wabbajack"); yield return ErrorResponse.Fail("Installing in this folder may overwrite Wabbajack");
} }
if (installPath.ToString().Length != 0 && installPath != LastInstallPath && if (installPath.ToString().Length != 0 && installPath != LastInstallPath && !OverwriteFiles &&
!Installer.AutomaticallyOverwrite &&
Directory.EnumerateFileSystemEntries(installPath.ToString()).Any()) Directory.EnumerateFileSystemEntries(installPath.ToString()).Any())
{ {
string message = yield return ErrorResponse.Fail("There are files in the install folder, please tick 'Overwrite Installation' to confirm you want to install to this folder " + Environment.NewLine +
"There are existing files in the chosen install path, they will be deleted or overwritten (if updating existing modlist), continue?"; "if you are updating an existing modlist, then this is expected and can be overwritten.");
string title = "Files found in install folder";
MessageBoxButtons buttons = MessageBoxButtons.YesNo;
DialogResult result = MessageBox.Show(message, title, buttons);
if (result == DialogResult.Yes)
{
// everythings fine
}
else
{
Installer.Location.TargetPath = "".ToAbsolutePath();
}
} }
if (KnownFolders.IsInSpecialFolder(installPath) || KnownFolders.IsInSpecialFolder(downloadPath)) if (KnownFolders.IsInSpecialFolder(installPath) || KnownFolders.IsInSpecialFolder(downloadPath))
{ {
yield return ErrorResponse.Fail("Can't install a modlist into Windows protected locations - such as Downloads, Documents etc"); yield return ErrorResponse.Fail("Can't install into Windows locations such as Documents etc, please make a new folder for the modlist - C:\\ModList\\ for example.");
}
// Disabled Because it was causing issues for people trying to update lists.
//if (installPath.ToString().Length > 0 && downloadPath.ToString().Length > 0 && !HasEnoughSpace(installPath, downloadPath)){
// yield return ErrorResponse.Fail("Can't install modlist due to lack of free hard drive space, please read the modlist Readme to learn more.");
//}
}
/*
private bool HasEnoughSpace(AbsolutePath inpath, AbsolutePath downpath)
{
string driveLetterInPath = inpath.ToString().Substring(0,1);
string driveLetterDownPath = inpath.ToString().Substring(0,1);
DriveInfo driveUsedInPath = new DriveInfo(driveLetterInPath);
DriveInfo driveUsedDownPath = new DriveInfo(driveLetterDownPath);
long spaceRequiredforInstall = ModlistMetadata.DownloadMetadata.SizeOfInstalledFiles;
long spaceRequiredforDownload = ModlistMetadata.DownloadMetadata.SizeOfArchives;
long spaceInstRemaining = driveUsedInPath.AvailableFreeSpace;
long spaceDownRemaining = driveUsedDownPath.AvailableFreeSpace;
if ( driveLetterInPath == driveLetterDownPath)
{
long totalSpaceRequired = spaceRequiredforInstall + spaceRequiredforDownload;
if (spaceInstRemaining < totalSpaceRequired)
{
return false;
}
} else
{
if( spaceInstRemaining < spaceRequiredforInstall || spaceDownRemaining < spaceRequiredforDownload)
{
return false;
} }
} }
return true;
}*/
private async Task BeginSlideShow(CancellationToken token) private async Task BeginSlideShow(CancellationToken token)
{ {
@ -411,6 +448,13 @@ public class InstallerVM : BackNavigatingVM, IBackNavigatingVM, ICpuStatusVM
} }
} }
private void ConfirmOverwrite()
{
AbsolutePath prev = Installer.Location.TargetPath;
Installer.Location.TargetPath = "".ToAbsolutePath();
Installer.Location.TargetPath = prev;
}
private async Task BeginInstall() private async Task BeginInstall()
{ {
await Task.Run(async () => await Task.Run(async () =>
@ -520,8 +564,15 @@ public class InstallerVM : BackNavigatingVM, IBackNavigatingVM, ICpuStatusVM
} }
private void PopulateSlideShow(ModList modList) private void PopulateSlideShow(ModList modList)
{
if (ModlistMetadata.ImageContainsTitle && ModlistMetadata.DisplayVersionOnlyInInstallerView)
{
SlideShowTitle = "v" + ModlistMetadata.Version.ToString();
}
else
{ {
SlideShowTitle = modList.Name; SlideShowTitle = modList.Name;
}
SlideShowAuthor = modList.Author; SlideShowAuthor = modList.Author;
SlideShowDescription = modList.Description; SlideShowDescription = modList.Description;
SlideShowImage = ModListImage; SlideShowImage = ModListImage;

View File

@ -1,22 +1,12 @@
using System; using System;
using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reactive.Disposables; using System.Reactive.Disposables;
using System.Reactive.Linq;
using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using ReactiveUI; using ReactiveUI;
using ReactiveUI.Fody.Helpers; using ReactiveUI.Fody.Helpers;
using Wabbajack.Common;
using Wabbajack.Installer; using Wabbajack.Installer;
using Wabbajack;
using Wabbajack.DTOs;
using Wabbajack.DTOs.Interventions; using Wabbajack.DTOs.Interventions;
using Wabbajack.Interventions;
using Wabbajack.Paths; using Wabbajack.Paths;
using Wabbajack.Util;
namespace Wabbajack namespace Wabbajack
{ {
@ -30,8 +20,8 @@ namespace Wabbajack
[Reactive] [Reactive]
public IInstaller ActiveInstallation { get; private set; } public IInstaller ActiveInstallation { get; private set; }
[Reactive]
[Reactive] public Mo2ModlistInstallationSettings CurrentSettings { get; set; } public Mo2ModlistInstallationSettings CurrentSettings { get; set; }
public FilePickerVM Location { get; } public FilePickerVM Location { get; }
@ -69,90 +59,6 @@ namespace Wabbajack
PathType = FilePickerVM.PathTypeOptions.Folder, PathType = FilePickerVM.PathTypeOptions.Folder,
PromptTitle = "Select a location for MO2 downloads", PromptTitle = "Select a location for MO2 downloads",
}; };
/* TODO
DownloadLocation.AdditionalError = this.WhenAny(x => x.DownloadLocation.TargetPath)
.Select(x => Utils.IsDirectoryPathValid(x));
Location.AdditionalError = Observable.CombineLatest(
this.WhenAny(x => x.Location.TargetPath),
this.WhenAny(x => x.DownloadLocation.TargetPath),
resultSelector: (target, download) => (target, download))
.ObserveOn(RxApp.TaskpoolScheduler)
.Select(i => MO2Installer.CheckValidInstallPath(i.target, i.download, Parent.ModList?.SourceModList?.GameType.MetaData()))
.ObserveOnGuiThread();
_CanInstall = Observable.CombineLatest(
this.WhenAny(x => x.Location.ErrorState),
this.WhenAny(x => x.DownloadLocation.ErrorState),
installerVM.WhenAny(x => x.ModListLocation.ErrorState),
resultSelector: (loc, modlist, download) =>
{
return ErrorResponse.FirstFail(loc, modlist, download);
})
.ToProperty(this, nameof(CanInstall));
// Have Installation location updates modify the downloads location if empty or the same path
this.WhenAny(x => x.Location.TargetPath)
.Skip(1) // Don't do it initially
.Subscribe(installPath =>
{
if (DownloadLocation.TargetPath == default || DownloadLocation.TargetPath == installPath)
{
if (installPath.Exists) DownloadLocation.TargetPath = installPath.Combine("downloads");
}
})
.DisposeWith(CompositeDisposable);
// Have Download location updates change if the same as the install path
this.WhenAny(x => x.DownloadLocation.TargetPath)
.Skip(1) // Don't do it initially
.Subscribe(downloadPath =>
{
if (downloadPath != default && downloadPath == Location.TargetPath)
{
DownloadLocation.TargetPath = Location.TargetPath.Combine("downloads");
}
})
.DisposeWith(CompositeDisposable);
// Load settings
_CurrentSettings = installerVM.WhenAny(x => x.ModListLocation.TargetPath)
.Select(path => path == default ? null : installerVM.MWVM.Settings.Installer.Mo2ModlistSettings.TryCreate(path))
.ToGuiProperty(this, nameof(CurrentSettings));
this.WhenAny(x => x.CurrentSettings)
.Pairwise()
.Subscribe(settingsPair =>
{
SaveSettings(settingsPair.Previous);
if (settingsPair.Current == null) return;
Location.TargetPath = settingsPair.Current.InstallationLocation;
DownloadLocation.TargetPath = settingsPair.Current.DownloadLocation;
AutomaticallyOverwrite = settingsPair.Current.AutomaticallyOverrideExistingInstall;
})
.DisposeWith(CompositeDisposable);
installerVM.MWVM.Settings.SaveSignal
.Subscribe(_ => SaveSettings(CurrentSettings))
.DisposeWith(CompositeDisposable);
// Hook onto user interventions, and intercept MO2 specific ones for customization
this.WhenAny(x => x.ActiveInstallation)
.Select(x => x?.LogMessages ?? Observable.Empty<IStatusMessage>())
.Switch()
.Subscribe(x =>
{
switch (x)
{
case ConfirmUpdateOfExistingInstall c:
if (AutomaticallyOverwrite)
{
c.Confirm();
}
break;
default:
break;
}
})
.DisposeWith(CompositeDisposable);
*/
} }
public void Unload() public void Unload()

View File

@ -16,11 +16,8 @@ using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Orc.FileAssociation; using Orc.FileAssociation;
using Wabbajack.Common; using Wabbajack.Common;
using Wabbajack.Downloaders.GameFile;
using Wabbajack;
using Wabbajack.DTOs.Interventions; using Wabbajack.DTOs.Interventions;
using Wabbajack.Interventions; using Wabbajack.Interventions;
using Wabbajack.LoginManagers;
using Wabbajack.Messages; using Wabbajack.Messages;
using Wabbajack.Models; using Wabbajack.Models;
using Wabbajack.Networking.WabbajackClientApi; using Wabbajack.Networking.WabbajackClientApi;
@ -39,8 +36,6 @@ namespace Wabbajack
{ {
public MainWindow MainWindow { get; } public MainWindow MainWindow { get; }
public MainSettings Settings { get; }
[Reactive] [Reactive]
public ViewModel ActivePane { get; private set; } public ViewModel ActivePane { get; private set; }
@ -76,7 +71,7 @@ namespace Wabbajack
[Reactive] [Reactive]
public bool UpdateAvailable { get; private set; } public bool UpdateAvailable { get; private set; }
public MainWindowVM(ILogger<MainWindowVM> logger, MainSettings settings, Client wjClient, public MainWindowVM(ILogger<MainWindowVM> logger, Client wjClient,
IServiceProvider serviceProvider, ModeSelectionVM modeSelectionVM, ModListGalleryVM modListGalleryVM, ResourceMonitor resourceMonitor, IServiceProvider serviceProvider, ModeSelectionVM modeSelectionVM, ModListGalleryVM modListGalleryVM, ResourceMonitor resourceMonitor,
InstallerVM installer, CompilerVM compilerVM, SettingsVM settingsVM, WebBrowserVM webBrowserVM) InstallerVM installer, CompilerVM compilerVM, SettingsVM settingsVM, WebBrowserVM webBrowserVM)
{ {
@ -85,7 +80,6 @@ namespace Wabbajack
_resourceMonitor = resourceMonitor; _resourceMonitor = resourceMonitor;
_serviceProvider = serviceProvider; _serviceProvider = serviceProvider;
ConverterRegistration.Register(); ConverterRegistration.Register();
Settings = settings;
Installer = installer; Installer = installer;
Compiler = compilerVM; Compiler = compilerVM;
SettingsPane = settingsVM; SettingsPane = settingsVM;

View File

@ -2,28 +2,32 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.IO; using System.IO;
using System.Linq;
using System.Reflection; using System.Reflection;
using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Windows.Input; using System.Windows.Input;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using ReactiveUI; using ReactiveUI;
using Wabbajack; using Wabbajack.Common;
using Wabbajack.Downloaders;
using Wabbajack.LoginManagers; using Wabbajack.LoginManagers;
using Wabbajack.Messages; using Wabbajack.Messages;
using Wabbajack.Networking.WabbajackClientApi; using Wabbajack.Networking.WabbajackClientApi;
using Wabbajack.RateLimiter;
using Wabbajack.Services.OSIntegrated;
using Wabbajack.Services.OSIntegrated.TokenProviders; using Wabbajack.Services.OSIntegrated.TokenProviders;
using Wabbajack.Util;
using Wabbajack.View_Models.Settings; using Wabbajack.View_Models.Settings;
namespace Wabbajack namespace Wabbajack
{ {
public class SettingsVM : BackNavigatingVM public class SettingsVM : BackNavigatingVM
{ {
private readonly Configuration.MainSettings _settings;
private readonly SettingsManager _settingsManager;
public LoginManagerVM Login { get; } public LoginManagerVM Login { get; }
public PerformanceSettings Performance { get; } public PerformanceSettings Performance { get; }
public FiltersSettings Filters { get; }
public AuthorFilesVM AuthorFile { get; } public AuthorFilesVM AuthorFile { get; }
public ICommand OpenTerminalCommand { get; } public ICommand OpenTerminalCommand { get; }
@ -31,12 +35,30 @@ namespace Wabbajack
public SettingsVM(ILogger<SettingsVM> logger, IServiceProvider provider) public SettingsVM(ILogger<SettingsVM> logger, IServiceProvider provider)
: base(logger) : base(logger)
{ {
_settings = provider.GetRequiredService<Configuration.MainSettings>();
_settingsManager = provider.GetRequiredService<SettingsManager>();
Login = new LoginManagerVM(provider.GetRequiredService<ILogger<LoginManagerVM>>(), this, Login = new LoginManagerVM(provider.GetRequiredService<ILogger<LoginManagerVM>>(), this,
provider.GetRequiredService<IEnumerable<INeedsLogin>>()); provider.GetRequiredService<IEnumerable<INeedsLogin>>());
AuthorFile = new AuthorFilesVM(provider.GetRequiredService<ILogger<AuthorFilesVM>>()!, AuthorFile = new AuthorFilesVM(provider.GetRequiredService<ILogger<AuthorFilesVM>>()!,
provider.GetRequiredService<WabbajackApiTokenProvider>()!, provider.GetRequiredService<Client>()!, this); provider.GetRequiredService<WabbajackApiTokenProvider>()!, provider.GetRequiredService<Client>()!, this);
OpenTerminalCommand = ReactiveCommand.CreateFromTask(OpenTerminal); OpenTerminalCommand = ReactiveCommand.CreateFromTask(OpenTerminal);
BackCommand = ReactiveCommand.Create(NavigateBack.Send); Performance = new PerformanceSettings(
_settings,
provider.GetRequiredService<IResource<DownloadDispatcher>>(),
provider.GetRequiredService<SystemParametersConstructor>());
BackCommand = ReactiveCommand.Create(() =>
{
NavigateBack.Send();
Unload();
});
}
public override void Unload()
{
_settingsManager.Save(Configuration.MainSettings.SettingsFileName, _settings).FireAndForget();
base.Unload();
} }
private async Task OpenTerminal() private async Task OpenTerminal()

View File

@ -1,24 +1,7 @@
using System; using System.Reactive.Disposables;
using System.Collections.Generic;
using System.Linq;
using System.Reactive.Disposables;
using System.Text;
using System.Threading.Tasks;
using System.Windows; using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using ReactiveUI; using ReactiveUI;
using ReactiveUI.Fody.Helpers;
using Wabbajack;
using System.Windows.Controls.Primitives;
using System.Reactive.Linq; using System.Reactive.Linq;
using Wabbajack.Common;
using Wabbajack.RateLimiter; using Wabbajack.RateLimiter;
namespace Wabbajack namespace Wabbajack
@ -36,17 +19,6 @@ namespace Wabbajack
public static readonly DependencyProperty ProgressPercentProperty = DependencyProperty.Register(nameof(ProgressPercent), typeof(Percent), typeof(CpuView), public static readonly DependencyProperty ProgressPercentProperty = DependencyProperty.Register(nameof(ProgressPercent), typeof(Percent), typeof(CpuView),
new FrameworkPropertyMetadata(default(Percent), WireNotifyPropertyChanged)); new FrameworkPropertyMetadata(default(Percent), WireNotifyPropertyChanged));
public MainSettings SettingsHook
{
get => (MainSettings)GetValue(SettingsHookProperty);
set => SetValue(SettingsHookProperty, value);
}
public static readonly DependencyProperty SettingsHookProperty = DependencyProperty.Register(nameof(SettingsHook), typeof(MainSettings), typeof(CpuView),
new FrameworkPropertyMetadata(default(SettingsVM), WireNotifyPropertyChanged));
private bool _ShowingSettings;
public bool ShowingSettings { get => _ShowingSettings; set => this.RaiseAndSetIfChanged(ref _ShowingSettings, value); }
public CpuView() public CpuView()
{ {
InitializeComponent(); InitializeComponent();

View File

@ -12,7 +12,7 @@
x:TypeArguments="local:InstallerVM" x:TypeArguments="local:InstallerVM"
mc:Ignorable="d"> mc:Ignorable="d">
<local:AttentionBorder x:Name="AttentionBorder" ClipToBounds="True"> <local:AttentionBorder x:Name="AttentionBorder" ClipToBounds="True">
<Grid Margin="5"> <Grid Margin="6">
<Grid.RowDefinitions> <Grid.RowDefinitions>
<RowDefinition Height="*" /> <RowDefinition Height="*" />
<RowDefinition Height="3*" /> <RowDefinition Height="3*" />
@ -23,6 +23,7 @@
<ColumnDefinition Width="*" /> <ColumnDefinition Width="*" />
<ColumnDefinition Width="*" /> <ColumnDefinition Width="*" />
<ColumnDefinition Width="*" /> <ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<TextBlock Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="5" <TextBlock Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="5"
x:Name="TitleText" x:Name="TitleText"
@ -124,7 +125,7 @@
<TextBlock Grid.Row="1" <TextBlock Grid.Row="1"
Margin="0,10,0,0" Margin="0,10,0,0"
HorizontalAlignment="Center" HorizontalAlignment="Center"
Text="Readme" /> Text="Modlist Readme" />
</Grid> </Grid>
<Grid Grid.Row="1" Grid.Column="4" <Grid Grid.Row="1" Grid.Column="4"
VerticalAlignment="Center" VerticalAlignment="Center"
@ -133,6 +134,29 @@
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
</Grid.RowDefinitions> </Grid.RowDefinitions>
<Button
x:Name="OpenWikiButton"
Width="50"
Height="50"
Style="{StaticResource CircleButtonStyle}">
<icon:PackIconFontAwesome
Width="25"
Height="25"
Foreground="{Binding Foreground, RelativeSource={RelativeSource AncestorType={x:Type Button}}}"
Kind="QuestionSolid" />
</Button>
<TextBlock Grid.Row="1"
Margin="0,10,0,0"
HorizontalAlignment="Center"
Text="Help and Wiki" />
</Grid>
<Grid Grid.Row="1" Grid.Column="5"
VerticalAlignment="Center"
Background="Transparent" Grid.ColumnSpan="2" Margin="0,0,10,0">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Button <Button
x:Name="CloseButton" x:Name="CloseButton"
Width="50" Width="50"

View File

@ -46,6 +46,9 @@ namespace Wabbajack
this.WhenAny(x => x.ViewModel.OpenReadmeCommand) this.WhenAny(x => x.ViewModel.OpenReadmeCommand)
.BindToStrict(this, x => x.OpenReadmeButton.Command) .BindToStrict(this, x => x.OpenReadmeButton.Command)
.DisposeWith(dispose); .DisposeWith(dispose);
this.WhenAny(x => x.ViewModel.OpenWikiCommand)
.BindToStrict(this, x => x.OpenWikiButton.Command)
.DisposeWith(dispose);
this.WhenAny(x => x.ViewModel.CloseWhenCompleteCommand) this.WhenAny(x => x.ViewModel.CloseWhenCompleteCommand)
.BindToStrict(this, x => x.CloseButton.Command) .BindToStrict(this, x => x.CloseButton.Command)
.DisposeWith(dispose); .DisposeWith(dispose);

View File

@ -39,6 +39,13 @@
FontSize="14" FontSize="14"
Text="Target Modlist" Text="Target Modlist"
TextAlignment="Center" /> TextAlignment="Center" />
<TextBlock x:Name="errorTextBox"
Grid.Row="3"
FontFamily="Verdana" FontSize="10" FontWeight="ExtraBold"
Background="{StaticResource WindowBackgroundBrush}"
Foreground="Red"
Text=""
TextAlignment="Left" Margin="0,79,0,-45" Grid.ColumnSpan="3" />
<local:FilePicker Grid.Row="1" Grid.Column="2" <local:FilePicker Grid.Row="1" Grid.Column="2"
x:Name="ModListLocationPicker" x:Name="ModListLocationPicker"
Height="30" Height="30"
@ -74,10 +81,11 @@
<RowDefinition Height="*" /> <RowDefinition Height="*" />
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
<RowDefinition Height="*" /> <RowDefinition Height="*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions> </Grid.RowDefinitions>
<local:BeginButton Grid.Row="1" <local:BeginButton Grid.Row="1"
x:Name="BeginButton" x:Name="BeginButton"
HorizontalAlignment="Right" HorizontalAlignment="Center"
VerticalAlignment="Center" /> VerticalAlignment="Center" />
<icon:PackIconFontAwesome Grid.Row="2" <icon:PackIconFontAwesome Grid.Row="2"
x:Name="ErrorSummaryIconGlow" x:Name="ErrorSummaryIconGlow"
@ -92,8 +100,27 @@
<icon:PackIconFontAwesome Grid.Row="2" <icon:PackIconFontAwesome Grid.Row="2"
x:Name="ErrorSummaryIcon" x:Name="ErrorSummaryIcon"
HorizontalAlignment="Center" HorizontalAlignment="Center"
VerticalAlignment="Top"
Foreground="{StaticResource WarningBrush}" Foreground="{StaticResource WarningBrush}"
Kind="ExclamationTriangleSolid" /> Kind="ExclamationTriangleSolid" />
<CheckBox Grid.Row="2" Grid.Column="2"
HorizontalAlignment="Center"
VerticalAlignment="Bottom"
x:Name="OverwriteCheckBox"
Content="Overwrite Installation"
IsChecked="False"
ToolTip="Confirm to overwrite files in install folder.">
<CheckBox.Style>
<Style TargetType="CheckBox">
<Setter Property="Opacity" Value="0.6" />
<Style.Triggers>
<DataTrigger Binding="{Binding IsMouseOver, RelativeSource={RelativeSource Self}}" Value="True">
<Setter Property="Opacity" Value="1" />
</DataTrigger>
</Style.Triggers>
</Style>
</CheckBox.Style>
</CheckBox>
</Grid> </Grid>
</Grid> </Grid>
</rxui:ReactiveUserControl> </rxui:ReactiveUserControl>

View File

@ -39,6 +39,8 @@ namespace Wabbajack
this.WhenAny(x => x.ViewModel.BeginCommand) this.WhenAny(x => x.ViewModel.BeginCommand)
.BindToStrict(this, x => x.BeginButton.Command) .BindToStrict(this, x => x.BeginButton.Command)
.DisposeWith(dispose); .DisposeWith(dispose);
this.BindStrict(ViewModel, vm => vm.OverwriteFiles, x => x.OverwriteCheckBox.IsChecked)
.DisposeWith(dispose);
// Error handling // Error handling
@ -47,6 +49,11 @@ namespace Wabbajack
.BindToStrict(this, view => view.BeginButton.IsEnabled) .BindToStrict(this, view => view.BeginButton.IsEnabled)
.DisposeWith(dispose); .DisposeWith(dispose);
this.WhenAnyValue(x => x.ViewModel.ErrorState)
.Select(v => v.Reason)
.BindToStrict(this, view => view.errorTextBox.Text)
.DisposeWith(dispose);
this.WhenAnyValue(x => x.ViewModel.ErrorState) this.WhenAnyValue(x => x.ViewModel.ErrorState)
.Select(v => v.Failed ? Visibility.Visible : Visibility.Hidden) .Select(v => v.Failed ? Visibility.Visible : Visibility.Hidden)
.BindToStrict(this, view => view.ErrorSummaryIcon.Visibility) .BindToStrict(this, view => view.ErrorSummaryIcon.Visibility)

View File

@ -324,20 +324,6 @@
<local:CpuView Grid.Column="2" <local:CpuView Grid.Column="2"
x:Name="CpuView" x:Name="CpuView"
ViewModel="{Binding}" /> ViewModel="{Binding}" />
<!--
<local:AttentionBorder Grid.Column="2"
x:Name="UserInterventionsControl"
Content="{Binding ActiveGlobalUserIntervention}">
<local:AttentionBorder.Resources>
<DataTemplate DataType="{x:Type lib1:ConfirmationIntervention}">
<local:ConfirmationInterventionView ViewModel="{Binding}" />
</DataTemplate>
<DataTemplate DataType="{x:Type local:ConfirmUpdateOfExistingInstallVM}">
<local:ConfirmUpdateOfExistingInstallView ViewModel="{Binding}" />
</DataTemplate>
</local:AttentionBorder.Resources>
</local:AttentionBorder>
-->
<local:InstallationCompleteView Grid.Column="2" <local:InstallationCompleteView Grid.Column="2"
x:Name="InstallComplete" x:Name="InstallComplete"
ViewModel="{Binding}" /> ViewModel="{Binding}" />

View File

@ -46,21 +46,5 @@
FontSize="14" FontSize="14"
PickerVM="{Binding DownloadLocation}" PickerVM="{Binding DownloadLocation}"
ToolTip="The directory where modlist archives will be downloaded to" /> ToolTip="The directory where modlist archives will be downloaded to" />
<CheckBox Grid.Row="2" Grid.Column="2"
HorizontalAlignment="Right"
Content="Overwrite Installation"
IsChecked="{Binding AutomaticallyOverwrite}"
ToolTip="If installing over an existing installation, automatically replace it without asking permission.">
<CheckBox.Style>
<Style TargetType="CheckBox">
<Setter Property="Opacity" Value="0.6" />
<Style.Triggers>
<DataTrigger Binding="{Binding IsMouseOver, RelativeSource={RelativeSource Self}}" Value="True">
<Setter Property="Opacity" Value="1" />
</DataTrigger>
</Style.Triggers>
</Style>
</CheckBox.Style>
</CheckBox>
</Grid> </Grid>
</UserControl> </UserControl>

View File

@ -1,50 +0,0 @@
<rxui:ReactiveUserControl
x:Class="Wabbajack.ConfirmUpdateOfExistingInstallView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:lib="clr-namespace:Wabbajack;assembly=Wabbajack"
xmlns:local="clr-namespace:Wabbajack"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:rxui="http://reactiveui.net"
d:DesignHeight="450"
d:DesignWidth="800"
x:TypeArguments="local:ConfirmUpdateOfExistingInstallVM"
mc:Ignorable="d">
<Grid Margin="10">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="10" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="5*" />
<RowDefinition Height="Auto" />
<RowDefinition Height="2*" />
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="3"
x:Name="ShortDescription"
Margin="0,0,0,5"
FontFamily="Lucida Sans"
FontSize="14"
FontWeight="Bold"
TextWrapping="WrapWithOverflow" />
<TextBlock Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="3"
x:Name="ExtendedDescription"
TextWrapping="WrapWithOverflow" />
<CheckBox Grid.Row="2" Grid.Column="2"
x:Name="AutoOverwriteCheckbox"
Margin="4"
HorizontalAlignment="Right"
Content="Remember"
IsChecked="{Binding Installer.AutomaticallyOverwrite}"
ToolTip="If installing over an existing installation next time, automatically replace it without asking permission." />
<Button Grid.Row="3" Grid.Column="0"
x:Name="CancelButton"
Content="Cancel" />
<Button Grid.Row="3" Grid.Column="2"
x:Name="ConfirmButton"
Content="Confirm" />
</Grid>
</rxui:ReactiveUserControl>

View File

@ -1,51 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reactive.Disposables;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using ReactiveUI;
using Wabbajack;
namespace Wabbajack
{
/// <summary>
/// Interaction logic for ConfirmUpdateOfExistingInstallView.xaml
/// </summary>
public partial class ConfirmUpdateOfExistingInstallView : ReactiveUserControl<ConfirmUpdateOfExistingInstallVM>
{
public ConfirmUpdateOfExistingInstallView()
{
InitializeComponent();
this.WhenActivated(dispose =>
{
this.WhenAny(x => x.ViewModel.ShortDescription)
.BindToStrict(this, x => x.ShortDescription.Text)
.DisposeWith(dispose);
this.WhenAny(x => x.ViewModel.ExtendedDescription)
.BindToStrict(this, x => x.ExtendedDescription.Text)
.DisposeWith(dispose);
this.WhenAny(x => x.ViewModel.Source.ConfirmCommand)
.BindToStrict(this, x => x.ConfirmButton.Command)
.DisposeWith(dispose);
this.WhenAny(x => x.ViewModel.Source.CancelCommand)
.BindToStrict(this, x => x.CancelButton.Command)
.DisposeWith(dispose);
this.BindStrict(this.ViewModel, x => x.Installer.AutomaticallyOverwrite, x => x.AutoOverwriteCheckbox.IsChecked,
vmToViewConverter: x => x,
viewToVmConverter: x => x ?? false)
.DisposeWith(dispose);
});
}
}
}

View File

@ -1,26 +1,17 @@
using System; using System;
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using System.ComponentModel; using System.ComponentModel;
using System.Linq;
using System.Reactive.Linq; using System.Reactive.Linq;
using System.Threading;
using System.Windows; using System.Windows;
using System.Windows.Input; using System.Windows.Input;
using DynamicData;
using DynamicData.Binding; using DynamicData.Binding;
using MahApps.Metro.Controls; using MahApps.Metro.Controls;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using ReactiveUI; using ReactiveUI;
using ReactiveUI.Fody.Helpers;
using Wabbajack.Common; using Wabbajack.Common;
using Wabbajack.DTOs;
using Wabbajack.DTOs.DownloadStates;
using Wabbajack.DTOs.Interventions;
using Wabbajack.Messages; using Wabbajack.Messages;
using Wabbajack.Paths.IO; using Wabbajack.Paths.IO;
using Wabbajack.UserIntervention;
using Wabbajack.Util; using Wabbajack.Util;
using Wabbajack.Views;
namespace Wabbajack namespace Wabbajack
{ {
@ -30,7 +21,6 @@ namespace Wabbajack
public partial class MainWindow : MetroWindow public partial class MainWindow : MetroWindow
{ {
private MainWindowVM _mwvm; private MainWindowVM _mwvm;
private MainSettings _settings;
private readonly ILogger<MainWindow> _logger; private readonly ILogger<MainWindow> _logger;
private readonly SystemParametersConstructor _systemParams; private readonly SystemParametersConstructor _systemParams;
@ -85,25 +75,8 @@ namespace Wabbajack
else if (p.SystemPageSize < 2e+10) else if (p.SystemPageSize < 2e+10)
_logger.LogInformation("Pagefile below recommended! Consider increasing to 20000MB. A suboptimal pagefile can cause crashes and poor in-game performance"); _logger.LogInformation("Pagefile below recommended! Consider increasing to 20000MB. A suboptimal pagefile can cause crashes and poor in-game performance");
//Warmup();
var _ = updater.Run(); var _ = updater.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);
}*/
// Bring window to the front if it isn't already // Bring window to the front if it isn't already
this.Initialized += (s, e) => this.Initialized += (s, e) =>
{ {
@ -138,44 +111,6 @@ namespace Wabbajack
} }
public void Init(MainWindowVM vm, MainSettings settings)
{
DataContext = vm;
_mwvm = vm;
_settings = settings;
}
private void RunWhenLoaded(Action a)
{
if (IsLoaded)
{
a();
}
else
{
this.Loaded += (sender, e) =>
{
a();
};
}
}
private void LoadSettings()
{
Width = _settings.Width;
Height = _settings.Height;
Left = _settings.PosX;
Top = _settings.PosY;
}
private void DefaultSettings()
{
Width = 1300;
Height = 960;
Left = 15;
Top = 15;
}
private void Window_Closing(object sender, CancelEventArgs e) private void Window_Closing(object sender, CancelEventArgs e)
{ {
_mwvm.ShutdownApplication().Wait(); _mwvm.ShutdownApplication().Wait();

View File

@ -6,7 +6,6 @@
xmlns:local="clr-namespace:Wabbajack" xmlns:local="clr-namespace:Wabbajack"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:rxui="http://reactiveui.net" xmlns:rxui="http://reactiveui.net"
xmlns:xwpf="http://schemas.xceed.com/wpf/xaml/toolkit"
d:DesignHeight="450" d:DesignHeight="450"
d:DesignWidth="800" d:DesignWidth="800"
x:TypeArguments="local:SettingsVM" x:TypeArguments="local:SettingsVM"
@ -32,17 +31,19 @@
<ColumnDefinition Width="5" /> <ColumnDefinition Width="5" />
<ColumnDefinition Width="*" /> <ColumnDefinition Width="*" />
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Grid.ColumnSpan="2" <TextBlock
Grid.Column="0"
Grid.ColumnSpan="2"
FontFamily="Lucida Sans" FontFamily="Lucida Sans"
FontSize="20" FontSize="20"
FontWeight="Bold" FontWeight="Bold"
Text="Misc Settings" /> Text="Misc Settings" />
<Grid Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="3"> <Grid
Grid.Row="2"
Grid.Column="0"
Grid.ColumnSpan="3">
<Grid.RowDefinitions> <Grid.RowDefinitions>
<RowDefinition /> <RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions> </Grid.RowDefinitions>
<Grid.Resources> <Grid.Resources>
<Style BasedOn="{StaticResource MainButtonStyle}" TargetType="Button"> <Style BasedOn="{StaticResource MainButtonStyle}" TargetType="Button">
@ -55,32 +56,9 @@
</Style.Triggers> </Style.Triggers>
</Style> </Style>
</Grid.Resources> </Grid.Resources>
<CheckBox Grid.Row="0" <Button
Name="FilterPersistCheckBox"
Margin="0,5,0,0"
HorizontalAlignment="Left"
VerticalAlignment="Top"
Content="Gallery filters are saved on exit">
<CheckBox.LayoutTransform>
<ScaleTransform ScaleX="1.2" ScaleY="1.2" />
</CheckBox.LayoutTransform>
</CheckBox>
<CheckBox Grid.Row="1"
Name="UseCompressionCheckBox"
Margin="0,5,0,0"
HorizontalAlignment="Left"
VerticalAlignment="Top"
Content="Use NTFS LZS compression during install">
<CheckBox.LayoutTransform>
<ScaleTransform ScaleX="1.2" ScaleY="1.2" />
</CheckBox.LayoutTransform>
</CheckBox>
<Button Grid.Row="2"
Name="ClearCefCache"
Margin="0,5,0,0"
Content="Clear In-App Browser Cache" />
<Button Grid.Row="3"
Name="OpenTerminal" Name="OpenTerminal"
Grid.Row="0"
Margin="0,5,0,0" Margin="0,5,0,0"
Content="Launch Wabbajack CLI" /> Content="Launch Wabbajack CLI" />
</Grid> </Grid>

View File

@ -15,10 +15,6 @@ namespace Wabbajack
this.WhenActivated(disposable => this.WhenActivated(disposable =>
{ {
// Bind Values // Bind Values
this.BindStrict(this.ViewModel, x => x.Filters.IsPersistent, x => x.FilterPersistCheckBox.IsChecked)
.DisposeWith(disposable);
this.BindStrict(this.ViewModel, x => x.Filters.UseCompression, x => x.UseCompressionCheckBox.IsChecked)
.DisposeWith(disposable);
this.WhenAnyValue(x => x.ViewModel.OpenTerminalCommand) this.WhenAnyValue(x => x.ViewModel.OpenTerminalCommand)
.BindToStrict(this, x => x.OpenTerminal.Command) .BindToStrict(this, x => x.OpenTerminal.Command)
.DisposeWith(disposable); .DisposeWith(disposable);

View File

@ -24,7 +24,7 @@
<RowDefinition Height="10" /> <RowDefinition Height="10" />
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
<RowDefinition Height="25" /> <RowDefinition Height="25" />
<RowDefinition Height="25" /> <RowDefinition Height="Auto" />
<RowDefinition Height="25" /> <RowDefinition Height="25" />
<RowDefinition Height="25" /> <RowDefinition Height="25" />
<RowDefinition Height="25" /> <RowDefinition Height="25" />
@ -34,16 +34,43 @@
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" /> <ColumnDefinition Width="Auto" />
<ColumnDefinition Width="5" /> <ColumnDefinition Width="5" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" /> <ColumnDefinition Width="*" />
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Grid.ColumnSpan="2" <TextBlock
Grid.Column="0"
Grid.ColumnSpan="3"
FontFamily="Lucida Sans" FontFamily="Lucida Sans"
FontSize="20" FontSize="20"
FontWeight="Bold" FontWeight="Bold"
Text="Performance" /> Text="Performance" />
<Button Grid.Row="2" x:Name="EditResourceSettings"> <Button x:Name="EditResourceSettings" Grid.Row="2">
<TextBlock FontSize="14" FontWeight="Bold">Edit Resource Usage Settings and Close Wabbajack</TextBlock> <TextBlock FontSize="14" FontWeight="Bold">Edit Resource Usage Settings and Close Wabbajack</TextBlock>
</Button> </Button>
<TextBlock
Grid.Row="4"
FontSize="14"
Foreground="{StaticResource ForegroundBrush}"
Text="Maximum RAM per download thread (MB)"
ToolTip="Defines the maximum amount of RAM each download thread can use for buffering. Set to 0 to disable this limit completely." />
<xwpf:IntegerUpDown
x:Name="MaximumMemoryPerDownloadThreadIntegerUpDown"
Grid.Row="4"
Grid.Column="2"
Width="80"
HorizontalAlignment="Left"
Foreground="{StaticResource ForegroundBrush}"
Maximum="10000"
Minimum="0" />
<Button
x:Name="ResetMaximumMemoryPerDownloadThread"
Grid.Row="4"
Grid.Column="3"
Margin="20,0,0,0"
Padding="10,0"
HorizontalAlignment="Left">
<TextBlock FontSize="14">Reset</TextBlock>
</Button>
</Grid> </Grid>
</Border> </Border>
</rxui:ReactiveUserControl> </rxui:ReactiveUserControl>

View File

@ -1,4 +1,5 @@
using System; using System;
using System.Reactive.Disposables;
using ReactiveUI; using ReactiveUI;
using Wabbajack.Paths.IO; using Wabbajack.Paths.IO;
@ -15,12 +16,21 @@ namespace Wabbajack
this.WhenActivated(disposable => this.WhenActivated(disposable =>
{ {
this.BindStrict(
ViewModel,
x => x.MaximumMemoryPerDownloadThreadMb,
x => x.MaximumMemoryPerDownloadThreadIntegerUpDown.Value)
.DisposeWith(disposable);
this.EditResourceSettings.Command = ReactiveCommand.Create(() => this.EditResourceSettings.Command = ReactiveCommand.Create(() =>
{ {
UIUtils.OpenFile( UIUtils.OpenFile(
KnownFolders.WabbajackAppLocal.Combine("saved_settings", "resource_settings.json")); KnownFolders.WabbajackAppLocal.Combine("saved_settings", "resource_settings.json"));
Environment.Exit(0); Environment.Exit(0);
}); });
ResetMaximumMemoryPerDownloadThread.Command = ReactiveCommand.Create(() =>
{
ViewModel.ResetMaximumMemoryPerDownloadThreadMb();
});
}); });
} }
} }

View File

@ -2,7 +2,7 @@
<PropertyGroup> <PropertyGroup>
<OutputType>WinExe</OutputType> <OutputType>WinExe</OutputType>
<TargetFramework>net6.0-windows</TargetFramework> <TargetFramework>net7.0-windows</TargetFramework>
<UseWPF>true</UseWPF> <UseWPF>true</UseWPF>
<Platforms>x64</Platforms> <Platforms>x64</Platforms>
<RuntimeIdentifier>win10-x64</RuntimeIdentifier> <RuntimeIdentifier>win10-x64</RuntimeIdentifier>
@ -73,12 +73,12 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="DynamicData" Version="7.12.1" /> <PackageReference Include="DynamicData" Version="8.0.2" />
<PackageReference Include="Extended.Wpf.Toolkit" Version="4.4.0"> <PackageReference Include="Extended.Wpf.Toolkit" Version="4.4.0">
<NoWarn>NU1701</NoWarn> <NoWarn>NU1701</NoWarn>
</PackageReference> </PackageReference>
<PackageReference Include="Fizzler.Systems.HtmlAgilityPack" Version="1.2.1" /> <PackageReference Include="Fizzler.Systems.HtmlAgilityPack" Version="1.2.1" />
<PackageReference Include="Fody" Version="6.6.4"> <PackageReference Include="Fody" Version="6.8.0">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference> </PackageReference>
@ -95,11 +95,11 @@
<PackageReference Include="NLog.Extensions.Logging" Version="5.1.0" /> <PackageReference Include="NLog.Extensions.Logging" Version="5.1.0" />
<PackageReference Include="Orc.FileAssociation" Version="5.0.0-alpha0061" /> <PackageReference Include="Orc.FileAssociation" Version="5.0.0-alpha0061" />
<PackageReference Include="PInvoke.User32" Version="0.7.124" /> <PackageReference Include="PInvoke.User32" Version="0.7.124" />
<PackageReference Include="ReactiveUI" Version="18.3.1" /> <PackageReference Include="ReactiveUI" Version="19.5.1" />
<PackageReference Include="ReactiveUI.Fody" Version="18.3.1" /> <PackageReference Include="ReactiveUI.Fody" Version="19.5.1" />
<PackageReference Include="ReactiveUI.WPF" Version="18.3.1" /> <PackageReference Include="ReactiveUI.WPF" Version="19.5.1" />
<PackageReference Include="Silk.NET.DXGI" Version="2.16.0" /> <PackageReference Include="Silk.NET.DXGI" Version="2.16.0" />
<PackageReference Include="System.Reactive" Version="5.0.0" /> <PackageReference Include="System.Reactive" Version="6.0.1-preview.1" />
<PackageReference Include="WPFThemes.DarkBlend" Version="1.0.8" /> <PackageReference Include="WPFThemes.DarkBlend" Version="1.0.8" />
</ItemGroup> </ItemGroup>

View File

@ -1,14 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net6.0</TargetFramework> <TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="6.0.2-mauipre.1.22102.15" /> <PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="6.0.2-mauipre.1.22102.15" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="6.0.2-mauipre.1.22102.15" /> <PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="6.0.2-mauipre.1.22102.15" /> <PackageReference Include="Microsoft.Extensions.Hosting" Version="6.0.2-mauipre.1.22102.15" />
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="6.0.2-mauipre.1.22102.15" /> <PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="6.0.2-mauipre.1.22102.15" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="6.0.3" /> <PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="6.0.3" />

View File

@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<OutputType>Exe</OutputType> <OutputType>Exe</OutputType>
@ -13,11 +13,12 @@
<NoWarn>CS8600</NoWarn> <NoWarn>CS8600</NoWarn>
<NoWarn>CS8601</NoWarn> <NoWarn>CS8601</NoWarn>
<NoWarn>CS8618</NoWarn> <NoWarn>CS8618</NoWarn>
<TargetFramework>net7.0</TargetFramework>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="6.0.2-mauipre.1.22102.15" /> <PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="6.0.2-mauipre.1.22102.15" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="6.0.2-mauipre.1.22102.15" /> <PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="6.0.2-mauipre.1.22102.15" /> <PackageReference Include="Microsoft.Extensions.Hosting" Version="6.0.2-mauipre.1.22102.15" />
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="6.0.2-mauipre.1.22102.15" /> <PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="6.0.2-mauipre.1.22102.15" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="6.0.3" /> <PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="6.0.3" />

View File

@ -14,12 +14,21 @@ namespace Wabbajack.Common;
public static class HttpExtensions public static class HttpExtensions
{ {
private const string ChromeUserAgent =
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Safari/537.36";
public static HttpRequestMessage AddCookies(this HttpRequestMessage msg, Cookie[] cookies) public static HttpRequestMessage AddCookies(this HttpRequestMessage msg, Cookie[] cookies)
{ {
msg.Headers.Add("Cookie", string.Join(";", cookies.Select(c => $"{c.Name}={c.Value}"))); msg.Headers.Add("Cookie", string.Join(";", cookies.Select(c => $"{c.Name}={c.Value}")));
return msg; return msg;
} }
public static HttpRequestMessage AddChromeAgent(this HttpRequestMessage msg, string? overrideUserAgent = null)
{
msg.Headers.UserAgent.Clear();
msg.Headers.Add("User-Agent", overrideUserAgent ?? ChromeUserAgent);
return msg;
}
public static HttpRequestMessage AddHeaders(this HttpRequestMessage msg, IEnumerable<(string Key, string Value)> headers) public static HttpRequestMessage AddHeaders(this HttpRequestMessage msg, IEnumerable<(string Key, string Value)> headers)
{ {
foreach (var header in headers) foreach (var header in headers)
@ -29,17 +38,10 @@ public static class HttpExtensions
return msg; return msg;
} }
public static HttpRequestMessage AddChromeAgent(this HttpRequestMessage msg)
{
msg.Headers.Add("User-Agent",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Safari/537.36");
return msg;
}
public static HttpRequestMessage ToHttpRequestMessage(this ManualDownload.BrowserDownloadState browserState) public static HttpRequestMessage ToHttpRequestMessage(this ManualDownload.BrowserDownloadState browserState)
{ {
var msg = new HttpRequestMessage(HttpMethod.Get, browserState.Uri); var msg = new HttpRequestMessage(HttpMethod.Get, browserState.Uri);
msg.AddChromeAgent(); msg.AddChromeAgent(browserState.UserAgent);
msg.AddCookies(browserState.Cookies); msg.AddCookies(browserState.Cookies);
msg.AddHeaders(browserState.Headers); msg.AddHeaders(browserState.Headers);
return msg; return msg;

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net6.0</TargetFramework> <TargetFramework>net7.0</TargetFramework>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<PackageLicenseExpression>GPL-3.0-or-later</PackageLicenseExpression> <PackageLicenseExpression>GPL-3.0-or-later</PackageLicenseExpression>
<Version>$(VERSION)</Version> <Version>$(VERSION)</Version>
@ -34,7 +34,7 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="6.0.3" /> <PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="6.0.3" />
<PackageReference Include="System.Reactive" Version="5.0.0" /> <PackageReference Include="System.Reactive" Version="6.0.1-preview.1" />
</ItemGroup> </ItemGroup>
<PropertyGroup Condition=" '$(OS)' == 'Windows_NT' "> <PropertyGroup Condition=" '$(OS)' == 'Windows_NT' ">

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net6.0</TargetFramework> <TargetFramework>net7.0</TargetFramework>
<IsPackable>false</IsPackable> <IsPackable>false</IsPackable>

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net6.0</TargetFramework> <TargetFramework>net7.0</TargetFramework>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<Version>$(VERSION)</Version> <Version>$(VERSION)</Version>
<PackageLicenseExpression>GPL-3.0-or-later</PackageLicenseExpression> <PackageLicenseExpression>GPL-3.0-or-later</PackageLicenseExpression>

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net6.0</TargetFramework> <TargetFramework>net7.0</TargetFramework>
<IsPackable>false</IsPackable> <IsPackable>false</IsPackable>
</PropertyGroup> </PropertyGroup>

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net6.0</TargetFramework> <TargetFramework>net7.0</TargetFramework>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks> <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<PackageLicenseExpression>GPL-3.0-or-later</PackageLicenseExpression> <PackageLicenseExpression>GPL-3.0-or-later</PackageLicenseExpression>

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net6.0</TargetFramework> <TargetFramework>net7.0</TargetFramework>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<IsPackable>false</IsPackable> <IsPackable>false</IsPackable>

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net6.0</TargetFramework> <TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
</PropertyGroup> </PropertyGroup>

View File

@ -0,0 +1,27 @@
namespace Wabbajack.Configuration;
public class MainSettings
{
public const string SettingsFileName = "app_settings";
private const int SettingsVersion = 1;
public int CurrentSettingsVersion { get; set; }
public PerformanceSettings PerformanceSettings { get; set; } = new();
public bool Upgrade()
{
if (CurrentSettingsVersion == SettingsVersion)
{
return false;
}
if (CurrentSettingsVersion < 1)
{
PerformanceSettings.MaximumMemoryPerDownloadThreadMb = -1;
}
CurrentSettingsVersion = SettingsVersion;
return true;
}
}

View File

@ -0,0 +1,6 @@
namespace Wabbajack.Configuration;
public class PerformanceSettings
{
public int MaximumMemoryPerDownloadThreadMb { get; set; }
}

View File

@ -0,0 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>

View File

@ -2,7 +2,7 @@
<PropertyGroup> <PropertyGroup>
<OutputType>Exe</OutputType> <OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework> <TargetFramework>net7.0</TargetFramework>
<PackageLicenseExpression>GPL-3.0-or-later</PackageLicenseExpression> <PackageLicenseExpression>GPL-3.0-or-later</PackageLicenseExpression>
<Version>$(VERSION)</Version> <Version>$(VERSION)</Version>
<NoWarn>CS8600</NoWarn> <NoWarn>CS8600</NoWarn>

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net6.0</TargetFramework> <TargetFramework>net7.0</TargetFramework>
<IsPackable>false</IsPackable> <IsPackable>false</IsPackable>
</PropertyGroup> </PropertyGroup>

View File

@ -21,7 +21,7 @@ public class GameMetaData
public int[] SteamIDs { get; internal init; } = Array.Empty<int>(); public int[] SteamIDs { get; internal init; } = Array.Empty<int>();
// to get gog ids: https://www.gogdb.org // to get gog ids: https://www.gogdb.org
public int[] GOGIDs { get; internal init; } = Array.Empty<int>(); public long[] GOGIDs { get; internal init; } = Array.Empty<long>();
// to get these ids, split the numbers from the letters in file names found in // to get these ids, split the numbers from the letters in file names found in
// C:\ProgramData\Origin\LocalContent\{game name)\*.mfst // C:\ProgramData\Origin\LocalContent\{game name)\*.mfst

View File

@ -14,7 +14,7 @@ public static class GameRegistry
{ {
Game = Game.Morrowind, Game = Game.Morrowind,
SteamIDs = new[] {22320}, SteamIDs = new[] {22320},
GOGIDs = new[] {1440163901, 1435828767}, GOGIDs = new long[] {1440163901, 1435828767},
NexusName = "morrowind", NexusName = "morrowind",
NexusGameId = 100, NexusGameId = 100,
MO2Name = "Morrowind", MO2Name = "Morrowind",
@ -38,7 +38,7 @@ public static class GameRegistry
MO2Name = "Oblivion", MO2Name = "Oblivion",
MO2ArchiveName = "oblivion", MO2ArchiveName = "oblivion",
SteamIDs = new[] {22330}, SteamIDs = new[] {22330},
GOGIDs = new[] {1458058109}, GOGIDs = new long[] {1458058109},
RequiredFiles = new[] RequiredFiles = new[]
{ {
"oblivion.exe".ToRelativePath() "oblivion.exe".ToRelativePath()
@ -56,7 +56,7 @@ public static class GameRegistry
MO2Name = "Fallout 3", MO2Name = "Fallout 3",
MO2ArchiveName = "fallout3", MO2ArchiveName = "fallout3",
SteamIDs = new[] {22300, 22370}, // base game and GotY SteamIDs = new[] {22300, 22370}, // base game and GotY
GOGIDs = new[] {1454315831}, // GotY edition GOGIDs = new long[] {1454315831}, // GotY edition
RequiredFiles = new[] RequiredFiles = new[]
{ {
"Fallout3.exe".ToRelativePath() "Fallout3.exe".ToRelativePath()
@ -73,7 +73,7 @@ public static class GameRegistry
MO2Name = "New Vegas", MO2Name = "New Vegas",
MO2ArchiveName = "falloutnv", MO2ArchiveName = "falloutnv",
SteamIDs = new[] {22380, 22490}, // normal and RU version SteamIDs = new[] {22380, 22490}, // normal and RU version
GOGIDs = new[] {1454587428}, GOGIDs = new long[] {1454587428},
RequiredFiles = new[] RequiredFiles = new[]
{ {
"FalloutNV.exe".ToRelativePath() "FalloutNV.exe".ToRelativePath()
@ -107,7 +107,7 @@ public static class GameRegistry
MO2Name = "Skyrim Special Edition", MO2Name = "Skyrim Special Edition",
MO2ArchiveName = "skyrimse", MO2ArchiveName = "skyrimse",
SteamIDs = new[] {489830}, SteamIDs = new[] {489830},
GOGIDs = new[] GOGIDs = new long[]
{ {
1711230643,// The Elder Scrolls V: Skyrim Special Edition AKA Base Game 1711230643,// The Elder Scrolls V: Skyrim Special Edition AKA Base Game
1801825368,// The Elder Scrolls V: Skyrim Anniversary Edition AKA The Store Bundle 1801825368,// The Elder Scrolls V: Skyrim Anniversary Edition AKA The Store Bundle
@ -130,6 +130,7 @@ public static class GameRegistry
MO2Name = "Fallout 4", MO2Name = "Fallout 4",
MO2ArchiveName = "fallout4", MO2ArchiveName = "fallout4",
SteamIDs = new[] {377160}, SteamIDs = new[] {377160},
GOGIDs = new long[]{1998527297},
RequiredFiles = new[] RequiredFiles = new[]
{ {
"Fallout4.exe".ToRelativePath() "Fallout4.exe".ToRelativePath()
@ -182,7 +183,7 @@ public static class GameRegistry
MO2Name = "Enderal Special Edition", MO2Name = "Enderal Special Edition",
MO2ArchiveName = "enderalse", MO2ArchiveName = "enderalse",
SteamIDs = new[] {976620}, SteamIDs = new[] {976620},
GOGIDs = new [] {1708684988}, GOGIDs = new long[] {1708684988},
RequiredFiles = new[] RequiredFiles = new[]
{ {
"SkyrimSE.exe".ToRelativePath() "SkyrimSE.exe".ToRelativePath()
@ -216,7 +217,7 @@ public static class GameRegistry
MO2Name = "Darkest Dungeon", MO2Name = "Darkest Dungeon",
NexusGameId = 804, NexusGameId = 804,
SteamIDs = new[] {262060}, SteamIDs = new[] {262060},
GOGIDs = new[] {1450711444}, GOGIDs = new long[] {1450711444},
EpicGameStoreIDs = new[] {"b4eecf70e3fe4e928b78df7855a3fc2d"}, EpicGameStoreIDs = new[] {"b4eecf70e3fe4e928b78df7855a3fc2d"},
IsGenericMO2Plugin = true, IsGenericMO2Plugin = true,
RequiredFiles = new[] RequiredFiles = new[]
@ -235,7 +236,7 @@ public static class GameRegistry
MO2ArchiveName = "dishonored", MO2ArchiveName = "dishonored",
NexusGameId = 802, NexusGameId = 802,
SteamIDs = new[] {205100}, SteamIDs = new[] {205100},
GOGIDs = new[] {1701063787}, GOGIDs = new long[] {1701063787},
RequiredFiles = new[] RequiredFiles = new[]
{ {
@"Binaries\Win32\Dishonored.exe".ToRelativePath() @"Binaries\Win32\Dishonored.exe".ToRelativePath()
@ -252,7 +253,7 @@ public static class GameRegistry
MO2Name = "The Witcher: Enhanced Edition", MO2Name = "The Witcher: Enhanced Edition",
MO2ArchiveName = "witcher", MO2ArchiveName = "witcher",
SteamIDs = new[] {20900}, // normal and GotY SteamIDs = new[] {20900}, // normal and GotY
GOGIDs = new[] {1207658924}, // normal, GotY and both in packages GOGIDs = new long[] {1207658924}, // normal, GotY and both in packages
RequiredFiles = new[] RequiredFiles = new[]
{ {
@"System\witcher.exe".ToRelativePath() @"System\witcher.exe".ToRelativePath()
@ -269,7 +270,7 @@ public static class GameRegistry
MO2Name = "The Witcher 3: Wild Hunt", MO2Name = "The Witcher 3: Wild Hunt",
MO2ArchiveName = "witcher3", MO2ArchiveName = "witcher3",
SteamIDs = new[] {292030, 499450}, // normal and GotY SteamIDs = new[] {292030, 499450}, // normal and GotY
GOGIDs = new[] GOGIDs = new long[]
{1207664643, 1495134320, 1207664663, 1640424747}, // normal, GotY and both in packages {1207664643, 1495134320, 1207664663, 1640424747}, // normal, GotY and both in packages
RequiredFiles = new[] RequiredFiles = new[]
{ {
@ -287,7 +288,7 @@ public static class GameRegistry
MO2ArchiveName = "stardewvalley", MO2ArchiveName = "stardewvalley",
NexusGameId = 1303, NexusGameId = 1303,
SteamIDs = new[] {413150}, SteamIDs = new[] {413150},
GOGIDs = new[] {1453375253}, GOGIDs = new long[] {1453375253},
IsGenericMO2Plugin = true, IsGenericMO2Plugin = true,
RequiredFiles = new[] RequiredFiles = new[]
{ {
@ -305,7 +306,7 @@ public static class GameRegistry
MO2ArchiveName = "kingdomcomedeliverance", MO2ArchiveName = "kingdomcomedeliverance",
NexusGameId = 2298, NexusGameId = 2298,
SteamIDs = new[] {379430}, SteamIDs = new[] {379430},
GOGIDs = new[] {1719198803}, GOGIDs = new long[] {1719198803},
IsGenericMO2Plugin = true, IsGenericMO2Plugin = true,
RequiredFiles = new[] RequiredFiles = new[]
{ {
@ -339,7 +340,7 @@ public static class GameRegistry
NexusGameId = 1634, NexusGameId = 1634,
MO2Name = "No Man's Sky", MO2Name = "No Man's Sky",
SteamIDs = new[] {275850}, SteamIDs = new[] {275850},
GOGIDs = new[] {1446213994}, GOGIDs = new long[] {1446213994},
RequiredFiles = new[] RequiredFiles = new[]
{ {
@"Binaries\NMS.exe".ToRelativePath() @"Binaries\NMS.exe".ToRelativePath()
@ -356,7 +357,7 @@ public static class GameRegistry
MO2Name = "Dragon Age: Origins", MO2Name = "Dragon Age: Origins",
SteamIDs = new[] {47810}, SteamIDs = new[] {47810},
OriginIDs = new[] {"DR:169789300", "DR:208591800"}, OriginIDs = new[] {"DR:169789300", "DR:208591800"},
GOGIDs = new[] {1949616134}, GOGIDs = new long[] {1949616134},
RequiredFiles = new[] RequiredFiles = new[]
{ {
@"bin_ship\daorigins.exe".ToRelativePath() @"bin_ship\daorigins.exe".ToRelativePath()
@ -404,7 +405,7 @@ public static class GameRegistry
MO2Name = "Kerbal Space Program", MO2Name = "Kerbal Space Program",
NexusGameId = 272, NexusGameId = 272,
SteamIDs = new[] {220200}, SteamIDs = new[] {220200},
GOGIDs = new[] {1429864849}, GOGIDs = new long[] {1429864849},
IsGenericMO2Plugin = true, IsGenericMO2Plugin = true,
RequiredFiles = new[] RequiredFiles = new[]
{ {
@ -432,7 +433,7 @@ public static class GameRegistry
{ {
Game = Game.Cyberpunk2077, Game = Game.Cyberpunk2077,
SteamIDs = new[] {1091500}, SteamIDs = new[] {1091500},
GOGIDs = new [] {2093619782, 1423049311}, GOGIDs = new long[] {2093619782, 1423049311},
EpicGameStoreIDs = new[] {"5beededaad9743df90e8f07d92df153f"}, EpicGameStoreIDs = new[] {"5beededaad9743df90e8f07d92df153f"},
MO2Name = "Cyberpunk 2077", MO2Name = "Cyberpunk 2077",
NexusName = "cyberpunk2077", NexusName = "cyberpunk2077",
@ -466,7 +467,7 @@ public static class GameRegistry
{ {
Game = Game.DragonsDogma, Game = Game.DragonsDogma,
SteamIDs = new[] {367500 }, SteamIDs = new[] {367500 },
GOGIDs = new []{1242384383}, GOGIDs = new long[]{1242384383},
MO2Name = "Dragon's Dogma: Dark Arisen", MO2Name = "Dragon's Dogma: Dark Arisen",
MO2ArchiveName = "dragonsdogma", MO2ArchiveName = "dragonsdogma",
NexusName = "dragonsdogma", NexusName = "dragonsdogma",
@ -520,7 +521,7 @@ public static class GameRegistry
MO2Name = "Mount & Blade II: Bannerlord", MO2Name = "Mount & Blade II: Bannerlord",
MO2ArchiveName = "mountandblade2bannerlord", MO2ArchiveName = "mountandblade2bannerlord",
SteamIDs = new[] { 261550 }, SteamIDs = new[] { 261550 },
GOGIDs = new [] { GOGIDs = new long[] {
1564781494, //Mount & Blade II: Bannerlord : Game 1564781494, //Mount & Blade II: Bannerlord : Game
1681929523, //Mount & Blade II: Bannerlord - Digital Deluxe : Package 1681929523, //Mount & Blade II: Bannerlord - Digital Deluxe : Package
1802539526, //Mount & Blade II: Bannerlord : Package 1802539526, //Mount & Blade II: Bannerlord : Package

View File

@ -16,7 +16,7 @@ public class ManualDownload : AUserIntervention<ManualDownload.BrowserDownloadSt
Archive = archive; Archive = archive;
} }
public record BrowserDownloadState(Uri Uri, Cookie[] Cookies, (string Key, string Value)[] Headers) public record BrowserDownloadState(Uri Uri, Cookie[] Cookies, (string Key, string Value)[] Headers, string UserAgent)
{ {
} }

View File

@ -30,6 +30,8 @@ public class ModlistMetadata
[JsonPropertyName("image_contains_title")] [JsonPropertyName("image_contains_title")]
public bool ImageContainsTitle { get; set; } public bool ImageContainsTitle { get; set; }
[JsonPropertyName("DisplayVersionOnlyInInstallerView")] public bool DisplayVersionOnlyInInstallerView { get; set; }
[JsonPropertyName("force_down")] public bool ForceDown { get; set; } [JsonPropertyName("force_down")] public bool ForceDown { get; set; }
[JsonPropertyName("links")] public LinksObject Links { get; set; } = new(); [JsonPropertyName("links")] public LinksObject Links { get; set; } = new();

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net6.0</TargetFramework> <TargetFramework>net7.0</TargetFramework>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<Version>$(VERSION)</Version> <Version>$(VERSION)</Version>
<PackageLicenseExpression>GPL-3.0-or-later</PackageLicenseExpression> <PackageLicenseExpression>GPL-3.0-or-later</PackageLicenseExpression>

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net6.0</TargetFramework> <TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
</PropertyGroup> </PropertyGroup>

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net6.0</TargetFramework> <TargetFramework>net7.0</TargetFramework>
<IsPackable>false</IsPackable> <IsPackable>false</IsPackable>
</PropertyGroup> </PropertyGroup>
@ -11,7 +11,7 @@
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
</PackageReference> </PackageReference>
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="6.0.2-mauipre.1.22102.15" /> <PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="7.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.5.0-preview-20221003-04" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.5.0-preview-20221003-04" />
<PackageReference Include="xunit" Version="2.4.2" /> <PackageReference Include="xunit" Version="2.4.2" />
<PackageReference Include="Xunit.DependencyInjection.Logging" Version="8.0.1" /> <PackageReference Include="Xunit.DependencyInjection.Logging" Version="8.0.1" />

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net6.0</TargetFramework> <TargetFramework>net7.0</TargetFramework>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<Version>$(VERSION)</Version> <Version>$(VERSION)</Version>
<PackageLicenseExpression>GPL-3.0-or-later</PackageLicenseExpression> <PackageLicenseExpression>GPL-3.0-or-later</PackageLicenseExpression>

View File

@ -5,6 +5,8 @@ using GameFinder.StoreHandlers.EGS;
using GameFinder.StoreHandlers.GOG; using GameFinder.StoreHandlers.GOG;
using GameFinder.StoreHandlers.Origin; using GameFinder.StoreHandlers.Origin;
using GameFinder.StoreHandlers.Steam; using GameFinder.StoreHandlers.Steam;
using GameFinder.StoreHandlers.Steam.Models;
using GameFinder.StoreHandlers.Steam.Models.ValueTypes;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Wabbajack.DTOs; using Wabbajack.DTOs;
using Wabbajack.Paths; using Wabbajack.Paths;
@ -19,10 +21,10 @@ public class GameLocator : IGameLocator
private readonly EGSHandler? _egs; private readonly EGSHandler? _egs;
private readonly OriginHandler? _origin; private readonly OriginHandler? _origin;
private readonly Dictionary<int, AbsolutePath> _steamGames = new(); private readonly Dictionary<AppId, AbsolutePath> _steamGames = new();
private readonly Dictionary<long, AbsolutePath> _gogGames = new(); private readonly Dictionary<GOGGameId, AbsolutePath> _gogGames = new();
private readonly Dictionary<string, AbsolutePath> _egsGames = new(StringComparer.OrdinalIgnoreCase); private readonly Dictionary<EGSGameId, AbsolutePath> _egsGames = new();
private readonly Dictionary<string, AbsolutePath> _originGames = new(StringComparer.OrdinalIgnoreCase); private readonly Dictionary<OriginGameId, AbsolutePath> _originGames = new();
private readonly Dictionary<Game, AbsolutePath> _locationCache; private readonly Dictionary<Game, AbsolutePath> _locationCache;
private readonly ILogger<GameLocator> _logger; private readonly ILogger<GameLocator> _logger;
@ -30,19 +32,20 @@ public class GameLocator : IGameLocator
public GameLocator(ILogger<GameLocator> logger) public GameLocator(ILogger<GameLocator> logger)
{ {
_logger = logger; _logger = logger;
var fileSystem = NexusMods.Paths.FileSystem.Shared;
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{ {
var windowsRegistry = new WindowsRegistry(); var windowsRegistry = new WindowsRegistry();
_steam = new SteamHandler(windowsRegistry); _steam = new SteamHandler(fileSystem, windowsRegistry);
_gog = new GOGHandler(windowsRegistry); _gog = new GOGHandler(windowsRegistry, fileSystem);
_egs = new EGSHandler(windowsRegistry); _egs = new EGSHandler(windowsRegistry, fileSystem);
_origin = new OriginHandler(); _origin = new OriginHandler(fileSystem);
} }
else else
{ {
_steam = new SteamHandler(null); _steam = new SteamHandler(fileSystem, null);
} }
_locationCache = new Dictionary<Game, AbsolutePath>(); _locationCache = new Dictionary<Game, AbsolutePath>();
@ -54,7 +57,7 @@ public class GameLocator : IGameLocator
{ {
try try
{ {
FindStoreGames(_steam, _steamGames, game => game.Path); FindStoreGames(_steam, _steamGames, game => (AbsolutePath)game.Path.GetFullPath());
} }
catch (Exception e) catch (Exception e)
{ {
@ -63,7 +66,7 @@ public class GameLocator : IGameLocator
try try
{ {
FindStoreGames(_gog, _gogGames, game => game.Path); FindStoreGames(_gog, _gogGames, game => (AbsolutePath)game.Path.GetFullPath());
} }
catch (Exception e) catch (Exception e)
{ {
@ -72,7 +75,7 @@ public class GameLocator : IGameLocator
try try
{ {
FindStoreGames(_egs, _egsGames, game => game.InstallLocation); FindStoreGames(_egs, _egsGames, game => (AbsolutePath)game.InstallLocation.GetFullPath());
} }
catch (Exception e) catch (Exception e)
{ {
@ -81,7 +84,7 @@ public class GameLocator : IGameLocator
try try
{ {
FindStoreGames(_origin, _originGames, game => game.InstallPath); FindStoreGames(_origin, _originGames, game => (AbsolutePath)game.InstallPath.GetFullPath());
} }
catch (Exception e) catch (Exception e)
{ {
@ -92,8 +95,9 @@ public class GameLocator : IGameLocator
private void FindStoreGames<TGame, TId>( private void FindStoreGames<TGame, TId>(
AHandler<TGame, TId>? handler, AHandler<TGame, TId>? handler,
Dictionary<TId, AbsolutePath> paths, Dictionary<TId, AbsolutePath> paths,
Func<TGame, string> getPath) Func<TGame, AbsolutePath> getPath)
where TGame : class where TGame : class, IGame
where TId : notnull
{ {
if (handler is null) return; if (handler is null) return;
@ -103,7 +107,7 @@ public class GameLocator : IGameLocator
{ {
try try
{ {
var path = getPath(game).ToAbsolutePath(); var path = getPath(game);
if (!path.DirectoryExists()) if (!path.DirectoryExists())
{ {
_logger.LogError("Game does not exist: {Game}", game); _logger.LogError("Game does not exist: {Game}", game);
@ -160,28 +164,28 @@ public class GameLocator : IGameLocator
foreach (var id in metaData.SteamIDs) foreach (var id in metaData.SteamIDs)
{ {
if (!_steamGames.TryGetValue(id, out var found)) continue; if (!_steamGames.TryGetValue(AppId.From((uint)id), out var found)) continue;
path = found; path = found;
return true; return true;
} }
foreach (var id in metaData.GOGIDs) foreach (var id in metaData.GOGIDs)
{ {
if (!_gogGames.TryGetValue(id, out var found)) continue; if (!_gogGames.TryGetValue(GOGGameId.From(id), out var found)) continue;
path = found; path = found;
return true; return true;
} }
foreach (var id in metaData.EpicGameStoreIDs) foreach (var id in metaData.EpicGameStoreIDs)
{ {
if (!_egsGames.TryGetValue(id, out var found)) continue; if (!_egsGames.TryGetValue(EGSGameId.From(id), out var found)) continue;
path = found; path = found;
return true; return true;
} }
foreach (var id in metaData.OriginIDs) foreach (var id in metaData.OriginIDs)
{ {
if (!_originGames.TryGetValue(id, out var found)) continue; if (!_originGames.TryGetValue(OriginGameId.From(id), out var found)) continue;
path = found; path = found;
return true; return true;
} }

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net6.0</TargetFramework> <TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
</PropertyGroup> </PropertyGroup>
@ -18,10 +18,10 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="GameFinder.StoreHandlers.EGS" Version="2.2.2" /> <PackageReference Include="GameFinder.StoreHandlers.EGS" Version="4.0.0" />
<PackageReference Include="GameFinder.StoreHandlers.GOG" Version="2.2.2" /> <PackageReference Include="GameFinder.StoreHandlers.GOG" Version="4.0.0" />
<PackageReference Include="GameFinder.StoreHandlers.Origin" Version="2.2.2" /> <PackageReference Include="GameFinder.StoreHandlers.Origin" Version="4.0.0" />
<PackageReference Include="GameFinder.StoreHandlers.Steam" Version="2.2.2" /> <PackageReference Include="GameFinder.StoreHandlers.Steam" Version="4.0.0" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -112,7 +112,7 @@ public class GoogleDriveDownloader : ADownloader<DTOs.DownloadStates.GoogleDrive
{ {
var initialUrl = $"https://drive.google.com/uc?id={state.Id}&export=download"; var initialUrl = $"https://drive.google.com/uc?id={state.Id}&export=download";
var msg = new HttpRequestMessage(HttpMethod.Get, initialUrl); var msg = new HttpRequestMessage(HttpMethod.Get, initialUrl);
msg.UseChromeUserAgent(); msg.AddChromeAgent();
using var response = await _client.SendAsync(msg, token); using var response = await _client.SendAsync(msg, token);
var cookies = response.GetSetCookies(); var cookies = response.GetSetCookies();
@ -145,18 +145,18 @@ public class GoogleDriveDownloader : ADownloader<DTOs.DownloadStates.GoogleDrive
var url = $"https://drive.google.com/uc?export=download&confirm={warning.Value}&id={state.Id}"; var url = $"https://drive.google.com/uc?export=download&confirm={warning.Value}&id={state.Id}";
var httpState = new HttpRequestMessage(HttpMethod.Get, url); var httpState = new HttpRequestMessage(HttpMethod.Get, url);
httpState.UseChromeUserAgent(); httpState.AddChromeAgent();
return httpState; return httpState;
} }
else else
{ {
var url = $"https://drive.google.com/file/d/{state.Id}/edit"; var url = $"https://drive.google.com/file/d/{state.Id}/edit";
var msg = new HttpRequestMessage(HttpMethod.Get, url); var msg = new HttpRequestMessage(HttpMethod.Get, url);
msg.UseChromeUserAgent(); msg.AddChromeAgent();
using var response = await _client.SendAsync(msg, token); using var response = await _client.SendAsync(msg, token);
msg = new HttpRequestMessage(HttpMethod.Get, url); msg = new HttpRequestMessage(HttpMethod.Get, url);
msg.UseChromeUserAgent(); msg.AddChromeAgent();
return !response.IsSuccessStatusCode ? null : msg; return !response.IsSuccessStatusCode ? null : msg;
} }
} }

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net6.0</TargetFramework> <TargetFramework>net7.0</TargetFramework>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<Version>$(VERSION)</Version> <Version>$(VERSION)</Version>
<PackageLicenseExpression>GPL-3.0-or-later</PackageLicenseExpression> <PackageLicenseExpression>GPL-3.0-or-later</PackageLicenseExpression>

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net6.0</TargetFramework> <TargetFramework>net7.0</TargetFramework>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<Version>$(VERSION)</Version> <Version>$(VERSION)</Version>
<PackageLicenseExpression>GPL-3.0-or-later</PackageLicenseExpression> <PackageLicenseExpression>GPL-3.0-or-later</PackageLicenseExpression>

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net6.0</TargetFramework> <TargetFramework>net7.0</TargetFramework>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
</PropertyGroup> </PropertyGroup>

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net6.0</TargetFramework> <TargetFramework>net7.0</TargetFramework>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<PackageLicenseExpression>GPL-3.0-or-later</PackageLicenseExpression> <PackageLicenseExpression>GPL-3.0-or-later</PackageLicenseExpression>
<Version>$(VERSION)</Version> <Version>$(VERSION)</Version>

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net6.0</TargetFramework> <TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
</PropertyGroup> </PropertyGroup>

View File

@ -1,13 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net6.0</TargetFramework> <TargetFramework>net7.0</TargetFramework>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="HtmlAgilityPack" Version="1.11.46" /> <PackageReference Include="HtmlAgilityPack" Version="1.11.46" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="6.0.2-mauipre.1.22102.15" /> <PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="6.0.3" /> <PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="6.0.3" />
</ItemGroup> </ItemGroup>

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net6.0</TargetFramework> <TargetFramework>net7.0</TargetFramework>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
</PropertyGroup> </PropertyGroup>

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net6.0</TargetFramework> <TargetFramework>net7.0</TargetFramework>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
</PropertyGroup> </PropertyGroup>

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net6.0</TargetFramework> <TargetFramework>net7.0</TargetFramework>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<PackageLicenseExpression>GPL-3.0-or-later</PackageLicenseExpression> <PackageLicenseExpression>GPL-3.0-or-later</PackageLicenseExpression>
<Version>$(VERSION)</Version> <Version>$(VERSION)</Version>

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net6.0</TargetFramework> <TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
</PropertyGroup> </PropertyGroup>

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net6.0</TargetFramework> <TargetFramework>net7.0</TargetFramework>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<Version>$(VERSION)</Version> <Version>$(VERSION)</Version>
<PackageLicenseExpression>GPL-3.0-or-later</PackageLicenseExpression> <PackageLicenseExpression>GPL-3.0-or-later</PackageLicenseExpression>

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net6.0</TargetFramework> <TargetFramework>net7.0</TargetFramework>
<IsPackable>false</IsPackable> <IsPackable>false</IsPackable>
</PropertyGroup> </PropertyGroup>
@ -11,7 +11,7 @@
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
</PackageReference> </PackageReference>
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="6.0.2-mauipre.1.22102.15" /> <PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="6.0.3" /> <PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="6.0.3" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.5.0-preview-20221003-04" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.5.0-preview-20221003-04" />
<PackageReference Include="xunit" Version="2.4.2" /> <PackageReference Include="xunit" Version="2.4.2" />

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net6.0</TargetFramework> <TargetFramework>net7.0</TargetFramework>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<Version>$(VERSION)</Version> <Version>$(VERSION)</Version>
<PackageLicenseExpression>GPL-3.0-or-later</PackageLicenseExpression> <PackageLicenseExpression>GPL-3.0-or-later</PackageLicenseExpression>

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net6.0</TargetFramework> <TargetFramework>net7.0</TargetFramework>
<IsPackable>false</IsPackable> <IsPackable>false</IsPackable>
</PropertyGroup> </PropertyGroup>

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net6.0</TargetFramework> <TargetFramework>net7.0</TargetFramework>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<Version>$(VERSION)</Version> <Version>$(VERSION)</Version>
<PackageLicenseExpression>GPL-3.0-or-later</PackageLicenseExpression> <PackageLicenseExpression>GPL-3.0-or-later</PackageLicenseExpression>

View File

@ -2,7 +2,7 @@
<PropertyGroup> <PropertyGroup>
<OutputType>Exe</OutputType> <OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework> <TargetFramework>net7.0</TargetFramework>
<RootNamespace>Wabbajac.Hash.xxHash64.Benchmark</RootNamespace> <RootNamespace>Wabbajac.Hash.xxHash64.Benchmark</RootNamespace>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks> <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup> </PropertyGroup>

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net6.0</TargetFramework> <TargetFramework>net7.0</TargetFramework>
<IsPackable>false</IsPackable> <IsPackable>false</IsPackable>
</PropertyGroup> </PropertyGroup>

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net6.0</TargetFramework> <TargetFramework>net7.0</TargetFramework>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<Version>$(VERSION)</Version> <Version>$(VERSION)</Version>
<PackageLicenseExpression>GPL-3.0-or-later</PackageLicenseExpression> <PackageLicenseExpression>GPL-3.0-or-later</PackageLicenseExpression>

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net6.0</TargetFramework> <TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
</PropertyGroup> </PropertyGroup>

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net6.0</TargetFramework> <TargetFramework>net7.0</TargetFramework>
<IsPackable>false</IsPackable> <IsPackable>false</IsPackable>
</PropertyGroup> </PropertyGroup>
@ -11,7 +11,7 @@
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
</PackageReference> </PackageReference>
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="6.0.2-mauipre.1.22102.15" /> <PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="7.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.5.0-preview-20221003-04" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.5.0-preview-20221003-04" />
<PackageReference Include="xunit" Version="2.4.2" /> <PackageReference Include="xunit" Version="2.4.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5"> <PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net6.0</TargetFramework> <TargetFramework>net7.0</TargetFramework>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<Version>$(VERSION)</Version> <Version>$(VERSION)</Version>
<PackageLicenseExpression>GPL-3.0-or-later</PackageLicenseExpression> <PackageLicenseExpression>GPL-3.0-or-later</PackageLicenseExpression>

View File

@ -231,7 +231,7 @@ public class MainWindowViewModel : ViewModelBase
ShowInCenter = true, ShowInCenter = true,
ContentTitle = "Wabbajack Launcher: Bad startup path", ContentTitle = "Wabbajack Launcher: Bad startup path",
ContentMessage = ContentMessage =
"Cannot start in the root of a drive, or protected folder locations such as Downloads, Desktop etc.\nPlease move Wabbajack to another folder." "Cannot start in the root of a drive, or protected folder locations such as Downloads, Desktop etc.\nPlease move Wabbajack to another folder, creating a new folder if necessary ( example : C:\\Wabbajack\\), outside of these locations."
}); });
var result = await msg.Show(); var result = await msg.Show();
Environment.Exit(1); Environment.Exit(1);

View File

@ -16,6 +16,7 @@
</ItemGroup> </ItemGroup>
<PropertyGroup> <PropertyGroup>
<ApplicationIcon>Resources\Icons\wabbajack.ico</ApplicationIcon> <ApplicationIcon>Resources\Icons\wabbajack.ico</ApplicationIcon>
<TargetFramework>net7.0-windows</TargetFramework>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Avalonia.Themes.Fluent" Version="11.0.0-preview4" /> <PackageReference Include="Avalonia.Themes.Fluent" Version="11.0.0-preview4" />
@ -30,7 +31,7 @@
<PackageReference Include="JetBrains.Annotations" Version="2022.1.0" /> <PackageReference Include="JetBrains.Annotations" Version="2022.1.0" />
<PackageReference Include="MessageBox.Avalonia" Version="2.3.1-prev2" /> <PackageReference Include="MessageBox.Avalonia" Version="2.3.1-prev2" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="6.0.2-mauipre.1.22102.15" /> <PackageReference Include="Microsoft.Extensions.Hosting" Version="6.0.2-mauipre.1.22102.15" />
<PackageReference Include="ReactiveUI.Fody" Version="18.3.1" /> <PackageReference Include="ReactiveUI.Fody" Version="19.5.1" />
<PackageReference Include="System.Security.Cryptography.ProtectedData" Version="6.0.2-mauipre.1.22102.15" /> <PackageReference Include="System.Security.Cryptography.ProtectedData" Version="6.0.2-mauipre.1.22102.15" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net6.0</TargetFramework> <TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
</PropertyGroup> </PropertyGroup>

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net6.0</TargetFramework> <TargetFramework>net7.0</TargetFramework>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<PackageLicenseExpression>GPL-3.0-or-later</PackageLicenseExpression> <PackageLicenseExpression>GPL-3.0-or-later</PackageLicenseExpression>
<Version>$(VERSION)</Version> <Version>$(VERSION)</Version>

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net6.0</TargetFramework> <TargetFramework>net7.0</TargetFramework>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<PackageLicenseExpression>GPL-3.0-or-later</PackageLicenseExpression> <PackageLicenseExpression>GPL-3.0-or-later</PackageLicenseExpression>
<Version>$(VERSION)</Version> <Version>$(VERSION)</Version>

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net6.0</TargetFramework> <TargetFramework>net7.0</TargetFramework>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<Version>$(VERSION)</Version> <Version>$(VERSION)</Version>
<PackageLicenseExpression>GPL-3.0-or-later</PackageLicenseExpression> <PackageLicenseExpression>GPL-3.0-or-later</PackageLicenseExpression>

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net6.0</TargetFramework> <TargetFramework>net7.0</TargetFramework>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<IsPackable>false</IsPackable> <IsPackable>false</IsPackable>

View File

@ -10,13 +10,6 @@ namespace Wabbajack.Networking.Http;
public static class Extensions public static class Extensions
{ {
public static HttpRequestMessage UseChromeUserAgent(this HttpRequestMessage msg)
{
msg.Headers.UserAgent.Clear();
msg.Headers.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.110 Safari/537.36");
return msg;
}
public static async Task<T> GetJsonFromSendAsync<T>(this HttpClient client, HttpRequestMessage msg, public static async Task<T> GetJsonFromSendAsync<T>(this HttpClient client, HttpRequestMessage msg,
JsonSerializerOptions opts, CancellationToken? token = null) JsonSerializerOptions opts, CancellationToken? token = null)
{ {

View File

@ -7,6 +7,7 @@ using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Downloader; using Downloader;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Wabbajack.Configuration;
using Wabbajack.Hashing.xxHash64; using Wabbajack.Hashing.xxHash64;
using Wabbajack.Paths; using Wabbajack.Paths;
using Wabbajack.Paths.IO; using Wabbajack.Paths.IO;
@ -20,17 +21,19 @@ internal class ResumableDownloader
private readonly HttpRequestMessage _msg; private readonly HttpRequestMessage _msg;
private readonly AbsolutePath _outputPath; private readonly AbsolutePath _outputPath;
private readonly AbsolutePath _packagePath; private readonly AbsolutePath _packagePath;
private readonly PerformanceSettings _performanceSettings;
private readonly ILogger<SingleThreadedDownloader> _logger; private readonly ILogger<SingleThreadedDownloader> _logger;
private CancellationToken _token; private CancellationToken _token;
private Exception? _error; private Exception? _error;
public ResumableDownloader(HttpRequestMessage msg, AbsolutePath outputPath, IJob job, ILogger<SingleThreadedDownloader> logger) public ResumableDownloader(HttpRequestMessage msg, AbsolutePath outputPath, IJob job, PerformanceSettings performanceSettings, ILogger<SingleThreadedDownloader> logger)
{ {
_job = job; _job = job;
_msg = msg; _msg = msg;
_outputPath = outputPath; _outputPath = outputPath;
_packagePath = outputPath.WithExtension(Extension.FromPath(".download_package")); _packagePath = outputPath.WithExtension(Extension.FromPath(".download_package"));
_performanceSettings = performanceSettings;
_logger = logger; _logger = logger;
} }
@ -99,8 +102,10 @@ internal class ResumableDownloader
private DownloadConfiguration CreateConfiguration(HttpRequestMessage message) private DownloadConfiguration CreateConfiguration(HttpRequestMessage message)
{ {
var maximumMemoryPerDownloadThreadMb = Math.Max(0, _performanceSettings.MaximumMemoryPerDownloadThreadMb);
var configuration = new DownloadConfiguration var configuration = new DownloadConfiguration
{ {
MaximumMemoryBufferBytes = maximumMemoryPerDownloadThreadMb * 1024 * 1024,
Timeout = (int)TimeSpan.FromSeconds(120).TotalMilliseconds, Timeout = (int)TimeSpan.FromSeconds(120).TotalMilliseconds,
ReserveStorageSpaceBeforeStartingDownload = true, ReserveStorageSpaceBeforeStartingDownload = true,
RequestConfiguration = new RequestConfiguration RequestConfiguration = new RequestConfiguration

View File

@ -7,6 +7,7 @@ using System.Net.Http.Headers;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Wabbajack.Configuration;
using Wabbajack.Hashing.xxHash64; using Wabbajack.Hashing.xxHash64;
using Wabbajack.Networking.Http.Interfaces; using Wabbajack.Networking.Http.Interfaces;
using Wabbajack.Paths; using Wabbajack.Paths;
@ -19,18 +20,20 @@ public class SingleThreadedDownloader : IHttpDownloader
{ {
private readonly HttpClient _client; private readonly HttpClient _client;
private readonly ILogger<SingleThreadedDownloader> _logger; private readonly ILogger<SingleThreadedDownloader> _logger;
private readonly PerformanceSettings _settings;
public SingleThreadedDownloader(ILogger<SingleThreadedDownloader> logger, HttpClient client) public SingleThreadedDownloader(ILogger<SingleThreadedDownloader> logger, HttpClient client, MainSettings settings)
{ {
_logger = logger; _logger = logger;
_client = client; _client = client;
_settings = settings.PerformanceSettings;
} }
public async Task<Hash> Download(HttpRequestMessage message, AbsolutePath outputPath, IJob job, public async Task<Hash> Download(HttpRequestMessage message, AbsolutePath outputPath, IJob job,
CancellationToken token) CancellationToken token)
{ {
Exception downloadError = null!; Exception downloadError = null!;
var downloader = new ResumableDownloader(message, outputPath, job, _logger); var downloader = new ResumableDownloader(message, outputPath, job, _settings, _logger);
for (var i = 0; i < 3; i++) for (var i = 0; i < 3; i++)
{ {
try try

View File

@ -1,18 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net6.0</TargetFramework> <TargetFramework>net7.0</TargetFramework>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<PackageLicenseExpression>GPL-3.0-or-later</PackageLicenseExpression> <PackageLicenseExpression>GPL-3.0-or-later</PackageLicenseExpression>
<Version>$(VERSION)</Version> <Version>$(VERSION)</Version>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Downloader" Version="3.0.4" /> <PackageReference Include="Downloader" Version="3.0.6" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="6.0.2-mauipre.1.22102.15" /> <PackageReference Include="Microsoft.Extensions.Logging" Version="6.0.2-mauipre.1.22102.15" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Wabbajack.Configuration\Wabbajack.Configuration.csproj" />
<ProjectReference Include="..\Wabbajack.Downloaders.Interfaces\Wabbajack.Downloaders.Interfaces.csproj" /> <ProjectReference Include="..\Wabbajack.Downloaders.Interfaces\Wabbajack.Downloaders.Interfaces.csproj" />
<ProjectReference Include="..\Wabbajack.Hashing.xxHash64\Wabbajack.Hashing.xxHash64.csproj" /> <ProjectReference Include="..\Wabbajack.Hashing.xxHash64\Wabbajack.Hashing.xxHash64.csproj" />
<ProjectReference Include="..\Wabbajack.Networking.Http.Interfaces\Wabbajack.Networking.Http.Interfaces.csproj" /> <ProjectReference Include="..\Wabbajack.Networking.Http.Interfaces\Wabbajack.Networking.Http.Interfaces.csproj" />

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net6.0</TargetFramework> <TargetFramework>net7.0</TargetFramework>
<IsPackable>false</IsPackable> <IsPackable>false</IsPackable>
</PropertyGroup> </PropertyGroup>

View File

@ -8,15 +8,15 @@ using Wabbajack.DTOs;
using Wabbajack.DTOs.Logins; using Wabbajack.DTOs.Logins;
using Wabbajack.Networking.Http.Interfaces; using Wabbajack.Networking.Http.Interfaces;
using Wabbajack.Networking.NexusApi.DTOs; using Wabbajack.Networking.NexusApi.DTOs;
using Wabbajack.Networking.WabbajackClientApi;
using Wabbajack.RateLimiter; using Wabbajack.RateLimiter;
using ClientConfiguration = Wabbajack.Networking.WabbajackClientApi.Configuration;
namespace Wabbajack.Networking.NexusApi; namespace Wabbajack.Networking.NexusApi;
public class ProxiedNexusApi : NexusApi public class ProxiedNexusApi : NexusApi
{ {
private readonly ITokenProvider<WabbajackApiState> _apiState; private readonly ITokenProvider<WabbajackApiState> _apiState;
private readonly Configuration _wabbajackClientConfiguration; private readonly ClientConfiguration _wabbajackClientConfiguration;
public HashSet<string> ProxiedEndpoints = new() public HashSet<string> ProxiedEndpoints = new()
{ {
@ -28,7 +28,7 @@ public class ProxiedNexusApi : NexusApi
public ProxiedNexusApi(ITokenProvider<NexusApiState> apiKey, ILogger<ProxiedNexusApi> logger, HttpClient client, public ProxiedNexusApi(ITokenProvider<NexusApiState> apiKey, ILogger<ProxiedNexusApi> logger, HttpClient client,
IResource<HttpClient> limiter, IResource<HttpClient> limiter,
ApplicationInfo appInfo, JsonSerializerOptions jsonOptions, ITokenProvider<WabbajackApiState> apiState, ApplicationInfo appInfo, JsonSerializerOptions jsonOptions, ITokenProvider<WabbajackApiState> apiState,
Configuration wabbajackClientConfiguration) ClientConfiguration wabbajackClientConfiguration)
: base(apiKey, logger, client, limiter, appInfo, jsonOptions) : base(apiKey, logger, client, limiter, appInfo, jsonOptions)
{ {
_apiState = apiState; _apiState = apiState;

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net6.0</TargetFramework> <TargetFramework>net7.0</TargetFramework>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<PackageLicenseExpression>GPL-3.0-or-later</PackageLicenseExpression> <PackageLicenseExpression>GPL-3.0-or-later</PackageLicenseExpression>
<Version>$(VERSION)</Version> <Version>$(VERSION)</Version>
@ -12,7 +12,7 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="6.0.2-mauipre.1.22102.15" /> <PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="6.0.3" /> <PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="6.0.3" />
</ItemGroup> </ItemGroup>

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net6.0</TargetFramework> <TargetFramework>net7.0</TargetFramework>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<IsPackable>false</IsPackable> <IsPackable>false</IsPackable>
@ -12,7 +12,7 @@
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
</PackageReference> </PackageReference>
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="6.0.2-mauipre.1.22102.15" /> <PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="7.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.5.0-preview-20221003-04" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.5.0-preview-20221003-04" />
<PackageReference Include="xunit" Version="2.4.2" /> <PackageReference Include="xunit" Version="2.4.2" />
<PackageReference Include="Xunit.DependencyInjection" Version="8.6.1" /> <PackageReference Include="Xunit.DependencyInjection" Version="8.6.1" />

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net6.0</TargetFramework> <TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
</PropertyGroup> </PropertyGroup>

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net6.0</TargetFramework> <TargetFramework>net7.0</TargetFramework>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<Version>$(VERSION)</Version> <Version>$(VERSION)</Version>
<PackageLicenseExpression>GPL-3.0-or-later</PackageLicenseExpression> <PackageLicenseExpression>GPL-3.0-or-later</PackageLicenseExpression>

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net6.0</TargetFramework> <TargetFramework>net7.0</TargetFramework>
<IsPackable>false</IsPackable> <IsPackable>false</IsPackable>
</PropertyGroup> </PropertyGroup>

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net6.0</TargetFramework> <TargetFramework>net7.0</TargetFramework>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<PackageLicenseExpression>GPL-3.0-or-later</PackageLicenseExpression> <PackageLicenseExpression>GPL-3.0-or-later</PackageLicenseExpression>
<Version>$(VERSION)</Version> <Version>$(VERSION)</Version>

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net6.0</TargetFramework> <TargetFramework>net7.0</TargetFramework>
<IsPackable>false</IsPackable> <IsPackable>false</IsPackable>
</PropertyGroup> </PropertyGroup>

View File

@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net6.0</TargetFramework> <TargetFramework>net7.0</TargetFramework>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<PackageLicenseExpression>GPL-3.0-or-later</PackageLicenseExpression> <PackageLicenseExpression>GPL-3.0-or-later</PackageLicenseExpression>
<Version>$(VERSION)</Version> <Version>$(VERSION)</Version>

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net6.0</TargetFramework> <TargetFramework>net7.0</TargetFramework>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<IsPackable>false</IsPackable> <IsPackable>false</IsPackable>

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net6.0</TargetFramework> <TargetFramework>net7.0</TargetFramework>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
</PropertyGroup> </PropertyGroup>

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net6.0</TargetFramework> <TargetFramework>net7.0</TargetFramework>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
</PropertyGroup> </PropertyGroup>

Some files were not shown because too many files have changed in this diff Show More