From a94dcb9cbbc2c14d5e8219706372eae71f69dcd5 Mon Sep 17 00:00:00 2001 From: Justin Swanson Date: Thu, 8 Aug 2024 03:41:42 -0500 Subject: [PATCH] Write builder only ensures mods exist on LO if separated mod --- .../Binary/Translations/BinaryWriteBuilder.cs | 27 +- .../Builders/BuilderPassthroughTests.cs | 241 ++++++++++++++++++ 2 files changed, 259 insertions(+), 9 deletions(-) create mode 100644 Mutagen.Bethesda.UnitTests/Plugins/Builders/BuilderPassthroughTests.cs diff --git a/Mutagen.Bethesda.Core/Plugins/Binary/Translations/BinaryWriteBuilder.cs b/Mutagen.Bethesda.Core/Plugins/Binary/Translations/BinaryWriteBuilder.cs index 657ca3b67..2bf7f753e 100644 --- a/Mutagen.Bethesda.Core/Plugins/Binary/Translations/BinaryWriteBuilder.cs +++ b/Mutagen.Bethesda.Core/Plugins/Binary/Translations/BinaryWriteBuilder.cs @@ -2,6 +2,7 @@ using Mutagen.Bethesda.Installs.DI; using Mutagen.Bethesda.Plugins.Binary.Parameters; using Mutagen.Bethesda.Plugins.Binary.Streams; +using Mutagen.Bethesda.Plugins.Meta; using Mutagen.Bethesda.Plugins.Order; using Mutagen.Bethesda.Plugins.Records; using Mutagen.Bethesda.Strings; @@ -173,12 +174,17 @@ public BinaryModdedWriteBuilderTargetChoice WithDefaultLoadOrder() _loadOrderSetter = (m, p) => { var dataFolder = p._dataFolderGetter?.Invoke(m, p._param) ?? throw new ArgumentNullException("Data folder source was not set"); - var lo = LoadOrder.Import(dataFolder, m.GameRelease, p._param.FileSystem); - return p._param with + var lo = LoadOrder.Import(dataFolder, m.GameRelease, p._param.FileSystem); + LoadOrder? modFlagsLo = null; + if (GameConstants.Get(m.GameRelease).SeparateMasterLoadOrders) { - LoadOrder = new LoadOrder( + modFlagsLo = new LoadOrder( lo.ListedOrder.ResolveAllModsExist(), - disposeItems: false), + disposeItems: false); + } + return p._param with + { + LoadOrder = modFlagsLo, MastersListOrdering = new MastersListOrderingByLoadOrder(lo), LowerRangeDisallowedHandler = ALowerRangeDisallowedHandlerOption.AddPlaceholder(lo) }; @@ -199,19 +205,22 @@ public BinaryModdedWriteBuilderDataFolderChoice WithLoadOrder( { _loadOrderSetter = (m, p) => { + var loArray = loadOrder + .Where(x => x != m.ModKey) + .ToArray(); var dataFolder = p._dataFolderGetter?.Invoke(m, p._param); - if (dataFolder == null) + if (dataFolder == null || !GameConstants.Get(m.GameRelease).SeparateMasterLoadOrders) { return p._param with { - MastersListOrdering = new MastersListOrderingByLoadOrder(loadOrder), - LowerRangeDisallowedHandler = ALowerRangeDisallowedHandlerOption.AddPlaceholder(loadOrder) + MastersListOrdering = new MastersListOrderingByLoadOrder(loArray), + LowerRangeDisallowedHandler = ALowerRangeDisallowedHandlerOption.AddPlaceholder(loArray) }; } else { var lo = LoadOrder.Import( - dataFolder.Value, loadOrder, + dataFolder.Value, loArray, m.GameRelease, p._param.FileSystem); return p._param with { @@ -234,7 +243,7 @@ public BinaryModdedWriteBuilderDataFolderChoice WithLoadOrderFromHea _loadOrderSetter = (m, p) => { var dataFolder = p._dataFolderGetter?.Invoke(m, p._param); - if (dataFolder == null) + if (dataFolder == null || !GameConstants.Get(m.GameRelease).SeparateMasterLoadOrders) { var lo = _mod.MasterReferences.Select(x => x.Master).ToArray(); return p._param with diff --git a/Mutagen.Bethesda.UnitTests/Plugins/Builders/BuilderPassthroughTests.cs b/Mutagen.Bethesda.UnitTests/Plugins/Builders/BuilderPassthroughTests.cs new file mode 100644 index 000000000..b8b070505 --- /dev/null +++ b/Mutagen.Bethesda.UnitTests/Plugins/Builders/BuilderPassthroughTests.cs @@ -0,0 +1,241 @@ +using System.IO.Abstractions; +using FluentAssertions; +using Mutagen.Bethesda.Plugins; +using Mutagen.Bethesda.Plugins.Binary.Parameters; +using Mutagen.Bethesda.Plugins.Exceptions; +using Mutagen.Bethesda.Plugins.Records; +using Mutagen.Bethesda.Skyrim; +using Mutagen.Bethesda.Starfield; +using Mutagen.Bethesda.Testing.AutoData; +using Noggog; +using Xunit; + +namespace Mutagen.Bethesda.UnitTests.Plugins.Builders; + +public class BuilderPassthroughTests +{ + public class Payload + { + public Payload( + IFileSystem fileSystem, + DirectoryPath existingDataFolder, + ModKey normalMasterKey, + ModKey smallMasterKey, + ModKey mediumMasterKey, + ModKey originatingKey) + { + NormalMasterKey = normalMasterKey; + SmallMasterKey = smallMasterKey; + MediumMasterKey = mediumMasterKey; + OriginatingKey = originatingKey; + FileSystem = fileSystem; + DataFolder = existingDataFolder; + } + + public ModKey NormalMasterKey { get; } + public ModKey SmallMasterKey { get; } + public ModKey MediumMasterKey { get; } + public ModKey OriginatingKey { get; } + public IFileSystem FileSystem { get; } + public DirectoryPath DataFolder { get; } + + public async Task WriteMod( + TModGetter mod, + bool useDataFolder) + where TModGetter : IModGetter + { + var modPath = Path.Combine(DataFolder, mod.ModKey.ToString()); + await mod.BeginWrite + .WithLoadOrder(new ModKey[] + { + NormalMasterKey, + MediumMasterKey, + SmallMasterKey + }) + .WithDataFolder(DataFolder) + .ToPath(modPath) + .WithFileSystem(FileSystem) + .WriteAsync(); + return modPath; + } + } + + [Theory, MutagenAutoData] + public async Task NonSeparated( + Payload payload) + { + var normalMaster = new SkyrimMod(payload.NormalMasterKey, SkyrimRelease.SkyrimSE) + { + IsMaster = true, + }; + var normalNpc = normalMaster.Npcs.AddNew(); + normalNpc.EditorID = "Normal"; + var smallMaster = new SkyrimMod(payload.SmallMasterKey, SkyrimRelease.SkyrimSE) + { + IsSmallMaster = true, + }; + var smallNpc = smallMaster.Npcs.AddNew(); + smallNpc.EditorID = "Small"; + var originating = new SkyrimMod(payload.OriginatingKey, SkyrimRelease.SkyrimSE); + var originatingNpc = originating.Npcs.AddNew(); + originatingNpc.EditorID = "Originating"; + + originating.Npcs.GetOrAddAsOverride(normalNpc); + originating.Npcs.GetOrAddAsOverride(smallNpc); + + normalMaster.WriteToBinary(Path.Combine(payload.DataFolder, normalMaster.ModKey.FileName), new BinaryWriteParameters() + { + FileSystem = payload.FileSystem + }); + smallMaster.WriteToBinary(Path.Combine(payload.DataFolder, smallMaster.ModKey.FileName), new BinaryWriteParameters() + { + FileSystem = payload.FileSystem + }); + + var modPath = await payload.WriteMod( + originating, + useDataFolder: false); + using var mod = SkyrimMod.Create(SkyrimRelease.SkyrimSE) + .FromPath(modPath) + .WithFileSystem(payload.FileSystem) + .Construct(); + + mod.Npcs.Should().HaveCount(3); + mod.Npcs.TryGetValue(normalNpc.FormKey, out var normalNpcReimport) + .Should().BeTrue(); + normalNpcReimport!.FormKey.Should().Be(normalNpc.FormKey); + mod.Npcs.TryGetValue(smallNpc.FormKey, out var smallNpcReimport) + .Should().BeTrue(); + smallNpcReimport!.FormKey.Should().Be(smallNpc.FormKey); + mod.Npcs.TryGetValue(originatingNpc.FormKey, out var originatingNpcReimport) + .Should().BeTrue(); + originatingNpcReimport!.FormKey.Should().Be(originatingNpc.FormKey); + } + + [Theory, MutagenAutoData] + public async Task Separated( + Payload payload) + { + var normalMaster = new StarfieldMod(payload.NormalMasterKey, StarfieldRelease.Starfield) + { + IsMaster = true, + }; + var normalNpc = normalMaster.Npcs.AddNew(); + normalNpc.EditorID = "Normal"; + var smallMaster = new StarfieldMod(payload.SmallMasterKey, StarfieldRelease.Starfield) + { + IsSmallMaster = true, + }; + var smallNpc = smallMaster.Npcs.AddNew(); + smallNpc.EditorID = "Small"; + var mediumMaster = new StarfieldMod(payload.MediumMasterKey, StarfieldRelease.Starfield) + { + IsMediumMaster = true, + }; + var mediumNpc = mediumMaster.Npcs.AddNew(); + mediumNpc.EditorID = "Medium"; + var originating = new StarfieldMod(payload.OriginatingKey, StarfieldRelease.Starfield); + var originatingNpc = originating.Npcs.AddNew(); + originatingNpc.EditorID = "Originating"; + + originating.Npcs.GetOrAddAsOverride(normalNpc); + originating.Npcs.GetOrAddAsOverride(smallNpc); + originating.Npcs.GetOrAddAsOverride(mediumNpc); + + normalMaster.WriteToBinary(Path.Combine(payload.DataFolder, normalMaster.ModKey.FileName), new BinaryWriteParameters() + { + FileSystem = payload.FileSystem + }); + smallMaster.WriteToBinary(Path.Combine(payload.DataFolder, smallMaster.ModKey.FileName), new BinaryWriteParameters() + { + FileSystem = payload.FileSystem + }); + mediumMaster.WriteToBinary(Path.Combine(payload.DataFolder, mediumMaster.ModKey.FileName), new BinaryWriteParameters() + { + FileSystem = payload.FileSystem + }); + + var modPath = await payload.WriteMod( + originating, + useDataFolder: false); + using var mod = StarfieldMod.Create(StarfieldRelease.Starfield) + .FromPath(modPath) + .WithLoadOrderFromHeaderMasters() + .WithNoDataFolder() + .WithFileSystem(payload.FileSystem) + .Construct(); + + Assert.Throws(() => + { + mod.Npcs.Should().HaveCount(4); + }); + } + + [Theory, MutagenAutoData] + public async Task SeparatedWithDataFolder( + Payload payload) + { + var normalMaster = new StarfieldMod(payload.NormalMasterKey, StarfieldRelease.Starfield) + { + IsMaster = true, + }; + var normalNpc = normalMaster.Npcs.AddNew(); + normalNpc.EditorID = "Normal"; + var smallMaster = new StarfieldMod(payload.SmallMasterKey, StarfieldRelease.Starfield) + { + IsSmallMaster = true, + }; + var smallNpc = smallMaster.Npcs.AddNew(); + smallNpc.EditorID = "Small"; + var mediumMaster = new StarfieldMod(payload.MediumMasterKey, StarfieldRelease.Starfield) + { + IsMediumMaster = true, + }; + var mediumNpc = mediumMaster.Npcs.AddNew(); + mediumNpc.EditorID = "Medium"; + var originating = new StarfieldMod(payload.OriginatingKey, StarfieldRelease.Starfield); + var originatingNpc = originating.Npcs.AddNew(); + originatingNpc.EditorID = "Originating"; + + originating.Npcs.GetOrAddAsOverride(normalNpc); + originating.Npcs.GetOrAddAsOverride(smallNpc); + originating.Npcs.GetOrAddAsOverride(mediumNpc); + + normalMaster.WriteToBinary(Path.Combine(payload.DataFolder, normalMaster.ModKey.FileName), new BinaryWriteParameters() + { + FileSystem = payload.FileSystem + }); + smallMaster.WriteToBinary(Path.Combine(payload.DataFolder, smallMaster.ModKey.FileName), new BinaryWriteParameters() + { + FileSystem = payload.FileSystem + }); + mediumMaster.WriteToBinary(Path.Combine(payload.DataFolder, mediumMaster.ModKey.FileName), new BinaryWriteParameters() + { + FileSystem = payload.FileSystem + }); + + var modPath = await payload.WriteMod( + originating, + useDataFolder: true); + using var mod = StarfieldMod.Create(StarfieldRelease.Starfield) + .FromPath(modPath) + .WithLoadOrderFromHeaderMasters() + .WithDataFolder(payload.DataFolder) + .WithFileSystem(payload.FileSystem) + .Construct(); + + mod.Npcs.Should().HaveCount(4); + mod.Npcs.TryGetValue(normalNpc.FormKey, out var normalNpcReimport) + .Should().BeTrue(); + normalNpcReimport!.FormKey.Should().Be(normalNpc.FormKey); + mod.Npcs.TryGetValue(smallNpc.FormKey, out var smallNpcReimport) + .Should().BeTrue(); + smallNpcReimport!.FormKey.Should().Be(smallNpc.FormKey); + mod.Npcs.TryGetValue(mediumNpc.FormKey, out var mediumNpcReimport) + .Should().BeTrue(); + mediumNpcReimport!.FormKey.Should().Be(mediumNpc.FormKey); + mod.Npcs.TryGetValue(originatingNpc.FormKey, out var originatingNpcReimport) + .Should().BeTrue(); + originatingNpcReimport!.FormKey.Should().Be(originatingNpc.FormKey); + } +} \ No newline at end of file