2019-10-30 12:29:06 +00:00
using System ;
using System.Collections.Generic ;
using System.Linq ;
2019-12-04 01:26:26 +00:00
using System.Threading.Tasks ;
2022-09-25 22:36:12 +00:00
using Microsoft.Extensions.Logging ;
2019-10-30 12:29:06 +00:00
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 ;
2019-10-30 12:29:06 +00:00
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 ;
2019-10-30 12:29:06 +00:00
2021-10-23 16:51:17 +00:00
public DeconstructBSAs ( ACompiler compiler ) : base ( compiler )
{
_mo2Compiler = ( MO2Compiler ) compiler ;
_includeDirectly = _mo2Compiler . ModInis . Where ( kv = >
2019-10-30 12:29:06 +00:00
{
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
} ;
2019-10-30 12:29:06 +00:00
2021-10-23 16:51:17 +00:00
_microstackWithInclude = bsa = > new List < ICompilationStep >
2019-10-30 12:29:06 +00:00
{
2022-10-04 04:43:21 +00:00
_directMatch ,
_matchSimilar ,
_includePatches . WithBSA ( bsa ) ,
_includeAll
2021-10-23 16:51:17 +00:00
} ;
}
2019-10-30 12:29:06 +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 ;
2019-10-30 12:29:06 +00:00
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 ;
2020-04-20 21:36:33 +00:00
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 ) ;
2019-10-30 12:29:06 +00:00
2021-10-23 16:51:17 +00:00
var sourceFiles = source . File . Children ;
2019-10-30 12:29:06 +00:00
2021-10-23 16:51:17 +00:00
var stack = defaultInclude ? _microstackWithInclude ( source . File ) : _microstack ( source . File ) ;
2019-10-30 12:29:06 +00:00
2022-07-27 03:56:30 +00:00
var id = Guid . NewGuid ( ) . ToString ( ) . ToRelativePath ( ) ;
2020-04-27 21:32:19 +00:00
2020-06-26 19:01:10 +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);
}
2019-10-30 12:29:06 +00:00
2022-09-25 22:36:12 +00:00
var matches = await sourceFiles . SelectAsync (
async e = > await _mo2Compiler . RunStack ( stack ,
2022-07-27 03:56:30 +00:00
new RawSourceFile ( e , Consts . BSACreationDir . Combine ( id , ( RelativePath ) e . Name ) ) ) )
2021-10-23 16:51:17 +00:00
. ToList ( ) ;
2019-10-30 12:29:06 +00:00
2021-09-27 12:42:46 +00:00
2021-10-23 16:51:17 +00:00
foreach ( var match in matches )
{
2022-07-27 03:56:30 +00:00
if ( match is IgnoredDirectly ignored )
throw new CompilerException ( $"File required for BSA {source.Path} creation doesn't exist: {match.To} reason {ignored.Reason}" ) ;
2019-10-31 02:24:42 +00:00
2021-10-23 16:51:17 +00:00
_mo2Compiler . ExtraFiles . Add ( match ) ;
2019-10-30 12:29:06 +00:00
}
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 ;
2019-10-30 12:29:06 +00:00
}
2021-10-23 16:51:17 +00:00
}