mirror of
https://github.com/wabbajack-tools/wabbajack.git
synced 2024-08-30 18:42:17 +00:00
Compare commits
46 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
1fad0f1d73 | ||
|
c5dae97060 | ||
|
931de94230 | ||
|
4cc08cfc0a | ||
|
f58b6190c6 | ||
|
dee84004f5 | ||
|
75a07ea050 | ||
|
8281e77247 | ||
|
fa4d9ff60e | ||
|
278e06139e | ||
|
ec36b8ab4a | ||
|
0ffe0ca8f4 | ||
|
dfeec6b235 | ||
|
c3e8621de6 | ||
|
d911eab6d8 | ||
|
1c5726245a | ||
|
a4f3782eb9 | ||
|
c8bce3a849 | ||
|
2d72370c32 | ||
|
22fcd4b5c8 | ||
|
fdce8e2f1b | ||
|
5cc6d866ea | ||
|
a545cb375a | ||
|
59b2f1a7a1 | ||
|
81d92e6d7b | ||
|
d41940aada | ||
|
ef22b2c389 | ||
|
94f780c6a7 | ||
|
ae640f48b2 | ||
|
a96aef7edd | ||
|
5e0d6ccb82 | ||
|
781cdb3848 | ||
|
8544a6b2e8 | ||
|
09457d6cb7 | ||
|
d9920fefdc | ||
|
749baf1bdf | ||
|
cd03d2991f | ||
|
f956943f45 | ||
|
a6e6758333 | ||
|
9aac41cf69 | ||
|
720a3b1f45 | ||
|
1b949b538a | ||
|
12409ababb | ||
|
a1da63984b | ||
|
37a5b7ce28 | ||
|
7cf03886b7 |
2
.github/workflows/tests.yaml
vendored
2
.github/workflows/tests.yaml
vendored
@ -7,7 +7,7 @@ on:
|
||||
branches: [ main ]
|
||||
|
||||
env:
|
||||
VERSION: 3.6.0.0
|
||||
VERSION: 3.6.1.1
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
28
CHANGELOG.md
28
CHANGELOG.md
@ -1,5 +1,33 @@
|
||||
### Changelog
|
||||
|
||||
#### Version - 3.7.2.0 - 8/25/2024
|
||||
* Added a new button to the installer configuration window for verifying installs. This runs the same code as the verify CLI command, now it's in the UI for easier access. The output of this command
|
||||
is written to a `.html` file and opened in the default browser.
|
||||
* When a modlist install fails due to one or more missing non-nexus files, the installer will now write a `.html` file with all the links and instructions, and open it with the default browser. This data was
|
||||
previsoously only written to the log file.
|
||||
|
||||
#### Version - 3.7.1.1 - 8/13/2024
|
||||
* HOTFIX: buggy release pipeline caused some corruption in the files of 3.7.1.0
|
||||
|
||||
#### Version - 3.7.1.0 - 8/13/2024
|
||||
* Fixed file paths with special characters corrupting when packed into BSAs
|
||||
* This issue only affected Fallout 3, Fallout NV and Skyrim LE
|
||||
* Added logging to determine which downloaded files cannot be hashed
|
||||
* This could occur in the downloading phase when installing a modlist when there are broken/corrupted files in the downloads folder
|
||||
* Fixed Wabbajack crashing when double-clicking the browser window titlebar or URL
|
||||
* Fixed Wabbajack always using explorer.exe instead of the default file browser
|
||||
|
||||
#### Version - 3.7.0.0 - 6/21/2024
|
||||
* Added Starfield support
|
||||
* Note: Hashes were added earlier, but the earlier version was not fully compatible due to Wabbajack extracting the BA2 archives incorrectly. This has been fixed.
|
||||
* Updated GameFinder dependency
|
||||
* Updated WebView dependency
|
||||
* Updated other dependencies
|
||||
|
||||
#### Version - 3.6.1.1 - 5/30/2024
|
||||
* Fixed `set-nexus-api-key` CLI command
|
||||
* Fixed other issues related to OAuth
|
||||
|
||||
#### Version - 3.6.1.0 - 5/26/2024
|
||||
* Fixed a race condition on renewing Nexus Mods OAuth2 tokens
|
||||
* Added `set-nexus-api-key` CLI command
|
||||
|
@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
https://go.microsoft.com/fwlink/?LinkID=208121.
|
||||
-->
|
||||
<Project>
|
||||
<PropertyGroup>
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Any CPU</Platform>
|
||||
<PublishDir>bin\Release\Publish</PublishDir>
|
||||
<PublishProtocol>FileSystem</PublishProtocol>
|
||||
<_TargetId>Folder</_TargetId>
|
||||
<TargetFramework>net8.0-windows</TargetFramework>
|
||||
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
|
||||
<SelfContained>true</SelfContained>
|
||||
<PublishSingleFile>false</PublishSingleFile>
|
||||
<PublishReadyToRun>false</PublishReadyToRun>
|
||||
</PropertyGroup>
|
||||
</Project>
|
@ -56,7 +56,6 @@ namespace Wabbajack
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static void OpenWebsite(Uri url)
|
||||
{
|
||||
Process.Start(new ProcessStartInfo("cmd.exe", $"/c start {url}")
|
||||
@ -64,16 +63,23 @@ namespace Wabbajack
|
||||
CreateNoWindow = true,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
public static void OpenFolder(AbsolutePath path)
|
||||
{
|
||||
Process.Start(new ProcessStartInfo(KnownFolders.Windows.Combine("explorer.exe").ToString(), path.ToString())
|
||||
string folderPath = path.ToString();
|
||||
if (!folderPath.EndsWith(Path.DirectorySeparatorChar.ToString()))
|
||||
{
|
||||
CreateNoWindow = true,
|
||||
folderPath += Path.DirectorySeparatorChar.ToString();
|
||||
}
|
||||
|
||||
Process.Start(new ProcessStartInfo()
|
||||
{
|
||||
FileName = folderPath,
|
||||
UseShellExecute = true,
|
||||
Verb = "open"
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
public static AbsolutePath OpenFileDialog(string filter, string initialDirectory = null)
|
||||
{
|
||||
OpenFileDialog ofd = new OpenFileDialog();
|
||||
|
@ -35,6 +35,9 @@ using Wabbajack.Paths.IO;
|
||||
using Wabbajack.Services.OSIntegrated;
|
||||
using Wabbajack.Util;
|
||||
using System.Windows.Forms;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Wabbajack.CLI.Verbs;
|
||||
using Wabbajack.VFS;
|
||||
|
||||
namespace Wabbajack;
|
||||
|
||||
@ -151,6 +154,8 @@ public class InstallerVM : BackNavigatingVM, IBackNavigatingVM, ICpuStatusVM
|
||||
public ReactiveCommand<Unit, Unit> GoToInstallCommand { get; }
|
||||
public ReactiveCommand<Unit, Unit> BeginCommand { get; }
|
||||
|
||||
public ReactiveCommand<Unit, Unit> VerifyCommand { get; }
|
||||
|
||||
public InstallerVM(ILogger<InstallerVM> logger, DTOSerializer dtos, SettingsManager settingsManager, IServiceProvider serviceProvider,
|
||||
SystemParametersConstructor parametersConstructor, IGameLocator gameLocator, LogStream loggerProvider, ResourceMonitor resourceMonitor,
|
||||
Wabbajack.Services.OSIntegrated.Configuration configuration, HttpClient client, DownloadDispatcher dispatcher, IEnumerable<INeedsLogin> logins,
|
||||
@ -175,6 +180,8 @@ public class InstallerVM : BackNavigatingVM, IBackNavigatingVM, ICpuStatusVM
|
||||
BackCommand = ReactiveCommand.Create(() => NavigateToGlobal.Send(NavigateToGlobal.ScreenType.ModeSelectionView));
|
||||
|
||||
BeginCommand = ReactiveCommand.Create(() => BeginInstall().FireAndForget());
|
||||
|
||||
VerifyCommand = ReactiveCommand.Create(() => Verify().FireAndForget());
|
||||
|
||||
OpenReadmeCommand = ReactiveCommand.Create(() =>
|
||||
{
|
||||
@ -455,6 +462,37 @@ public class InstallerVM : BackNavigatingVM, IBackNavigatingVM, ICpuStatusVM
|
||||
Installer.Location.TargetPath = prev;
|
||||
}
|
||||
|
||||
private async Task Verify()
|
||||
{
|
||||
await Task.Run(async () =>
|
||||
{
|
||||
InstallState = InstallState.Installing;
|
||||
|
||||
StatusText = $"Verifying {ModList.Name}";
|
||||
|
||||
|
||||
var cmd = new VerifyModlistInstall(_serviceProvider.GetRequiredService<ILogger<VerifyModlistInstall>>(), _dtos,
|
||||
_serviceProvider.GetRequiredService<IResource<FileHashCache>>(),
|
||||
_serviceProvider.GetRequiredService<TemporaryFileManager>());
|
||||
|
||||
var result = await cmd.Run(ModListLocation.TargetPath, Installer.Location.TargetPath, _cancellationToken);
|
||||
|
||||
if (result != 0)
|
||||
{
|
||||
TaskBarUpdate.Send($"Error during verification of {ModList.Name}", TaskbarItemProgressState.Error);
|
||||
InstallState = InstallState.Failure;
|
||||
StatusText = $"Error during install of {ModList.Name}";
|
||||
StatusProgress = Percent.Zero;
|
||||
}
|
||||
else
|
||||
{
|
||||
TaskBarUpdate.Send($"Finished verification of {ModList.Name}", TaskbarItemProgressState.Normal);
|
||||
InstallState = InstallState.Success;
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
private async Task BeginInstall()
|
||||
{
|
||||
await Task.Run(async () =>
|
||||
|
@ -77,7 +77,7 @@ namespace Wabbajack
|
||||
|
||||
public void AfterInstallNavigation()
|
||||
{
|
||||
Process.Start("explorer.exe", Location.TargetPath.ToString());
|
||||
UIUtils.OpenFolder(Location.TargetPath);
|
||||
}
|
||||
|
||||
public async Task<bool> Install()
|
||||
|
@ -25,7 +25,6 @@ public partial class BrowserWindow : MetroWindow
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
|
||||
_disposable = new CompositeDisposable();
|
||||
_serviceProvider = serviceProvider;
|
||||
Browser = _serviceProvider.GetRequiredService<WebView2>();
|
||||
@ -43,7 +42,10 @@ public partial class BrowserWindow : MetroWindow
|
||||
|
||||
private void UIElement_OnMouseDown(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
base.DragMove();
|
||||
if (e.LeftButton == MouseButtonState.Pressed)
|
||||
{
|
||||
base.DragMove();
|
||||
}
|
||||
}
|
||||
|
||||
private void BrowserWindow_OnActivated(object sender, EventArgs e)
|
||||
|
@ -82,6 +82,7 @@
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition Height="*" />
|
||||
</Grid.RowDefinitions>
|
||||
<local:BeginButton Grid.Row="1"
|
||||
x:Name="BeginButton"
|
||||
@ -104,12 +105,12 @@
|
||||
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.">
|
||||
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" />
|
||||
@ -121,6 +122,13 @@
|
||||
</Style>
|
||||
</CheckBox.Style>
|
||||
</CheckBox>
|
||||
<Button Grid.Row="3" Grid.Column="2"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Bottom"
|
||||
x:Name="VerifyButton"
|
||||
Content="Verify Installation"
|
||||
ToolTip="Scan the output folders, creating a report on any corrupt or missing files.">
|
||||
</Button>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</rxui:ReactiveUserControl>
|
||||
|
@ -39,6 +39,9 @@ namespace Wabbajack
|
||||
this.WhenAny(x => x.ViewModel.BeginCommand)
|
||||
.BindToStrict(this, x => x.BeginButton.Command)
|
||||
.DisposeWith(dispose);
|
||||
this.WhenAny(x => x.ViewModel.VerifyCommand)
|
||||
.BindToStrict(this, x => x.VerifyButton.Command)
|
||||
.DisposeWith(dispose);
|
||||
this.BindStrict(ViewModel, vm => vm.OverwriteFiles, x => x.OverwriteCheckBox.IsChecked)
|
||||
.DisposeWith(dispose);
|
||||
|
||||
@ -48,6 +51,11 @@ namespace Wabbajack
|
||||
.Select(v => !v.Failed)
|
||||
.BindToStrict(this, view => view.BeginButton.IsEnabled)
|
||||
.DisposeWith(dispose);
|
||||
|
||||
this.WhenAnyValue(x => x.ViewModel.ErrorState)
|
||||
.Select(v => !v.Failed)
|
||||
.BindToStrict(this, view => view.VerifyButton.IsEnabled)
|
||||
.DisposeWith(dispose);
|
||||
|
||||
this.WhenAnyValue(x => x.ViewModel.ErrorState)
|
||||
.Select(v => v.Reason)
|
||||
|
@ -144,7 +144,10 @@ namespace Wabbajack
|
||||
|
||||
private void UIElement_OnMouseDown(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
this.DragMove();
|
||||
if (e.LeftButton == MouseButtonState.Pressed)
|
||||
{
|
||||
this.DragMove();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -90,22 +90,23 @@
|
||||
<PackageReference Include="MahApps.Metro" Version="2.4.10" />
|
||||
<PackageReference Include="MahApps.Metro.IconPacks" Version="4.11.0" />
|
||||
<PackageReference Include="Microsoft-WindowsAPICodePack-Shell" Version="1.1.5" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.WebUtilities" Version="8.0.5" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.WebUtilities" Version="8.0.6" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0" />
|
||||
<PackageReference Include="Microsoft.Web.WebView2" Version="1.0.2478.35" />
|
||||
<PackageReference Include="Microsoft.Web.WebView2" Version="1.0.2535.41" />
|
||||
<PackageReference Include="NLog.Extensions.Logging" Version="5.3.5" />
|
||||
<PackageReference Include="Orc.FileAssociation" Version="5.0.0-alpha0061" />
|
||||
<PackageReference Include="Orc.FileAssociation" Version="5.0.0" />
|
||||
<PackageReference Include="PInvoke.User32" Version="0.7.124" />
|
||||
<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.18.0" />
|
||||
<PackageReference Include="Silk.NET.DXGI" Version="2.21.0" />
|
||||
<PackageReference Include="System.Reactive" Version="6.0.1-preview.1" />
|
||||
<PackageReference Include="WPFThemes.DarkBlend" Version="1.0.8" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Wabbajack.CLI.Builder\Wabbajack.CLI.Builder.csproj" />
|
||||
<ProjectReference Include="..\Wabbajack.CLI\Wabbajack.CLI.csproj" />
|
||||
<ProjectReference Include="..\Wabbajack.Services.OSIntegrated\Wabbajack.Services.OSIntegrated.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
|
@ -8,7 +8,7 @@
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="8.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="8.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="8.0.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="8.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="8.0.0" />
|
||||
|
7
Wabbajack.CLI/Properties/launchSettings.json
Normal file
7
Wabbajack.CLI/Properties/launchSettings.json
Normal file
@ -0,0 +1,7 @@
|
||||
{
|
||||
"profiles": {
|
||||
"Wabbajack.CLI": {
|
||||
"commandName": "Project"
|
||||
}
|
||||
}
|
||||
}
|
@ -1,29 +1,23 @@
|
||||
|
||||
using System.CommandLine;
|
||||
using System.CommandLine.Invocation;
|
||||
using System.CommandLine.NamingConventionBinder;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Wabbajack.CLI.Builder;
|
||||
using Wabbajack.DTOs.Logins;
|
||||
using Wabbajack.Paths;
|
||||
using Wabbajack.Paths.IO;
|
||||
using Wabbajack.Services.OSIntegrated;
|
||||
|
||||
namespace Wabbajack.CLI.Verbs;
|
||||
|
||||
public class SetNexusApiKey
|
||||
{
|
||||
private readonly EncryptedJsonTokenProvider<NexusApiState> _tokenProvider;
|
||||
private readonly EncryptedJsonTokenProvider<NexusOAuthState> _tokenProvider;
|
||||
private readonly ILogger<SetNexusApiKey> _logger;
|
||||
|
||||
public SetNexusApiKey(EncryptedJsonTokenProvider<NexusApiState> tokenProvider, ILogger<SetNexusApiKey> logger)
|
||||
public SetNexusApiKey(EncryptedJsonTokenProvider<NexusOAuthState> tokenProvider, ILogger<SetNexusApiKey> logger)
|
||||
{
|
||||
_tokenProvider = tokenProvider;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public static VerbDefinition Definition = new VerbDefinition("set-nexus-api-key",
|
||||
public static VerbDefinition Definition = new("set-nexus-api-key",
|
||||
"Sets the Nexus API key to the specified value",
|
||||
[
|
||||
new OptionDefinition(typeof(string), "k", "key", "The Nexus API key")
|
||||
@ -38,7 +32,7 @@ public class SetNexusApiKey
|
||||
}
|
||||
else
|
||||
{
|
||||
await _tokenProvider.SetToken(new NexusApiState { ApiKey = key });
|
||||
await _tokenProvider.SetToken(new() { ApiKey = key });
|
||||
_logger.LogInformation("Set Nexus API Key to {key}", key);
|
||||
return 0;
|
||||
}
|
||||
|
@ -1,5 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
@ -26,11 +28,12 @@ public class VerifyModlistInstall
|
||||
private readonly DTOSerializer _dtos;
|
||||
private readonly ILogger<VerifyModlistInstall> _logger;
|
||||
|
||||
public VerifyModlistInstall(ILogger<VerifyModlistInstall> logger, DTOSerializer dtos, IResource<FileHashCache> limiter)
|
||||
public VerifyModlistInstall(ILogger<VerifyModlistInstall> logger, DTOSerializer dtos, IResource<FileHashCache> limiter, TemporaryFileManager temporaryFileManager)
|
||||
{
|
||||
_limiter = limiter;
|
||||
_logger = logger;
|
||||
_dtos = dtos;
|
||||
_temporaryFileManager = temporaryFileManager;
|
||||
}
|
||||
|
||||
public static VerbDefinition Definition = new("verify-modlist-install", "Verify a modlist installed correctly",
|
||||
@ -42,6 +45,7 @@ public class VerifyModlistInstall
|
||||
});
|
||||
|
||||
private readonly IResource<FileHashCache> _limiter;
|
||||
private readonly TemporaryFileManager _temporaryFileManager;
|
||||
|
||||
|
||||
public async Task<int> Run(AbsolutePath modlistLocation, AbsolutePath installFolder, CancellationToken token)
|
||||
@ -52,7 +56,9 @@ public class VerifyModlistInstall
|
||||
_logger.LogInformation("Indexing files");
|
||||
var byTo = list.Directives.ToDictionary(d => d.To);
|
||||
|
||||
var reportFile = _temporaryFileManager.CreateFile(Ext.Html);
|
||||
|
||||
|
||||
_logger.LogInformation("Scanning files");
|
||||
var errors = await list.Directives.PMapAllBatchedAsync(_limiter, async directive =>
|
||||
{
|
||||
@ -68,7 +74,7 @@ public class VerifyModlistInstall
|
||||
return new Result
|
||||
{
|
||||
Path = directive.To,
|
||||
Message = $"File does not exist directive {directive.GetType()}"
|
||||
Message = $"File does not exist"
|
||||
};
|
||||
}
|
||||
|
||||
@ -112,11 +118,30 @@ public class VerifyModlistInstall
|
||||
_logger.LogInformation("Found {Count} errors", errors.Count);
|
||||
|
||||
|
||||
foreach (var error in errors)
|
||||
|
||||
{
|
||||
_logger.LogError("{File} | {Message}", error.Path, error.Message);
|
||||
await using var stream = new StreamWriter(reportFile.Path.Open(FileMode.Create, FileAccess.Write));
|
||||
await stream.WriteLineAsync(
|
||||
"<html><head></head><body>");
|
||||
await stream.WriteLineAsync($"<h1>Verification Report for {modlistLocation}</h1>");
|
||||
|
||||
foreach (var error in errors)
|
||||
{
|
||||
if (error == null) continue;
|
||||
await stream.WriteLineAsync($"<div class=\"error\">{error.Message} | {error.Path}</div>");
|
||||
_logger.LogError("{File} | {Message}", error.Path, error.Message);
|
||||
}
|
||||
|
||||
await stream.WriteLineAsync("</body></html>");
|
||||
}
|
||||
|
||||
_logger.LogInformation("Report written to {Report}", reportFile.Path);
|
||||
|
||||
Process.Start(new ProcessStartInfo("cmd.exe", $"/c start {reportFile}")
|
||||
{
|
||||
CreateNoWindow = true,
|
||||
});
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -8,24 +8,23 @@
|
||||
<PackageLicenseExpression>GPL-3.0-or-later</PackageLicenseExpression>
|
||||
<Version>$(VERSION)</Version>
|
||||
<AssemblyName>wabbajack-cli</AssemblyName>
|
||||
<PublishTrimmed>false</PublishTrimmed>
|
||||
<PublishTrimmed>true</PublishTrimmed>
|
||||
<TimeMode>linked</TimeMode>
|
||||
<NoWarn>CS8600</NoWarn>
|
||||
<NoWarn>CS8601</NoWarn>
|
||||
<NoWarn>CS8618</NoWarn>
|
||||
<JsonSerializerIsReflectionEnabledByDefault>true</JsonSerializerIsReflectionEnabledByDefault>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="8.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="8.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="8.0.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="8.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="8.0.0" />
|
||||
<PackageReference Include="NLog" Version="5.2.5" />
|
||||
<PackageReference Include="NLog.Extensions.Logging" Version="5.3.5" />
|
||||
<PackageReference Include="SixLabors.ImageSharp" Version="3.0.2" />
|
||||
<PackageReference Include="SixLabors.ImageSharp" Version="3.1.4" />
|
||||
<PackageReference Include="System.CommandLine" Version="2.0.0-beta4.22272.1" />
|
||||
<PackageReference Include="System.CommandLine.NamingConventionBinder" Version="2.0.0-beta4.22272.1" />
|
||||
</ItemGroup>
|
||||
|
@ -14,13 +14,13 @@
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="8.0.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
|
||||
<PackageReference Include="xunit" Version="2.6.1" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.3">
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.10.0" />
|
||||
<PackageReference Include="xunit" Version="2.8.1" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.8.1">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="coverlet.collector" Version="6.0.0">
|
||||
<PackageReference Include="coverlet.collector" Version="6.0.2">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
|
@ -55,6 +55,7 @@ public class CompressionTests
|
||||
{
|
||||
if (name == "tes4.bsa") return; // not sure why is is failing
|
||||
|
||||
|
||||
var reader = await BSADispatch.Open(path);
|
||||
|
||||
var dataStates = await reader.Files
|
||||
@ -78,7 +79,6 @@ public class CompressionTests
|
||||
|
||||
var rebuiltStream = new MemoryStream();
|
||||
await build.Build(rebuiltStream, CancellationToken.None);
|
||||
rebuiltStream.Position = 0;
|
||||
|
||||
var reader2 = await BSADispatch.Open(new MemoryStreamFactory(rebuiltStream, path, path.LastModifiedUtc()));
|
||||
await reader.Files.Zip(reader2.Files)
|
||||
|
@ -12,15 +12,15 @@
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="8.0.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
|
||||
<PackageReference Include="xunit" Version="2.6.1" />
|
||||
<PackageReference Include="Xunit.DependencyInjection" Version="8.9.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.10.0" />
|
||||
<PackageReference Include="xunit" Version="2.8.1" />
|
||||
<PackageReference Include="Xunit.DependencyInjection" Version="9.3.0" />
|
||||
<PackageReference Include="Xunit.DependencyInjection.Logging" Version="8.1.0" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.3">
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.8.1">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="coverlet.collector" Version="6.0.0">
|
||||
<PackageReference Include="coverlet.collector" Version="6.0.2">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
|
@ -10,7 +10,7 @@ using Wabbajack.DTOs.BSA.ArchiveStates;
|
||||
using Wabbajack.DTOs.BSA.FileStates;
|
||||
using Wabbajack.Paths.IO;
|
||||
|
||||
namespace Wabbajack.Compression.BSA.FO4Archive;
|
||||
namespace Wabbajack.Compression.BSA.BA2Archive;
|
||||
|
||||
public class Builder : IBuilder
|
||||
{
|
||||
@ -33,7 +33,7 @@ public class Builder : IBuilder
|
||||
|
||||
break;
|
||||
case BA2EntryType.DX10:
|
||||
var resultdx10 = await DX10FileEntryBuilder.Create((BA2DX10File)state, src, _slab, token);
|
||||
var resultdx10 = await DX10FileEntryBuilder.Create((BA2DX10File)state, src, _slab, _state.Compression == 3, token);
|
||||
lock (_entries)
|
||||
{
|
||||
_entries.Add(resultdx10);
|
||||
@ -59,6 +59,13 @@ public class Builder : IBuilder
|
||||
bw.Write((uint) _entries.Count);
|
||||
var tableOffsetLoc = bw.BaseStream.Position;
|
||||
bw.Write((ulong) 0);
|
||||
if(_state.Version == 2 || _state.Version == 3)
|
||||
{
|
||||
bw.Write(_state.Unknown1);
|
||||
bw.Write(_state.Unknown2);
|
||||
if (_state.Version == 3)
|
||||
bw.Write(_state.Compression);
|
||||
}
|
||||
|
||||
foreach (var entry in _entries) entry.WriteHeader(bw, token);
|
||||
|
93
Wabbajack.Compression.BSA/BA2Archive/ChunkBuilder.cs
Normal file
93
Wabbajack.Compression.BSA/BA2Archive/ChunkBuilder.cs
Normal file
@ -0,0 +1,93 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using ICSharpCode.SharpZipLib.Zip.Compression;
|
||||
using ICSharpCode.SharpZipLib.Zip.Compression.Streams;
|
||||
using K4os.Compression.LZ4;
|
||||
using K4os.Compression.LZ4.Encoders;
|
||||
using Wabbajack.Common;
|
||||
using Wabbajack.DTOs.BSA.FileStates;
|
||||
using Wabbajack.DTOs.GitHub;
|
||||
|
||||
namespace Wabbajack.Compression.BSA.BA2Archive;
|
||||
|
||||
public class ChunkBuilder
|
||||
{
|
||||
private BA2Chunk _chunk;
|
||||
private Stream _dataSlab;
|
||||
private long _offsetOffset;
|
||||
private uint _packSize;
|
||||
|
||||
public static async Task<ChunkBuilder> Create(BA2DX10File state, BA2Chunk chunk, Stream src,
|
||||
DiskSlabAllocator slab, bool useLz4Compression, CancellationToken token)
|
||||
{
|
||||
var builder = new ChunkBuilder {_chunk = chunk};
|
||||
|
||||
if (!chunk.Compressed)
|
||||
{
|
||||
builder._dataSlab = slab.Allocate(chunk.FullSz);
|
||||
await src.CopyToLimitAsync(builder._dataSlab, (int) chunk.FullSz, token);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!useLz4Compression)
|
||||
{
|
||||
var deflater = new Deflater(Deflater.BEST_COMPRESSION);
|
||||
await using var ms = new MemoryStream();
|
||||
await using (var ds = new DeflaterOutputStream(ms, deflater))
|
||||
{
|
||||
ds.IsStreamOwner = false;
|
||||
await src.CopyToLimitAsync(ds, (int)chunk.FullSz, token);
|
||||
}
|
||||
|
||||
builder._dataSlab = slab.Allocate(ms.Length);
|
||||
ms.Position = 0;
|
||||
await ms.CopyToLimitAsync(builder._dataSlab, (int)ms.Length, token);
|
||||
builder._packSize = (uint)ms.Length;
|
||||
}
|
||||
else
|
||||
{
|
||||
byte[] full = new byte[chunk.FullSz];
|
||||
await using (var copyStream = new MemoryStream())
|
||||
{
|
||||
await src.CopyToLimitAsync(copyStream, (int)chunk.FullSz, token);
|
||||
full = copyStream.ToArray();
|
||||
}
|
||||
var maxOutput = LZ4Codec.MaximumOutputSize((int)chunk.FullSz);
|
||||
byte[] compressed = new byte[maxOutput];
|
||||
int compressedSize = LZ4Codec.Encode(full, 0, full.Length, compressed, 0, compressed.Length, LZ4Level.L12_MAX);
|
||||
var ms = new MemoryStream(compressed, 0, compressedSize);
|
||||
builder._dataSlab = slab.Allocate(compressedSize);
|
||||
ms.Position = 0;
|
||||
await ms.CopyToLimitAsync(builder._dataSlab, compressedSize, token);
|
||||
builder._packSize = (uint)compressedSize;
|
||||
}
|
||||
}
|
||||
|
||||
builder._dataSlab.Position = 0;
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
public void WriteHeader(BinaryWriter bw)
|
||||
{
|
||||
_offsetOffset = bw.BaseStream.Position;
|
||||
bw.Write((ulong) 0);
|
||||
bw.Write(_packSize);
|
||||
bw.Write(_chunk.FullSz);
|
||||
bw.Write(_chunk.StartMip);
|
||||
bw.Write(_chunk.EndMip);
|
||||
bw.Write(_chunk.Align);
|
||||
}
|
||||
|
||||
public async ValueTask WriteData(BinaryWriter bw, CancellationToken token)
|
||||
{
|
||||
var pos = bw.BaseStream.Position;
|
||||
bw.BaseStream.Position = _offsetOffset;
|
||||
bw.Write((ulong) pos);
|
||||
bw.BaseStream.Position = pos;
|
||||
await _dataSlab.CopyToLimitAsync(bw.BaseStream, (int) _dataSlab.Length, token);
|
||||
await _dataSlab.DisposeAsync();
|
||||
}
|
||||
}
|
179
Wabbajack.Compression.BSA/BA2Archive/DX10Entry.cs
Normal file
179
Wabbajack.Compression.BSA/BA2Archive/DX10Entry.cs
Normal file
@ -0,0 +1,179 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using DirectXTex;
|
||||
using ICSharpCode.SharpZipLib.Zip.Compression;
|
||||
using K4os.Compression.LZ4;
|
||||
using K4os.Compression.LZ4.Streams;
|
||||
using Wabbajack.Common;
|
||||
using Wabbajack.Compression.BSA.BA2Archive;
|
||||
using Wabbajack.DTOs.BSA.FileStates;
|
||||
using Wabbajack.DTOs.Streams;
|
||||
using Wabbajack.Paths;
|
||||
|
||||
namespace Wabbajack.Compression.BSA.BA2Archive;
|
||||
|
||||
public class DX10Entry : IBA2FileEntry
|
||||
{
|
||||
private readonly Reader _bsa;
|
||||
private ushort _chunkHdrLen;
|
||||
private List<TextureChunk> _chunks;
|
||||
private uint _dirHash;
|
||||
private string _extension;
|
||||
private byte _format;
|
||||
private ushort _height;
|
||||
private int _index;
|
||||
private uint _nameHash;
|
||||
private byte _numChunks;
|
||||
private byte _numMips;
|
||||
private ushort _unk16;
|
||||
private byte _unk8;
|
||||
private ushort _width;
|
||||
private readonly byte _isCubemap;
|
||||
private readonly byte _tileMode;
|
||||
|
||||
public DX10Entry(Reader ba2Reader, int idx)
|
||||
{
|
||||
_bsa = ba2Reader;
|
||||
var _rdr = ba2Reader._rdr;
|
||||
_nameHash = _rdr.ReadUInt32();
|
||||
FullPath = _nameHash.ToString("X");
|
||||
_extension = Encoding.UTF8.GetString(_rdr.ReadBytes(4));
|
||||
_dirHash = _rdr.ReadUInt32();
|
||||
_unk8 = _rdr.ReadByte();
|
||||
_numChunks = _rdr.ReadByte();
|
||||
_chunkHdrLen = _rdr.ReadUInt16();
|
||||
_height = _rdr.ReadUInt16();
|
||||
_width = _rdr.ReadUInt16();
|
||||
_numMips = _rdr.ReadByte();
|
||||
_format = _rdr.ReadByte();
|
||||
_isCubemap = _rdr.ReadByte();
|
||||
_tileMode = _rdr.ReadByte();
|
||||
_index = idx;
|
||||
|
||||
_chunks = Enumerable.Range(0, _numChunks)
|
||||
.Select(_ => new TextureChunk(_rdr))
|
||||
.ToList();
|
||||
}
|
||||
private DirectXTexUtility.TexMetadata? _metadata = null;
|
||||
|
||||
public DirectXTexUtility.TexMetadata Metadata
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_metadata == null)
|
||||
_metadata = DirectXTexUtility.GenerateMetadata(_width, _height, _numMips, (DirectXTexUtility.DXGIFormat)_format, _isCubemap == 1);
|
||||
return (DirectXTexUtility.TexMetadata)_metadata;
|
||||
}
|
||||
}
|
||||
|
||||
private uint _headerSize = 0;
|
||||
public uint HeaderSize
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_headerSize > 0)
|
||||
return _headerSize;
|
||||
uint size = 0;
|
||||
size += (uint)Marshal.SizeOf(DirectXTexUtility.DDSHeader.DDSMagic);
|
||||
size += (uint)Marshal.SizeOf<DirectXTexUtility.DDSHeader>();
|
||||
var pixelFormat = DirectXTexUtility.GetPixelFormat(Metadata);
|
||||
var hasDx10Header = DirectXTexUtility.HasDx10Header(pixelFormat);
|
||||
if (hasDx10Header)
|
||||
size += (uint)Marshal.SizeOf<DirectXTexUtility.DX10Header>();
|
||||
|
||||
return _headerSize = size;
|
||||
}
|
||||
}
|
||||
|
||||
public string FullPath { get; set; }
|
||||
|
||||
public RelativePath Path => FullPath.ToRelativePath();
|
||||
public uint Size => (uint)_chunks.Sum(f => f._fullSz) + HeaderSize;
|
||||
|
||||
public AFile State => new BA2DX10File
|
||||
{
|
||||
Path = Path,
|
||||
NameHash = _nameHash,
|
||||
Extension = _extension,
|
||||
DirHash = _dirHash,
|
||||
Unk8 = _unk8,
|
||||
ChunkHdrLen = _chunkHdrLen,
|
||||
Height = _height,
|
||||
Width = _width,
|
||||
NumMips = _numMips,
|
||||
PixelFormat = _format,
|
||||
IsCubeMap = _isCubemap,
|
||||
TileMode = _tileMode,
|
||||
Index = _index,
|
||||
Chunks = _chunks.Select(ch => new BA2Chunk
|
||||
{
|
||||
FullSz = ch._fullSz,
|
||||
StartMip = ch._startMip,
|
||||
EndMip = ch._endMip,
|
||||
Align = ch._align,
|
||||
Compressed = ch._packSz != 0
|
||||
}).ToArray()
|
||||
};
|
||||
|
||||
public async ValueTask CopyDataTo(Stream output, CancellationToken token)
|
||||
{
|
||||
var bw = new BinaryWriter(output);
|
||||
|
||||
WriteHeader(bw);
|
||||
|
||||
await using var fs = await _bsa._streamFactory.GetStream();
|
||||
using var br = new BinaryReader(fs);
|
||||
foreach (var chunk in _chunks)
|
||||
{
|
||||
var full = new byte[chunk._fullSz];
|
||||
var isCompressed = chunk._packSz != 0;
|
||||
|
||||
br.BaseStream.Seek((long)chunk._offset, SeekOrigin.Begin);
|
||||
|
||||
if (!isCompressed)
|
||||
{
|
||||
await br.BaseStream.ReadAsync(full, token);
|
||||
}
|
||||
else
|
||||
{
|
||||
var compressed = new byte[chunk._packSz];
|
||||
await br.BaseStream.ReadAsync(compressed, token);
|
||||
if (_bsa._compression == 3)
|
||||
{
|
||||
LZ4Codec.PartialDecode(compressed, full);
|
||||
}
|
||||
else
|
||||
{
|
||||
var inflater = new Inflater();
|
||||
inflater.SetInput(compressed);
|
||||
inflater.Inflate(full);
|
||||
}
|
||||
}
|
||||
|
||||
await bw.BaseStream.WriteAsync(full, token);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public async ValueTask<IStreamFactory> GetStreamFactory(CancellationToken token)
|
||||
{
|
||||
var ms = new MemoryStream();
|
||||
await CopyDataTo(ms, token);
|
||||
ms.Position = 0;
|
||||
return new MemoryStreamFactory(ms, Path, _bsa._streamFactory.LastModifiedUtc);
|
||||
}
|
||||
|
||||
private void WriteHeader(BinaryWriter bw)
|
||||
{
|
||||
DirectXTexUtility.GenerateDDSHeader(Metadata, DirectXTexUtility.DDSFlags.FORCEDX10EXTMISC2, out var header, out var header10);
|
||||
var headerBytes = DirectXTexUtility.EncodeDDSHeader(header, header10);
|
||||
bw.Write(headerBytes);
|
||||
}
|
||||
}
|
||||
|
@ -1,18 +1,20 @@
|
||||
using DirectXTex;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Compression.BSA;
|
||||
using Wabbajack.DTOs.BSA.FileStates;
|
||||
using Wabbajack.DTOs.Texture;
|
||||
|
||||
namespace Wabbajack.Compression.BSA.FO4Archive;
|
||||
namespace Wabbajack.Compression.BSA.BA2Archive;
|
||||
|
||||
public class DX10FileEntryBuilder : IFileBuilder
|
||||
{
|
||||
private List<ChunkBuilder> _chunks;
|
||||
private BA2DX10File _state;
|
||||
private uint _headerSize = 0;
|
||||
|
||||
public uint FileHash => _state.NameHash;
|
||||
public uint DirHash => _state.DirHash;
|
||||
@ -43,20 +45,36 @@ public class DX10FileEntryBuilder : IFileBuilder
|
||||
foreach (var chunk in _chunks)
|
||||
await chunk.WriteData(wtr, token);
|
||||
}
|
||||
public uint GetHeaderSize(BA2DX10File state)
|
||||
{
|
||||
if (_headerSize > 0)
|
||||
return _headerSize;
|
||||
|
||||
public static async Task<DX10FileEntryBuilder> Create(BA2DX10File state, Stream src, DiskSlabAllocator slab,
|
||||
uint size = 0;
|
||||
size += (uint)Marshal.SizeOf(DirectXTexUtility.DDSHeader.DDSMagic);
|
||||
size += (uint)Marshal.SizeOf<DirectXTexUtility.DDSHeader>();
|
||||
var metadata = DirectXTexUtility.GenerateMetadata(state.Width, state.Height, state.NumMips, (DirectXTexUtility.DXGIFormat)state.PixelFormat, state.IsCubeMap == 1);
|
||||
var pixelFormat = DirectXTexUtility.GetPixelFormat(metadata);
|
||||
var hasDx10Header = DirectXTexUtility.HasDx10Header(pixelFormat);
|
||||
if (hasDx10Header)
|
||||
size += (uint)Marshal.SizeOf<DirectXTexUtility.DX10Header>();
|
||||
|
||||
return _headerSize = size;
|
||||
}
|
||||
|
||||
public static async Task<DX10FileEntryBuilder> Create(BA2DX10File state, Stream src, DiskSlabAllocator slab, bool useLz4Compression,
|
||||
CancellationToken token)
|
||||
{
|
||||
var builder = new DX10FileEntryBuilder {_state = state};
|
||||
|
||||
var headerSize = DDS.HeaderSizeForFormat((DXGI_FORMAT) state.PixelFormat) + 4;
|
||||
var headerSize = builder.GetHeaderSize(state);
|
||||
new BinaryReader(src).ReadBytes((int) headerSize);
|
||||
|
||||
// This can't be parallel because it all runs off the same base IO stream.
|
||||
builder._chunks = new List<ChunkBuilder>();
|
||||
|
||||
foreach (var chunk in state.Chunks)
|
||||
builder._chunks.Add(await ChunkBuilder.Create(state, chunk, src, slab, token));
|
||||
builder._chunks.Add(await ChunkBuilder.Create(state, chunk, src, slab, useLz4Compression, token));
|
||||
|
||||
return builder;
|
||||
}
|
@ -9,7 +9,7 @@ using Wabbajack.DTOs.BSA.FileStates;
|
||||
using Wabbajack.DTOs.Streams;
|
||||
using Wabbajack.Paths;
|
||||
|
||||
namespace Wabbajack.Compression.BSA.FO4Archive;
|
||||
namespace Wabbajack.Compression.BSA.BA2Archive;
|
||||
|
||||
public class FileEntry : IBA2FileEntry
|
||||
{
|
@ -6,7 +6,7 @@ using ICSharpCode.SharpZipLib.Zip.Compression.Streams;
|
||||
using Wabbajack.Common;
|
||||
using Wabbajack.DTOs.BSA.FileStates;
|
||||
|
||||
namespace Wabbajack.Compression.BSA.FO4Archive;
|
||||
namespace Wabbajack.Compression.BSA.BA2Archive;
|
||||
|
||||
public class FileEntryBuilder : IFileBuilder
|
||||
{
|
@ -1,6 +1,6 @@
|
||||
using Wabbajack.Compression.BSA.Interfaces;
|
||||
|
||||
namespace Wabbajack.Compression.BSA.FO4Archive;
|
||||
namespace Wabbajack.Compression.BSA.BA2Archive;
|
||||
|
||||
internal interface IBA2FileEntry : IFile
|
||||
{
|
@ -2,7 +2,7 @@ using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Wabbajack.Compression.BSA.FO4Archive;
|
||||
namespace Wabbajack.Compression.BSA.BA2Archive;
|
||||
|
||||
internal interface IFileBuilder
|
||||
{
|
@ -7,7 +7,7 @@ using Wabbajack.Compression.BSA.Interfaces;
|
||||
using Wabbajack.DTOs.BSA.ArchiveStates;
|
||||
using Wabbajack.DTOs.Streams;
|
||||
|
||||
namespace Wabbajack.Compression.BSA.FO4Archive;
|
||||
namespace Wabbajack.Compression.BSA.BA2Archive;
|
||||
|
||||
public class Reader : IReader
|
||||
{
|
||||
@ -15,9 +15,17 @@ public class Reader : IReader
|
||||
internal string _headerMagic;
|
||||
internal ulong _nameTableOffset;
|
||||
internal uint _numFiles;
|
||||
internal uint _unknown1;
|
||||
internal uint _unknown2;
|
||||
internal uint _compression;
|
||||
internal BinaryReader _rdr;
|
||||
public IStreamFactory _streamFactory;
|
||||
internal BA2EntryType _type;
|
||||
|
||||
/// <summary>
|
||||
/// Fallout 4 - Version 1, 7 or 8
|
||||
/// Starfield - Version 2 or 3
|
||||
/// </summary>
|
||||
internal uint _version;
|
||||
|
||||
private Reader(Stream stream)
|
||||
@ -37,7 +45,10 @@ public class Reader : IReader
|
||||
Version = _version,
|
||||
HeaderMagic = _headerMagic,
|
||||
Type = _type,
|
||||
HasNameTable = HasNameTable
|
||||
HasNameTable = HasNameTable,
|
||||
Unknown1 = _unknown1,
|
||||
Unknown2 = _unknown2,
|
||||
Compression = _compression,
|
||||
};
|
||||
|
||||
|
||||
@ -67,6 +78,10 @@ public class Reader : IReader
|
||||
_numFiles = _rdr.ReadUInt32();
|
||||
_nameTableOffset = _rdr.ReadUInt64();
|
||||
|
||||
_unknown1 = (_version == 2 || _version == 3) ? _rdr.ReadUInt32() : 0;
|
||||
_unknown2 = (_version == 2 || _version == 3) ? _rdr.ReadUInt32() : 0;
|
||||
_compression = (_version == 3) ? _rdr.ReadUInt32() : 0;
|
||||
|
||||
var files = new List<IBA2FileEntry>();
|
||||
for (var idx = 0; idx < _numFiles; idx += 1)
|
||||
switch (_type)
|
||||
@ -94,4 +109,4 @@ public class Reader : IReader
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
using System.IO;
|
||||
|
||||
namespace Wabbajack.Compression.BSA.FO4Archive;
|
||||
namespace Wabbajack.Compression.BSA.BA2Archive;
|
||||
|
||||
public class TextureChunk
|
||||
{
|
@ -22,7 +22,7 @@ public static class BSADispatch
|
||||
{
|
||||
FileType.TES3 => await Reader.Load(new NativeFileStreamFactory(filename)),
|
||||
FileType.BSA => await TES5Archive.Reader.Load(new NativeFileStreamFactory(filename)),
|
||||
FileType.BA2 => await FO4Archive.Reader.Load(new NativeFileStreamFactory(filename)),
|
||||
FileType.BA2 => await BA2Archive.Reader.Load(new NativeFileStreamFactory(filename)),
|
||||
_ => throw new InvalidDataException("Filename is not a .bsa or .ba2")
|
||||
};
|
||||
}
|
||||
@ -34,7 +34,7 @@ public static class BSADispatch
|
||||
{
|
||||
FileType.TES3 => await Reader.Load(factory),
|
||||
FileType.BSA => await TES5Archive.Reader.Load(factory),
|
||||
FileType.BA2 => await FO4Archive.Reader.Load(factory),
|
||||
FileType.BA2 => await BA2Archive.Reader.Load(factory),
|
||||
_ => throw new InvalidDataException("Filename is not a .bsa or .ba2")
|
||||
};
|
||||
}
|
||||
@ -46,7 +46,7 @@ public static class BSADispatch
|
||||
{
|
||||
FileType.TES3 => await Reader.Load(factory),
|
||||
FileType.BSA => await TES5Archive.Reader.Load(factory),
|
||||
FileType.BA2 => await FO4Archive.Reader.Load(factory),
|
||||
FileType.BA2 => await BA2Archive.Reader.Load(factory),
|
||||
_ => throw new InvalidDataException("Filename is not a .bsa or .ba2")
|
||||
};
|
||||
}
|
||||
@ -57,7 +57,7 @@ public static class BSADispatch
|
||||
{
|
||||
TES3State tes3 => new Builder(tes3),
|
||||
BSAState bsa => TES5Archive.Builder.Create(bsa, manager),
|
||||
BA2State ba2 => FO4Archive.Builder.Create(ba2, manager),
|
||||
BA2State ba2 => BA2Archive.Builder.Create(ba2, manager),
|
||||
_ => throw new NotImplementedException()
|
||||
};
|
||||
}
|
||||
|
@ -23,6 +23,7 @@ public static class BinaryHelperExtensions
|
||||
return version switch
|
||||
{
|
||||
VersionType.TES3 => Encoding.ASCII,
|
||||
VersionType.FO3 => Encoding.UTF8,
|
||||
VersionType.SSE => Windows1252,
|
||||
_ => Encoding.UTF7
|
||||
};
|
||||
|
@ -1,215 +0,0 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using Wabbajack.DTOs.Texture;
|
||||
|
||||
namespace Compression.BSA;
|
||||
/*
|
||||
* Copied from https://raw.githubusercontent.com/AlexxEG/BSA_Browser/master/Sharp.BSA.BA2/BA2Util/DDS.cs
|
||||
* which is also GPL3 code. Modified slightly for Wabbajack
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copied from dds.h. Includes (almost) only stuff I need in this project.
|
||||
*
|
||||
* Link: https://github.com/digitalutopia1/BA2Lib/blob/master/BA2Lib/dds.h
|
||||
*
|
||||
*/
|
||||
|
||||
public class DDS
|
||||
{
|
||||
public const int DDS_MAGIC = 0x20534444; // "DDS "
|
||||
|
||||
public const int DDS_FOURCC = 0x00000004; // DDPF_FOURCC
|
||||
public const int DDS_RGB = 0x00000040; // DDPF_RGB
|
||||
public const int DDS_RGBA = 0x00000041; // DDPF_RGB | DDPF_ALPHAPIXELS
|
||||
|
||||
public const int
|
||||
DDS_HEADER_FLAGS_TEXTURE = 0x00001007; // DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT
|
||||
|
||||
public const int DDS_HEADER_FLAGS_MIPMAP = 0x00020000; // DDSD_MIPMAPCOUNT
|
||||
public const int DDS_HEADER_FLAGS_LINEARSIZE = 0x00080000; // DDSD_LINEARSIZE
|
||||
|
||||
public const int DDS_SURFACE_FLAGS_TEXTURE = 0x00001000; // DDSCAPS_TEXTURE
|
||||
public const int DDS_SURFACE_FLAGS_MIPMAP = 0x00400008; // DDSCAPS_COMPLEX | DDSCAPS_MIPMAP
|
||||
|
||||
public const int DDS_ALPHA_MODE_UNKNOWN = 0x0;
|
||||
|
||||
public static uint HeaderSizeForFormat(DXGI_FORMAT fmt)
|
||||
{
|
||||
switch (fmt)
|
||||
{
|
||||
case DXGI_FORMAT.BC1_UNORM_SRGB:
|
||||
case DXGI_FORMAT.BC3_UNORM_SRGB:
|
||||
case DXGI_FORMAT.BC4_UNORM:
|
||||
case DXGI_FORMAT.BC5_SNORM:
|
||||
case DXGI_FORMAT.BC6H_UF16:
|
||||
case DXGI_FORMAT.BC7_UNORM:
|
||||
case DXGI_FORMAT.BC7_UNORM_SRGB:
|
||||
return DDS_HEADER_DXT10.Size + DDS_HEADER.Size;
|
||||
default:
|
||||
return DDS_HEADER.Size;
|
||||
}
|
||||
}
|
||||
|
||||
public static uint MAKEFOURCC(char ch0, char ch1, char ch2, char ch3)
|
||||
{
|
||||
// This is alien to me...
|
||||
return (byte) ch0 | ((uint) (byte) ch1 << 8) | ((uint) (byte) ch2 << 16) | ((uint) (byte) ch3 << 24);
|
||||
}
|
||||
}
|
||||
|
||||
public enum DXT10_RESOURCE_DIMENSION
|
||||
{
|
||||
DIMENSION_TEXTURE1D = 2,
|
||||
DIMENSION_TEXTURE2D = 3,
|
||||
DIMENSION_TEXTURE3D = 4
|
||||
}
|
||||
|
||||
[Flags]
|
||||
public enum DDSCAPS2 : uint
|
||||
{
|
||||
CUBEMAP = 0x200,
|
||||
CUBEMAP_POSITIVEX = 0x400,
|
||||
CUBEMAP_NEGATIVEX = 0x800,
|
||||
CUBEMAP_POSITIVEY = 0x1000,
|
||||
CUBEMAP_NEGATIVEY = 0x2000,
|
||||
CUBEMAP_POSITIVEZ = 0x4000,
|
||||
CUBEMAP_NEGATIVEZ = 0x8000,
|
||||
CUBEMAP_ALLFACES = 0xFC00
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
public struct DDS_HEADER
|
||||
{
|
||||
public uint dwSize;
|
||||
public uint dwHeaderFlags;
|
||||
public uint dwHeight;
|
||||
public uint dwWidth;
|
||||
public uint dwPitchOrLinearSize;
|
||||
public uint dwDepth; // only if DDS_HEADER_FLAGS_VOLUME is set in dwHeaderFlags
|
||||
public uint dwMipMapCount;
|
||||
public uint dwReserved1; // [11]
|
||||
public DDS_PIXELFORMAT PixelFormat; // ddspf
|
||||
public uint dwSurfaceFlags;
|
||||
public uint dwCubemapFlags;
|
||||
public uint dwReserved2; // [3]
|
||||
|
||||
public uint GetSize()
|
||||
{
|
||||
// 9 uint + DDS_PIXELFORMAT uints + 2 uint arrays with 14 uints total
|
||||
// each uint 4 bytes each
|
||||
return 9 * 4 + PixelFormat.GetSize() + 14 * 4;
|
||||
}
|
||||
|
||||
|
||||
public void Write(BinaryWriter bw)
|
||||
{
|
||||
bw.Write(dwSize);
|
||||
bw.Write(dwHeaderFlags);
|
||||
bw.Write(dwHeight);
|
||||
bw.Write(dwWidth);
|
||||
bw.Write(dwPitchOrLinearSize);
|
||||
bw.Write(dwDepth);
|
||||
bw.Write(dwMipMapCount);
|
||||
|
||||
// Just write it multiple times, since it's never assigned a value anyway
|
||||
for (var i = 0; i < 11; i++)
|
||||
bw.Write(dwReserved1);
|
||||
|
||||
// DDS_PIXELFORMAT
|
||||
bw.Write(PixelFormat.dwSize);
|
||||
bw.Write(PixelFormat.dwFlags);
|
||||
bw.Write(PixelFormat.dwFourCC);
|
||||
bw.Write(PixelFormat.dwRGBBitCount);
|
||||
bw.Write(PixelFormat.dwRBitMask);
|
||||
bw.Write(PixelFormat.dwGBitMask);
|
||||
bw.Write(PixelFormat.dwBBitMask);
|
||||
bw.Write(PixelFormat.dwABitMask);
|
||||
|
||||
bw.Write(dwSurfaceFlags);
|
||||
bw.Write(dwCubemapFlags);
|
||||
|
||||
// Just write it multiple times, since it's never assigned a value anyway
|
||||
for (var i = 0; i < 3; i++)
|
||||
bw.Write(dwReserved2);
|
||||
}
|
||||
|
||||
public static uint Size
|
||||
{
|
||||
get
|
||||
{
|
||||
unsafe
|
||||
{
|
||||
return (uint) (sizeof(DDS_HEADER) + sizeof(int) * 10 + sizeof(int) * 2);
|
||||
}
|
||||
|
||||
;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
public struct DDS_HEADER_DXT10
|
||||
{
|
||||
public uint dxgiFormat;
|
||||
public uint resourceDimension;
|
||||
public uint miscFlag;
|
||||
public uint arraySize;
|
||||
public uint miscFlags2;
|
||||
|
||||
public void Write(BinaryWriter bw)
|
||||
{
|
||||
bw.Write(dxgiFormat);
|
||||
bw.Write(resourceDimension);
|
||||
bw.Write(miscFlag);
|
||||
bw.Write(arraySize);
|
||||
bw.Write(miscFlags2);
|
||||
}
|
||||
|
||||
public static uint Size
|
||||
{
|
||||
get
|
||||
{
|
||||
unsafe
|
||||
{
|
||||
return (uint) sizeof(DDS_HEADER_DXT10);
|
||||
}
|
||||
|
||||
;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
public struct DDS_PIXELFORMAT
|
||||
{
|
||||
public uint dwSize;
|
||||
public uint dwFlags;
|
||||
public uint dwFourCC;
|
||||
public uint dwRGBBitCount;
|
||||
public uint dwRBitMask;
|
||||
public uint dwGBitMask;
|
||||
public uint dwBBitMask;
|
||||
public uint dwABitMask;
|
||||
|
||||
public DDS_PIXELFORMAT(uint size, uint flags, uint fourCC, uint rgbBitCount, uint rBitMask, uint gBitMask,
|
||||
uint bBitMask, uint aBitMask)
|
||||
{
|
||||
dwSize = size;
|
||||
dwFlags = flags;
|
||||
dwFourCC = fourCC;
|
||||
dwRGBBitCount = rgbBitCount;
|
||||
dwRBitMask = rBitMask;
|
||||
dwGBitMask = gBitMask;
|
||||
dwBBitMask = bBitMask;
|
||||
dwABitMask = aBitMask;
|
||||
}
|
||||
|
||||
public uint GetSize()
|
||||
{
|
||||
// 8 uints, each 4 bytes each
|
||||
return 8 * 4;
|
||||
}
|
||||
}
|
1116
Wabbajack.Compression.BSA/DirectXTexUtil.cs
Normal file
1116
Wabbajack.Compression.BSA/DirectXTexUtil.cs
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,69 +0,0 @@
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using ICSharpCode.SharpZipLib.Zip.Compression;
|
||||
using ICSharpCode.SharpZipLib.Zip.Compression.Streams;
|
||||
using Wabbajack.Common;
|
||||
using Wabbajack.DTOs.BSA.FileStates;
|
||||
|
||||
namespace Wabbajack.Compression.BSA.FO4Archive;
|
||||
|
||||
public class ChunkBuilder
|
||||
{
|
||||
private BA2Chunk _chunk;
|
||||
private Stream _dataSlab;
|
||||
private long _offsetOffset;
|
||||
private uint _packSize;
|
||||
|
||||
public static async Task<ChunkBuilder> Create(BA2DX10File state, BA2Chunk chunk, Stream src,
|
||||
DiskSlabAllocator slab, CancellationToken token)
|
||||
{
|
||||
var builder = new ChunkBuilder {_chunk = chunk};
|
||||
|
||||
if (!chunk.Compressed)
|
||||
{
|
||||
builder._dataSlab = slab.Allocate(chunk.FullSz);
|
||||
await src.CopyToLimitAsync(builder._dataSlab, (int) chunk.FullSz, token);
|
||||
}
|
||||
else
|
||||
{
|
||||
var deflater = new Deflater(Deflater.BEST_COMPRESSION);
|
||||
await using var ms = new MemoryStream();
|
||||
await using (var ds = new DeflaterOutputStream(ms, deflater))
|
||||
{
|
||||
ds.IsStreamOwner = false;
|
||||
await src.CopyToLimitAsync(ds, (int) chunk.FullSz, token);
|
||||
}
|
||||
|
||||
builder._dataSlab = slab.Allocate(ms.Length);
|
||||
ms.Position = 0;
|
||||
await ms.CopyToLimitAsync(builder._dataSlab, (int) ms.Length, token);
|
||||
builder._packSize = (uint) ms.Length;
|
||||
}
|
||||
|
||||
builder._dataSlab.Position = 0;
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
public void WriteHeader(BinaryWriter bw)
|
||||
{
|
||||
_offsetOffset = bw.BaseStream.Position;
|
||||
bw.Write((ulong) 0);
|
||||
bw.Write(_packSize);
|
||||
bw.Write(_chunk.FullSz);
|
||||
bw.Write(_chunk.StartMip);
|
||||
bw.Write(_chunk.EndMip);
|
||||
bw.Write(_chunk.Align);
|
||||
}
|
||||
|
||||
public async ValueTask WriteData(BinaryWriter bw, CancellationToken token)
|
||||
{
|
||||
var pos = bw.BaseStream.Position;
|
||||
bw.BaseStream.Position = _offsetOffset;
|
||||
bw.Write((ulong) pos);
|
||||
bw.BaseStream.Position = pos;
|
||||
await _dataSlab.CopyToLimitAsync(bw.BaseStream, (int) _dataSlab.Length, token);
|
||||
await _dataSlab.DisposeAsync();
|
||||
}
|
||||
}
|
@ -1,249 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Compression.BSA;
|
||||
using ICSharpCode.SharpZipLib.Zip.Compression;
|
||||
using Wabbajack.Common;
|
||||
using Wabbajack.DTOs.BSA.FileStates;
|
||||
using Wabbajack.DTOs.Streams;
|
||||
using Wabbajack.DTOs.Texture;
|
||||
using Wabbajack.Paths;
|
||||
|
||||
namespace Wabbajack.Compression.BSA.FO4Archive;
|
||||
|
||||
public class DX10Entry : IBA2FileEntry
|
||||
{
|
||||
private readonly Reader _bsa;
|
||||
private ushort _chunkHdrLen;
|
||||
private List<TextureChunk> _chunks;
|
||||
private uint _dirHash;
|
||||
private string _extension;
|
||||
private byte _format;
|
||||
private ushort _height;
|
||||
private int _index;
|
||||
private uint _nameHash;
|
||||
private byte _numChunks;
|
||||
private byte _numMips;
|
||||
private ushort _unk16;
|
||||
private byte _unk8;
|
||||
private ushort _width;
|
||||
private readonly byte _isCubemap;
|
||||
private readonly byte _tileMode;
|
||||
|
||||
public DX10Entry(Reader ba2Reader, int idx)
|
||||
{
|
||||
_bsa = ba2Reader;
|
||||
var _rdr = ba2Reader._rdr;
|
||||
_nameHash = _rdr.ReadUInt32();
|
||||
FullPath = _nameHash.ToString("X");
|
||||
_extension = Encoding.UTF8.GetString(_rdr.ReadBytes(4));
|
||||
_dirHash = _rdr.ReadUInt32();
|
||||
_unk8 = _rdr.ReadByte();
|
||||
_numChunks = _rdr.ReadByte();
|
||||
_chunkHdrLen = _rdr.ReadUInt16();
|
||||
_height = _rdr.ReadUInt16();
|
||||
_width = _rdr.ReadUInt16();
|
||||
_numMips = _rdr.ReadByte();
|
||||
_format = _rdr.ReadByte();
|
||||
_isCubemap = _rdr.ReadByte();
|
||||
_tileMode = _rdr.ReadByte();
|
||||
_index = idx;
|
||||
|
||||
_chunks = Enumerable.Range(0, _numChunks)
|
||||
.Select(_ => new TextureChunk(_rdr))
|
||||
.ToList();
|
||||
}
|
||||
|
||||
public uint HeaderSize => DDS.HeaderSizeForFormat((DXGI_FORMAT) _format);
|
||||
|
||||
public string FullPath { get; set; }
|
||||
|
||||
public RelativePath Path => FullPath.ToRelativePath();
|
||||
public uint Size => (uint) _chunks.Sum(f => f._fullSz) + HeaderSize + sizeof(uint);
|
||||
|
||||
public AFile State => new BA2DX10File
|
||||
{
|
||||
Path = Path,
|
||||
NameHash = _nameHash,
|
||||
Extension = _extension,
|
||||
DirHash = _dirHash,
|
||||
Unk8 = _unk8,
|
||||
ChunkHdrLen = _chunkHdrLen,
|
||||
Height = _height,
|
||||
Width = _width,
|
||||
NumMips = _numMips,
|
||||
PixelFormat = _format,
|
||||
IsCubeMap = _isCubemap,
|
||||
TileMode = _tileMode,
|
||||
Index = _index,
|
||||
Chunks = _chunks.Select(ch => new BA2Chunk
|
||||
{
|
||||
FullSz = ch._fullSz,
|
||||
StartMip = ch._startMip,
|
||||
EndMip = ch._endMip,
|
||||
Align = ch._align,
|
||||
Compressed = ch._packSz != 0
|
||||
}).ToArray()
|
||||
};
|
||||
|
||||
public async ValueTask CopyDataTo(Stream output, CancellationToken token)
|
||||
{
|
||||
var bw = new BinaryWriter(output);
|
||||
|
||||
WriteHeader(bw);
|
||||
|
||||
await using var fs = await _bsa._streamFactory.GetStream();
|
||||
using var br = new BinaryReader(fs);
|
||||
foreach (var chunk in _chunks)
|
||||
{
|
||||
var full = new byte[chunk._fullSz];
|
||||
var isCompressed = chunk._packSz != 0;
|
||||
|
||||
br.BaseStream.Seek((long) chunk._offset, SeekOrigin.Begin);
|
||||
|
||||
if (!isCompressed)
|
||||
{
|
||||
await br.BaseStream.ReadAsync(full, token);
|
||||
}
|
||||
else
|
||||
{
|
||||
var compressed = new byte[chunk._packSz];
|
||||
await br.BaseStream.ReadAsync(compressed, token);
|
||||
var inflater = new Inflater();
|
||||
inflater.SetInput(compressed);
|
||||
inflater.Inflate(full);
|
||||
}
|
||||
|
||||
await bw.BaseStream.WriteAsync(full, token);
|
||||
}
|
||||
}
|
||||
|
||||
public async ValueTask<IStreamFactory> GetStreamFactory(CancellationToken token)
|
||||
{
|
||||
var ms = new MemoryStream();
|
||||
await CopyDataTo(ms, token);
|
||||
ms.Position = 0;
|
||||
return new MemoryStreamFactory(ms, Path, _bsa._streamFactory.LastModifiedUtc);
|
||||
}
|
||||
|
||||
private void WriteHeader(BinaryWriter bw)
|
||||
{
|
||||
var ddsHeader = new DDS_HEADER();
|
||||
|
||||
ddsHeader.dwSize = ddsHeader.GetSize();
|
||||
ddsHeader.dwHeaderFlags = DDS.DDS_HEADER_FLAGS_TEXTURE | DDS.DDS_HEADER_FLAGS_LINEARSIZE |
|
||||
DDS.DDS_HEADER_FLAGS_MIPMAP;
|
||||
ddsHeader.dwHeight = _height;
|
||||
ddsHeader.dwWidth = _width;
|
||||
ddsHeader.dwMipMapCount = _numMips;
|
||||
ddsHeader.PixelFormat.dwSize = ddsHeader.PixelFormat.GetSize();
|
||||
ddsHeader.dwDepth = 1;
|
||||
ddsHeader.dwSurfaceFlags = DDS.DDS_SURFACE_FLAGS_TEXTURE | DDS.DDS_SURFACE_FLAGS_MIPMAP;
|
||||
ddsHeader.dwCubemapFlags = _isCubemap == 1 ? (uint)(DDSCAPS2.CUBEMAP
|
||||
| DDSCAPS2.CUBEMAP_NEGATIVEX | DDSCAPS2.CUBEMAP_POSITIVEX
|
||||
| DDSCAPS2.CUBEMAP_NEGATIVEY | DDSCAPS2.CUBEMAP_POSITIVEY
|
||||
| DDSCAPS2.CUBEMAP_NEGATIVEZ | DDSCAPS2.CUBEMAP_POSITIVEZ
|
||||
| DDSCAPS2.CUBEMAP_ALLFACES) : 0u;
|
||||
|
||||
|
||||
switch ((DXGI_FORMAT) _format)
|
||||
{
|
||||
case DXGI_FORMAT.BC1_UNORM:
|
||||
ddsHeader.PixelFormat.dwFlags = DDS.DDS_FOURCC;
|
||||
ddsHeader.PixelFormat.dwFourCC = DDS.MAKEFOURCC('D', 'X', 'T', '1');
|
||||
ddsHeader.dwPitchOrLinearSize = (uint) (_width * _height / 2); // 4bpp
|
||||
break;
|
||||
case DXGI_FORMAT.BC2_UNORM:
|
||||
ddsHeader.PixelFormat.dwFlags = DDS.DDS_FOURCC;
|
||||
ddsHeader.PixelFormat.dwFourCC = DDS.MAKEFOURCC('D', 'X', 'T', '3');
|
||||
ddsHeader.dwPitchOrLinearSize = (uint) (_width * _height); // 8bpp
|
||||
break;
|
||||
case DXGI_FORMAT.BC3_UNORM:
|
||||
ddsHeader.PixelFormat.dwFlags = DDS.DDS_FOURCC;
|
||||
ddsHeader.PixelFormat.dwFourCC = DDS.MAKEFOURCC('D', 'X', 'T', '5');
|
||||
ddsHeader.dwPitchOrLinearSize = (uint) (_width * _height); // 8bpp
|
||||
break;
|
||||
case DXGI_FORMAT.BC5_UNORM:
|
||||
ddsHeader.PixelFormat.dwFlags = DDS.DDS_FOURCC;
|
||||
if (_bsa.UseATIFourCC)
|
||||
ddsHeader.PixelFormat.dwFourCC =
|
||||
DDS.MAKEFOURCC('A', 'T', 'I',
|
||||
'2'); // this is more correct but the only thing I have found that supports it is the nvidia photoshop plugin
|
||||
else
|
||||
ddsHeader.PixelFormat.dwFourCC = DDS.MAKEFOURCC('B', 'C', '5', 'U');
|
||||
ddsHeader.dwPitchOrLinearSize = (uint) (_width * _height); // 8bpp
|
||||
break;
|
||||
case DXGI_FORMAT.BC1_UNORM_SRGB:
|
||||
ddsHeader.PixelFormat.dwFlags = DDS.DDS_FOURCC;
|
||||
ddsHeader.PixelFormat.dwFourCC = DDS.MAKEFOURCC('D', 'X', '1', '0');
|
||||
ddsHeader.dwPitchOrLinearSize = (uint) (_width * _height / 2); // 4bpp
|
||||
break;
|
||||
case DXGI_FORMAT.BC3_UNORM_SRGB:
|
||||
case DXGI_FORMAT.BC6H_UF16:
|
||||
case DXGI_FORMAT.BC4_UNORM:
|
||||
case DXGI_FORMAT.BC5_SNORM:
|
||||
case DXGI_FORMAT.BC7_UNORM:
|
||||
case DXGI_FORMAT.BC7_UNORM_SRGB:
|
||||
ddsHeader.PixelFormat.dwFlags = DDS.DDS_FOURCC;
|
||||
ddsHeader.PixelFormat.dwFourCC = DDS.MAKEFOURCC('D', 'X', '1', '0');
|
||||
ddsHeader.dwPitchOrLinearSize = (uint) (_width * _height); // 8bpp
|
||||
break;
|
||||
case DXGI_FORMAT.R8G8B8A8_UNORM:
|
||||
case DXGI_FORMAT.R8G8B8A8_UNORM_SRGB:
|
||||
ddsHeader.PixelFormat.dwFlags = DDS.DDS_RGBA;
|
||||
ddsHeader.PixelFormat.dwRGBBitCount = 32;
|
||||
ddsHeader.PixelFormat.dwRBitMask = 0x000000FF;
|
||||
ddsHeader.PixelFormat.dwGBitMask = 0x0000FF00;
|
||||
ddsHeader.PixelFormat.dwBBitMask = 0x00FF0000;
|
||||
ddsHeader.PixelFormat.dwABitMask = 0xFF000000;
|
||||
ddsHeader.dwPitchOrLinearSize = (uint) (_width * _height * 4); // 32bpp
|
||||
break;
|
||||
case DXGI_FORMAT.B8G8R8A8_UNORM:
|
||||
case DXGI_FORMAT.B8G8R8X8_UNORM:
|
||||
ddsHeader.PixelFormat.dwFlags = DDS.DDS_RGBA;
|
||||
ddsHeader.PixelFormat.dwRGBBitCount = 32;
|
||||
ddsHeader.PixelFormat.dwRBitMask = 0x00FF0000;
|
||||
ddsHeader.PixelFormat.dwGBitMask = 0x0000FF00;
|
||||
ddsHeader.PixelFormat.dwBBitMask = 0x000000FF;
|
||||
ddsHeader.PixelFormat.dwABitMask = 0xFF000000;
|
||||
ddsHeader.dwPitchOrLinearSize = (uint) (_width * _height * 4); // 32bpp
|
||||
break;
|
||||
case DXGI_FORMAT.R8_UNORM:
|
||||
ddsHeader.PixelFormat.dwFlags = DDS.DDS_RGB;
|
||||
ddsHeader.PixelFormat.dwRGBBitCount = 8;
|
||||
ddsHeader.PixelFormat.dwRBitMask = 0xFF;
|
||||
ddsHeader.dwPitchOrLinearSize = (uint) (_width * _height); // 8bpp
|
||||
break;
|
||||
default:
|
||||
throw new Exception("Unsupported DDS header format. File: " + FullPath);
|
||||
}
|
||||
|
||||
bw.Write((uint) DDS.DDS_MAGIC);
|
||||
ddsHeader.Write(bw);
|
||||
|
||||
switch ((DXGI_FORMAT) _format)
|
||||
{
|
||||
case DXGI_FORMAT.BC1_UNORM_SRGB:
|
||||
case DXGI_FORMAT.BC3_UNORM_SRGB:
|
||||
case DXGI_FORMAT.BC4_UNORM:
|
||||
case DXGI_FORMAT.BC5_SNORM:
|
||||
case DXGI_FORMAT.BC6H_UF16:
|
||||
case DXGI_FORMAT.BC7_UNORM:
|
||||
case DXGI_FORMAT.BC7_UNORM_SRGB:
|
||||
var dxt10 = new DDS_HEADER_DXT10
|
||||
{
|
||||
dxgiFormat = _format,
|
||||
resourceDimension = (uint) DXT10_RESOURCE_DIMENSION.DIMENSION_TEXTURE2D,
|
||||
miscFlag = 0,
|
||||
arraySize = 1,
|
||||
miscFlags2 = DDS.DDS_ALPHA_MODE_UNKNOWN
|
||||
};
|
||||
dxt10.Write(bw);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
@ -12,13 +12,13 @@
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
|
||||
<PackageReference Include="xunit" Version="2.6.1" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.3">
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.10.0" />
|
||||
<PackageReference Include="xunit" Version="2.8.1" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.8.1">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="coverlet.collector" Version="6.0.0">
|
||||
<PackageReference Include="coverlet.collector" Version="6.0.2">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
|
@ -11,18 +11,18 @@
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
|
||||
<PackageReference Include="xunit" Version="2.6.1" />
|
||||
<PackageReference Include="Xunit.DependencyInjection" Version="8.9.0" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.3">
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.10.0" />
|
||||
<PackageReference Include="xunit" Version="2.8.1" />
|
||||
<PackageReference Include="Xunit.DependencyInjection" Version="9.3.0" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.8.1">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="coverlet.collector" Version="6.0.0">
|
||||
<PackageReference Include="coverlet.collector" Version="6.0.2">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="YamlDotNet" Version="13.7.1" />
|
||||
<PackageReference Include="YamlDotNet" Version="15.1.6" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
@ -17,4 +17,7 @@ public class BA2State : IArchive
|
||||
public BA2EntryType Type { get; set; }
|
||||
public string HeaderMagic { get; set; }
|
||||
public uint Version { get; set; }
|
||||
public uint Unknown1 { get; set; }
|
||||
public uint Unknown2 { get; set; }
|
||||
public uint Compression { get; set; }
|
||||
}
|
@ -11,15 +11,15 @@
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="8.0.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
|
||||
<PackageReference Include="xunit" Version="2.6.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="8.0.1" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.10.0" />
|
||||
<PackageReference Include="xunit" Version="2.8.1" />
|
||||
<PackageReference Include="Xunit.DependencyInjection.Logging" Version="8.1.0" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.3">
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.8.1">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="coverlet.collector" Version="6.0.0">
|
||||
<PackageReference Include="coverlet.collector" Version="6.0.2">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
|
@ -148,8 +148,9 @@ public class DownloadDispatcher
|
||||
|
||||
return result;
|
||||
}
|
||||
catch (HttpException)
|
||||
catch (HttpException ex)
|
||||
{
|
||||
_logger.LogError($"Failed verifying {a.State.PrimaryKeyString}: {ex}");
|
||||
await _verificationCache.Put(a.State, false);
|
||||
return false;
|
||||
}
|
||||
|
@ -18,11 +18,11 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="GameFinder.StoreHandlers.EADesktop" Version="4.1.0" />
|
||||
<PackageReference Include="GameFinder.StoreHandlers.EGS" Version="4.1.0" />
|
||||
<PackageReference Include="GameFinder.StoreHandlers.GOG" Version="4.1.0" />
|
||||
<PackageReference Include="GameFinder.StoreHandlers.Origin" Version="4.1.0" />
|
||||
<PackageReference Include="GameFinder.StoreHandlers.Steam" Version="4.1.0" />
|
||||
<PackageReference Include="GameFinder.StoreHandlers.EADesktop" Version="4.2.2" />
|
||||
<PackageReference Include="GameFinder.StoreHandlers.EGS" Version="4.2.2" />
|
||||
<PackageReference Include="GameFinder.StoreHandlers.GOG" Version="4.2.2" />
|
||||
<PackageReference Include="GameFinder.StoreHandlers.Origin" Version="4.2.2" />
|
||||
<PackageReference Include="GameFinder.StoreHandlers.Steam" Version="4.2.2" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
@ -12,7 +12,7 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="HtmlAgilityPack" Version="1.11.54" />
|
||||
<PackageReference Include="HtmlAgilityPack" Version="1.11.61" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="8.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
|
@ -6,8 +6,8 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="HtmlAgilityPack" Version="1.11.54" />
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="8.0.0" />
|
||||
<PackageReference Include="HtmlAgilityPack" Version="1.11.61" />
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="8.0.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="8.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
|
@ -13,7 +13,7 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="HtmlAgilityPack" Version="1.11.54" />
|
||||
<PackageReference Include="HtmlAgilityPack" Version="1.11.61" />
|
||||
<PackageReference Include="MegaApiClient" Version="1.10.3" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="8.0.0" />
|
||||
</ItemGroup>
|
||||
|
@ -217,8 +217,9 @@ public class NexusDownloader : ADownloader<Nexus>, IUrlDownloader
|
||||
|
||||
return fileInfo.info.FileId == state.FileID;
|
||||
}
|
||||
catch (HttpException)
|
||||
catch (HttpException ex)
|
||||
{
|
||||
_logger.LogError($"HttpException: {ex} on {archive.Name}");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -11,17 +11,17 @@
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="8.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="8.0.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="8.0.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
|
||||
<PackageReference Include="xunit" Version="2.6.1" />
|
||||
<PackageReference Include="Xunit.DependencyInjection" Version="8.9.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.10.0" />
|
||||
<PackageReference Include="xunit" Version="2.8.1" />
|
||||
<PackageReference Include="Xunit.DependencyInjection" Version="9.3.0" />
|
||||
<PackageReference Include="Xunit.DependencyInjection.Logging" Version="8.1.0" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.3">
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.8.1">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="coverlet.collector" Version="6.0.0">
|
||||
<PackageReference Include="coverlet.collector" Version="6.0.2">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
|
@ -12,15 +12,15 @@
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="FluentAssertions" Version="6.12.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.10.0" />
|
||||
<PackageReference Include="Shipwreck.Phash" Version="0.5.0" />
|
||||
<PackageReference Include="SixLabors.ImageSharp" Version="3.0.2" />
|
||||
<PackageReference Include="xunit" Version="2.6.1" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.3">
|
||||
<PackageReference Include="SixLabors.ImageSharp" Version="3.1.4" />
|
||||
<PackageReference Include="xunit" Version="2.8.1" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.8.1">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="coverlet.collector" Version="6.0.0">
|
||||
<PackageReference Include="coverlet.collector" Version="6.0.2">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
|
@ -11,14 +11,14 @@
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.10.0" />
|
||||
<PackageReference Include="System.Data.HashFunction.xxHash" Version="2.0.0" />
|
||||
<PackageReference Include="xunit" Version="2.6.1" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.3">
|
||||
<PackageReference Include="xunit" Version="2.8.1" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.8.1">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="coverlet.collector" Version="6.0.0">
|
||||
<PackageReference Include="coverlet.collector" Version="6.0.2">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
|
@ -11,14 +11,14 @@
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="8.0.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
|
||||
<PackageReference Include="xunit" Version="2.6.1" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.3">
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="8.0.1" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.10.0" />
|
||||
<PackageReference Include="xunit" Version="2.8.1" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.8.1">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="coverlet.collector" Version="6.0.0">
|
||||
<PackageReference Include="coverlet.collector" Version="6.0.2">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
|
@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
@ -22,6 +23,7 @@ using Wabbajack.DTOs;
|
||||
using Wabbajack.DTOs.BSA.FileStates;
|
||||
using Wabbajack.DTOs.Directives;
|
||||
using Wabbajack.DTOs.DownloadStates;
|
||||
using Wabbajack.DTOs.Interventions;
|
||||
using Wabbajack.DTOs.JsonConverters;
|
||||
using Wabbajack.Hashing.PHash;
|
||||
using Wabbajack.Hashing.xxHash64;
|
||||
@ -123,6 +125,12 @@ public class StandardInstaller : AInstaller<StandardInstaller>
|
||||
var missing = ModList.Archives.Where(a => !HashedArchives.ContainsKey(a.Hash)).ToList();
|
||||
if (missing.Count > 0)
|
||||
{
|
||||
if (missing.Any(m => m.State is not Nexus))
|
||||
{
|
||||
ShowMissingManualReport(missing.Where(m => m.State is not Nexus).ToArray());
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach (var a in missing)
|
||||
_logger.LogCritical("Unable to download {name} ({primaryKeyString})", a.Name,
|
||||
a.State.PrimaryKeyString);
|
||||
@ -168,6 +176,46 @@ public class StandardInstaller : AInstaller<StandardInstaller>
|
||||
return true;
|
||||
}
|
||||
|
||||
private void ShowMissingManualReport(Archive[] toArray)
|
||||
{
|
||||
_logger.LogError("Writing Manual helper report");
|
||||
var report = _configuration.Downloads.Combine("MissingManuals.html");
|
||||
{
|
||||
using var writer = new StreamWriter(report.Open(FileMode.Create, FileAccess.Write, FileShare.None));
|
||||
writer.Write("<html><head><title>Missing Manual Downloads</title></head><body>");
|
||||
writer.Write("<h1>Missing Manual Downloads</h1>");
|
||||
writer.Write(
|
||||
"<p>Wabbajack was unable to download the following archives automaticall. Please download them manually and place them in the downloads folder you chose during the install setup.</p>");
|
||||
foreach (var archive in toArray)
|
||||
{
|
||||
switch (archive.State)
|
||||
{
|
||||
case Manual manual:
|
||||
writer.Write($"<h3>{archive.Name}</h1>");
|
||||
writer.Write($"<p>{manual.Prompt}</p>");
|
||||
writer.Write($"<p>Download URL: <a href=\"{manual.Url}\">{manual.Url}</a></p>");
|
||||
break;
|
||||
case MediaFire mediaFire:
|
||||
writer.Write($"<h3>{archive.Name}</h1>");
|
||||
writer.Write($"<p>Download URL: <a href=\"{mediaFire.Url}\">{mediaFire.Url}</a></p>");
|
||||
break;
|
||||
default:
|
||||
writer.Write($"<h3>{archive.Name}</h1>");
|
||||
writer.Write($"<p>Unknown download type</p>");
|
||||
writer.Write($"<p>Primary Key (may not be helpful): <a href=\"{archive.State.PrimaryKeyString}\">{archive.State.PrimaryKeyString}</a></p>");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
writer.Write("</body></html>");
|
||||
}
|
||||
|
||||
Process.Start(new ProcessStartInfo("cmd.exe", $"/c start {report}")
|
||||
{
|
||||
CreateNoWindow = true,
|
||||
});
|
||||
}
|
||||
|
||||
private Task RemapMO2File()
|
||||
{
|
||||
var iniFile = _configuration.Install.Combine("ModOrganizer.ini");
|
||||
@ -247,7 +295,16 @@ public class StandardInstaller : AInstaller<StandardInstaller>
|
||||
var metaFile = download.WithExtension(Ext.Meta);
|
||||
|
||||
var found = bySize[download.Size()];
|
||||
var hash = await FileHashCache.FileHashCachedAsync(download, token);
|
||||
Hash hash = default;
|
||||
try
|
||||
{
|
||||
hash = await FileHashCache.FileHashCachedAsync(download, token);
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
_logger.LogError($"Failed to get hash for file {download}!");
|
||||
throw;
|
||||
}
|
||||
var archive = found.FirstOrDefault(f => f.Hash == hash);
|
||||
|
||||
IEnumerable<string> meta;
|
||||
|
@ -24,7 +24,7 @@
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="ini-parser-netstandard" Version="2.5.2" />
|
||||
<PackageReference Include="Octopus.Octodiff" Version="2.0.468" />
|
||||
<PackageReference Include="Octopus.Octodiff" Version="2.0.546" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
@ -19,15 +19,15 @@
|
||||
<TargetFramework>net8.0-windows</TargetFramework>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Avalonia.Themes.Fluent" Version="11.0.5" />
|
||||
<PackageReference Include="Avalonia.Themes.Fluent" Version="11.0.10" />
|
||||
<PackageReference Include="GitInfo" Version="3.3.3">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Avalonia" Version="11.0.5" />
|
||||
<PackageReference Include="Avalonia.Desktop" Version="11.0.5" />
|
||||
<PackageReference Include="Avalonia.Diagnostics" Version="11.0.5" />
|
||||
<PackageReference Include="Avalonia.ReactiveUI" Version="11.0.5" />
|
||||
<PackageReference Include="Avalonia" Version="11.0.10" />
|
||||
<PackageReference Include="Avalonia.Desktop" Version="11.0.10" />
|
||||
<PackageReference Include="Avalonia.Diagnostics" Version="11.0.10" />
|
||||
<PackageReference Include="Avalonia.ReactiveUI" Version="11.0.10" />
|
||||
<PackageReference Include="JetBrains.Annotations" Version="2023.3.0" />
|
||||
<PackageReference Include="MessageBox.Avalonia" Version="3.1.5.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0" />
|
||||
|
@ -12,13 +12,13 @@
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
|
||||
<PackageReference Include="xunit" Version="2.6.1" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.3">
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.10.0" />
|
||||
<PackageReference Include="xunit" Version="2.8.1" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.8.1">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="coverlet.collector" Version="6.0.0">
|
||||
<PackageReference Include="coverlet.collector" Version="6.0.2">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
|
@ -11,15 +11,15 @@
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
|
||||
<PackageReference Include="xunit" Version="2.6.1" />
|
||||
<PackageReference Include="Xunit.DependencyInjection" Version="8.9.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.10.0" />
|
||||
<PackageReference Include="xunit" Version="2.8.1" />
|
||||
<PackageReference Include="Xunit.DependencyInjection" Version="9.3.0" />
|
||||
<PackageReference Include="Xunit.DependencyInjection.Logging" Version="8.1.0" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.3">
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.8.1">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="coverlet.collector" Version="6.0.0">
|
||||
<PackageReference Include="coverlet.collector" Version="6.0.2">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
|
@ -3,6 +3,6 @@ using Wabbajack.Networking.Http.Interfaces;
|
||||
|
||||
namespace Wabbajack.Networking.NexusApi;
|
||||
|
||||
public interface AuthInfo : ITokenProvider<NexusOAuthState>
|
||||
public interface IAuthInfo : ITokenProvider<NexusOAuthState>
|
||||
{
|
||||
}
|
@ -188,7 +188,6 @@ public class NexusApi
|
||||
protected virtual async ValueTask<HttpRequestMessage> GenerateMessage(HttpMethod method, string uri,
|
||||
params object?[] parameters)
|
||||
{
|
||||
using var _ = await _authLock.WaitAsync();
|
||||
var msg = new HttpRequestMessage();
|
||||
msg.Method = method;
|
||||
|
||||
@ -232,6 +231,7 @@ public class NexusApi
|
||||
|
||||
private async ValueTask<(bool IsApiKey, string code)> GetAuthInfo()
|
||||
{
|
||||
using var _ = await _authLock.WaitAsync();
|
||||
if (AuthInfo.HaveToken())
|
||||
{
|
||||
var info = await AuthInfo.Get();
|
||||
@ -272,6 +272,8 @@ public class NexusApi
|
||||
var response = await _client.PostAsync($"https://users.nexusmods.com/oauth/token", content, cancel);
|
||||
var responseString = await response.Content.ReadAsStringAsync(cancel);
|
||||
var newJwt = JsonSerializer.Deserialize<JwtTokenReply>(responseString);
|
||||
if (newJwt != null)
|
||||
newJwt.ReceivedAt = DateTime.UtcNow.ToFileTimeUtc();
|
||||
|
||||
state.OAuth = newJwt;
|
||||
await AuthInfo.SetToken(state);
|
||||
|
@ -12,7 +12,7 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="8.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="8.0.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="8.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
|
@ -12,16 +12,16 @@
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="8.0.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
|
||||
<PackageReference Include="xunit" Version="2.6.1" />
|
||||
<PackageReference Include="Xunit.DependencyInjection" Version="8.9.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="8.0.1" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.10.0" />
|
||||
<PackageReference Include="xunit" Version="2.8.1" />
|
||||
<PackageReference Include="Xunit.DependencyInjection" Version="9.3.0" />
|
||||
<PackageReference Include="Xunit.DependencyInjection.Logging" Version="8.1.0" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.3">
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.8.1">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="coverlet.collector" Version="6.0.0">
|
||||
<PackageReference Include="coverlet.collector" Version="6.0.2">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
|
@ -14,7 +14,7 @@
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="8.0.0" />
|
||||
<PackageReference Include="Octokit" Version="9.0.0" />
|
||||
<PackageReference Include="YamlDotNet" Version="13.7.1" />
|
||||
<PackageReference Include="YamlDotNet" Version="15.1.6" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
@ -12,13 +12,13 @@
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="FsCheck.Xunit" Version="2.16.6" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
|
||||
<PackageReference Include="xunit" Version="2.6.1" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.3">
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.10.0" />
|
||||
<PackageReference Include="xunit" Version="2.8.1" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.8.1">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="coverlet.collector" Version="6.0.0">
|
||||
<PackageReference Include="coverlet.collector" Version="6.0.2">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
|
@ -11,13 +11,13 @@
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
|
||||
<PackageReference Include="xunit" Version="2.6.1" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.3">
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.10.0" />
|
||||
<PackageReference Include="xunit" Version="2.8.1" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.8.1">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="coverlet.collector" Version="6.0.0">
|
||||
<PackageReference Include="coverlet.collector" Version="6.0.2">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
|
@ -12,13 +12,13 @@
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
|
||||
<PackageReference Include="xunit" Version="2.6.1" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.3">
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.10.0" />
|
||||
<PackageReference Include="xunit" Version="2.8.1" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.8.1">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="coverlet.collector" Version="6.0.0">
|
||||
<PackageReference Include="coverlet.collector" Version="6.0.2">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
|
@ -5,7 +5,7 @@ using Wabbajack.Networking.NexusApi;
|
||||
|
||||
namespace Wabbajack.Services.OSIntegrated.TokenProviders;
|
||||
|
||||
public class NexusApiTokenProvider : EncryptedJsonTokenProvider<NexusOAuthState>, AuthInfo
|
||||
public class NexusApiTokenProvider : EncryptedJsonTokenProvider<NexusOAuthState>, IAuthInfo
|
||||
{
|
||||
public NexusApiTokenProvider(ILogger<NexusApiTokenProvider> logger, DTOSerializer dtos) : base(logger, dtos,
|
||||
"nexus-oauth-info")
|
||||
|
@ -17,7 +17,7 @@
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="8.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="8.0.1" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
@ -11,21 +11,21 @@
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="8.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="8.0.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="8.0.0" />
|
||||
<PackageReference Include="System.Data.SQLite.Core" Version="1.0.118" />
|
||||
<PackageReference Include="Xunit.DependencyInjection" Version="8.9.0" />
|
||||
<PackageReference Include="Xunit.DependencyInjection" Version="9.3.0" />
|
||||
<PackageReference Include="Xunit.DependencyInjection.Logging" Version="8.1.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
|
||||
<PackageReference Include="xunit" Version="2.6.1" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.3">
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.10.0" />
|
||||
<PackageReference Include="xunit" Version="2.8.1" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.8.1">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="coverlet.collector" Version="6.0.0">
|
||||
<PackageReference Include="coverlet.collector" Version="6.0.2">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
|
@ -8,7 +8,7 @@ mkdir c:\tmp\publish-wj
|
||||
dotnet clean
|
||||
dotnet publish Wabbajack.App.Wpf\Wabbajack.App.Wpf.csproj --framework "net8.0-windows" --runtime win-x64 --configuration Release /p:Platform=x64 -o c:\tmp\publish-wj\app /p:IncludeNativeLibrariesForSelfExtract=true --self-contained /p:DebugType=embedded
|
||||
dotnet publish Wabbajack.Launcher\Wabbajack.Launcher.csproj --framework "net8.0-windows" --runtime win-x64 --configuration Release /p:Platform=x64 -o c:\tmp\publish-wj\launcher /p:PublishSingleFile=true /p:PublishSingleFile=true /p:IncludeNativeLibrariesForSelfExtract=true --self-contained /p:DebugType=embedded
|
||||
dotnet publish c:\oss\Wabbajack\Wabbajack.CLI\Wabbajack.CLI.csproj --framework "net8.0-windows" --runtime win-x64 --configuration Release /p:Platform=x64 -o c:\tmp\publish-wj\app\cli /p:IncludeNativeLibrariesForSelfExtract=true --self-contained /p:DebugType=embedded
|
||||
dotnet publish Wabbajack.CLI\Wabbajack.CLI.csproj --framework "net8.0-windows" --runtime win-x64 --configuration Release /p:Platform=x64 -o c:\tmp\publish-wj\app\cli /p:IncludeNativeLibrariesForSelfExtract=true --self-contained /p:DebugType=embedded
|
||||
"C:\Program Files (x86)\Windows Kits\10\bin\10.0.19041.0\x64\signtool.exe" sign /fd sha256 /tr http://ts.ssl.com /td sha256 /sha1 8c26a8e0bf3e70eb89721cc4d86a87137153ccba c:\tmp\publish-wj\app\Wabbajack.exe
|
||||
"C:\Program Files (x86)\Windows Kits\10\bin\10.0.19041.0\x64\signtool.exe" sign /fd sha256 /tr http://ts.ssl.com /td sha256 /sha1 8c26a8e0bf3e70eb89721cc4d86a87137153ccba c:\tmp\publish-wj\launcher\Wabbajack.exe
|
||||
"C:\Program Files (x86)\Windows Kits\10\bin\10.0.19041.0\x64\signtool.exe" sign /fd sha256 /tr http://ts.ssl.com /td sha256 /sha1 8c26a8e0bf3e70eb89721cc4d86a87137153ccba c:\tmp\publish-wj\app\cli\wabbajack-cli.exe
|
||||
|
Loading…
x
Reference in New Issue
Block a user