Skip to content

Commit 9f155b3

Browse files
committed
Filter group output mods from profile link cache
was locking output files
1 parent 2d7165d commit 9f155b3

2 files changed

Lines changed: 47 additions & 11 deletions

File tree

Synthesis.Bethesda.GUI/ViewModels/Profiles/Plugins/ProfileSimpleLinkCache.cs

Lines changed: 28 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
using DynamicData;
44
using Mutagen.Bethesda;
55
using Mutagen.Bethesda.Environments.DI;
6+
using Mutagen.Bethesda.Plugins;
7+
using Mutagen.Bethesda.Plugins.Analysis;
68
using Mutagen.Bethesda.Plugins.Cache;
79
using Mutagen.Bethesda.Plugins.Records;
810
using Noggog;
@@ -19,6 +21,11 @@ public interface IProfileSimpleLinkCacheVm
1921
ILinkCache? SimpleLinkCache { get; }
2022
}
2123

24+
public interface IProfileGroupModKeyProvider
25+
{
26+
IObservable<IReadOnlySet<ModKey>> GroupModKeys { get; }
27+
}
28+
2229
public class ProfileSimpleLinkCacheVm : ViewModel, IProfileSimpleLinkCacheVm
2330
{
2431
private readonly ObservableAsPropertyHelper<ILinkCache?> _simpleLinkCache;
@@ -29,6 +36,7 @@ public ProfileSimpleLinkCacheVm(
2936
IGameReleaseContext gameReleaseContext,
3037
IProfileLoadOrder loadOrder,
3138
IProfileOverridesVm overrides,
39+
IProfileGroupModKeyProvider groupModKeyProvider,
3240
ISchedulerProvider schedulerProvider)
3341
{
3442
_simpleLinkCache = Observable.CombineLatest(
@@ -37,27 +45,37 @@ public ProfileSimpleLinkCacheVm(
3745
.QueryWhenChanged()
3846
.Select(q => q.Where(x => x.Enabled).Select(x => x.ModKey).ToArray())
3947
.StartWithEmpty(),
40-
(dataFolder, loadOrder) => (dataFolder, loadOrder))
48+
groupModKeyProvider.GroupModKeys,
49+
(dataFolder, loadOrder, groupKeys) => (dataFolder, loadOrder, groupKeys))
4150
.Throttle(TimeSpan.FromMilliseconds(100), schedulerProvider.TaskPool)
4251
.Select(x =>
4352
{
53+
// Exclude Synthesis output mods (and their split siblings like _1, _2, etc.)
54+
// from the link cache import. Importing them would hold file handles via
55+
// binary overlays, blocking MoveFinalResults from overwriting them on
56+
// subsequent runs.
57+
var filteredLoadOrder = x.loadOrder
58+
.Where(mk => !x.groupKeys.Contains(mk)
59+
&& !x.groupKeys.Any(gk => MultiModFileAnalysis.IsSplitModSibling(mk, gk)))
60+
.ToArray();
61+
4462
return Observable.Create<(ILinkCache? Cache, IDisposable Disposable)>(obs =>
4563
{
4664
try
4765
{
48-
var loadOrder = Mutagen.Bethesda.Plugins.Order.LoadOrder.Import(
66+
var importedLoadOrder = Mutagen.Bethesda.Plugins.Order.LoadOrder.Import(
4967
x.dataFolder,
50-
x.loadOrder,
68+
filteredLoadOrder,
5169
gameReleaseContext.Release,
5270
factory: (modPath) => ModInstantiator.ImportGetter(modPath, gameReleaseContext.Release));
5371
obs.OnNext(
54-
(loadOrder.ToUntypedImmutableLinkCache(LinkCachePreferences.OnlyIdentifiers()),
55-
loadOrder));
56-
obs.OnCompleted();
57-
// ToDo
58-
// Figure out why returning this is disposing too early.
59-
// Gets disposed undesirably, which makes formlink pickers fail
60-
// return loadOrder;
72+
(importedLoadOrder.ToUntypedImmutableLinkCache(LinkCachePreferences.OnlyIdentifiers()),
73+
importedLoadOrder));
74+
// Don't call OnCompleted - it triggers immediate subscription disposal,
75+
// which would dispose the load order before DisposePrevious can manage it.
76+
// Instead, return it as the disposable so Switch() disposes it
77+
// when a new inner observable arrives or when the chain tears down.
78+
return importedLoadOrder;
6179
}
6280
catch (Exception ex)
6381
{

Synthesis.Bethesda.GUI/ViewModels/Profiles/ProfileVm.cs

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737

3838
namespace Synthesis.Bethesda.GUI.ViewModels.Profiles;
3939

40-
public class ProfileVm : ViewModel
40+
public class ProfileVm : ViewModel, IProfileGroupModKeyProvider
4141
{
4242
private readonly StartRun _startRun;
4343
private readonly ILogger _logger;
@@ -100,6 +100,8 @@ public class ProfileVm : ViewModel
100100

101101
public IObservable<ILinkCache?> SimpleLinkCache { get; }
102102

103+
public IObservable<IReadOnlySet<ModKey>> GroupModKeys { get; }
104+
103105
public ILockToCurrentVersioning LockSetting { get; }
104106
public IProfileExporter Exporter { get; }
105107

@@ -208,6 +210,22 @@ public ProfileVm(
208210
.QueryWhenChanged(q => q.ToHashSet())
209211
.Replay(1).RefCount();
210212

213+
// All group mod keys (enabled and disabled) for filtering from link cache imports.
214+
// Includes disabled groups since their output files may still exist in the data directory.
215+
GroupModKeys = Groups.Connect()
216+
.Transform(x => x.ModKey)
217+
.QueryWhenChanged(q =>
218+
{
219+
var set = new HashSet<ModKey>();
220+
foreach (var r in q)
221+
{
222+
if (r.Succeeded) set.Add(r.Value);
223+
}
224+
return (IReadOnlySet<ModKey>)set;
225+
})
226+
.StartWith((IReadOnlySet<ModKey>)new HashSet<ModKey>())
227+
.Replay(1).RefCount();
228+
211229
_globalError = Observable.CombineLatest(
212230
overrides.WhenAnyValue(x => x.DataFolderResult),
213231
loadOrder.WhenAnyValue(x => x.State),

0 commit comments

Comments
 (0)