Change imc handling in caches slightly.

This commit is contained in:
Ottermandias 2023-06-13 16:01:38 +02:00
parent 03cb88be10
commit 636f14a06d
4 changed files with 62 additions and 54 deletions

View file

@ -165,7 +165,7 @@ public class CollectionCache : IDisposable
var (paths, manipulations) = ModData.RemoveMod(mod); var (paths, manipulations) = ModData.RemoveMod(mod);
if (addMetaChanges) if (addMetaChanges)
++_collection.ChangeCounter; _collection.IncrementCounter();
foreach (var path in paths) foreach (var path in paths)
{ {
@ -240,7 +240,7 @@ public class CollectionCache : IDisposable
if (addMetaChanges) if (addMetaChanges)
{ {
++_collection.ChangeCounter; _collection.IncrementCounter();
if (mod.TotalManipulations > 0) if (mod.TotalManipulations > 0)
AddMetaFiles(false); AddMetaFiles(false);

View file

@ -174,7 +174,7 @@ public class CollectionCacheManager : IDisposable
cache.AddMetaFiles(true); cache.AddMetaFiles(true);
++collection.ChangeCounter; collection.IncrementCounter();
MetaFileManager.ApplyDefaultFiles(collection); MetaFileManager.ApplyDefaultFiles(collection);
} }
@ -280,7 +280,7 @@ public class CollectionCacheManager : IDisposable
private void IncrementCounters() private void IncrementCounters()
{ {
foreach (var collection in _storage.Where(c => c.HasCache)) foreach (var collection in _storage.Where(c => c.HasCache))
++collection.ChangeCounter; collection.IncrementCounter();
MetaFileManager.CharacterUtility.LoadingFinished -= IncrementCounters; MetaFileManager.CharacterUtility.LoadingFinished -= IncrementCounters;
} }

View file

@ -1,7 +1,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis; using System.Diagnostics.CodeAnalysis;
using OtterGui.Filesystem; using System.Linq;
using Penumbra.Meta; using Penumbra.Meta;
using Penumbra.Meta.Files; using Penumbra.Meta.Files;
using Penumbra.Meta.Manipulations; using Penumbra.Meta.Manipulations;
@ -11,113 +11,117 @@ namespace Penumbra.Collections.Cache;
public readonly struct ImcCache : IDisposable public readonly struct ImcCache : IDisposable
{ {
private readonly Dictionary< Utf8GamePath, ImcFile > _imcFiles = new(); private readonly Dictionary<Utf8GamePath, ImcFile> _imcFiles = new();
private readonly List< ImcManipulation > _imcManipulations = new(); private readonly List<(ImcManipulation, ImcFile)> _imcManipulations = new();
public ImcCache() public ImcCache()
{ } { }
public void SetFiles(ModCollection collection, bool fromFullCompute) public void SetFiles(ModCollection collection, bool fromFullCompute)
{ {
if (fromFullCompute) if (fromFullCompute)
{
foreach (var path in _imcFiles.Keys) foreach (var path in _imcFiles.Keys)
collection._cache!.ForceFileSync(path, CreateImcPath(collection, path)); collection._cache!.ForceFileSync(path, CreateImcPath(collection, path));
}
else else
{
foreach (var path in _imcFiles.Keys) foreach (var path in _imcFiles.Keys)
collection._cache!.ForceFile(path, CreateImcPath(collection, path)); collection._cache!.ForceFile(path, CreateImcPath(collection, path));
}
} }
public void Reset(ModCollection collection) public void Reset(ModCollection collection)
{ {
foreach( var (path, file) in _imcFiles ) foreach (var (path, file) in _imcFiles)
{ {
collection._cache!.RemovePath( path ); collection._cache!.RemovePath(path);
file.Reset(); file.Reset();
} }
_imcManipulations.Clear(); _imcManipulations.Clear();
} }
public bool ApplyMod( MetaFileManager manager, ModCollection collection, ImcManipulation manip ) public bool ApplyMod(MetaFileManager manager, ModCollection collection, ImcManipulation manip)
{ {
if( !manip.Validate() ) if (!manip.Validate())
{
return false; return false;
}
_imcManipulations.AddOrReplace( manip ); var idx = _imcManipulations.FindIndex(p => p.Item1.Equals(manip));
if (idx < 0)
{
idx = _imcManipulations.Count;
_imcManipulations.Add((manip, null!));
}
var path = manip.GamePath(); var path = manip.GamePath();
try try
{ {
if( !_imcFiles.TryGetValue( path, out var file ) ) if (!_imcFiles.TryGetValue(path, out var file))
{ file = new ImcFile(manager, manip);
file = new ImcFile( manager, manip );
}
if( !manip.Apply( file ) ) _imcManipulations[idx] = (manip, file);
{ if (!manip.Apply(file))
return false; return false;
}
_imcFiles[ path ] = file; _imcFiles[path] = file;
var fullPath = CreateImcPath( collection, path ); var fullPath = CreateImcPath(collection, path);
collection._cache!.ForceFile( path, fullPath ); collection._cache!.ForceFile(path, fullPath);
return true; return true;
} }
catch( ImcException e ) catch (ImcException e)
{ {
manager.ValidityChecker.ImcExceptions.Add( e ); manager.ValidityChecker.ImcExceptions.Add(e);
Penumbra.Log.Error( e.ToString() ); Penumbra.Log.Error(e.ToString());
} }
catch( Exception e ) catch (Exception e)
{ {
Penumbra.Log.Error( $"Could not apply IMC Manipulation {manip}:\n{e}" ); Penumbra.Log.Error($"Could not apply IMC Manipulation {manip}:\n{e}");
} }
return false; return false;
} }
public bool RevertMod( MetaFileManager manager, ModCollection collection, ImcManipulation m ) public bool RevertMod(MetaFileManager manager, ModCollection collection, ImcManipulation m)
{ {
if( !m.Validate() || !_imcManipulations.Remove( m ) ) if (!m.Validate())
return false;
var idx = _imcManipulations.FindIndex(p => p.Item1.Equals(m));
if (idx < 0)
return false;
var (_, file) = _imcManipulations[idx];
_imcManipulations.RemoveAt(idx);
if (_imcManipulations.All(p => !ReferenceEquals(p.Item2, file)))
{ {
return false; _imcFiles.Remove(file.Path);
} collection._cache!.ForceFile(file.Path, FullPath.Empty);
file.Dispose();
var path = m.GamePath(); return true;
if( !_imcFiles.TryGetValue( path, out var file ) ) }
{
return false; var def = ImcFile.GetDefault(manager, file.Path, m.EquipSlot, m.Variant, out _);
} var manip = m.Copy(def);
if (!manip.Apply(file))
var def = ImcFile.GetDefault( manager, path, m.EquipSlot, m.Variant, out _ );
var manip = m.Copy( def );
if( !manip.Apply( file ) )
return false; return false;
var fullPath = CreateImcPath( collection, path ); var fullPath = CreateImcPath(collection, file.Path);
collection._cache!.ForceFile( path, fullPath ); collection._cache!.ForceFile(file.Path, fullPath);
return true; return true;
} }
public void Dispose() public void Dispose()
{ {
foreach( var file in _imcFiles.Values ) foreach (var file in _imcFiles.Values)
file.Dispose(); file.Dispose();
_imcFiles.Clear(); _imcFiles.Clear();
_imcManipulations.Clear(); _imcManipulations.Clear();
} }
private static FullPath CreateImcPath( ModCollection collection, Utf8GamePath path ) private static FullPath CreateImcPath(ModCollection collection, Utf8GamePath path)
=> new($"|{collection.Name}_{collection.ChangeCounter}|{path}"); => new($"|{collection.Name}_{collection.ChangeCounter}|{path}");
public bool GetImcFile(Utf8GamePath path, [NotNullWhen(true)] out ImcFile? file) public bool GetImcFile(Utf8GamePath path, [NotNullWhen(true)] out ImcFile? file)
=> _imcFiles.TryGetValue(path, out file); => _imcFiles.TryGetValue(path, out file);
} }

View file

@ -47,7 +47,11 @@ public partial class ModCollection
/// Count the number of changes of the effective file list. /// Count the number of changes of the effective file list.
/// This is used for material and imc changes. /// This is used for material and imc changes.
/// </summary> /// </summary>
public int ChangeCounter { get; internal set; } public int ChangeCounter { get; private set; }
/// <summary> Increment the number of changes in the effective file list. </summary>
public int IncrementCounter()
=> ++ChangeCounter;
/// <summary> /// <summary>
/// If a ModSetting is null, it can be inherited from other collections. /// If a ModSetting is null, it can be inherited from other collections.