Try to make the cache a bit more stable and resetting the cached list more sensible.

This commit is contained in:
Ottermandias 2021-08-13 16:32:26 +02:00
parent 1bf144e1f5
commit afcb481dd2
11 changed files with 132 additions and 72 deletions

View file

@ -5,11 +5,19 @@ using Penumbra.Util;
namespace Penumbra.Mods
{
public delegate void OnModFileSystemChange();
public static partial class ModFileSystem
{
// The root folder that should be used as the base for all structured mods.
public static ModFolder Root = ModFolder.CreateRoot();
// Gets invoked every time the file system changes.
public static event OnModFileSystemChange? ModFileSystemChanged;
internal static void InvokeChange()
=> ModFileSystemChanged?.Invoke();
// Find a specific mod folder by its path from Root.
// Returns true if the folder was found, and false if not.
// The out parameter will contain the furthest existing folder.
@ -69,7 +77,6 @@ namespace Penumbra.Mods
// Move a mod to the filesystem location specified by sortOrder and rename its SortOrderName.
// Creates all necessary Subfolders.
// Does NOT save.
public static void Move( this ModData mod, string sortOrder )
{
var split = sortOrder.Split( new[] { '/' }, StringSplitOptions.RemoveEmptyEntries );
@ -79,8 +86,10 @@ namespace Penumbra.Mods
folder = folder.FindOrCreateSubFolder( split[ i ] ).Item1;
}
MoveNoSave( mod, folder );
RenameNoSave( mod, split.Last() );
if( MoveNoSave( mod, folder ) || RenameNoSave( mod, split.Last() ) )
{
SaveMod( mod );
}
}
// Moves folder to target.
@ -126,6 +135,7 @@ namespace Penumbra.Mods
}
config.Save();
InvokeChange();
}
// Sets and saves the sort order of a single mod, removing the entry if it is unnecessary.
@ -143,6 +153,7 @@ namespace Penumbra.Mods
}
config.Save();
InvokeChange();
}
private static bool RenameNoSave( this ModFolder target, string newName )

View file

@ -148,8 +148,12 @@ namespace Penumbra.Mods
PluginLog.Error( $"Could not delete the mod {modFolder.Name}:\n{e}" );
}
Mods.Remove( modFolder.Name );
Collections.RemoveModFromCaches( modFolder );
if( Mods.TryGetValue( modFolder.Name, out var mod ) )
{
mod.SortOrder.ParentFolder.RemoveMod( mod );
Mods.Remove( modFolder.Name );
Collections.RemoveModFromCaches( modFolder );
}
}
}

View file

