Get rid off EQDP files

This commit is contained in:
Ottermandias 2024-06-16 01:02:42 +02:00
parent 9ecc4ab46d
commit 600fd2ecd3
23 changed files with 192 additions and 246 deletions

View file

@ -1,8 +1,5 @@
using OtterGui;
using Penumbra.GameData.Enums;
using Penumbra.GameData.Structs;
using Penumbra.Interop.Services;
using Penumbra.Interop.Structs;
using Penumbra.Meta;
using Penumbra.Meta.Files;
using Penumbra.Meta.Manipulations;
@ -11,108 +8,60 @@ namespace Penumbra.Collections.Cache;
public sealed class EqdpCache(MetaFileManager manager, ModCollection collection) : MetaCacheBase<EqdpIdentifier, EqdpEntry>(manager, collection)
{
private readonly ExpandedEqdpFile?[] _eqdpFiles = new ExpandedEqdpFile[CharacterUtilityData.EqdpIndices.Length]; // TODO: female Hrothgar
private readonly Dictionary<(PrimaryId Id, GenderRace GenderRace, bool Accessory), EqdpEntry> _fullEntries = [];
public override void SetFiles()
{
for (var i = 0; i < CharacterUtilityData.EqdpIndices.Length; ++i)
Manager.SetFile(_eqdpFiles[i], CharacterUtilityData.EqdpIndices[i]);
}
{ }
public void SetFile(MetaIndex index)
{
var i = CharacterUtilityData.EqdpIndices.IndexOf(index);
if (i != -1)
Manager.SetFile(_eqdpFiles[i], index);
}
public void ResetFiles()
{
foreach (var t in CharacterUtilityData.EqdpIndices)
Manager.SetFile(null, t);
}
public bool TryGetFullEntry(PrimaryId id, GenderRace genderRace, bool accessory, out EqdpEntry entry)
=> _fullEntries.TryGetValue((id, genderRace, accessory), out entry);
protected override void IncorporateChangesInternal()
{
foreach (var (identifier, (_, entry)) in this)
Apply(GetFile(identifier)!, identifier, entry);
Penumbra.Log.Verbose($"{Collection.AnonymizedName}: Loaded {Count} delayed EQDP manipulations.");
}
public ExpandedEqdpFile? EqdpFile(GenderRace race, bool accessory)
=> _eqdpFiles[Array.IndexOf(CharacterUtilityData.EqdpIndices, CharacterUtilityData.EqdpIdx(race, accessory))]; // TODO: female Hrothgar
public MetaList.MetaReverter? TemporarilySetFile(GenderRace genderRace, bool accessory)
{
var idx = CharacterUtilityData.EqdpIdx(genderRace, accessory);
if (idx < 0)
{
Penumbra.Log.Warning($"Invalid Gender, Race or Accessory for EQDP file {genderRace}, {accessory}.");
return null;
}
var i = CharacterUtilityData.EqdpIndices.IndexOf(idx);
if (i < 0)
{
Penumbra.Log.Warning($"Invalid Gender, Race or Accessory for EQDP file {genderRace}, {accessory}.");
return null;
}
return Manager.TemporarilySetFile(_eqdpFiles[i], idx);
}
{ }
public void Reset()
{
foreach (var file in _eqdpFiles.OfType<ExpandedEqdpFile>())
{
var relevant = CharacterUtility.RelevantIndices[file.Index.Value];
file.Reset(Keys.Where(m => m.FileIndex() == relevant).Select(m => m.SetId));
}
Clear();
_fullEntries.Clear();
}
protected override void ApplyModInternal(EqdpIdentifier identifier, EqdpEntry entry)
{
if (GetFile(identifier) is { } file)
Apply(file, identifier, entry);
var tuple = (identifier.SetId, identifier.GenderRace, identifier.Slot.IsAccessory());
var mask = Eqdp.Mask(identifier.Slot);
if (!_fullEntries.TryGetValue(tuple, out var currentEntry))
currentEntry = ExpandedEqdpFile.GetDefault(Manager, identifier);
_fullEntries[tuple] = (currentEntry & ~mask) | (entry & mask);
}
protected override void RevertModInternal(EqdpIdentifier identifier)
{
if (GetFile(identifier) is { } file)
Apply(file, identifier, ExpandedEqdpFile.GetDefault(Manager, identifier));
}
var tuple = (identifier.SetId, identifier.GenderRace, identifier.Slot.IsAccessory());
var mask = Eqdp.Mask(identifier.Slot);
public static bool Apply(ExpandedEqdpFile file, EqdpIdentifier identifier, EqdpEntry entry)
{
var origEntry = file[identifier.SetId];
var mask = Eqdp.Mask(identifier.Slot);
if ((origEntry & mask) == entry)
return false;
file[identifier.SetId] = (origEntry & ~mask) | entry;
return true;
if (_fullEntries.TryGetValue(tuple, out var currentEntry))
{
var def = ExpandedEqdpFile.GetDefault(Manager, identifier);
var newEntry = (currentEntry & ~mask) | (def & mask);
if (currentEntry != newEntry)
{
_fullEntries[tuple] = newEntry;
}
else
{
var slots = tuple.Item3 ? EquipSlotExtensions.AccessorySlots : EquipSlotExtensions.EquipmentSlots;
if (slots.All(s => !ContainsKey(identifier with { Slot = s })))
_fullEntries.Remove(tuple);
else
_fullEntries[tuple] = newEntry;
}
}
}
protected override void Dispose(bool _)
{
for (var i = 0; i < _eqdpFiles.Length; ++i)
{
_eqdpFiles[i]?.Dispose();
_eqdpFiles[i] = null;
}
Clear();
}
private ExpandedEqdpFile? GetFile(EqdpIdentifier identifier)
{
if (!Manager.CharacterUtility.Ready)
return null;
var index = Array.IndexOf(CharacterUtilityData.EqdpIndices, identifier.FileIndex());
return _eqdpFiles[index] ??= new ExpandedEqdpFile(Manager, identifier.GenderRace, identifier.Slot.IsAccessory());
_fullEntries.Clear();
}
}

