33using DynamicData ;
44using Mutagen . Bethesda ;
55using Mutagen . Bethesda . Environments . DI ;
6+ using Mutagen . Bethesda . Plugins ;
7+ using Mutagen . Bethesda . Plugins . Analysis ;
68using Mutagen . Bethesda . Plugins . Cache ;
79using Mutagen . Bethesda . Plugins . Records ;
810using 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+
2229public 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 {
0 commit comments