@ -80,9 +80,6 @@ namespace Penumbra
SettingsInterface = new SettingsInterface( this );
PluginInterface.UiBuilder.DisableGposeUiHide = true;
PluginInterface.UiBuilder.OnBuildUi += SettingsInterface.Draw;
if( Configuration.EnableHttpApi )
{
CreateWebServer();
@ -147,9 +144,9 @@ namespace Penumbra
public void Dispose()
{
SettingsInterface.Dispose();
ActorRefresher.Dispose();
PlayerWatcher.Dispose();
PluginInterface.UiBuilder.OnBuildUi -= SettingsInterface.Draw;
PluginInterface.CommandManager.RemoveHandler( CommandName );
PluginInterface.Dispose();

View file

@ -141,22 +141,19 @@ namespace Penumbra.UI
_manager.Collections.SetCurrentCollection( _collections[ idx + 1 ] );
_currentCollectionIndex = idx;
_selector.ReloadSelection();
_selector.Cache.ResetModList();
_selector.Cache.TriggerListReset();
if( _selector.Mod != null )
{
_selector.SelectModByDir( _selector.Mod.Data.BasePath.Name );
}
}
public void SetCurrentCollection( ModCollection collection )
{
var idx = Array.IndexOf( _collections, collection ) - 1;
if( idx >= 0 && idx != _currentCollectionIndex )
if( idx >= 0 )
{
_manager.Collections.SetCurrentCollection( _collections[ idx + 1 ] );
_currentCollectionIndex = idx;
_selector.Cache.ResetModList();
if( _selector.Mod != null )
{
_selector.SelectModByDir( _selector.Mod.Data.BasePath.Name );
}
SetCurrentCollection( idx );
}
}

View file

@ -1,3 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Dalamud.Plugin;
@ -5,7 +6,7 @@ using Penumbra.Mods;
namespace Penumbra.UI
{
public class ModListCache
public class ModListCache : IDisposable
{
public const uint DisabledModColor = 0xFF666666u;
public const uint ConflictingModColor = 0xFFAAAAFFu;
@ -17,10 +18,13 @@ namespace Penumbra.UI
private readonly List< (bool visible, uint color) > _visibleMods = new();
private readonly Dictionary< ModFolder, (bool visible, bool enabled) > _visibleFolders = new();
private string _modFilter = "";
private string _modFilterChanges = "";
private string _modFilterAuthor = "";
private ModFilter _stateFilter = ModFilterExtensions.UnfilteredStateMods;
private string _modFilter = "";
private string _modFilterChanges = "";
private string _modFilterAuthor = "";
private ModFilter _stateFilter = ModFilterExtensions.UnfilteredStateMods;
private bool _listResetNecessary = false;
private bool _filterResetNecessary = false;
public ModFilter StateFilter
{
@ -31,7 +35,7 @@ namespace Penumbra.UI
_stateFilter = value;
if( diff )
{
ResetFilters();
TriggerFilterReset();
}
}
}
@ -40,11 +44,41 @@ namespace Penumbra.UI
{
_manager = manager;
ResetModList();
ModFileSystem.ModFileSystemChanged += TriggerListReset;
}
public void Dispose()
{
ModFileSystem.ModFileSystemChanged -= TriggerListReset;
}
public int Count
=> _modsInOrder.Count;
public bool Update()
{
if( _listResetNecessary )
{
ResetModList();
return true;
}
if( _filterResetNecessary )
{
ResetFilters();
return true;
}
return false;
}
public void TriggerListReset()
=> _listResetNecessary = true;
public void TriggerFilterReset()
=> _filterResetNecessary = true;
public void RemoveMod( Mod.Mod mod )
{
var idx = _modsInOrder.IndexOf( mod );
@ -58,7 +92,7 @@ namespace Penumbra.UI
private void SetFolderAndParentsVisible( ModFolder? folder )
{
while( folder != null && (!_visibleFolders.TryGetValue(folder, out var state) || !state.visible) )
while( folder != null && ( !_visibleFolders.TryGetValue( folder, out var state ) || !state.visible ) )
{
_visibleFolders[ folder ] = ( true, true );
folder = folder.Parent;
@ -103,7 +137,7 @@ namespace Penumbra.UI
ResetFilters();
}
public void ResetModList()
private void ResetModList()
{
_modsInOrder.Clear();
_visibleMods.Clear();
@ -119,9 +153,12 @@ namespace Penumbra.UI
_visibleMods.Add( CheckFilters( mod ) );
}
}
_listResetNecessary = false;
_filterResetNecessary = false;
}
public void ResetFilters()
private void ResetFilters()
{
_visibleMods.Clear();
_visibleFolders.Clear();
@ -130,6 +167,7 @@ namespace Penumbra.UI
{
_visibleMods.Add( CheckFilters( mod ) );
}
_filterResetNecessary = false;
}
public (Mod.Mod? mod, int idx) GetModByName( string name )
@ -263,7 +301,7 @@ namespace Penumbra.UI
return ret;
}
ret.Item1 = true;
ret.Item1 = true;
SetFolderAndParentsVisible( mod.Data.SortOrder.ParentFolder );
return ret;
}

View file

@ -442,7 +442,7 @@ namespace Penumbra.UI
// If the mod is enabled in the current collection, its conflicts may have changed.
if( Mod!.Settings.Enabled )
{
_selector.Cache.ResetFilters();
_selector.Cache.TriggerFilterReset();
}
}
}

View file

@ -113,7 +113,7 @@ namespace Penumbra.UI
{
if( _modManager.ChangeModGroup( group.GroupName, groupName, Mod.Data ) && Mod.Data.Meta.RefreshHasGroupsWithConfig() )
{
_selector.Cache.ResetFilters();
_selector.Cache.TriggerFilterReset();
}
}
}
@ -132,7 +132,7 @@ namespace Penumbra.UI
_selector.SaveCurrentMod();
if( Mod!.Data.Meta.RefreshHasGroupsWithConfig() )
{
_selector.Cache.ResetFilters();
_selector.Cache.TriggerFilterReset();
}
}
}
@ -173,7 +173,7 @@ namespace Penumbra.UI
if( Mod!.Data.Meta.RefreshHasGroupsWithConfig() )
{
_selector.Cache.ResetFilters();
_selector.Cache.TriggerFilterReset();
}
}
}
@ -190,7 +190,7 @@ namespace Penumbra.UI
{
if( _modManager.ChangeModGroup( group.GroupName, groupName, Mod.Data ) && Mod.Data.Meta.RefreshHasGroupsWithConfig() )
{
_selector.Cache.ResetFilters();
_selector.Cache.TriggerFilterReset();
}
}
}
@ -238,7 +238,7 @@ namespace Penumbra.UI
if( Mod.Data.Meta.RefreshHasGroupsWithConfig() )
{
_selector.Cache.ResetFilters();
_selector.Cache.TriggerFilterReset();
}
}
@ -347,7 +347,6 @@ namespace Penumbra.UI
_selector.SaveCurrentMod();
_selector.ReloadCurrentMod();
_selector.Cache.ResetModList();
}
}
@ -369,8 +368,7 @@ namespace Penumbra.UI
{
Meta.FileSwaps[ key ] = newValue;
_selector.SaveCurrentMod();
_selector.ReloadCurrentMod();
_selector.Cache.ResetModList();
_selector.Cache.TriggerListReset();
}
}
}