View file

@ -1,7 +1,5 @@
using Penumbra.GameData.Enums;
using Penumbra.GameData.Structs;
using Penumbra.Interop.Services;
using Penumbra.Interop.Structs;
using Penumbra.Meta;
using Penumbra.Meta.Manipulations;
using Penumbra.Mods.Editor;
@ -115,48 +113,18 @@ public class MetaCache(MetaFileManager manager, ModCollection collection)
~MetaCache()
=> Dispose();
/// <summary> Set a single file. </summary>
public void SetFile(MetaIndex metaIndex)
{
switch (metaIndex)
{
case MetaIndex.Eqp:
break;
case MetaIndex.Gmp:
break;
case MetaIndex.HumanCmp:
Rsp.SetFiles();
break;
case MetaIndex.FaceEst:
case MetaIndex.HairEst:
case MetaIndex.HeadEst:
case MetaIndex.BodyEst:
break;
default:
Eqdp.SetFile(metaIndex);
break;
}
}
/// <summary> Set the currently relevant IMC files for the collection cache. </summary>
public void SetImcFiles(bool fromFullCompute)
=> Imc.SetFiles(fromFullCompute);
public MetaList.MetaReverter? TemporarilySetEqdpFile(GenderRace genderRace, bool accessory)
=> Eqdp.TemporarilySetFile(genderRace, accessory);
/// <summary> Try to obtain a manipulated IMC file. </summary>
public bool GetImcFile(Utf8GamePath path, [NotNullWhen(true)] out Meta.Files.ImcFile? file)
=> Imc.GetFile(path, out file);
internal EqdpEntry GetEqdpEntry(GenderRace race, bool accessory, PrimaryId primaryId)
{
var eqdpFile = Eqdp.EqdpFile(race, accessory);
if (eqdpFile != null)
return primaryId.Id < eqdpFile.Count ? eqdpFile[primaryId] : default;
return Meta.Files.ExpandedEqdpFile.GetDefault(manager, race, accessory, primaryId);
}
=> Eqdp.TryGetFullEntry(primaryId, race, accessory, out var entry)
? entry
: Meta.Files.ExpandedEqdpFile.GetDefault(manager, race, accessory, primaryId);
internal EstEntry GetEstEntry(EstType type, GenderRace genderRace, PrimaryId primaryId)
=> Est.GetEstEntry(new EstIdentifier(primaryId, type, genderRace));

View file

@ -1,14 +1,9 @@
using OtterGui.Classes;
using Penumbra.GameData.Enums;
using Penumbra.Mods;
using Penumbra.Interop.Structs;
using Penumbra.Meta.Files;
using Penumbra.Meta.Manipulations;
using Penumbra.String.Classes;
using Penumbra.Collections.Cache;
using Penumbra.Interop.Services;
using Penumbra.Mods.Editor;
using Penumbra.GameData.Structs;
namespace Penumbra.Collections;
@ -68,35 +63,4 @@ public partial class ModCollection
internal SingleArray<ModConflicts> Conflicts(Mod mod)
=> _cache?.Conflicts(mod) ?? new SingleArray<ModConflicts>();
public void SetFiles(CharacterUtility utility)
{
if (_cache == null)
{
utility.ResetAll();
}
else
{
_cache.Meta.SetFiles();
Penumbra.Log.Debug($"Set CharacterUtility resources for collection {Identifier}.");
}
}
public void SetMetaFile(CharacterUtility utility, MetaIndex idx)
{
if (_cache == null)
utility.ResetResource(idx);
else
_cache.Meta.SetFile(idx);
}
// Used for short periods of changed files.
public MetaList.MetaReverter? TemporarilySetEqdpFile(CharacterUtility utility, GenderRace genderRace, bool accessory)
{
if (_cache != null)
return _cache?.Meta.TemporarilySetEqdpFile(genderRace, accessory);
var idx = CharacterUtilityData.EqdpIdx(genderRace, accessory);
return idx >= 0 ? utility.TemporarilyResetResource(idx) : null;
}
}