Wabbajack 3.3.0.0 Update (#2416)

* added more visible error messages to avoid user confusion

added hard drive free space detection, added red error message text, removed overwrite checkbox, added wiki button link

extended the error text for starting wabbajack in protected location

removed debug code

shortened error message to fit in text box

* restored warning removed in error, updated changelog, removed debug includes

* Update InstallerVM.cs

* Update InstallerVM.cs

* Update MainWindowViewModel.cs

* added json optional flag to only show version number over modlist image in installer view, if the modlist image already contains the title

removed debug code

change to pascal case and match existing code style

update changelog

* Fix manual downloads sometimes launching in browser

* Fix manual downloads from secure servers

* Remove duplicate user agent code

* Create configuration project and performance settings

* Bind new performance settings to UI

* Use performance settings to limit maximum memory per download

* Remove unused settings and related classes

* Updated CHANGELOG.md

* update CHANGELOG.md

* moved the existing files popup to an error message , heralding the return of the overwrite install checkbox

* added newline

* reverted erroneous edit

* gogID for fallout4 added

* update CHANGELOG.md

* Fix deadlock when loading new settings

* change folder/directory check logic

* update CHANGELOG.md

* revert unnecessary change

* update CHANGELOG.md

* Bump Wabbajack to .NET 7

* Bump ReactiveUI packages & deps

* Update GameFinder to 4.0.0

* Update CHANGELOG.md

* Update CHANGELOG.md

---------

Co-authored-by: JanuarySnow <bobfordiscord12@gmail.com>
Co-authored-by: JanuarySnow <85711747+JanuarySnow@users.noreply.github.com>
Co-authored-by: UrbanCMC <UrbanCMC@web.de>
Co-authored-by: trawzified <55751269+tr4wzified@users.noreply.github.com>
This commit is contained in:
Luca 2023-10-12 20:33:06 +02:00 committed by GitHub
parent 0cba392b66
commit fab17a6ae0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
107 changed files with 580 additions and 903 deletions

View File

@ -1,21 +1,32 @@
### 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
* Code cleanup: re-added some network and diagnostic code missing since 2.5
#### Version - 3.2.0.0 - 7/16/2023
* 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
* 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.
* 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 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
* 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 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 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
* 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.
* 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 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
* 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 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
#### Version - 3.1.0.0 - 5/7/2023
* Fixed Readme opening twice

View File

@ -3,7 +3,6 @@ using System.Reactive.Concurrency;
using System.Reactive.Disposables;
using System.Runtime.InteropServices;
using System.Security.Principal;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Threading;
using Microsoft.Extensions.DependencyInjection;
@ -166,7 +165,6 @@ namespace Wabbajack
services.AddSingleton<LauncherUpdater>();
services.AddSingleton<ResourceMonitor>();
services.AddSingleton<MainSettings>();
services.AddTransient<CompilerVM>();
services.AddTransient<InstallerVM>();
services.AddTransient<ModeSelectionVM>();
@ -182,7 +180,7 @@ namespace Wabbajack
services.AddTransient<LoversLabLoginHandler>();
// Login Managers
//Disabled LL because it is currently not used and broken due to the way LL butchers their API
//services.AddAllSingleton<INeedsLogin, LoversLabLoginManager>();
services.AddAllSingleton<INeedsLogin, NexusLoginManager>();

View File

@ -8,6 +8,7 @@ using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Microsoft.VisualBasic.CompilerServices;
using Newtonsoft.Json;
using Wabbajack.Common;
using Wabbajack.Downloaders;
using Wabbajack.DTOs;
using Wabbajack.DTOs.DownloadStates;
@ -27,9 +28,9 @@ namespace Wabbajack
private readonly HttpClient _client;
private readonly Client _wjclient;
private readonly DTOSerializer _dtos;
private readonly DownloadDispatcher _downloader;
private static Uri GITHUB_REPO_RELEASES = new("https://api.github.com/repos/wabbajack-tools/wabbajack/releases");
public LauncherUpdater(ILogger<LauncherUpdater> logger, HttpClient client, Client wjclient, DTOSerializer dtos,
@ -41,8 +42,8 @@ namespace Wabbajack
_dtos = dtos;
_downloader = downloader;
}
public static Lazy<AbsolutePath> CommonFolder = new (() =>
{
var entryPoint = KnownFolders.EntryPoint;
@ -105,7 +106,7 @@ namespace Wabbajack
var launcherFolder = KnownFolders.EntryPoint.Parent;
var exePath = launcherFolder.Combine("Wabbajack.exe");
var launcherVersion = FileVersionInfo.GetVersionInfo(exePath.ToString());
if (release != default && release.version > Version.Parse(launcherVersion.FileVersion!))
@ -119,7 +120,7 @@ namespace Wabbajack
Name = release.asset.Name,
Size = release.asset.Size
}, tempPath, CancellationToken.None);
if (tempPath.Size() != release.asset.Size)
{
_logger.LogInformation(
@ -130,12 +131,12 @@ namespace Wabbajack
if (exePath.FileExists())
exePath.Delete();
await tempPath.MoveToAsync(exePath, true, CancellationToken.None);
_logger.LogInformation("Finished updating wabbajack");
await _wjclient.SendMetric("updated_launcher", $"{launcherVersion.FileVersion} -> {release.version}");
}
}
private async Task<Release[]> GetReleases()
{
_logger.LogInformation("Getting new Wabbajack version list");
@ -146,7 +147,7 @@ namespace Wabbajack
private HttpRequestMessage MakeMessage(Uri uri)
{
var msg = new HttpRequestMessage(HttpMethod.Get, uri);
msg.UseChromeUserAgent();
msg.AddChromeAgent();
return msg;
}

View File

@ -1,84 +1,11 @@
using System;
using System.Collections.Generic;
using System.Reactive;
using System.Reactive.Subjects;
using System.Threading.Tasks;
using Newtonsoft.Json;
using Wabbajack.Compiler;
using Wabbajack.Downloaders;
using Wabbajack.DTOs.JsonConverters;
using Wabbajack;
using Wabbajack.Paths;
using Consts = Wabbajack.Consts;
using Wabbajack.RateLimiter;
using Wabbajack.Util;
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")]
public class Mo2ModlistInstallationSettings
{
@ -87,105 +14,41 @@ namespace Wabbajack
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 PerformanceSettings()
private readonly Configuration.MainSettings _settings;
private readonly int _defaultMaximumMemoryPerDownloadThreadMb;
public PerformanceSettings(Configuration.MainSettings settings, IResource<DownloadDispatcher> downloadResources, SystemParametersConstructor systemParams)
{
_reduceHDDThreads = true;
_favorPerfOverRam = false;
_diskThreads = Environment.ProcessorCount;
_downloadThreads = Environment.ProcessorCount <= 8 ? Environment.ProcessorCount : 8;
}
var p = systemParams.Create();
private int _downloadThreads;
public int DownloadThreads { get => _downloadThreads; set => RaiseAndSetIfChanged(ref _downloadThreads, value); }
private int _diskThreads;
public int DiskThreads { get => _diskThreads; set => RaiseAndSetIfChanged(ref _diskThreads, value); }
_settings = settings;
// Split half of available memory among download threads
_defaultMaximumMemoryPerDownloadThreadMb = (int)(p.SystemMemorySize / downloadResources.MaxTasks / 1024 / 1024) / 2;
_maximumMemoryPerDownloadThreadMb = settings.PerformanceSettings.MaximumMemoryPerDownloadThreadMb;
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;
set
if (MaximumMemoryPerDownloadThreadMb < 0)
{
Consts.UseNetworkWorkaroundMode = value;
RaiseAndSetIfChanged(ref _networkWorkaroundMode, value);
ResetMaximumMemoryPerDownloadThreadMb();
}
}
private bool _disableTextureResizing;
public bool DisableTextureResizing
private int _maximumMemoryPerDownloadThreadMb;
public int MaximumMemoryPerDownloadThreadMb
{
get => _disableTextureResizing;
get => _maximumMemoryPerDownloadThreadMb;
set
{
RaiseAndSetIfChanged(ref _disableTextureResizing, value);
RaiseAndSetIfChanged(ref _maximumMemoryPerDownloadThreadMb, value);
_settings.PerformanceSettings.MaximumMemoryPerDownloadThreadMb = value;
}
}
/*
public void SetProcessorSettings(ABatchProcessor processor)
public void ResetMaximumMemoryPerDownloadThreadMb()
{
processor.DownloadThreads = DownloadThreads;
processor.DiskThreads = DiskThreads;
processor.ReduceHDDThreads = ReduceHDDThreads;
processor.FavorPerfOverRam = FavorPerfOverRam;
if (processor is MO2Compiler mo2c)
mo2c.DisableTextureResizing = DisableTextureResizing;
}*/
MaximumMemoryPerDownloadThreadMb = _defaultMaximumMemoryPerDownloadThreadMb;
}
}
[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.Tasks;
using Wabbajack.DTOs;
using Wabbajack.DTOs.DownloadStates;
using Wabbajack.DTOs.Interventions;
using Wabbajack.Paths;
namespace Wabbajack.UserIntervention;
@ -17,18 +14,18 @@ public class ManualDownloadHandler : BrowserWindowViewModel
//await WaitForReady();
var archive = Intervention.Archive;
var md = Intervention.Archive.State as Manual;
HeaderText = $"Manual download ({md.Url.Host})";
Instructions = string.IsNullOrWhiteSpace(md.Prompt) ? $"Please download {archive.Name}" : md.Prompt;
await NavigateTo(md.Url);
var uri = await WaitForDownloadUri(token, async () =>
var task = WaitForDownloadUri(token, async () =>
{
await RunJavaScript("Array.from(document.getElementsByTagName(\"iframe\")).forEach(f => f.remove())");
});
await NavigateTo(md.Url);
var uri = await task;
Intervention.Finish(uri);
}
}

