experimental first iteration of persistent transient resources on startup

This commit is contained in:
Stanley Dimant
2022-12-13 12:01:40 +01:00
parent a807a874f0
commit 9ba6827816
7 changed files with 128 additions and 47 deletions

View File

@@ -8,7 +8,6 @@ using FFXIVClientStructs.FFXIV.Client.Game.Character;
using FFXIVClientStructs.FFXIV.Client.Graphics.Scene; using FFXIVClientStructs.FFXIV.Client.Graphics.Scene;
using FFXIVClientStructs.FFXIV.Client.System.Resource; using FFXIVClientStructs.FFXIV.Client.System.Resource;
using MareSynchronos.API; using MareSynchronos.API;
using MareSynchronos.FileCache;
using MareSynchronos.Interop; using MareSynchronos.Interop;
using MareSynchronos.Managers; using MareSynchronos.Managers;
using MareSynchronos.Models; using MareSynchronos.Models;
@@ -24,16 +23,16 @@ public class CharacterDataFactory
{ {
private readonly DalamudUtil _dalamudUtil; private readonly DalamudUtil _dalamudUtil;
private readonly IpcManager _ipcManager; private readonly IpcManager _ipcManager;
private readonly TransientResourceManager transientResourceManager; private readonly TransientResourceManager _transientResourceManager;
private readonly FileCacheManager fileDbManager; private readonly FileReplacementFactory _fileReplacementFactory;
public CharacterDataFactory(DalamudUtil dalamudUtil, IpcManager ipcManager, TransientResourceManager transientResourceManager, FileCacheManager fileDbManager) public CharacterDataFactory(DalamudUtil dalamudUtil, IpcManager ipcManager, TransientResourceManager transientResourceManager, FileReplacementFactory fileReplacementFactory)
{ {
Logger.Verbose("Creating " + nameof(CharacterDataFactory)); Logger.Verbose("Creating " + nameof(CharacterDataFactory));
this.fileDbManager = fileDbManager;
_dalamudUtil = dalamudUtil; _dalamudUtil = dalamudUtil;
_ipcManager = ipcManager; _ipcManager = ipcManager;
this.transientResourceManager = transientResourceManager; _transientResourceManager = transientResourceManager;
_fileReplacementFactory = fileReplacementFactory;
} }
private unsafe bool CheckForPointer(IntPtr playerPointer) private unsafe bool CheckForPointer(IntPtr playerPointer)
@@ -281,7 +280,7 @@ public class CharacterDataFactory
foreach (var item in previousData.FileReplacements[objectKind]) foreach (var item in previousData.FileReplacements[objectKind])
{ {
transientResourceManager.RemoveTransientResource(charaPointer, item); _transientResourceManager.RemoveTransientResource(charaPointer, item);
} }
if (objectKind == ObjectKind.Player) if (objectKind == ObjectKind.Player)
@@ -293,7 +292,7 @@ public class CharacterDataFactory
{ {
foreach (var item in previousData.FileReplacements[objectKind]) foreach (var item in previousData.FileReplacements[objectKind])
{ {
transientResourceManager.AddSemiTransientResource(objectKind, item); _transientResourceManager.AddSemiTransientResource(objectKind, item);
} }
previousData.FileReplacements[objectKind].Clear(); previousData.FileReplacements[objectKind].Clear();
@@ -315,9 +314,9 @@ public class CharacterDataFactory
private unsafe void ManageSemiTransientData(CharacterData previousData, ObjectKind objectKind, IntPtr charaPointer) private unsafe void ManageSemiTransientData(CharacterData previousData, ObjectKind objectKind, IntPtr charaPointer)
{ {
transientResourceManager.PersistTransientResources(charaPointer, objectKind, CreateFileReplacement); _transientResourceManager.PersistTransientResources(charaPointer, objectKind, CreateFileReplacement);
foreach (var item in transientResourceManager.GetSemiTransientResources(objectKind)) foreach (var item in _transientResourceManager.GetSemiTransientResources(objectKind))
{ {
if (!previousData.FileReplacements.ContainsKey(objectKind)) if (!previousData.FileReplacements.ContainsKey(objectKind))
{ {
@@ -331,7 +330,7 @@ public class CharacterDataFactory
if (string.Equals(penumResolve, gamePath, StringComparison.Ordinal)) if (string.Equals(penumResolve, gamePath, StringComparison.Ordinal))
{ {
Logger.Verbose("PenumResolve was same as GamePath, not adding " + item); Logger.Verbose("PenumResolve was same as GamePath, not adding " + item);
transientResourceManager.RemoveTransientResource(charaPointer, item); _transientResourceManager.RemoveTransientResource(charaPointer, item);
} }
else else
{ {
@@ -354,10 +353,10 @@ public class CharacterDataFactory
foreach (var item in previousData.FileReplacements[objectKind]) foreach (var item in previousData.FileReplacements[objectKind])
{ {
transientResourceManager.RemoveTransientResource(charaPointer, item); _transientResourceManager.RemoveTransientResource(charaPointer, item);
} }
foreach (var item in transientResourceManager.GetTransientResources((IntPtr)weaponObject)) foreach (var item in _transientResourceManager.GetTransientResources((IntPtr)weaponObject))
{ {
Logger.Verbose("Found transient weapon resource: " + item); Logger.Verbose("Found transient weapon resource: " + item);
AddReplacement(item, objectKind, previousData, 1, true); AddReplacement(item, objectKind, previousData, 1, true);
@@ -371,10 +370,10 @@ public class CharacterDataFactory
foreach (var item in previousData.FileReplacements[objectKind]) foreach (var item in previousData.FileReplacements[objectKind])
{ {
transientResourceManager.RemoveTransientResource((IntPtr)offHandWeapon, item); _transientResourceManager.RemoveTransientResource((IntPtr)offHandWeapon, item);
} }
foreach (var item in transientResourceManager.GetTransientResources((IntPtr)offHandWeapon)) foreach (var item in _transientResourceManager.GetTransientResources((IntPtr)offHandWeapon))
{ {
Logger.Verbose("Found transient offhand weapon resource: " + item); Logger.Verbose("Found transient offhand weapon resource: " + item);
AddReplacement(item, objectKind, previousData, 1, true); AddReplacement(item, objectKind, previousData, 1, true);
@@ -402,7 +401,7 @@ public class CharacterDataFactory
foreach (var item in previousData.FileReplacements[objectKind]) foreach (var item in previousData.FileReplacements[objectKind])
{ {
transientResourceManager.RemoveTransientResource(charaPointer, item); _transientResourceManager.RemoveTransientResource(charaPointer, item);
} }
} }
@@ -420,17 +419,14 @@ public class CharacterDataFactory
private FileReplacement CreateFileReplacement(string path, bool doNotReverseResolve = false) private FileReplacement CreateFileReplacement(string path, bool doNotReverseResolve = false)
{ {
var fileReplacement = new FileReplacement(fileDbManager); var fileReplacement = _fileReplacementFactory.Create();
if (!doNotReverseResolve) if (!doNotReverseResolve)
{ {
fileReplacement.GamePaths = fileReplacement.ReverseResolvePath(path);
_ipcManager.PenumbraReverseResolvePlayer(path).ToList();
fileReplacement.SetResolvedPath(path);
} }
else else
{ {
fileReplacement.GamePaths = new List<string> { path }; fileReplacement.ResolvePath(path);
fileReplacement.SetResolvedPath(_ipcManager.PenumbraResolvePath(path)!);
} }
return fileReplacement; return fileReplacement;

View File

@@ -0,0 +1,22 @@
using MareSynchronos.FileCache;
using MareSynchronos.Managers;
using MareSynchronos.Models;
namespace MareSynchronos.Factories;
public class FileReplacementFactory
{
private readonly FileCacheManager fileCacheManager;
private readonly IpcManager ipcManager;
public FileReplacementFactory(FileCacheManager fileCacheManager, IpcManager ipcManager)
{
this.fileCacheManager = fileCacheManager;
this.ipcManager = ipcManager;
}
public FileReplacement Create()
{
return new FileReplacement(fileCacheManager, ipcManager);
}
}

View File

@@ -10,14 +10,6 @@ using System.Text;
namespace MareSynchronos.FileCache; namespace MareSynchronos.FileCache;
public enum FileState
{
Valid,
RequireUpdate,
RequireDeletion
}
public class FileCacheManager : IDisposable public class FileCacheManager : IDisposable
{ {
private const string PenumbraPrefix = "{penumbra}"; private const string PenumbraPrefix = "{penumbra}";
@@ -227,6 +219,11 @@ public class FileCacheManager : IDisposable
return fileCache; return fileCache;
} }
public string ResolveFileReplacement(string gamePath)
{
return _ipcManager.PenumbraResolvePath(gamePath);
}
public void Dispose() public void Dispose()
{ {
WriteOutFullCsv(); WriteOutFullCsv();

View File

@@ -0,0 +1,11 @@
using MareSynchronos.Models;
namespace MareSynchronos.FileCache;
public enum FileState
{
Valid,
RequireUpdate,
RequireDeletion
}

View File

@@ -1,12 +1,12 @@
using MareSynchronos.API; using MareSynchronos.API;
using MareSynchronos.Factories;
using MareSynchronos.Models; using MareSynchronos.Models;
using MareSynchronos.Utils; using MareSynchronos.Utils;
using System; using System;
using System.Collections.Concurrent; using System.Collections.Concurrent;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO;
using System.Linq; using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace MareSynchronos.Managers; namespace MareSynchronos.Managers;
@@ -16,20 +16,39 @@ public class TransientResourceManager : IDisposable
{ {
private readonly IpcManager manager; private readonly IpcManager manager;
private readonly DalamudUtil dalamudUtil; private readonly DalamudUtil dalamudUtil;
private readonly FileReplacementFactory fileReplacementFactory;
private readonly string configurationDirectory;
public event TransientResourceLoadedEvent? TransientResourceLoaded; public event TransientResourceLoadedEvent? TransientResourceLoaded;
public IntPtr[] PlayerRelatedPointers = Array.Empty<IntPtr>(); public IntPtr[] PlayerRelatedPointers = Array.Empty<IntPtr>();
private readonly string[] FileTypesToHandle = new[] { "tmb", "pap", "avfx", "atex", "sklb", "eid", "phyb", "scd", "skp" }; private readonly string[] FileTypesToHandle = new[] { "tmb", "pap", "avfx", "atex", "sklb", "eid", "phyb", "scd", "skp" };
private string PersistentDataCache => Path.Combine(configurationDirectory, "PersistentTransientData.lst");
private ConcurrentDictionary<IntPtr, HashSet<string>> TransientResources { get; } = new(); private ConcurrentDictionary<IntPtr, HashSet<string>> TransientResources { get; } = new();
private ConcurrentDictionary<ObjectKind, HashSet<FileReplacement>> SemiTransientResources { get; } = new(); private ConcurrentDictionary<ObjectKind, HashSet<FileReplacement>> SemiTransientResources { get; } = new();
public TransientResourceManager(IpcManager manager, DalamudUtil dalamudUtil) public TransientResourceManager(IpcManager manager, DalamudUtil dalamudUtil, FileReplacementFactory fileReplacementFactory, string configurationDirectory)
{ {
manager.PenumbraResourceLoadEvent += Manager_PenumbraResourceLoadEvent; manager.PenumbraResourceLoadEvent += Manager_PenumbraResourceLoadEvent;
this.manager = manager; this.manager = manager;
this.dalamudUtil = dalamudUtil; this.dalamudUtil = dalamudUtil;
this.fileReplacementFactory = fileReplacementFactory;
this.configurationDirectory = configurationDirectory;
dalamudUtil.FrameworkUpdate += DalamudUtil_FrameworkUpdate; dalamudUtil.FrameworkUpdate += DalamudUtil_FrameworkUpdate;
dalamudUtil.ClassJobChanged += DalamudUtil_ClassJobChanged; dalamudUtil.ClassJobChanged += DalamudUtil_ClassJobChanged;
if (File.Exists(PersistentDataCache))
{
var persistentEntities = File.ReadAllLines(PersistentDataCache);
SemiTransientResources.TryAdd(ObjectKind.Player, new HashSet<FileReplacement>());
foreach (var line in persistentEntities)
{
var fileReplacement = fileReplacementFactory.Create();
fileReplacement.ResolvePath(line);
if (fileReplacement.HasFileReplacement)
{
SemiTransientResources[ObjectKind.Player].Add(fileReplacement);
}
}
}
} }
private void DalamudUtil_ClassJobChanged() private void DalamudUtil_ClassJobChanged()
@@ -180,6 +199,10 @@ public class TransientResourceManager : IDisposable
} }
} }
if (objectKind == ObjectKind.Player && SemiTransientResources.TryGetValue(ObjectKind.Player, out var fileReplacements))
{
File.WriteAllLines(PersistentDataCache, fileReplacements.SelectMany(p => p.GamePaths).Distinct(StringComparer.OrdinalIgnoreCase));
}
TransientResources[gameObject].Clear(); TransientResources[gameObject].Clear();
} }
@@ -189,6 +212,11 @@ public class TransientResourceManager : IDisposable
manager.PenumbraResourceLoadEvent -= Manager_PenumbraResourceLoadEvent; manager.PenumbraResourceLoadEvent -= Manager_PenumbraResourceLoadEvent;
dalamudUtil.ClassJobChanged -= DalamudUtil_ClassJobChanged; dalamudUtil.ClassJobChanged -= DalamudUtil_ClassJobChanged;
TransientResources.Clear(); TransientResources.Clear();
SemiTransientResources.Clear();
if (SemiTransientResources.ContainsKey(ObjectKind.Player))
{
File.WriteAllLines(PersistentDataCache, SemiTransientResources[ObjectKind.Player].SelectMany(p => p.GamePaths).Distinct(StringComparer.OrdinalIgnoreCase));
}
} }
internal void AddSemiTransientResource(ObjectKind objectKind, FileReplacement item) internal void AddSemiTransientResource(ObjectKind objectKind, FileReplacement item)

View File

@@ -5,16 +5,20 @@ using System.Threading.Tasks;
using MareSynchronos.API; using MareSynchronos.API;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using MareSynchronos.FileCache; using MareSynchronos.FileCache;
using MareSynchronos.Managers;
using System;
namespace MareSynchronos.Models; namespace MareSynchronos.Models;
public class FileReplacement public class FileReplacement
{ {
private readonly FileCacheManager fileDbManager; private readonly FileCacheManager fileDbManager;
private readonly IpcManager ipcManager;
public FileReplacement(FileCacheManager fileDbManager) public FileReplacement(FileCacheManager fileDbManager, IpcManager ipcManager)
{ {
this.fileDbManager = fileDbManager; this.fileDbManager = fileDbManager;
this.ipcManager = ipcManager;
} }
public bool Computed => IsFileSwap || !HasFileReplacement || !string.IsNullOrEmpty(Hash); public bool Computed => IsFileSwap || !HasFileReplacement || !string.IsNullOrEmpty(Hash);
@@ -29,7 +33,7 @@ public class FileReplacement
public string ResolvedPath { get; set; } = string.Empty; public string ResolvedPath { get; set; } = string.Empty;
public void SetResolvedPath(string path) private void SetResolvedPath(string path)
{ {
ResolvedPath = path.ToLowerInvariant().Replace('\\', '/'); ResolvedPath = path.ToLowerInvariant().Replace('\\', '/');
if (!HasFileReplacement || IsFileSwap) return; if (!HasFileReplacement || IsFileSwap) return;
@@ -43,10 +47,18 @@ public class FileReplacement
public bool Verify() public bool Verify()
{ {
var cache = fileDbManager.GetFileCacheByPath(ResolvedPath); if (!IsFileSwap)
if (cache == null) return false; {
Hash = cache.Hash; var cache = fileDbManager.GetFileCacheByPath(ResolvedPath);
return true; if (cache == null) return false;
Hash = cache.Hash;
return true;
}
var resolvedPath = fileDbManager.ResolveFileReplacement(GamePaths.First());
ResolvedPath = resolvedPath.ToLowerInvariant();
return IsFileSwap;
} }
public FileReplacementDto ToFileReplacementDto() public FileReplacementDto ToFileReplacementDto()
@@ -58,10 +70,23 @@ public class FileReplacement
FileSwapPath = IsFileSwap ? ResolvedPath : string.Empty FileSwapPath = IsFileSwap ? ResolvedPath : string.Empty
}; };
} }
public override string ToString() public override string ToString()
{ {
StringBuilder builder = new(); StringBuilder builder = new();
builder.AppendLine($"Modded: {HasFileReplacement} - {string.Join(",", GamePaths)} => {ResolvedPath}"); builder.AppendLine($"Modded: {HasFileReplacement} - {string.Join(",", GamePaths)} => {ResolvedPath}");
return builder.ToString(); return builder.ToString();
} }
internal void ReverseResolvePath(string path)
{
GamePaths = ipcManager.PenumbraReverseResolvePlayer(path).ToList();
SetResolvedPath(path);
}
internal void ResolvePath(string path)
{
GamePaths = new List<string> { path };
SetResolvedPath(ipcManager.PenumbraResolvePath(path));
}
} }

View File

@@ -36,10 +36,11 @@ public sealed class Plugin : IDalamudPlugin
private OnlinePlayerManager? _characterCacheManager; private OnlinePlayerManager? _characterCacheManager;
private readonly DownloadUi _downloadUi; private readonly DownloadUi _downloadUi;
private readonly FileDialogManager _fileDialogManager; private readonly FileDialogManager _fileDialogManager;
private readonly FileCacheManager _fileDbManager; private readonly FileCacheManager _fileCacheManager;
private readonly CompactUi _compactUi; private readonly CompactUi _compactUi;
private readonly UiShared _uiSharedComponent; private readonly UiShared _uiSharedComponent;
private readonly Dalamud.Localization _localization; private readonly Dalamud.Localization _localization;
private readonly FileReplacementFactory _fileReplacementFactory;
public Plugin(DalamudPluginInterface pluginInterface, CommandManager commandManager, public Plugin(DalamudPluginInterface pluginInterface, CommandManager commandManager,
@@ -62,9 +63,10 @@ public sealed class Plugin : IDalamudPlugin
_ipcManager = new IpcManager(_pluginInterface, _dalamudUtil); _ipcManager = new IpcManager(_pluginInterface, _dalamudUtil);
_fileDialogManager = new FileDialogManager(); _fileDialogManager = new FileDialogManager();
_fileDbManager = new FileCacheManager(_ipcManager, _configuration, _pluginInterface.ConfigDirectory.FullName); _fileCacheManager = new FileCacheManager(_ipcManager, _configuration, _pluginInterface.ConfigDirectory.FullName);
_apiController = new ApiController(_configuration, _dalamudUtil, _fileDbManager); _apiController = new ApiController(_configuration, _dalamudUtil, _fileCacheManager);
_periodicFileScanner = new PeriodicFileScanner(_ipcManager, _configuration, _fileDbManager, _apiController, _dalamudUtil); _periodicFileScanner = new PeriodicFileScanner(_ipcManager, _configuration, _fileCacheManager, _apiController, _dalamudUtil);
_fileReplacementFactory = new FileReplacementFactory(_fileCacheManager, _ipcManager);
_uiSharedComponent = _uiSharedComponent =
new UiShared(_ipcManager, _apiController, _periodicFileScanner, _fileDialogManager, _configuration, _dalamudUtil, _pluginInterface, _localization); new UiShared(_ipcManager, _apiController, _periodicFileScanner, _fileDialogManager, _configuration, _dalamudUtil, _pluginInterface, _localization);
@@ -118,7 +120,7 @@ public sealed class Plugin : IDalamudPlugin
_compactUi?.Dispose(); _compactUi?.Dispose();
_periodicFileScanner?.Dispose(); _periodicFileScanner?.Dispose();
_fileDbManager?.Dispose(); _fileCacheManager?.Dispose();
_playerManager?.Dispose(); _playerManager?.Dispose();
_characterCacheManager?.Dispose(); _characterCacheManager?.Dispose();
_ipcManager?.Dispose(); _ipcManager?.Dispose();
@@ -180,13 +182,13 @@ public sealed class Plugin : IDalamudPlugin
try try
{ {
_transientResourceManager = new TransientResourceManager(_ipcManager, _dalamudUtil); _transientResourceManager = new TransientResourceManager(_ipcManager, _dalamudUtil, _fileReplacementFactory, _pluginInterface.ConfigDirectory.FullName);
var characterCacheFactory = var characterCacheFactory =
new CharacterDataFactory(_dalamudUtil, _ipcManager, _transientResourceManager, _fileDbManager); new CharacterDataFactory(_dalamudUtil, _ipcManager, _transientResourceManager, _fileReplacementFactory);
_playerManager = new PlayerManager(_apiController, _ipcManager, _playerManager = new PlayerManager(_apiController, _ipcManager,
characterCacheFactory, _dalamudUtil, _transientResourceManager, _periodicFileScanner); characterCacheFactory, _dalamudUtil, _transientResourceManager, _periodicFileScanner);
_characterCacheManager = new OnlinePlayerManager(_apiController, _characterCacheManager = new OnlinePlayerManager(_apiController,
_dalamudUtil, _ipcManager, _playerManager, _fileDbManager); _dalamudUtil, _ipcManager, _playerManager, _fileCacheManager);
} }
catch (Exception ex) catch (Exception ex)
{ {