wabbajack/Wabbajack.Compiler/CompilationSteps/DeconstructBSAs.cs

132 lines
4.9 KiB
C#
Raw Permalink Normal View History

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
2022-09-25 22:36:12 +00:00
using Microsoft.Extensions.Logging;
using Wabbajack.Common;
2021-09-27 12:42:46 +00:00
using Wabbajack.Compression.BSA;
using Wabbajack.DTOs;
using Wabbajack.DTOs.BSA.ArchiveStates;
using Wabbajack.DTOs.Directives;
using Wabbajack.Paths;
using Wabbajack.Paths.IO;
using Wabbajack.VFS;
2021-10-23 16:51:17 +00:00
namespace Wabbajack.Compiler.CompilationSteps;
2021-10-23 16:51:17 +00:00
public class DeconstructBSAs : ACompilationStep
{
private readonly IEnumerable<RelativePath> _includeDirectly;
private readonly Func<VirtualFile, List<ICompilationStep>> _microstack;
private readonly Func<VirtualFile, List<ICompilationStep>> _microstackWithInclude;
private readonly MO2Compiler _mo2Compiler;
2022-10-04 04:43:21 +00:00
private readonly DirectMatch _directMatch;
private readonly MatchSimilarTextures _matchSimilar;
private readonly IncludePatches _includePatches;
private readonly DropAll _dropAll;
private readonly IncludeAll _includeAll;
2021-10-23 16:51:17 +00:00
public DeconstructBSAs(ACompiler compiler) : base(compiler)
{
_mo2Compiler = (MO2Compiler) compiler;
_includeDirectly = _mo2Compiler.ModInis.Where(kv =>
{
2021-10-23 16:51:17 +00:00
var general = kv.Value["General"];
if (general["notes"] != null && (general["notes"].Contains(Consts.WABBAJACK_INCLUDE) ||
general["notes"].Contains(Consts.WABBAJACK_NOMATCH_INCLUDE)))
return true;
if (general["comments"] != null && (general["comments"].Contains(Consts.WABBAJACK_INCLUDE) ||
general["comments"].Contains(Consts.WABBAJACK_NOMATCH_INCLUDE)))
return true;
return false;
})
.Select(kv => kv.Key.RelativeTo(_mo2Compiler._settings.Source))
.ToList();
2022-10-04 04:43:21 +00:00
// Cache these so their internal caches aren't recreated on every use
_directMatch = new DirectMatch(_mo2Compiler);
_matchSimilar = new MatchSimilarTextures(_mo2Compiler);
_includePatches = new IncludePatches(_mo2Compiler);
_dropAll = new DropAll(_mo2Compiler);
_includeAll = new IncludeAll(_mo2Compiler);
2021-10-23 16:51:17 +00:00
_microstack = bsa => new List<ICompilationStep>
{
2022-10-04 04:43:21 +00:00
_directMatch,
_matchSimilar,
_includePatches.WithBSA(bsa),
_dropAll
2021-10-23 16:51:17 +00:00
};
2021-10-23 16:51:17 +00:00
_microstackWithInclude = bsa => new List<ICompilationStep>
{
2022-10-04 04:43:21 +00:00
_directMatch,
_matchSimilar,
_includePatches.WithBSA(bsa),
_includeAll
2021-10-23 16:51:17 +00:00
};
}
2021-10-23 16:51:17 +00:00
public override async ValueTask<Directive?> Run(RawSourceFile source)
{
if (!Consts.SupportedBSAs.Contains(source.Path.Extension)) return null;
2021-10-23 16:51:17 +00:00
var defaultInclude = false;
if (source.Path.RelativeTo(_mo2Compiler._settings.Source)
.InFolder(_mo2Compiler._settings.Source.Combine(Consts.MO2ModFolderName)))
if (_includeDirectly.Any(path => source.Path.InFolder(path)))
defaultInclude = true;
2021-10-23 16:51:17 +00:00
if (source.AbsolutePath.Size() >= (long) 2 << 31)
{
var bsaTest = await BSADispatch.Open(source.AbsolutePath);
if (bsaTest.State is BSAState)
throw new CompilerException(
$"BSA {source.AbsolutePath.FileName} is over 2GB in size, very few programs (Including Wabbajack) can create BSA files this large without causing CTD issues." +
"Please re-compress this BSA into a more manageable size.");
}
2022-09-25 22:36:12 +00:00
_compiler._logger.LogInformation("Deconstructing BSA: {Name}", source.File.FullPath.FileName);
2021-10-23 16:51:17 +00:00
var sourceFiles = source.File.Children;
2021-10-23 16:51:17 +00:00
var stack = defaultInclude ? _microstackWithInclude(source.File) : _microstack(source.File);
var id = Guid.NewGuid().ToString().ToRelativePath();
2020-04-27 21:32:19 +00:00
2021-10-23 16:51:17 +00:00
Func<Task>? _cleanup = null;
if (defaultInclude)
{
//_cleanup = await source.File.Context.Stage(source.File.Children);
}
2022-09-25 22:36:12 +00:00
var matches = await sourceFiles.SelectAsync(
async e => await _mo2Compiler.RunStack(stack,
new RawSourceFile(e, Consts.BSACreationDir.Combine(id, (RelativePath) e.Name))))
2021-10-23 16:51:17 +00:00
.ToList();
2021-09-27 12:42:46 +00:00
2021-10-23 16:51:17 +00:00
foreach (var match in matches)
{
if (match is IgnoredDirectly ignored)
throw new CompilerException($"File required for BSA {source.Path} creation doesn't exist: {match.To} reason {ignored.Reason}");
2021-10-23 16:51:17 +00:00
_mo2Compiler.ExtraFiles.Add(match);
}
2021-10-23 16:51:17 +00:00
var bsa = await BSADispatch.Open(source.AbsolutePath);
var directive = new CreateBSA
{
State = bsa.State,
FileStates = bsa.Files.Select(f => f.State).ToArray(),
To = source.Path,
Hash = source.Hash,
TempID = (RelativePath) id
};
if (_cleanup != null)
await _cleanup();
return directive;
}
2021-10-23 16:51:17 +00:00
}