View File

@ -8,6 +8,7 @@ using System.Threading.Tasks;
using System.Web;
using Microsoft.Extensions.Logging;
using ReactiveUI;
using Wabbajack.Common;
using Wabbajack.DTOs.Interventions;
using Wabbajack.DTOs.Logins;
using Wabbajack.Messages;
@ -40,7 +41,7 @@ public abstract class OAuth2LoginHandler<TLoginType> : BrowserWindowViewModel
var tcs = new TaskCompletionSource<Uri>();
await NavigateTo(tlogin.AuthorizationEndpoint);
Browser!.Browser.CoreWebView2.Settings.UserAgent = "Wabbajack";
Browser!.Browser.NavigationStarting += (sender, args) =>
{
@ -50,7 +51,7 @@ public abstract class OAuth2LoginHandler<TLoginType> : BrowserWindowViewModel
tcs.TrySetResult(uri);
}
};
Instructions = $"Please log in and allow Wabbajack to access your {tlogin.SiteName} account";
var scopes = string.Join(" ", tlogin.Scopes);
@ -88,8 +89,7 @@ public abstract class OAuth2LoginHandler<TLoginType> : BrowserWindowViewModel
var msg = new HttpRequestMessage();
msg.Method = HttpMethod.Post;
msg.RequestUri = tlogin.TokenEndpoint;
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");
msg.AddChromeAgent();
msg.Headers.Add("Cookie", string.Join(";", cookies.Select(c => $"{c.Name}={c.Value}")));
msg.Content = new FormUrlEncodedContent(formData.ToList());
@ -101,6 +101,6 @@ public abstract class OAuth2LoginHandler<TLoginType> : BrowserWindowViewModel
Cookies = cookies,
ResultState = data!
});
}
}

