Merge remote-tracking branch 'origin/main'

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

View File

@ -1,21 +1,32 @@
### Changelog
#### 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