diff --git a/Mutagen.Bethesda.Autofac/MutagenModule.cs b/Mutagen.Bethesda.Autofac/MutagenModule.cs index 32d120f36f..638522e024 100644 --- a/Mutagen.Bethesda.Autofac/MutagenModule.cs +++ b/Mutagen.Bethesda.Autofac/MutagenModule.cs @@ -25,7 +25,6 @@ protected override void Load(ContainerBuilder builder) .InNamespacesOf( typeof(IArchiveReaderProvider), // typeof(IGetFontConfig), - typeof(IAssetProvider), typeof(IDataDirectoryLookup), typeof(IImplicitBaseMasterProvider), typeof(ILoadOrderWriter), @@ -48,5 +47,14 @@ protected override void Load(ContainerBuilder builder) builder.RegisterType() .As() .As(); + builder.RegisterType() + .As() + .AsSelf(); + builder.RegisterType() + .AsSelf(); + builder.RegisterType() + .AsSelf(); + builder.RegisterType() + .AsImplementedInterfaces(); } } \ No newline at end of file diff --git a/Mutagen.Bethesda.Core.UnitTests/Archives/GetApplicableArchivePathsTests.cs b/Mutagen.Bethesda.Core.UnitTests/Archives/GetApplicableArchivePathsTests.cs index 545c47736e..7226efbedd 100644 --- a/Mutagen.Bethesda.Core.UnitTests/Archives/GetApplicableArchivePathsTests.cs +++ b/Mutagen.Bethesda.Core.UnitTests/Archives/GetApplicableArchivePathsTests.cs @@ -7,6 +7,7 @@ using Mutagen.Bethesda.Inis.DI; using Mutagen.Bethesda.Installs.DI; using Mutagen.Bethesda.Plugins; +using Mutagen.Bethesda.Plugins.Order.DI; using Mutagen.Bethesda.Testing; using Noggog; using Noggog.Testing.IO; @@ -44,38 +45,23 @@ private GetApplicableArchivePaths GetClass(IFileSystem fs) var ext = new ArchiveExtensionProvider(gameReleaseInjection); return new GetApplicableArchivePaths( fs, - new GetArchiveIniListings( - fs, - new IniPathProvider( - gameReleaseInjection, - new IniPathLookupInjection(MyDocumentsPath))), new CheckArchiveApplicability( ext), new DataDirectoryInjection(BaseFolder), - ext); + ext, + new CachedArchiveListingDetailsProvider( + new LoadOrderListingsInjection(Array.Empty()), + new GetArchiveIniListings( + fs, + new IniPathProvider( + gameReleaseInjection, + new IniPathLookupInjection(MyDocumentsPath))))); } #region No ModKey + [Fact] - public void NoModKey_Unordered() - { - var fs = GetFileSystem(); - fs.File.WriteAllText(Path.Combine(BaseFolder, MyModBsa), string.Empty); - fs.File.WriteAllText(Path.Combine(BaseFolder, SkyrimBsa), string.Empty); - fs.File.WriteAllText(Path.Combine(BaseFolder, SomeExplicitListingBsa), string.Empty); - var get = GetClass(fs); - var applicable = get.Get(Enumerable.Empty()) - .ToArray(); - applicable.Should().Equal(new FilePath[] - { - Path.Combine(BaseFolder, MyModBsa), - Path.Combine(BaseFolder, SkyrimBsa), - Path.Combine(BaseFolder, SomeExplicitListingBsa), - }); - } - - [Fact] - public void NoModKey_Ordered() + public void NoModKey() { var fs = GetFileSystem(); fs.File.WriteAllText(Path.Combine(BaseFolder, MyModBsa), string.Empty); @@ -102,7 +88,7 @@ public void Empty() { var fs = GetFileSystem(); var get = GetClass(fs); - get.Get(TestConstants.Skyrim, Enumerable.Empty()) + get.Get(TestConstants.Skyrim) .Should().BeEmpty(); } @@ -119,41 +105,7 @@ public void NullModKey() } [Fact] - public void BaseMod_Unordered() - { - var fs = GetFileSystem(); - var get = GetClass(fs); - fs.File.WriteAllText(Path.Combine(BaseFolder, SkyrimBsa), string.Empty); - fs.File.WriteAllText(Path.Combine(BaseFolder, SomeExplicitListingBsa), string.Empty); - fs.File.WriteAllText(Path.Combine(BaseFolder, MyModBsa), string.Empty); - var applicable = get.Get(TestConstants.Skyrim, Enumerable.Empty()) - .ToArray(); - applicable.Should().Equal(new FilePath[] - { - Path.Combine(BaseFolder, SkyrimBsa), - Path.Combine(BaseFolder, SomeExplicitListingBsa) - }); - } - - [Fact] - public void Typical_Unordered() - { - var fs = GetFileSystem(); - var get = GetClass(fs); - fs.File.WriteAllText(Path.Combine(BaseFolder, $"{TestConstants.MasterModKey2.Name}.bsa"), string.Empty); - fs.File.WriteAllText(Path.Combine(BaseFolder, SomeExplicitListingBsa), string.Empty); - fs.File.WriteAllText(Path.Combine(BaseFolder, MyModBsa), string.Empty); - var applicable = get.Get(TestConstants.MasterModKey2, Enumerable.Empty()) - .ToArray(); - applicable.Should().Equal(new FilePath[] - { - Path.Combine(BaseFolder, $"{TestConstants.MasterModKey2.Name}.bsa"), - Path.Combine(BaseFolder, SomeExplicitListingBsa) - }); - } - - [Fact] - public void BaseMod_Ordered() + public void BaseMod() { var fs = GetFileSystem(); var get = GetClass(fs); @@ -170,7 +122,7 @@ public void BaseMod_Ordered() } [Fact] - public void Typical_Ordered() + public void Typical() { var fs = GetFileSystem(); var get = GetClass(fs); @@ -182,7 +134,7 @@ public void Typical_Ordered() applicable.Should().Equal(new FilePath[] { Path.Combine(BaseFolder, SomeExplicitListingBsa), - Path.Combine(BaseFolder, $"{TestConstants.MasterModKey2.Name}.bsa"), + Path.Combine(BaseFolder, $"{TestConstants.MasterModKey2.Name}.bsa") }); } #endregion diff --git a/Mutagen.Bethesda.Core/Archives/Archive.cs b/Mutagen.Bethesda.Core/Archives/Archive.cs index 2b945385e3..12421f3e8f 100644 --- a/Mutagen.Bethesda.Core/Archives/Archive.cs +++ b/Mutagen.Bethesda.Core/Archives/Archive.cs @@ -5,6 +5,8 @@ using Mutagen.Bethesda.Environments.DI; using Mutagen.Bethesda.Inis.DI; using Mutagen.Bethesda.Installs.DI; +using Mutagen.Bethesda.Plugins.Order; +using Mutagen.Bethesda.Plugins.Order.DI; using Stream = System.IO.Stream; namespace Mutagen.Bethesda.Archives; @@ -14,23 +16,28 @@ public static class Archive private static GetApplicableArchivePaths GetApplicableArchivePathsDi( GameRelease release, DirectoryPath dataFolderPath, - IFileSystem? fileSystem = null) + IEnumerable? modOrdering, + IFileSystem? fileSystem) { fileSystem ??= fileSystem.GetOrDefault(); var gameReleaseInjection = new GameReleaseInjection(release); var ext = new ArchiveExtensionProvider(gameReleaseInjection); + var lo = new LoadOrderListingsInjection( + modOrdering.EmptyIfNull().Select(x => new LoadOrderListing(x, enabled: true))); return new GetApplicableArchivePaths( fileSystem, - new GetArchiveIniListings( - fileSystem, - new IniPathProvider( - new GameReleaseInjection(release), - new IniPathLookup( - GameLocatorLookupCache.Instance))), new CheckArchiveApplicability( ext), new DataDirectoryInjection(dataFolderPath), - ext); + ext, + new CachedArchiveListingDetailsProvider( + lo, + new GetArchiveIniListings( + fileSystem, + new IniPathProvider( + new GameReleaseInjection(release), + new IniPathLookup( + GameLocatorLookupCache.Instance))))); } /// @@ -78,8 +85,8 @@ public static IEnumerable GetApplicableArchivePaths( GameRelease release, DirectoryPath dataFolderPath, IFileSystem? fileSystem = null, bool returnEmptyIfMissing = true) { - return GetApplicableArchivePathsDi(release, dataFolderPath, fileSystem) - .Get(returnEmptyIfMissing: returnEmptyIfMissing); + return GetApplicableArchivePathsDi(release, dataFolderPath, modOrdering: null, fileSystem: fileSystem) + .Get(); } /// @@ -89,13 +96,12 @@ public static IEnumerable GetApplicableArchivePaths( /// Folder to query within /// Archive ordering overload. Empty enumerable means no ordering. /// FileSystem to use - /// If ini file is missing, return empty instead of throwing an exception /// public static IEnumerable GetApplicableArchivePaths(GameRelease release, DirectoryPath dataFolderPath, IEnumerable? archiveOrdering, IFileSystem? fileSystem = null, bool returnEmptyIfMissing = true) { - return GetApplicableArchivePathsDi(release, dataFolderPath, fileSystem) - .Get(archiveOrdering, returnEmptyIfMissing: returnEmptyIfMissing); + return GetApplicableArchivePathsDi(release, dataFolderPath, archiveOrdering.EmptyIfNull().Select(ModKey.FromFileName), fileSystem) + .Get(); } /// @@ -105,13 +111,12 @@ public static IEnumerable GetApplicableArchivePaths(GameRelease releas /// Folder to query within /// Archive ordering overload based on a mod order. Empty enumerable means no ordering. /// FileSystem to use - /// If ini file is missing, return empty instead of throwing an exception /// public static IEnumerable GetApplicableArchivePaths(GameRelease release, DirectoryPath dataFolderPath, IEnumerable? modOrdering, IFileSystem? fileSystem = null, bool returnEmptyIfMissing = true) { - return GetApplicableArchivePathsDi(release, dataFolderPath, fileSystem) - .Get(modOrdering, returnEmptyIfMissing: returnEmptyIfMissing); + return GetApplicableArchivePathsDi(release, dataFolderPath, modOrdering, fileSystem) + .Get(); } /// @@ -123,13 +128,12 @@ public static IEnumerable GetApplicableArchivePaths(GameRelease releas /// Folder to query within /// ModKey to query about /// FileSystem to use - /// If ini file is missing, return empty instead of throwing an exception /// public static IEnumerable GetApplicableArchivePaths(GameRelease release, DirectoryPath dataFolderPath, ModKey modKey, IFileSystem? fileSystem = null, bool returnEmptyIfMissing = true) { - return GetApplicableArchivePathsDi(release, dataFolderPath, fileSystem) - .Get(modKey, returnEmptyIfMissing: returnEmptyIfMissing); + return GetApplicableArchivePathsDi(release, dataFolderPath, modOrdering: null, fileSystem: fileSystem) + .Get(modKey); } /// @@ -142,33 +146,13 @@ public static IEnumerable GetApplicableArchivePaths(GameRelease releas /// ModKey to query about /// Archive ordering overload. Empty enumerable means no ordering. /// FileSystem to use - /// If ini file is missing, return empty instead of throwing an exception /// public static IEnumerable GetApplicableArchivePaths(GameRelease release, DirectoryPath dataFolderPath, ModKey modKey, IEnumerable? archiveOrdering, - IFileSystem? fileSystem = null, bool returnEmptyIfMissing = true) - { - return GetApplicableArchivePathsDi(release, dataFolderPath, fileSystem) - .Get(modKey, archiveOrdering, returnEmptyIfMissing: returnEmptyIfMissing); - } - - /// - /// Enumerates all applicable Archives for a given release and ModKey that are within a given dataFolderPath.
- /// This call is intended to return Archives related to one specific mod.
- /// NOTE: It is currently a bit experimental - ///
- /// GameRelease to query for - /// Folder to query within - /// ModKey to query about - /// How to order the archive paths. Null for no ordering - /// FileSystem to use - /// If ini file is missing, return empty instead of throwing an exception - /// Full paths of Archives that apply to the given mod and exist - public static IEnumerable GetApplicableArchivePaths(GameRelease release, DirectoryPath dataFolderPath, - ModKey modKey, IComparer? archiveOrdering, IFileSystem? fileSystem = null, bool returnEmptyIfMissing = true) + IFileSystem? fileSystem = null) { - return GetApplicableArchivePathsDi(release, dataFolderPath, fileSystem) - .Get(modKey, archiveOrdering, returnEmptyIfMissing: returnEmptyIfMissing); + return GetApplicableArchivePathsDi(release, dataFolderPath, archiveOrdering.EmptyIfNull().Select(ModKey.FromFileName), fileSystem) + .Get(modKey); } /// diff --git a/Mutagen.Bethesda.Core/Archives/DI/CachedArchiveListingDetailsProvider.cs b/Mutagen.Bethesda.Core/Archives/DI/CachedArchiveListingDetailsProvider.cs new file mode 100644 index 0000000000..bf523ef1d7 --- /dev/null +++ b/Mutagen.Bethesda.Core/Archives/DI/CachedArchiveListingDetailsProvider.cs @@ -0,0 +1,53 @@ +using Mutagen.Bethesda.Plugins.Order.DI; +using Noggog; + +namespace Mutagen.Bethesda.Archives.DI; + +public class CachedArchiveListingDetailsProvider : IArchiveListingDetailsProvider +{ + private readonly ILoadOrderListingsProvider _listingsProvider; + private readonly IGetArchiveIniListings _getArchiveIniListings; + private readonly Lazy _payload; + + private class Payload + { + public required IReadOnlyList Listed { get; init; } + public required IReadOnlyList Priority { get; init; } + public required IReadOnlySet Set { get; init; } + } + + public CachedArchiveListingDetailsProvider( + ILoadOrderListingsProvider listingsProvider, + IGetArchiveIniListings getArchiveIniListings) + { + _listingsProvider = listingsProvider; + _getArchiveIniListings = getArchiveIniListings; + _payload = new Lazy(() => + { + var listed = new List(); + listed.AddRange(_getArchiveIniListings.TryGet().EmptyIfNull()); + listed.AddRange(_listingsProvider.Get() + .Where(x => x.Enabled) + .Select(x => x.ModKey) + .Select(x => x.FileName)); + return new Payload() + { + Listed = listed, + Priority = ((IEnumerable)listed).Reverse().ToList(), + Set = listed.ToHashSet(), + }; + }); + } + + public bool Empty => _payload.Value.Listed.Count == 0; + + public int PriorityIndexFor(FileName fileName) + { + return _payload.Value.Priority.IndexOf(fileName); + } + + public bool Contains(FileName fileName) + { + return _payload.Value.Set.Contains(fileName); + } +} \ No newline at end of file diff --git a/Mutagen.Bethesda.Core/Archives/DI/GetApplicableArchivePaths.cs b/Mutagen.Bethesda.Core/Archives/DI/GetApplicableArchivePaths.cs index 376a4ffbec..20c0d4a345 100644 --- a/Mutagen.Bethesda.Core/Archives/DI/GetApplicableArchivePaths.cs +++ b/Mutagen.Bethesda.Core/Archives/DI/GetApplicableArchivePaths.cs @@ -10,24 +10,7 @@ public interface IGetApplicableArchivePaths /// /// Enumerates all Archives /// - /// If ini file is missing, return empty instead of throwing an exception - IEnumerable Get(bool returnEmptyIfMissing = true); - - /// - /// Enumerates all Archives - /// - /// Archive ordering overload. Empty enumerable means no ordering. - /// If ini file is missing, return empty instead of throwing an exception - /// - IEnumerable Get(IEnumerable? archiveOrdering, bool returnEmptyIfMissing = true); - - /// - /// Enumerates all Archives - /// - /// Archive ordering overload based on a mod order. Empty enumerable means no ordering. - /// If ini file is missing, return empty instead of throwing an exception - /// - IEnumerable Get(IEnumerable? modOrdering, bool returnEmptyIfMissing = true); + IEnumerable Get(); /// /// Enumerates all applicable Archives for a given ModKey
@@ -35,118 +18,63 @@ public interface IGetApplicableArchivePaths /// NOTE: It is currently a bit experimental ///
/// ModKey to query about - /// If ini file is missing, return empty instead of throwing an exception /// - IEnumerable Get(ModKey modKey, bool returnEmptyIfMissing = true); - - /// - /// Enumerates all applicable Archives for a given ModKey
- /// This call is intended to return Archives related to one specific mod.
- /// NOTE: It is currently a bit experimental - ///
- /// ModKey to query about - /// Archive ordering overload. Empty enumerable means no ordering. - /// If ini file is missing, return empty instead of throwing an exception - /// - IEnumerable Get(ModKey modKey, IEnumerable? archiveOrdering, bool returnEmptyIfMissing = true); - - /// - /// Enumerates all applicable Archives for a given ModKey
- /// This call is intended to return Archives related to one specific mod.
- /// NOTE: It is currently a bit experimental - ///
- /// ModKey to query about - /// How to order the archive paths. Null for no ordering - /// If ini file is missing, return empty instead of throwing an exception - /// Full paths of Archives that apply to the given mod and exist - IEnumerable Get(ModKey modKey, IComparer? archiveOrdering, bool returnEmptyIfMissing = true); + IEnumerable Get(ModKey modKey); } public sealed class GetApplicableArchivePaths : IGetApplicableArchivePaths { private readonly IFileSystem _fileSystem; - private readonly IGetArchiveIniListings _iniListings; private readonly ICheckArchiveApplicability _applicability; private readonly IDataDirectoryProvider _dataDirectoryProvider; private readonly IArchiveExtensionProvider _archiveExtension; + private readonly IArchiveListingDetailsProvider _archiveListingDetailsProvider; public GetApplicableArchivePaths( IFileSystem fileSystem, - IGetArchiveIniListings iniListings, ICheckArchiveApplicability applicability, IDataDirectoryProvider dataDirectoryProvider, - IArchiveExtensionProvider archiveExtension) + IArchiveExtensionProvider archiveExtension, + IArchiveListingDetailsProvider ArchiveListingDetailsProvider) { _fileSystem = fileSystem; - _iniListings = iniListings; _applicability = applicability; _dataDirectoryProvider = dataDirectoryProvider; _archiveExtension = archiveExtension; + _archiveListingDetailsProvider = ArchiveListingDetailsProvider; } /// - public IEnumerable Get(bool returnEmptyIfMissing = true) + public IEnumerable Get() { - return GetInternal(default(ModKey?), GetPriorityOrderComparer(null, emptyIfMissing: returnEmptyIfMissing), returnEmptyIfMissing); + return GetInternal(default(ModKey?), GetPriorityOrderComparer()); } /// - public IEnumerable Get(IEnumerable? archiveOrdering, bool returnEmptyIfMissing = true) + public IEnumerable Get(ModKey modKey) { - return GetInternal(default(ModKey?), GetPriorityOrderComparer(archiveOrdering, emptyIfMissing: returnEmptyIfMissing), returnEmptyIfMissing); + return Get(modKey, GetPriorityOrderComparer()); } - public IEnumerable Get(IEnumerable? modOrdering, bool returnEmptyIfMissing = true) + private IEnumerable Get(ModKey modKey, IComparer? archiveOrdering) { - return GetInternal(default, GetPriorityModOrderComparer(modOrdering), returnEmptyIfMissing); - } - - /// - public IEnumerable Get(ModKey modKey, bool returnEmptyIfMissing = true) - { - return Get(modKey, GetPriorityOrderComparer(null, emptyIfMissing: returnEmptyIfMissing), returnEmptyIfMissing); - } - - /// - public IEnumerable Get(ModKey modKey, IEnumerable? archiveOrdering, bool returnEmptyIfMissing = true) - { - return Get(modKey, GetPriorityOrderComparer(archiveOrdering, emptyIfMissing: returnEmptyIfMissing), returnEmptyIfMissing); - } - - /// - public IEnumerable Get(ModKey modKey, IComparer? archiveOrdering, bool returnEmptyIfMissing = true) - { - return GetInternal(modKey, archiveOrdering, returnEmptyIfMissing); + return GetInternal(modKey, archiveOrdering); } - private IEnumerable GetInternal(ModKey? modKey, IComparer? archiveOrdering, bool returnEmptyIfMissing = true) + private IEnumerable GetInternal(ModKey? modKey, IComparer? archiveOrdering) { if (modKey.HasValue && modKey.Value.IsNull) { return Enumerable.Empty(); } - - if (returnEmptyIfMissing && !_fileSystem.Directory.Exists(_dataDirectoryProvider.Path)) - { - return Enumerable.Empty(); - } var ret = _fileSystem.Directory.EnumerateFilePaths(_dataDirectoryProvider.Path, searchPattern: $"*{_archiveExtension.Get()}"); if (modKey != null) { - IReadOnlyCollection iniListedArchives; - if (returnEmptyIfMissing) - { - iniListedArchives = (IReadOnlyCollection?)_iniListings.TryGet()?.ToHashSet() ?? Array.Empty(); - } - else - { - iniListedArchives = _iniListings.Get().ToHashSet(); - } ret = ret .Where(archive => { - if (iniListedArchives.Contains(archive.Name)) return true; + if (_archiveListingDetailsProvider.Contains(archive.Name)) return true; return _applicability.IsApplicable(modKey.Value, archive.Name); }); } @@ -158,55 +86,17 @@ private IEnumerable GetInternal(ModKey? modKey, IComparer? a } - private IComparer? GetPriorityOrderComparer(IEnumerable? listedArchiveOrdering, bool emptyIfMissing) + private IComparer? GetPriorityOrderComparer() { - if (emptyIfMissing) - { - listedArchiveOrdering ??= _iniListings.TryGet() ?? Enumerable.Empty(); - } - else - { - listedArchiveOrdering ??= _iniListings.Get(); - } - var archiveOrderingList = listedArchiveOrdering.ToList(); - if (archiveOrderingList.Count == 0) return null; - archiveOrderingList.Reverse(); + if (_archiveListingDetailsProvider.Empty) return null; return Comparer.Create((a, b) => { - var indexA = archiveOrderingList.IndexOf(a); - var indexB = archiveOrderingList.IndexOf(b); + var indexA = _archiveListingDetailsProvider.PriorityIndexFor(a); + var indexB = _archiveListingDetailsProvider.PriorityIndexFor(b); if (indexA == -1 && indexB == -1) return 0; if (indexA == -1) return 1; if (indexB == -1) return -1; return indexA - indexB; }); } - - private IComparer? GetPriorityModOrderComparer(IEnumerable? listedModOrdering) - { - if (listedModOrdering is null) return null; - - var iniListedArchives = _iniListings.Get().ToList(); - var modOrderingList = listedModOrdering.ToList(); - return Comparer.Create((a, b) => - { - var iniIndexOfA = iniListedArchives.IndexOf(a); - var iniIndexOfB = iniListedArchives.IndexOf(b); - - // Handle if any of the archives are listed in the ini file - if (iniIndexOfA != -1 || iniIndexOfB != -1) { - if (iniIndexOfA == -1) return 1; - if (iniIndexOfB == -1) return -1; - return iniIndexOfA - iniIndexOfB; - } - - // If neither are listed in the ini file, use the mod ordering - var modIndexA = modOrderingList.FindIndex(modKey => _applicability.IsApplicable(modKey, a)); - var modIndexB = modOrderingList.FindIndex(modKey => _applicability.IsApplicable(modKey, b)); - if (modIndexA == -1 && modIndexB == -1) return 0; - if (modIndexA == -1) return 1; - if (modIndexB == -1) return -1; - return modIndexA - modIndexB; - }); - } } \ No newline at end of file diff --git a/Mutagen.Bethesda.Core/Archives/DI/IArchiveListingDetailsProvider.cs b/Mutagen.Bethesda.Core/Archives/DI/IArchiveListingDetailsProvider.cs new file mode 100644 index 0000000000..cd68efe7ad --- /dev/null +++ b/Mutagen.Bethesda.Core/Archives/DI/IArchiveListingDetailsProvider.cs @@ -0,0 +1,10 @@ +using Noggog; + +namespace Mutagen.Bethesda.Archives.DI; + +public interface IArchiveListingDetailsProvider +{ + bool Empty { get; } + int PriorityIndexFor(FileName fileName); + bool Contains(FileName fileName); +} \ No newline at end of file diff --git a/Mutagen.Bethesda.Core/Assets/DI/ArchiveAssetProvider.cs b/Mutagen.Bethesda.Core/Assets/DI/ArchiveAssetProvider.cs index d6a855cc17..6f180a376c 100644 --- a/Mutagen.Bethesda.Core/Assets/DI/ArchiveAssetProvider.cs +++ b/Mutagen.Bethesda.Core/Assets/DI/ArchiveAssetProvider.cs @@ -3,7 +3,7 @@ using Mutagen.Bethesda.Archives; using Mutagen.Bethesda.Archives.DI; using Mutagen.Bethesda.Environments.DI; -using Mutagen.Bethesda.Plugins; + namespace Mutagen.Bethesda.Assets.DI; public class ArchiveAssetProvider : IAssetProvider @@ -29,12 +29,7 @@ public bool Exists(DataRelativePath assetPath) public bool TryGetStream(DataRelativePath assetPath, [MaybeNullWhen(false)] out Stream stream) { - return TryGetStream(assetPath, null, out stream); - } - - public bool TryGetStream(DataRelativePath assetPath, IEnumerable? modOrdering, [MaybeNullWhen(false)] out Stream stream) - { - var archiveFile = GetArchiveFile(assetPath, modOrdering); + var archiveFile = GetArchiveFile(assetPath); if (archiveFile is null) { stream = null; @@ -47,12 +42,7 @@ public bool TryGetStream(DataRelativePath assetPath, IEnumerable? modOrd public bool TryGetSize(DataRelativePath assetPath, out uint size) { - return TryGetSize(assetPath, null, out size); - } - - public bool TryGetSize(DataRelativePath assetPath, IEnumerable? modOrdering, out uint size) - { - var archiveFile = GetArchiveFile(assetPath, modOrdering); + var archiveFile = GetArchiveFile(assetPath); if (archiveFile is null) { size = 0; @@ -63,13 +53,13 @@ public bool TryGetSize(DataRelativePath assetPath, IEnumerable? modOrder return true; } - private IArchiveFile? GetArchiveFile(DataRelativePath assetPath, IEnumerable? modOrdering = null) + private IArchiveFile? GetArchiveFile(DataRelativePath assetPath) { var dataRelativeDirectoryPath = _fileSystem.Path.GetDirectoryName(assetPath.Path); if (dataRelativeDirectoryPath is null) return null; var fileName = _fileSystem.Path.GetFileName(assetPath.Path); - var applicableArchivePaths = _getApplicableArchivePaths.Get(modOrdering); + var applicableArchivePaths = _getApplicableArchivePaths.Get(); foreach (var archivePath in applicableArchivePaths) { var archiveReader = Archive.CreateReader(_gameReleaseContext.Release, archivePath, _fileSystem); diff --git a/Mutagen.Bethesda.Core/Assets/DI/AssetProviderMixIn.cs b/Mutagen.Bethesda.Core/Assets/DI/AssetProviderMixIn.cs index 081948ec6d..2fec839e9b 100644 --- a/Mutagen.Bethesda.Core/Assets/DI/AssetProviderMixIn.cs +++ b/Mutagen.Bethesda.Core/Assets/DI/AssetProviderMixIn.cs @@ -1,5 +1,6 @@ using System.Diagnostics.CodeAnalysis; using Mutagen.Bethesda.Plugins.Assets; + namespace Mutagen.Bethesda.Assets.DI; public static class AssetProviderMixIn diff --git a/Mutagen.Bethesda.Core/Assets/DI/DataDirectoryAssetProvider.cs b/Mutagen.Bethesda.Core/Assets/DI/DataDirectoryAssetProvider.cs index d2c2ae0401..bf7b61aeab 100644 --- a/Mutagen.Bethesda.Core/Assets/DI/DataDirectoryAssetProvider.cs +++ b/Mutagen.Bethesda.Core/Assets/DI/DataDirectoryAssetProvider.cs @@ -1,6 +1,7 @@ using System.Diagnostics.CodeAnalysis; using System.IO.Abstractions; using Mutagen.Bethesda.Environments.DI; + namespace Mutagen.Bethesda.Assets.DI; public class DataDirectoryAssetProvider : IAssetProvider diff --git a/Mutagen.Bethesda.Core/Assets/DI/GameAssetProvider.cs b/Mutagen.Bethesda.Core/Assets/DI/GameAssetProvider.cs index d04883d496..1e1138eeba 100644 --- a/Mutagen.Bethesda.Core/Assets/DI/GameAssetProvider.cs +++ b/Mutagen.Bethesda.Core/Assets/DI/GameAssetProvider.cs @@ -1,4 +1,5 @@ using System.Diagnostics.CodeAnalysis; + namespace Mutagen.Bethesda.Assets.DI; public class GameAssetProvider : IAssetProvider diff --git a/Mutagen.Bethesda.Core/Assets/DI/IAssetProvider.cs b/Mutagen.Bethesda.Core/Assets/DI/IAssetProvider.cs index e5f9d94171..c2dc5ff5ec 100644 --- a/Mutagen.Bethesda.Core/Assets/DI/IAssetProvider.cs +++ b/Mutagen.Bethesda.Core/Assets/DI/IAssetProvider.cs @@ -1,4 +1,5 @@ using System.Diagnostics.CodeAnalysis; + namespace Mutagen.Bethesda.Assets.DI; public interface IAssetProvider diff --git a/Mutagen.Bethesda.Core/Environments/DI/GameEnvironmentProvider.cs b/Mutagen.Bethesda.Core/Environments/DI/GameEnvironmentProvider.cs index 2434782707..e9b4ce5331 100644 --- a/Mutagen.Bethesda.Core/Environments/DI/GameEnvironmentProvider.cs +++ b/Mutagen.Bethesda.Core/Environments/DI/GameEnvironmentProvider.cs @@ -1,4 +1,5 @@ -using Mutagen.Bethesda.Plugins.Cache; +using Mutagen.Bethesda.Assets.DI; +using Mutagen.Bethesda.Plugins.Cache; using Mutagen.Bethesda.Plugins.Order.DI; using Mutagen.Bethesda.Plugins.Records; @@ -29,19 +30,22 @@ public sealed class GameEnvironmentProvider : IGameEnvironmentProvider private readonly IDataDirectoryProvider _dataDirectoryProvider; private readonly IPluginListingsPathContext _pluginListingsPathContext; private readonly ICreationClubListingsPathProvider _cccPath; + private readonly IAssetProvider _assetProvider; public GameEnvironmentProvider( IGameReleaseContext gameReleaseContext, ILoadOrderImporter loadOrderImporter, IDataDirectoryProvider dataDirectoryProvider, IPluginListingsPathContext pluginListingsPathContext, - ICreationClubListingsPathProvider cccPath) + ICreationClubListingsPathProvider cccPath, + IAssetProvider assetProvider) { _gameReleaseContext = gameReleaseContext; _loadOrderImporter = loadOrderImporter; _dataDirectoryProvider = dataDirectoryProvider; _pluginListingsPathContext = pluginListingsPathContext; _cccPath = cccPath; + _assetProvider = assetProvider; } public IGameEnvironment Construct(LinkCachePreferences? linkCachePrefs = null) @@ -55,6 +59,7 @@ public IGameEnvironment Construct(LinkCachePreferences? linkCachePrefs = null) creationClubListingsFilePath: _cccPath.Path, loadOrder: loadOrder, linkCache: loadOrder.ToUntypedImmutableLinkCache(linkCachePrefs), + assetProvider: _assetProvider, dispose: true); } } @@ -67,19 +72,22 @@ public sealed class GameEnvironmentProvider : IGameEnvironmentProvider loadOrderImporter, IDataDirectoryProvider dataDirectoryProvider, IPluginListingsPathContext pluginListingsPathContext, - ICreationClubListingsPathProvider cccPath) + ICreationClubListingsPathProvider cccPath, + IAssetProvider assetProvider) { _gameReleaseContext = gameReleaseContext; _loadOrderImporter = loadOrderImporter; _dataDirectoryProvider = dataDirectoryProvider; _pluginListingsPathContext = pluginListingsPathContext; _cccPath = cccPath; + _assetProvider = assetProvider; } public IGameEnvironment Construct(LinkCachePreferences? linkCachePrefs = null) @@ -93,6 +101,7 @@ public IGameEnvironment Construct(LinkCachePreferences? linkCachePrefs = n creationClubListingsFilePath: _cccPath.Path, loadOrder: loadOrder, linkCache: loadOrder.ToUntypedImmutableLinkCache(linkCachePrefs), + assetProvider: _assetProvider, dispose: true); } } @@ -106,19 +115,22 @@ public sealed class GameEnvironmentProvider : IGameEnvir private readonly IDataDirectoryProvider _dataDirectoryProvider; private readonly IPluginListingsPathContext _pluginListingsPathContext; private readonly ICreationClubListingsPathProvider _cccPath; + private readonly IAssetProvider _assetProvider; public GameEnvironmentProvider( IGameReleaseContext gameReleaseContext, ILoadOrderImporter loadOrderImporter, IDataDirectoryProvider dataDirectoryProvider, IPluginListingsPathContext pluginListingsPathContext, - ICreationClubListingsPathProvider cccPath) + ICreationClubListingsPathProvider cccPath, + IAssetProvider assetProvider) { _gameReleaseContext = gameReleaseContext; _loadOrderImporter = loadOrderImporter; _dataDirectoryProvider = dataDirectoryProvider; _pluginListingsPathContext = pluginListingsPathContext; _cccPath = cccPath; + _assetProvider = assetProvider; } public IGameEnvironment Construct(LinkCachePreferences? linkCachePrefs = null) @@ -132,6 +144,7 @@ public IGameEnvironment Construct(LinkCachePreferences? creationClubListingsFilePath: _cccPath.Path, loadOrder: loadOrder, linkCache: loadOrder.ToImmutableLinkCache(linkCachePrefs), + assetProvider: _assetProvider, dispose: true); } } \ No newline at end of file diff --git a/Mutagen.Bethesda.Core/Environments/DI/IGameDirectoryLookup.cs b/Mutagen.Bethesda.Core/Environments/DI/IGameDirectoryLookup.cs index ed878c9170..72229dd90c 100644 --- a/Mutagen.Bethesda.Core/Environments/DI/IGameDirectoryLookup.cs +++ b/Mutagen.Bethesda.Core/Environments/DI/IGameDirectoryLookup.cs @@ -34,4 +34,68 @@ public interface IGameDirectoryLookup /// Release to query /// The game directory, if located DirectoryPath? TryGet(GameRelease release); +} + +public class GameDirectoryLookupInjection : IGameDirectoryLookup +{ + private readonly GameRelease _release; + private readonly DirectoryPath[] _path; + + public GameDirectoryLookupInjection(GameRelease release, DirectoryPath? path) + { + _release = release; + if (path == null) + { + _path = []; + } + else + { + _path = [path.Value]; + } + } + + private void CheckRelease(GameRelease release) + { + if (release != _release) + { + throw new ArgumentException($"Accessed a game release the inejction was not intended for: {release} != {_release}", nameof(release)); + } + } + + public IEnumerable GetAll(GameRelease release) + { + CheckRelease(release); + return _path; + } + + public bool TryGet(GameRelease release, out DirectoryPath path) + { + if (release != _release || _path.Length == 0) + { + path = default; + return false; + } + + path = _path[0]; + return true; + } + + public DirectoryPath Get(GameRelease release) + { + CheckRelease(release); + return _path[0]; + } + + public DirectoryPath? TryGet(GameRelease release) + { + CheckRelease(release); + if (release != _release) + { + return default; + } + + if (_path.Length == 0) return default; + + return _path[0]; + } } \ No newline at end of file diff --git a/Mutagen.Bethesda.Core/Environments/GameEnvironment.cs b/Mutagen.Bethesda.Core/Environments/GameEnvironment.cs index ed42f8da72..a49355e4cf 100644 --- a/Mutagen.Bethesda.Core/Environments/GameEnvironment.cs +++ b/Mutagen.Bethesda.Core/Environments/GameEnvironment.cs @@ -1,4 +1,7 @@ +using Mutagen.Bethesda.Archives.DI; +using Mutagen.Bethesda.Assets.DI; using Mutagen.Bethesda.Environments.DI; +using Mutagen.Bethesda.Inis.DI; using Mutagen.Bethesda.Installs; using Mutagen.Bethesda.Installs.DI; using Mutagen.Bethesda.Plugins; @@ -76,6 +79,11 @@ public interface IGameEnvironment : IDisposable /// Convenience Link Cache to use created from the provided Load Order object ///
ILinkCache LinkCache { get; } + + /// + /// Convenience Asset Provider created from the environment's context + /// + IAssetProvider AssetProvider { get; } } public interface IGameEnvironment : IGameEnvironment @@ -123,6 +131,8 @@ public sealed class GameEnvironmentState : public ILinkCache LinkCache { get; } public ILoadOrderGetter> LoadOrder { get; } + + public IAssetProvider AssetProvider { get; } public GameEnvironmentState( GameRelease gameRelease, @@ -131,6 +141,7 @@ public GameEnvironmentState( FilePath? creationClubListingsFilePath, ILoadOrderGetter> loadOrder, ILinkCache linkCache, + IAssetProvider assetProvider, bool dispose = true) { GameRelease = gameRelease; @@ -139,6 +150,7 @@ public GameEnvironmentState( CreationClubListingsFilePath = creationClubListingsFilePath; LoadOrder = loadOrder; LinkCache = linkCache; + AssetProvider = assetProvider; _dispose = dispose; } @@ -155,10 +167,13 @@ public static IGameEnvironment Construct( LinkCachePreferences? linkCachePrefs = null) { Warmup.Init(); + var fs = IFileSystemExt.DefaultFilesystem; var dataDirectory = new DataDirectoryInjection(Path.Combine(gameFolder, "Data")); var gameReleaseInjection = new GameReleaseInjection(release); + var gameDir = new GameDirectoryInjection(gameFolder); + var gameDirLookup = new GameDirectoryLookupInjection(release, gameDir.Path); var pluginRawListingsReader = new PluginRawListingsReader( - IFileSystemExt.DefaultFilesystem, + fs, new PluginListingsParser( new PluginListingCommentTrimmer(), new LoadOrderListingParser( @@ -172,37 +187,61 @@ public static IGameEnvironment Construct( category, new CreationClubEnabledProvider( category), - new GameDirectoryInjection(gameFolder)); + gameDir); + var archiveExt = new ArchiveExtensionProvider(gameReleaseInjection); + var loListingsProvider = new LoadOrderListingsProvider( + new OrderListings(), + new ImplicitListingsProvider( + IFileSystemExt.DefaultFilesystem, + dataDirectory, + new ImplicitListingModKeyProvider( + gameReleaseInjection)), + new PluginListingsProvider( + gameReleaseInjection, + new TimestampedPluginListingsProvider( + IFileSystemExt.DefaultFilesystem, + new TimestampAligner(IFileSystemExt.DefaultFilesystem), + new TimestampedPluginListingsPreferences() { ThrowOnMissingMods = false }, + pluginRawListingsReader, + dataDirectory, + pluginListingsPathProvider), + new EnabledPluginListingsProvider( + IFileSystemExt.DefaultFilesystem, + pluginRawListingsReader, + pluginListingsPathProvider)), + new CreationClubListingsProvider( + IFileSystemExt.DefaultFilesystem, + dataDirectory, + creationClubListingsPathProvider, + new CreationClubRawListingsReader())); + + var assetProvider = new GameAssetProvider( + new DataDirectoryAssetProvider( + fs, + dataDirectory), + new ArchiveAssetProvider( + fs, + new GetApplicableArchivePaths( + fs, + new CheckArchiveApplicability( + archiveExt), + dataDirectory, + archiveExt, + new CachedArchiveListingDetailsProvider( + loListingsProvider, + new GetArchiveIniListings( + fs, + new IniPathProvider( + gameReleaseInjection, + new IniPathLookup( + gameDirLookup))))), + gameReleaseInjection)); return new GameEnvironmentProvider( gameReleaseInjection, new LoadOrderImporter( IFileSystemExt.DefaultFilesystem, dataDirectory, - new LoadOrderListingsProvider( - new OrderListings(), - new ImplicitListingsProvider( - IFileSystemExt.DefaultFilesystem, - dataDirectory, - new ImplicitListingModKeyProvider( - gameReleaseInjection)), - new PluginListingsProvider( - gameReleaseInjection, - new TimestampedPluginListingsProvider( - IFileSystemExt.DefaultFilesystem, - new TimestampAligner(IFileSystemExt.DefaultFilesystem), - new TimestampedPluginListingsPreferences() { ThrowOnMissingMods = false }, - pluginRawListingsReader, - dataDirectory, - pluginListingsPathProvider), - new EnabledPluginListingsProvider( - IFileSystemExt.DefaultFilesystem, - pluginRawListingsReader, - pluginListingsPathProvider)), - new CreationClubListingsProvider( - IFileSystemExt.DefaultFilesystem, - dataDirectory, - creationClubListingsPathProvider, - new CreationClubRawListingsReader())), + loListingsProvider, new ModImporter( IFileSystemExt.DefaultFilesystem, gameReleaseInjection), @@ -212,7 +251,8 @@ public static IGameEnvironment Construct( dataDirectory)), dataDirectory, pluginListingsPathProvider, - creationClubListingsPathProvider) + creationClubListingsPathProvider, + assetProvider) .Construct(); } @@ -246,6 +286,8 @@ public sealed class GameEnvironmentState : public ILinkCache LinkCache { get; } + public IAssetProvider AssetProvider { get; } + public GameEnvironmentState( GameRelease gameRelease, DirectoryPath dataFolderPath, @@ -253,6 +295,7 @@ public GameEnvironmentState( FilePath? creationClubListingsFilePath, ILoadOrder> loadOrder, ILinkCache linkCache, + IAssetProvider assetProvider, bool dispose = true) { GameRelease = gameRelease; @@ -262,6 +305,7 @@ public GameEnvironmentState( LoadOrder = loadOrder; LinkCache = linkCache; _dispose = dispose; + AssetProvider = assetProvider; } public void Dispose() @@ -277,10 +321,13 @@ public static IGameEnvironment Construct( LinkCachePreferences? linkCachePrefs = null) { Warmup.Init(); + var fs = IFileSystemExt.DefaultFilesystem; var dataDirectory = new DataDirectoryInjection(Path.Combine(gameFolder, "Data")); var gameReleaseInjection = new GameReleaseInjection(release); + var gameDir = new GameDirectoryInjection(gameFolder); + var gameDirLookup = new GameDirectoryLookupInjection(release, gameDir.Path); var pluginRawListingsReader = new PluginRawListingsReader( - IFileSystemExt.DefaultFilesystem, + fs, new PluginListingsParser( new PluginListingCommentTrimmer(), new LoadOrderListingParser( @@ -295,36 +342,59 @@ public static IGameEnvironment Construct( new CreationClubEnabledProvider( category), new GameDirectoryInjection(gameFolder)); + var loListingsProvider = new LoadOrderListingsProvider( + new OrderListings(), + new ImplicitListingsProvider( + IFileSystemExt.DefaultFilesystem, + dataDirectory, + new ImplicitListingModKeyProvider( + gameReleaseInjection)), + new PluginListingsProvider( + gameReleaseInjection, + new TimestampedPluginListingsProvider( + IFileSystemExt.DefaultFilesystem, + new TimestampAligner(IFileSystemExt.DefaultFilesystem), + new TimestampedPluginListingsPreferences() { ThrowOnMissingMods = false }, + pluginRawListingsReader, + dataDirectory, + pluginListingsPathProvider), + new EnabledPluginListingsProvider( + IFileSystemExt.DefaultFilesystem, + pluginRawListingsReader, + pluginListingsPathProvider)), + new CreationClubListingsProvider( + IFileSystemExt.DefaultFilesystem, + dataDirectory, + creationClubListingsPathProvider, + new CreationClubRawListingsReader())); + var archiveExt = new ArchiveExtensionProvider(gameReleaseInjection); + var assetProvider = new GameAssetProvider( + new DataDirectoryAssetProvider( + fs, + dataDirectory), + new ArchiveAssetProvider( + fs, + new GetApplicableArchivePaths( + fs, + new CheckArchiveApplicability( + archiveExt), + dataDirectory, + archiveExt, + new CachedArchiveListingDetailsProvider( + loListingsProvider, + new GetArchiveIniListings( + fs, + new IniPathProvider( + gameReleaseInjection, + new IniPathLookup( + gameDirLookup))))), + gameReleaseInjection)); return new GameEnvironmentProvider( gameReleaseInjection, new LoadOrderImporter( IFileSystemExt.DefaultFilesystem, dataDirectory, - new LoadOrderListingsProvider( - new OrderListings(), - new ImplicitListingsProvider( - IFileSystemExt.DefaultFilesystem, - dataDirectory, - new ImplicitListingModKeyProvider( - gameReleaseInjection)), - new PluginListingsProvider( - gameReleaseInjection, - new TimestampedPluginListingsProvider( - IFileSystemExt.DefaultFilesystem, - new TimestampAligner(IFileSystemExt.DefaultFilesystem), - new TimestampedPluginListingsPreferences() { ThrowOnMissingMods = false }, - pluginRawListingsReader, - dataDirectory, - pluginListingsPathProvider), - new EnabledPluginListingsProvider( - IFileSystemExt.DefaultFilesystem, - pluginRawListingsReader, - pluginListingsPathProvider)), - new CreationClubListingsProvider( - IFileSystemExt.DefaultFilesystem, - dataDirectory, - creationClubListingsPathProvider, - new CreationClubRawListingsReader())), + loListingsProvider, new ModImporter( IFileSystemExt.DefaultFilesystem, gameReleaseInjection), @@ -334,7 +404,8 @@ public static IGameEnvironment Construct( dataDirectory)), dataDirectory, pluginListingsPathProvider, - creationClubListingsPathProvider) + creationClubListingsPathProvider, + assetProvider) .Construct(); } @@ -376,6 +447,11 @@ public sealed class GameEnvironmentState : /// Convenience Link Cache to use created from the provided Load Order object ///
public ILinkCache LinkCache { get; } + + /// + /// Convenience Asset Provider created from the environment's context + /// + public IAssetProvider AssetProvider { get; } public GameEnvironmentState( GameRelease gameRelease, @@ -384,6 +460,7 @@ public GameEnvironmentState( FilePath? creationClubListingsFilePath, ILoadOrderGetter> loadOrder, ILinkCache linkCache, + IAssetProvider assetProvider, bool dispose = true) { GameRelease = gameRelease; @@ -392,6 +469,7 @@ public GameEnvironmentState( CreationClubListingsFilePath = creationClubListingsFilePath; LoadOrder = loadOrder; LinkCache = linkCache; + AssetProvider = assetProvider; _dispose = dispose; } @@ -408,10 +486,13 @@ public static IGameEnvironment Construct( LinkCachePreferences? linkCachePrefs = null) { Warmup.Init(); + var fs = IFileSystemExt.DefaultFilesystem; var dataDirectory = new DataDirectoryInjection(Path.Combine(gameFolder, "Data")); var gameReleaseInjection = new GameReleaseInjection(release); + var gameDir = new GameDirectoryInjection(gameFolder); + var gameDirLookup = new GameDirectoryLookupInjection(release, gameDir.Path); var pluginRawListingsReader = new PluginRawListingsReader( - IFileSystemExt.DefaultFilesystem, + fs, new PluginListingsParser( new PluginListingCommentTrimmer(), new LoadOrderListingParser( @@ -426,36 +507,59 @@ public static IGameEnvironment Construct( new CreationClubEnabledProvider( category), new GameDirectoryInjection(gameFolder)); + var loListingsProvider = new LoadOrderListingsProvider( + new OrderListings(), + new ImplicitListingsProvider( + IFileSystemExt.DefaultFilesystem, + dataDirectory, + new ImplicitListingModKeyProvider( + gameReleaseInjection)), + new PluginListingsProvider( + gameReleaseInjection, + new TimestampedPluginListingsProvider( + IFileSystemExt.DefaultFilesystem, + new TimestampAligner(IFileSystemExt.DefaultFilesystem), + new TimestampedPluginListingsPreferences() { ThrowOnMissingMods = false }, + pluginRawListingsReader, + dataDirectory, + pluginListingsPathProvider), + new EnabledPluginListingsProvider( + IFileSystemExt.DefaultFilesystem, + pluginRawListingsReader, + pluginListingsPathProvider)), + new CreationClubListingsProvider( + IFileSystemExt.DefaultFilesystem, + dataDirectory, + creationClubListingsPathProvider, + new CreationClubRawListingsReader())); + var archiveExt = new ArchiveExtensionProvider(gameReleaseInjection); + var assetProvider = new GameAssetProvider( + new DataDirectoryAssetProvider( + fs, + dataDirectory), + new ArchiveAssetProvider( + fs, + new GetApplicableArchivePaths( + fs, + new CheckArchiveApplicability( + archiveExt), + dataDirectory, + archiveExt, + new CachedArchiveListingDetailsProvider( + loListingsProvider, + new GetArchiveIniListings( + fs, + new IniPathProvider( + gameReleaseInjection, + new IniPathLookup( + gameDirLookup))))), + gameReleaseInjection)); return new GameEnvironmentProvider( gameReleaseInjection, new LoadOrderImporter( IFileSystemExt.DefaultFilesystem, dataDirectory, - new LoadOrderListingsProvider( - new OrderListings(), - new ImplicitListingsProvider( - IFileSystemExt.DefaultFilesystem, - dataDirectory, - new ImplicitListingModKeyProvider( - gameReleaseInjection)), - new PluginListingsProvider( - gameReleaseInjection, - new TimestampedPluginListingsProvider( - IFileSystemExt.DefaultFilesystem, - new TimestampAligner(IFileSystemExt.DefaultFilesystem), - new TimestampedPluginListingsPreferences() {ThrowOnMissingMods = false}, - pluginRawListingsReader, - dataDirectory, - pluginListingsPathProvider), - new EnabledPluginListingsProvider( - IFileSystemExt.DefaultFilesystem, - pluginRawListingsReader, - pluginListingsPathProvider)), - new CreationClubListingsProvider( - IFileSystemExt.DefaultFilesystem, - dataDirectory, - creationClubListingsPathProvider, - new CreationClubRawListingsReader())), + loListingsProvider, new ModImporter( IFileSystemExt.DefaultFilesystem, gameReleaseInjection), @@ -465,7 +569,8 @@ public static IGameEnvironment Construct( dataDirectory)), dataDirectory, pluginListingsPathProvider, - creationClubListingsPathProvider) + creationClubListingsPathProvider, + assetProvider) .Construct(); } diff --git a/Mutagen.Bethesda.Core/Environments/GameEnvironmentBuilder.cs b/Mutagen.Bethesda.Core/Environments/GameEnvironmentBuilder.cs index 3c65cf42ed..6c09a96ca9 100644 --- a/Mutagen.Bethesda.Core/Environments/GameEnvironmentBuilder.cs +++ b/Mutagen.Bethesda.Core/Environments/GameEnvironmentBuilder.cs @@ -3,6 +3,9 @@ using Mutagen.Bethesda.Plugins.Records; using System.Collections.Immutable; using System.IO.Abstractions; +using Mutagen.Bethesda.Archives.DI; +using Mutagen.Bethesda.Assets.DI; +using Mutagen.Bethesda.Inis.DI; using Mutagen.Bethesda.Installs.DI; using Mutagen.Bethesda.Plugins; using Mutagen.Bethesda.Plugins.Binary.Parameters; @@ -175,6 +178,9 @@ public IGameEnvironment Build() Release, GameLocatorLookupCache.Instance), DataDirectoryProvider); + + var gameDirectoryLookup = Resolve( + () => new GameDirectoryLookupInjection(Release.Release, dataDirectory.Path.Directory)); var pluginPathProvider = Resolve( () => new PluginListingsPathContext( @@ -240,10 +246,11 @@ public IGameEnvironment Build() filteredListings = filter(filteredListings); } + var loListings = new LoadOrderListingsInjection(filteredListings); var loGetter = new LoadOrderImporter( fs, dataDirectory, - new LoadOrderListingsInjection(filteredListings), + loListings, new ModImporter( fs, Release), @@ -260,13 +267,37 @@ public IGameEnvironment Build() var linkCache = lo.ToMutableLinkCache(MutableMods.ToArray()); + var archiveExt = new ArchiveExtensionProvider(Release); + var assetProvider = new GameAssetProvider( + new DataDirectoryAssetProvider( + fs, + dataDirectory), + new ArchiveAssetProvider( + fs, + new GetApplicableArchivePaths( + fs, + new CheckArchiveApplicability( + archiveExt), + dataDirectory, + archiveExt, + new CachedArchiveListingDetailsProvider( + loListings, + new GetArchiveIniListings( + fs, + new IniPathProvider( + Release, + new IniPathLookup( + gameDirectoryLookup))))), + Release)); + return new GameEnvironmentState( Release.Release, dataFolderPath: dataDirectory.Path, loadOrderFilePath: pluginPathProvider.Path, creationClubListingsFilePath: cccPath.Path, loadOrder: lo, - linkCache: linkCache); + linkCache: linkCache, + assetProvider: assetProvider); } } @@ -430,6 +461,9 @@ public IGameEnvironment Build() GameLocatorLookupCache.Instance), DataDirectoryProvider); + var gameDirectoryLookup = Resolve( + () => new GameDirectoryLookupInjection(Release.Release, dataDirectory.Path.Directory)); + var pluginPathProvider = Resolve( () => new PluginListingsPathContext( new PluginListingsPathProvider(), @@ -494,11 +528,12 @@ public IGameEnvironment Build() filteredListings = filter(filteredListings); } + var loListings = new LoadOrderListingsInjection(filteredListings); var loGetter = new LoadOrderImporter( fs, Release, dataDirectory, - new LoadOrderListingsInjection(filteredListings), + loListings, new KeyedMasterStyleReader( Release, fs), @@ -517,13 +552,37 @@ public IGameEnvironment Build() var linkCache = lo.ToUntypedMutableLinkCache(Release.Release.ToCategory(), MutableMods.ToArray()); + var archiveExt = new ArchiveExtensionProvider(Release); + var assetProvider = new GameAssetProvider( + new DataDirectoryAssetProvider( + fs, + dataDirectory), + new ArchiveAssetProvider( + fs, + new GetApplicableArchivePaths( + fs, + new CheckArchiveApplicability( + archiveExt), + dataDirectory, + archiveExt, + new CachedArchiveListingDetailsProvider( + loListings, + new GetArchiveIniListings( + fs, + new IniPathProvider( + Release, + new IniPathLookup( + gameDirectoryLookup))))), + Release)); + return new GameEnvironmentState( Release.Release, dataFolderPath: dataDirectory.Path, loadOrderFilePath: pluginPathProvider.Path, creationClubListingsFilePath: cccPath.Path, loadOrder: lo, - linkCache: linkCache); + linkCache: linkCache, + assetProvider: assetProvider); } } diff --git a/Mutagen.Bethesda.Core/Mutagen.Bethesda.Core.csproj b/Mutagen.Bethesda.Core/Mutagen.Bethesda.Core.csproj index 9c64737e49..cf1641ae1d 100644 --- a/Mutagen.Bethesda.Core/Mutagen.Bethesda.Core.csproj +++ b/Mutagen.Bethesda.Core/Mutagen.Bethesda.Core.csproj @@ -45,6 +45,7 @@ + cs content @@ -65,6 +66,7 @@ content Compile + diff --git a/Mutagen.Bethesda.Core/Strings/StringsFolderLookupOverlay.cs b/Mutagen.Bethesda.Core/Strings/StringsFolderLookupOverlay.cs index b6e220f46c..a6ee47b268 100644 --- a/Mutagen.Bethesda.Core/Strings/StringsFolderLookupOverlay.cs +++ b/Mutagen.Bethesda.Core/Strings/StringsFolderLookupOverlay.cs @@ -102,8 +102,7 @@ public static StringsFolderLookupOverlay TypicalFactory( } } foreach (var bsaFile in Archive.GetApplicableArchivePaths( - release, dataPath, modKey, instructions?.BsaOrdering, fileSystem: fileSystem, - returnEmptyIfMissing: true)) + release, dataPath, modKey, instructions?.BsaOrdering, fileSystem: fileSystem)) { try {