View file

@ -75,9 +75,9 @@ namespace Penumbra.UI
if( Custom.ImGuiCustom.InputOrText( _editMode, LabelEditName, ref name, 64 ) && _modManager.RenameMod( name, Mod!.Data ) )
{
_selector.SelectModByDir( Mod.Data.BasePath.Name );
if( !_modManager.Config.ModSortOrder.ContainsKey( Mod!.Data.BasePath.Name ) && Mod.Data.Rename( name ) )
if( !_modManager.Config.ModSortOrder.ContainsKey( Mod!.Data.BasePath.Name ) )
{
_selector.Cache.ResetModList();
Mod.Data.Rename( name );
}
}
}
@ -122,7 +122,7 @@ namespace Penumbra.UI
{
Meta.Author = author;
_selector.SaveCurrentMod();
_selector.Cache.ResetFilters();
_selector.Cache.TriggerFilterReset();
}
ImGui.EndGroup();
@ -205,7 +205,7 @@ namespace Penumbra.UI
{
Mod.Settings.Priority = priority;
_base.SaveCurrentCollection( Mod.Data.Resources.MetaManipulations.Count > 0 );
_selector.Cache.ResetFilters();
_selector.Cache.TriggerFilterReset();
}
if( ImGui.IsItemHovered() )
@ -222,7 +222,7 @@ namespace Penumbra.UI
{
Mod.Settings.Enabled = enabled;
_base.SaveCurrentCollection( Mod.Data.Resources.MetaManipulations.Count > 0 );
_selector.Cache.ResetFilters();
_selector.Cache.TriggerFilterReset();
}
}
@ -233,7 +233,6 @@ namespace Penumbra.UI
if( ImGui.InputText( "Sort Order", ref currentSortOrder, 256, ImGuiInputTextFlags.EnterReturnsTrue ) )
{
manager.ChangeSortOrder( mod, currentSortOrder );
selector.Cache.ResetModList();
selector.SelectModByDir( mod.BasePath.Name );
return true;
}

View file