View File

@ -23,7 +23,7 @@ public abstract class BrowserWindowViewModel : ViewModel
[Reactive] public string HeaderText { get; set; }
[Reactive] public string Instructions { get; set; }
[Reactive] public string Address { get; set; }
public BrowserWindow? Browser { get; set; }
@ -83,6 +83,11 @@ public abstract class BrowserWindowViewModel : ViewModel
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(""))
.Where(c => c.Domain.EndsWith(domainEnding));
return cookies.Select(c => new Cookie
@ -112,18 +117,20 @@ public abstract class BrowserWindowViewModel : ViewModel
{
var source = new TaskCompletionSource<Uri>();
var referer = _browser.Source;
while (_browser.CoreWebView2 == null)
await Task.Delay(10, token);
_browser.CoreWebView2.DownloadStarting += (sender, args) =>
{
try
{
source.SetResult(new Uri(args.DownloadOperation.Uri));
}
catch (Exception)
{
source.SetCanceled();
}
args.Cancel = true;
args.Handled = true;
};
@ -144,12 +151,16 @@ public abstract class BrowserWindowViewModel : ViewModel
}
var cookies = await GetCookies(uri.Host, token);
return new ManualDownload.BrowserDownloadState(uri, cookies, new[]
{
("Referer", referer.ToString())
});
return new ManualDownload.BrowserDownloadState(
uri,
cookies,
new[]
{
("Referer", referer?.ToString() ?? uri.ToString())
},
_browser.CoreWebView2.Settings.UserAgent);
}
public async Task<Hash> WaitForDownload(AbsolutePath path, CancellationToken token)
{
var source = new TaskCompletionSource();

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 CancellationToken _cancellationToken;
private FiltersSettings settings { get; set; } = new();
public ICommand ClearFiltersCommand { get; set; }
public ModListGalleryVM(ILogger<ModListGalleryVM> logger, Client wjClient, GameLocator locator,

View File

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

View File

@ -135,11 +135,14 @@ public class InstallerVM : BackNavigatingVM, IBackNavigatingVM, ICpuStatusVM
public LogStream LoggerProvider { get; }
private AbsolutePath LastInstallPath { get; set; }
[Reactive] public bool OverwriteFiles { get; set; }
// Command properties
public ReactiveCommand<Unit, Unit> ShowManifestCommand { get; }
public ReactiveCommand<Unit, Unit> OpenReadmeCommand { get; }
public ReactiveCommand<Unit, Unit> OpenWikiCommand { get; }
public ReactiveCommand<Unit, Unit> OpenDiscordButton { get; }
public ReactiveCommand<Unit, Unit> VisitModListWebsiteCommand { get; }
@ -178,6 +181,11 @@ public class InstallerVM : BackNavigatingVM, IBackNavigatingVM, ICpuStatusVM
UIUtils.OpenWebsite(new Uri(ModList!.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(() =>
{
UIUtils.OpenWebsite(ModList!.Website);
@ -219,7 +227,10 @@ public class InstallerVM : BackNavigatingVM, IBackNavigatingVM, ICpuStatusVM
{
UIUtils.OpenFolder(Installer.Location.TargetPath);
});
this.WhenAnyValue(x => x.OverwriteFiles)
.Subscribe(x => ConfirmOverwrite());
MessageBus.Current.Listen<LoadModlistForInstalling>()
.Subscribe(msg => LoadModlistFromGallery(msg.Path, msg.Metadata).FireAndForget())
.DisposeWith(CompositeDisposable);
@ -280,6 +291,10 @@ public class InstallerVM : BackNavigatingVM, IBackNavigatingVM, ICpuStatusVM
{
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)
{
if (!_gameLocator.TryFindLocation(game.Key, out var location))
@ -304,31 +319,53 @@ public class InstallerVM : BackNavigatingVM, IBackNavigatingVM, ICpuStatusVM
yield return ErrorResponse.Fail("Installing in this folder may overwrite Wabbajack");
}
if (installPath.ToString().Length != 0 && installPath != LastInstallPath &&
!Installer.AutomaticallyOverwrite &&
if (installPath.ToString().Length != 0 && installPath != LastInstallPath && !OverwriteFiles &&
Directory.EnumerateFileSystemEntries(installPath.ToString()).Any())
{
string message =
"There are existing files in the chosen install path, they will be deleted or overwritten (if updating existing modlist), continue?";
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();
}
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 +
"if you are updating an existing modlist, then this is expected and can be overwritten.");
}
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)
{
while (!token.IsCancellationRequested)
@ -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()
{
await Task.Run(async () =>
@ -521,7 +565,14 @@ public class InstallerVM : BackNavigatingVM, IBackNavigatingVM, ICpuStatusVM
private void PopulateSlideShow(ModList modList)
{
SlideShowTitle = modList.Name;
if (ModlistMetadata.ImageContainsTitle && ModlistMetadata.DisplayVersionOnlyInInstallerView)
{
SlideShowTitle = "v" + ModlistMetadata.Version.ToString();
}
else
{
SlideShowTitle = modList.Name;
}
SlideShowAuthor = modList.Author;
SlideShowDescription = modList.Description;
SlideShowImage = ModListImage;
@ -551,4 +602,4 @@ public class InstallerVM : BackNavigatingVM, IBackNavigatingVM, ICpuStatusVM
}
}
}
}

View File

@ -1,37 +1,27 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reactive.Disposables;
using System.Reactive.Linq;
using System.Text;
using System.Threading.Tasks;
using ReactiveUI;
using ReactiveUI.Fody.Helpers;
using Wabbajack.Common;
using Wabbajack.Installer;
using Wabbajack;
using Wabbajack.DTOs;
using Wabbajack.DTOs.Interventions;
using Wabbajack.Interventions;
using Wabbajack.Paths;
using Wabbajack.Util;
namespace Wabbajack
{
public class MO2InstallerVM : ViewModel, ISubInstallerVM
{
public InstallerVM Parent { get; }
[Reactive]
public ErrorResponse CanInstall { get; set; }
[Reactive]
public IInstaller ActiveInstallation { get; private set; }
[Reactive] public Mo2ModlistInstallationSettings CurrentSettings { get; set; }
[Reactive]
public Mo2ModlistInstallationSettings CurrentSettings { get; set; }
public FilePickerVM Location { get; }
@ -62,97 +52,13 @@ namespace Wabbajack
DownloadLocation.TargetPath = newPath.Combine("downloads");
}
}).DisposeWith(CompositeDisposable);
DownloadLocation = new FilePickerVM()
{
ExistCheckOption = FilePickerVM.CheckOptions.Off,
PathType = FilePickerVM.PathTypeOptions.Folder,
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()
@ -205,7 +111,7 @@ namespace Wabbajack
*/
return true;
}
public IUserIntervention InterventionConverter(IUserIntervention intervention)
{
switch (intervention)

View File

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

View File

@ -2,28 +2,32 @@
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using ReactiveUI;
using Wabbajack;
using Wabbajack.Common;
using Wabbajack.Downloaders;
using Wabbajack.LoginManagers;
using Wabbajack.Messages;
using Wabbajack.Networking.WabbajackClientApi;
using Wabbajack.RateLimiter;
using Wabbajack.Services.OSIntegrated;
using Wabbajack.Services.OSIntegrated.TokenProviders;
using Wabbajack.Util;
using Wabbajack.View_Models.Settings;
namespace Wabbajack
{
public class SettingsVM : BackNavigatingVM
{
private readonly Configuration.MainSettings _settings;
private readonly SettingsManager _settingsManager;
public LoginManagerVM Login { get; }
public PerformanceSettings Performance { get; }
public FiltersSettings Filters { get; }
public AuthorFilesVM AuthorFile { get; }
public ICommand OpenTerminalCommand { get; }
@ -31,12 +35,30 @@ namespace Wabbajack
public SettingsVM(ILogger<SettingsVM> logger, IServiceProvider provider)
: base(logger)
{
Login = new LoginManagerVM(provider.GetRequiredService<ILogger<LoginManagerVM>>(), this,
_settings = provider.GetRequiredService<Configuration.MainSettings>();
_settingsManager = provider.GetRequiredService<SettingsManager>();
Login = new LoginManagerVM(provider.GetRequiredService<ILogger<LoginManagerVM>>(), this,
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);
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()

View File

@ -1,24 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reactive.Disposables;
using System.Text;
using System.Threading.Tasks;
using System.Reactive.Disposables;
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.Fody.Helpers;
using Wabbajack;
using System.Windows.Controls.Primitives;
using System.Reactive.Linq;
using Wabbajack.Common;
using Wabbajack.RateLimiter;
namespace Wabbajack
@ -36,23 +19,12 @@ namespace Wabbajack
public static readonly DependencyProperty ProgressPercentProperty = DependencyProperty.Register(nameof(ProgressPercent), typeof(Percent), typeof(CpuView),
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()
{
InitializeComponent();
this.WhenActivated(disposable =>
{
this.WhenAny(x => x.ViewModel.StatusList)
.BindToStrict(this, x => x.CpuListControl.ItemsSource)
.DisposeWith(disposable);

View File

@ -12,7 +12,7 @@
x:TypeArguments="local:InstallerVM"
mc:Ignorable="d">
<local:AttentionBorder x:Name="AttentionBorder" ClipToBounds="True">
<Grid Margin="5">
<Grid Margin="6">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="3*" />
@ -23,6 +23,7 @@
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="5"
x:Name="TitleText"
@ -124,11 +125,34 @@
<TextBlock Grid.Row="1"
Margin="0,10,0,0"
HorizontalAlignment="Center"
Text="Readme" />
Text="Modlist Readme" />
</Grid>
<Grid Grid.Row="1" Grid.Column="4"
VerticalAlignment="Center"
Background="Transparent">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</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">
Background="Transparent" Grid.ColumnSpan="2" Margin="0,0,10,0">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />

View File

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

View File

@ -39,6 +39,13 @@
FontSize="14"
Text="Target Modlist"
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"
x:Name="ModListLocationPicker"
Height="30"
@ -74,10 +81,11 @@
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<local:BeginButton Grid.Row="1"
x:Name="BeginButton"
HorizontalAlignment="Right"
HorizontalAlignment="Center"
VerticalAlignment="Center" />
<icon:PackIconFontAwesome Grid.Row="2"
x:Name="ErrorSummaryIconGlow"
@ -92,8 +100,27 @@
<icon:PackIconFontAwesome Grid.Row="2"
x:Name="ErrorSummaryIcon"
HorizontalAlignment="Center"
VerticalAlignment="Top"
Foreground="{StaticResource WarningBrush}"
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>
</rxui:ReactiveUserControl>

View File

@ -39,14 +39,21 @@ namespace Wabbajack
this.WhenAny(x => x.ViewModel.BeginCommand)
.BindToStrict(this, x => x.BeginButton.Command)
.DisposeWith(dispose);
this.BindStrict(ViewModel, vm => vm.OverwriteFiles, x => x.OverwriteCheckBox.IsChecked)
.DisposeWith(dispose);
// Error handling
this.WhenAnyValue(x => x.ViewModel.ErrorState)
.Select(v => !v.Failed)
.BindToStrict(this, view => view.BeginButton.IsEnabled)
.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)
.Select(v => v.Failed ? Visibility.Visible : Visibility.Hidden)
.BindToStrict(this, view => view.ErrorSummaryIcon.Visibility)

View File

@ -324,20 +324,6 @@
<local:CpuView Grid.Column="2"
x:Name="CpuView"
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"
x:Name="InstallComplete"
ViewModel="{Binding}" />

View File

@ -46,21 +46,5 @@
FontSize="14"
PickerVM="{Binding DownloadLocation}"
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>
</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.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Reactive.Linq;
using System.Threading;
using System.Windows;
using System.Windows.Input;
using DynamicData;
using DynamicData.Binding;
using MahApps.Metro.Controls;
using Microsoft.Extensions.Logging;
using ReactiveUI;
using ReactiveUI.Fody.Helpers;
using Wabbajack.Common;
using Wabbajack.DTOs;
using Wabbajack.DTOs.DownloadStates;
using Wabbajack.DTOs.Interventions;
using Wabbajack.Messages;
using Wabbajack.Paths.IO;
using Wabbajack.UserIntervention;
using Wabbajack.Util;
using Wabbajack.Views;
namespace Wabbajack
{
@ -30,7 +21,6 @@ namespace Wabbajack
public partial class MainWindow : MetroWindow
{
private MainWindowVM _mwvm;
private MainSettings _settings;
private readonly ILogger<MainWindow> _logger;
private readonly SystemParametersConstructor _systemParams;
@ -75,7 +65,7 @@ namespace Wabbajack
var p = _systemParams.Create();
_logger.LogInformation("Detected Windows Version: {Version}", Environment.OSVersion.VersionString);
_logger.LogInformation(
"System settings - ({MemorySize} RAM) ({PageSize} Page), Display: {ScreenWidth} x {ScreenHeight} ({Vram} VRAM - VideoMemorySizeMb={ENBVRam})",
p.SystemMemorySize.ToFileSizeString(), p.SystemPageSize.ToFileSizeString(), p.ScreenWidth, p.ScreenHeight, p.VideoMemorySize.ToFileSizeString(), p.EnbLEVRAMSize);
@ -85,25 +75,8 @@ namespace Wabbajack
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");
//Warmup();
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
this.Initialized += (s, e) =>
{
@ -135,45 +108,7 @@ namespace Wabbajack
.BindToStrict(this, view => view.ResourceUsage.Text);
vm.WhenAnyValue(vm => vm.AppName)
.BindToStrict(this, view => view.AppName.Text);
}
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)

View File

@ -6,7 +6,6 @@
xmlns:local="clr-namespace:Wabbajack"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:rxui="http://reactiveui.net"
xmlns:xwpf="http://schemas.xceed.com/wpf/xaml/toolkit"
d:DesignHeight="450"
d:DesignWidth="800"
x:TypeArguments="local:SettingsVM"
@ -32,17 +31,19 @@
<ColumnDefinition Width="5" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Grid.ColumnSpan="2"
<TextBlock
Grid.Column="0"
Grid.ColumnSpan="2"
FontFamily="Lucida Sans"
FontSize="20"
FontWeight="Bold"
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>
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Grid.Resources>
<Style BasedOn="{StaticResource MainButtonStyle}" TargetType="Button">
@ -55,32 +56,9 @@
</Style.Triggers>
</Style>
</Grid.Resources>
<CheckBox Grid.Row="0"
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"
<Button
Name="OpenTerminal"
Grid.Row="0"
Margin="0,5,0,0"
Content="Launch Wabbajack CLI" />
</Grid>

View File

@ -15,10 +15,6 @@ namespace Wabbajack
this.WhenActivated(disposable =>
{
// 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)
.BindToStrict(this, x => x.OpenTerminal.Command)
.DisposeWith(disposable);

View File

@ -24,7 +24,7 @@
<RowDefinition Height="10" />
<RowDefinition Height="Auto" />
<RowDefinition Height="25" />
<RowDefinition Height="25" />
<RowDefinition Height="Auto" />
<RowDefinition Height="25" />
<RowDefinition Height="25" />
<RowDefinition Height="25" />
@ -34,16 +34,43 @@
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="5" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Grid.ColumnSpan="2"
<TextBlock
Grid.Column="0"
Grid.ColumnSpan="3"
FontFamily="Lucida Sans"
FontSize="20"
FontWeight="Bold"
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>
</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>
</Border>
</rxui:ReactiveUserControl>

View File

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

View File

@ -2,7 +2,7 @@
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net6.0-windows</TargetFramework>
<TargetFramework>net7.0-windows</TargetFramework>
<UseWPF>true</UseWPF>
<Platforms>x64</Platforms>
<RuntimeIdentifier>win10-x64</RuntimeIdentifier>
@ -73,12 +73,12 @@
</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">
<NoWarn>NU1701</NoWarn>
</PackageReference>
<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>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
@ -95,11 +95,11 @@
<PackageReference Include="NLog.Extensions.Logging" Version="5.1.0" />
<PackageReference Include="Orc.FileAssociation" Version="5.0.0-alpha0061" />
<PackageReference Include="PInvoke.User32" Version="0.7.124" />
<PackageReference Include="ReactiveUI" Version="18.3.1" />
<PackageReference Include="ReactiveUI.Fody" Version="18.3.1" />
<PackageReference Include="ReactiveUI.WPF" Version="18.3.1" />
<PackageReference Include="ReactiveUI" Version="19.5.1" />
<PackageReference Include="ReactiveUI.Fody" Version="19.5.1" />
<PackageReference Include="ReactiveUI.WPF" Version="19.5.1" />
<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" />
</ItemGroup>

View File

@ -1,14 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<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.Abstractions" Version="6.0.2-mauipre.1.22102.15" />
<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>
<OutputType>Exe</OutputType>
@ -13,11 +13,12 @@
<NoWarn>CS8600</NoWarn>
<NoWarn>CS8601</NoWarn>
<NoWarn>CS8618</NoWarn>
<TargetFramework>net7.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<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.Abstractions" Version="6.0.2-mauipre.1.22102.15" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="6.0.3" />

View File

@ -14,12 +14,21 @@ namespace Wabbajack.Common;
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)
{
msg.Headers.Add("Cookie", string.Join(";", cookies.Select(c => $"{c.Name}={c.Value}")));
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)
{
foreach (var header in headers)
@ -29,17 +38,10 @@ public static class HttpExtensions
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)
{
var msg = new HttpRequestMessage(HttpMethod.Get, browserState.Uri);
msg.AddChromeAgent();
msg.AddChromeAgent(browserState.UserAgent);
msg.AddCookies(browserState.Cookies);
msg.AddHeaders(browserState.Headers);
return msg;

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net7.0</TargetFramework>
<Nullable>enable</Nullable>
<PackageLicenseExpression>GPL-3.0-or-later</PackageLicenseExpression>
<Version>$(VERSION)</Version>
@ -34,7 +34,7 @@
<ItemGroup>
<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>
<PropertyGroup Condition=" '$(OS)' == 'Windows_NT' ">

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</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>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net7.0</TargetFramework>
<PackageLicenseExpression>GPL-3.0-or-later</PackageLicenseExpression>
<Version>$(VERSION)</Version>
<NoWarn>CS8600</NoWarn>

View File

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

View File

@ -21,7 +21,7 @@ public class GameMetaData
public int[] SteamIDs { get; internal init; } = Array.Empty<int>();
// 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
// C:\ProgramData\Origin\LocalContent\{game name)\*.mfst

View File

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

View File

@ -10,14 +10,14 @@ namespace Wabbajack.DTOs.Interventions;
public class ManualDownload : AUserIntervention<ManualDownload.BrowserDownloadState>
{
public Archive Archive { get; }
public ManualDownload(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")]
public bool ImageContainsTitle { get; set; }
[JsonPropertyName("DisplayVersionOnlyInInstallerView")] public bool DisplayVersionOnlyInInstallerView { get; set; }
[JsonPropertyName("force_down")] public bool ForceDown { get; set; }
[JsonPropertyName("links")] public LinksObject Links { get; set; } = new();

View File

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

View File

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

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net7.0</TargetFramework>
<IsPackable>false</IsPackable>
</PropertyGroup>
@ -11,7 +11,7 @@
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</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="xunit" Version="2.4.2" />
<PackageReference Include="Xunit.DependencyInjection.Logging" Version="8.0.1" />

View File

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

View File

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

View File

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

View File

@ -65,7 +65,7 @@ public class GoogleDriveDownloader : ADownloader<DTOs.DownloadStates.GoogleDrive
return new Uri(
$"https://drive.google.com/uc?id={(state as DTOs.DownloadStates.GoogleDrive)?.Id}&export=download");
}
public override IDownloadState? Resolve(IReadOnlyDictionary<string, string> iniData)
{
if (iniData.ContainsKey("directURL") && Uri.TryCreate(iniData["directURL"].CleanIniString(), UriKind.Absolute, out var uri))
@ -74,8 +74,8 @@ public class GoogleDriveDownloader : ADownloader<DTOs.DownloadStates.GoogleDrive
}
public override Priority Priority => Priority.Normal;
public async Task<T> DownloadStream<T>(Archive archive, Func<Stream, Task<T>> fn, CancellationToken token)
{
var state = archive.State as DTOs.DownloadStates.GoogleDrive;
@ -112,8 +112,8 @@ public class GoogleDriveDownloader : ADownloader<DTOs.DownloadStates.GoogleDrive
{
var initialUrl = $"https://drive.google.com/uc?id={state.Id}&export=download";
var msg = new HttpRequestMessage(HttpMethod.Get, initialUrl);
msg.UseChromeUserAgent();
msg.AddChromeAgent();
using var response = await _client.SendAsync(msg, token);
var cookies = response.GetSetCookies();
var warning = cookies.FirstOrDefault(c => c.Key.StartsWith("download_warning_"));
@ -124,7 +124,7 @@ public class GoogleDriveDownloader : ADownloader<DTOs.DownloadStates.GoogleDrive
var txt = await response.Content.ReadAsStringAsync(token);
if (txt.Contains("<title>Google Drive - Quota exceeded</title>"))
throw new Exception("Google Drive - Quota Exceeded");
doc.LoadHtml(txt);
var action = doc.DocumentNode.DescendantsAndSelf()
@ -133,7 +133,7 @@ public class GoogleDriveDownloader : ADownloader<DTOs.DownloadStates.GoogleDrive
.Select(d => d.GetAttributeValue("action", ""))
.FirstOrDefault();
if (action != null)
if (action != null)
warning = ("download_warning_", "t");
}
@ -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 httpState = new HttpRequestMessage(HttpMethod.Get, url);
httpState.UseChromeUserAgent();
httpState.AddChromeAgent();
return httpState;
}
else
{
var url = $"https://drive.google.com/file/d/{state.Id}/edit";
var msg = new HttpRequestMessage(HttpMethod.Get, url);
msg.UseChromeUserAgent();
msg.AddChromeAgent();
using var response = await _client.SendAsync(msg, token);
msg = new HttpRequestMessage(HttpMethod.Get, url);
msg.UseChromeUserAgent();
msg.AddChromeAgent();
return !response.IsSuccessStatusCode ? null : msg;
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,13 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net7.0</TargetFramework>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<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" />
</ItemGroup>

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net7.0</TargetFramework>
<IsPackable>false</IsPackable>
</PropertyGroup>
@ -11,7 +11,7 @@
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</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.NET.Test.Sdk" Version="17.5.0-preview-20221003-04" />
<PackageReference Include="xunit" Version="2.4.2" />

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net7.0</TargetFramework>
<IsPackable>false</IsPackable>
</PropertyGroup>
@ -11,7 +11,7 @@
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</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="xunit" Version="2.4.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">

View File

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

View File

@ -231,7 +231,7 @@ public class MainWindowViewModel : ViewModelBase
ShowInCenter = true,
ContentTitle = "Wabbajack Launcher: Bad startup path",
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();
Environment.Exit(1);

View File

@ -16,6 +16,7 @@
</ItemGroup>
<PropertyGroup>
<ApplicationIcon>Resources\Icons\wabbajack.ico</ApplicationIcon>
<TargetFramework>net7.0-windows</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Avalonia.Themes.Fluent" Version="11.0.0-preview4" />
@ -30,7 +31,7 @@
<PackageReference Include="JetBrains.Annotations" Version="2022.1.0" />
<PackageReference Include="MessageBox.Avalonia" Version="2.3.1-prev2" />
<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" />
</ItemGroup>
<ItemGroup>

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -10,13 +10,6 @@ namespace Wabbajack.Networking.Http;
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,
JsonSerializerOptions opts, CancellationToken? token = null)
{

View File

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

View File

@ -7,6 +7,7 @@ using System.Net.Http.Headers;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Wabbajack.Configuration;
using Wabbajack.Hashing.xxHash64;
using Wabbajack.Networking.Http.Interfaces;
using Wabbajack.Paths;
@ -19,18 +20,20 @@ public class SingleThreadedDownloader : IHttpDownloader
{
private readonly HttpClient _client;
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;
_client = client;
_settings = settings.PerformanceSettings;
}
public async Task<Hash> Download(HttpRequestMessage message, AbsolutePath outputPath, IJob job,
CancellationToken token)
{
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++)
{
try

View File

@ -1,18 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net7.0</TargetFramework>
<Nullable>enable</Nullable>
<PackageLicenseExpression>GPL-3.0-or-later</PackageLicenseExpression>
<Version>$(VERSION)</Version>
</PropertyGroup>
<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" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Wabbajack.Configuration\Wabbajack.Configuration.csproj" />
<ProjectReference Include="..\Wabbajack.Downloaders.Interfaces\Wabbajack.Downloaders.Interfaces.csproj" />
<ProjectReference Include="..\Wabbajack.Hashing.xxHash64\Wabbajack.Hashing.xxHash64.csproj" />
<ProjectReference Include="..\Wabbajack.Networking.Http.Interfaces\Wabbajack.Networking.Http.Interfaces.csproj" />

View File

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

View File

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

View File

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

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net7.0</TargetFramework>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
@ -12,7 +12,7 @@
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</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="xunit" Version="2.4.2" />
<PackageReference Include="Xunit.DependencyInjection" Version="8.6.1" />

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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