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.System.Resource;
using MareSynchronos.API;
using MareSynchronos.FileCache;
using MareSynchronos.Interop;
using MareSynchronos.Managers;
using MareSynchronos.Models;
@@ -24,16 +23,16 @@ public class CharacterDataFactory
{
private readonly DalamudUtil _dalamudUtil;
private readonly IpcManager _ipcManager;
private readonly TransientResourceManager transientResourceManager;
private readonly FileCacheManager fileDbManager;
private readonly TransientResourceManager _transientResourceManager;
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));
this.fileDbManager = fileDbManager;
_dalamudUtil = dalamudUtil;
_ipcManager = ipcManager;
this.transientResourceManager = transientResourceManager;
_transientResourceManager = transientResourceManager;
_fileReplacementFactory = fileReplacementFactory;
}
private unsafe bool CheckForPointer(IntPtr playerPointer)
@@ -281,7 +280,7 @@ public class CharacterDataFactory
foreach (var item in previousData.FileReplacements[objectKind])
{
transientResourceManager.RemoveTransientResource(charaPointer, item);
_transientResourceManager.RemoveTransientResource(charaPointer, item);
}
if (objectKind == ObjectKind.Player)
@@ -293,7 +292,7 @@ public class CharacterDataFactory
{
foreach (var item in previousData.FileReplacements[objectKind])
{
transientResourceManager.AddSemiTransientResource(objectKind, item);
_transientResourceManager.AddSemiTransientResource(objectKind, item);
}
previousData.FileReplacements[objectKind].Clear();
@@ -315,9 +314,9 @@ public class CharacterDataFactory
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))
{
@@ -331,7 +330,7 @@ public class CharacterDataFactory
if (string.Equals(penumResolve, gamePath, StringComparison.Ordinal))
{
Logger.Verbose("PenumResolve was same as GamePath, not adding " + item);
transientResourceManager.RemoveTransientResource(charaPointer, item);
_transientResourceManager.RemoveTransientResource(charaPointer, item);
}
else
{
@@ -354,10 +353,10 @@ public class CharacterDataFactory
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);
AddReplacement(item, objectKind, previousData, 1, true);
@@ -371,10 +370,10 @@ public class CharacterDataFactory
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);
AddReplacement(item, objectKind, previousData, 1, true);
@@ -402,7 +401,7 @@ public class CharacterDataFactory
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)
{
var fileReplacement = new FileReplacement(fileDbManager);
var fileReplacement = _fileReplacementFactory.Create();
if (!doNotReverseResolve)
{
fileReplacement.GamePaths =
_ipcManager.PenumbraReverseResolvePlayer(path).ToList();
fileReplacement.SetResolvedPath(path);
fileReplacement.ReverseResolvePath(path);
}
else
{
fileReplacement.GamePaths = new List<string> { path };
fileReplacement.SetResolvedPath(_ipcManager.PenumbraResolvePath(path)!);
fileReplacement.ResolvePath(path);
}
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;
public enum FileState
{
Valid,
RequireUpdate,
RequireDeletion
}
public class FileCacheManager : IDisposable
{
private const string PenumbraPrefix = "{penumbra}";
@@ -227,6 +219,11 @@ public class FileCacheManager : IDisposable
return fileCache;
}
public string ResolveFileReplacement(string gamePath)
{
return _ipcManager.PenumbraResolvePath(gamePath);
}
public void Dispose()
{
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.Factories;
using MareSynchronos.Models;
using MareSynchronos.Utils;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace MareSynchronos.Managers;
@@ -16,20 +16,39 @@ public class TransientResourceManager : IDisposable
{
private readonly IpcManager manager;
private readonly DalamudUtil dalamudUtil;
private readonly FileReplacementFactory fileReplacementFactory;
private readonly string configurationDirectory;
public event TransientResourceLoadedEvent? TransientResourceLoaded;
public IntPtr[] PlayerRelatedPointers = Array.Empty<IntPtr>();
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<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;
this.manager = manager;
this.dalamudUtil = dalamudUtil;
this.fileReplacementFactory = fileReplacementFactory;
this.configurationDirectory = configurationDirectory;
dalamudUtil.FrameworkUpdate += DalamudUtil_FrameworkUpdate;
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()
@@ -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();
}
@@ -189,6 +212,11 @@ public class TransientResourceManager : IDisposable
manager.PenumbraResourceLoadEvent -= Manager_PenumbraResourceLoadEvent;
dalamudUtil.ClassJobChanged -= DalamudUtil_ClassJobChanged;
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)

View File

@@ -5,16 +5,20 @@ using System.Threading.Tasks;
using MareSynchronos.API;
using System.Text.RegularExpressions;
using MareSynchronos.FileCache;
using MareSynchronos.Managers;
using System;
namespace MareSynchronos.Models;
public class FileReplacement
{
private readonly FileCacheManager fileDbManager;
private readonly IpcManager ipcManager;
public FileReplacement(FileCacheManager fileDbManager)
public FileReplacement(FileCacheManager fileDbManager, IpcManager ipcManager)
{
this.fileDbManager = fileDbManager;
this.ipcManager = ipcManager;
}
public bool Computed => IsFileSwap || !HasFileReplacement || !string.IsNullOrEmpty(Hash);
@@ -29,7 +33,7 @@ public class FileReplacement
public string ResolvedPath { get; set; } = string.Empty;
public void SetResolvedPath(string path)
private void SetResolvedPath(string path)
{
ResolvedPath = path.ToLowerInvariant().Replace('\\', '/');
if (!HasFileReplacement || IsFileSwap) return;
@@ -43,10 +47,18 @@ public class FileReplacement
public bool Verify()
{
var cache = fileDbManager.GetFileCacheByPath(ResolvedPath);
if (cache == null) return false;
Hash = cache.Hash;
return true;
if (!IsFileSwap)
{
var cache = fileDbManager.GetFileCacheByPath(ResolvedPath);
if (cache == null) return false;
Hash = cache.Hash;
return true;
}
var resolvedPath = fileDbManager.ResolveFileReplacement(GamePaths.First());
ResolvedPath = resolvedPath.ToLowerInvariant();
return IsFileSwap;
}
public FileReplacementDto ToFileReplacementDto()
@@ -58,10 +70,23 @@ public class FileReplacement
FileSwapPath = IsFileSwap ? ResolvedPath : string.Empty
};
}
public override string ToString()
{
StringBuilder builder = new();
builder.AppendLine($"Modded: {HasFileReplacement} - {string.Join(",", GamePaths)} => {ResolvedPath}");
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 readonly DownloadUi _downloadUi;
private readonly FileDialogManager _fileDialogManager;
private readonly FileCacheManager _fileDbManager;
private readonly FileCacheManager _fileCacheManager;
private readonly CompactUi _compactUi;
private readonly UiShared _uiSharedComponent;
private readonly Dalamud.Localization _localization;
private readonly FileReplacementFactory _fileReplacementFactory;
public Plugin(DalamudPluginInterface pluginInterface, CommandManager commandManager,
@@ -62,9 +63,10 @@ public sealed class Plugin : IDalamudPlugin
_ipcManager = new IpcManager(_pluginInterface, _dalamudUtil);
_fileDialogManager = new FileDialogManager();
_fileDbManager = new FileCacheManager(_ipcManager, _configuration, _pluginInterface.ConfigDirectory.FullName);
_apiController = new ApiController(_configuration, _dalamudUtil, _fileDbManager);
_periodicFileScanner = new PeriodicFileScanner(_ipcManager, _configuration, _fileDbManager, _apiController, _dalamudUtil);
_fileCacheManager = new FileCacheManager(_ipcManager, _configuration, _pluginInterface.ConfigDirectory.FullName);
_apiController = new ApiController(_configuration, _dalamudUtil, _fileCacheManager);
_periodicFileScanner = new PeriodicFileScanner(_ipcManager, _configuration, _fileCacheManager, _apiController, _dalamudUtil);
_fileReplacementFactory = new FileReplacementFactory(_fileCacheManager, _ipcManager);
_uiSharedComponent =
new UiShared(_ipcManager, _apiController, _periodicFileScanner, _fileDialogManager, _configuration, _dalamudUtil, _pluginInterface, _localization);
@@ -118,7 +120,7 @@ public sealed class Plugin : IDalamudPlugin
_compactUi?.Dispose();
_periodicFileScanner?.Dispose();
_fileDbManager?.Dispose();
_fileCacheManager?.Dispose();
_playerManager?.Dispose();
_characterCacheManager?.Dispose();
_ipcManager?.Dispose();
@@ -180,13 +182,13 @@ public sealed class Plugin : IDalamudPlugin
try
{
_transientResourceManager = new TransientResourceManager(_ipcManager, _dalamudUtil);
_transientResourceManager = new TransientResourceManager(_ipcManager, _dalamudUtil, _fileReplacementFactory, _pluginInterface.ConfigDirectory.FullName);
var characterCacheFactory =
new CharacterDataFactory(_dalamudUtil, _ipcManager, _transientResourceManager, _fileDbManager);
new CharacterDataFactory(_dalamudUtil, _ipcManager, _transientResourceManager, _fileReplacementFactory);
_playerManager = new PlayerManager(_apiController, _ipcManager,
characterCacheFactory, _dalamudUtil, _transientResourceManager, _periodicFileScanner);
_characterCacheManager = new OnlinePlayerManager(_apiController,
_dalamudUtil, _ipcManager, _playerManager, _fileDbManager);
_dalamudUtil, _ipcManager, _playerManager, _fileCacheManager);
}
catch (Exception ex)
{