@ -99,6 +99,7 @@ namespace Penumbra.UI
var mod = Mod;
Cache.RemoveMod( mod );
_modManager.DeleteMod( mod.Data.BasePath );
ModFileSystem.InvokeChange();
ClearSelection();
}
@ -166,7 +167,7 @@ namespace Penumbra.UI
var metaFile = new FileInfo( Path.Combine( newDir.FullName, "meta.json" ) );
modMeta.SaveToFile( metaFile );
_modManager.AddMod( newDir );
Cache.ResetModList();
ModFileSystem.InvokeChange();
SelectModByDir( newDir.Name );
}
catch( Exception e )
@ -367,10 +368,7 @@ namespace Penumbra.UI
var mod = Cache.GetMod( modIndex ).Item1;
if( mod != null )
{
if( mod.Data.Move( folder ) )
{
Cache.ResetModList();
}
mod.Data.Move( folder );
}
}
else if( IsDropping( DraggedFolderLabel ) )
@ -381,10 +379,7 @@ namespace Penumbra.UI
&& !ReferenceEquals( droppedFolder, folder )
&& !folder.FullName.StartsWith( folderName, StringComparison.InvariantCultureIgnoreCase ) )
{
if( droppedFolder.Move( folder ) )
{
Cache.ResetModList();
}
droppedFolder.Move( folder );
}
}
@ -484,7 +479,6 @@ namespace Penumbra.UI
if( _index >= 0 && _modManager.UpdateMod( Mod.Data, reloadMeta, recomputeMeta ) )
{
Cache.ResetModList();
SelectModByDir( Mod.Data.BasePath.Name );
_base._menu.InstalledTab.ModPanel.Details.ResetState();
}
@ -541,7 +535,7 @@ namespace Penumbra.UI
return;
}
Cache.ResetFilters();
Cache.TriggerFilterReset();
var collection = _modManager.Collections.CurrentCollection;
if( collection.Cache != null )
{
@ -561,21 +555,15 @@ namespace Penumbra.UI
return;
}
bool changes;
if( _newFolderName.Any() )
{
changes = folder.Rename( _newFolderName );
_newFolderName = string.Empty;
folder.Rename( _newFolderName );
}
else
{
changes = folder.Merge( folder.Parent! );
}
if( changes )
{
Cache.ResetModList();
folder.Merge( folder.Parent! );
}
_newFolderName = string.Empty;
}
private void DrawFolderContextMenu( ModFolder folder, int currentIdx, string treeName )
@ -629,21 +617,29 @@ namespace Penumbra.UI
{
_base._menu.CollectionsTab.SetCurrentCollection( collection );
}
if( ImGui.IsItemHovered() )
ImGui.SetTooltip( $"Switches to the currently set {tooltipLabel} collection, if it is not set to None and it is not the current collection already." );
{
ImGui.SetTooltip(
$"Switches to the currently set {tooltipLabel} collection, if it is not set to None and it is not the current collection already." );
}
}
private void DrawHeaderBar()
{
const float size = 200;
const float size = 200;
DrawModsSelectorFilter();
var textSize = ImGui.CalcTextSize( TabCollections.LabelCurrentCollection ).X + ImGui.GetStyle().ItemInnerSpacing.X;
var comboSize = size * ImGui.GetIO().FontGlobalScale;
var offset = comboSize + textSize;
var buttonSize = (ImGui.GetWindowContentRegionWidth() - offset - SelectorPanelWidth * _selectorScalingFactor - 4 * ImGui.GetStyle().ItemSpacing.X) / 2;
var buttonSize = ( ImGui.GetWindowContentRegionWidth()
- offset
- SelectorPanelWidth * _selectorScalingFactor
- 4 * ImGui.GetStyle().ItemSpacing.X )
/ 2;
ImGui.SameLine();
DrawCollectionButton("Default", "default", buttonSize, _modManager.Collections.DefaultCollection );
DrawCollectionButton( "Default", "default", buttonSize, _modManager.Collections.DefaultCollection );
ImGui.SameLine();
DrawCollectionButton( "Forced", "forced", buttonSize, _modManager.Collections.ForcedCollection );
@ -767,6 +763,11 @@ namespace Penumbra.UI
true, ImGuiWindowFlags.HorizontalScrollbar );
ImGui.PushStyleVar( ImGuiStyleVar.IndentSpacing, 12.5f );
if( Cache.Update() && Mod != null )
{
SelectModByDir( Mod.Data.BasePath.Name );
}
var modIndex = 0;
DrawFolderContent( _modManager.StructuredMods, ref modIndex );
ImGui.PopStyleVar();

View file

@ -107,7 +107,7 @@ namespace Penumbra.UI
if( ImGui.Checkbox( LabelSortFoldersFirst, ref foldersFirst ) )
{
_config.SortFoldersFirst = foldersFirst;
_base._menu.InstalledTab.Selector.Cache.ResetModList();
_base._menu.InstalledTab.Selector.Cache.TriggerListReset();
_configChanged = true;
}
}

View file

@ -1,10 +1,11 @@
using System;
using System.Numerics;
using Penumbra.Mods;
using Penumbra.Util;
namespace Penumbra.UI
{
public partial class SettingsInterface
public partial class SettingsInterface : IDisposable
{
private const float DefaultVerticalSpace = 20f;
@ -25,8 +26,22 @@ namespace Penumbra.UI
_menuBar = new MenuBar( this );
_menu = new SettingsMenu( this );
_modManager = Service< ModManager >.Get();
_plugin.PluginInterface.UiBuilder.DisableGposeUiHide = true;
_plugin.PluginInterface.UiBuilder.OnBuildUi += Draw;
_plugin.PluginInterface.UiBuilder.OnOpenConfigUi += OpenConfig;
}
public void Dispose()
{
_menu.InstalledTab.Selector.Cache.Dispose();
_plugin.PluginInterface.UiBuilder.OnBuildUi -= Draw;
_plugin.PluginInterface.UiBuilder.OnOpenConfigUi -= OpenConfig;
}
private void OpenConfig( object _1, EventArgs _2 )
=> _menu.Visible = true;
public void FlipVisibility()
=> _menu.Visible = !_menu.Visible;
@ -44,7 +59,7 @@ namespace Penumbra.UI
{
_menu.InstalledTab.Selector.ClearSelection();
_modManager.DiscoverMods( _plugin.Configuration.ModDirectory );
_menu.InstalledTab.Selector.Cache.ResetModList();
_menu.InstalledTab.Selector.Cache.TriggerListReset();
}
private void SaveCurrentCollection( bool recalculateMeta )
@ -61,7 +76,7 @@ namespace Penumbra.UI
{
current.CalculateEffectiveFileList( _modManager.BasePath, recalculateMeta,
current == _modManager.Collections.ActiveCollection );
_menu.InstalledTab.Selector.Cache.ResetFilters();
_menu.InstalledTab.Selector.Cache.TriggerFilterReset();
}
}
}