experimental first iteration of persistent transient resources on startup
This commit is contained in:
		| @@ -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; | ||||
|   | ||||
							
								
								
									
										22
									
								
								MareSynchronos/Factories/FileReplacementFactory.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								MareSynchronos/Factories/FileReplacementFactory.cs
									
									
									
									
									
										Normal 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); | ||||
|     } | ||||
| } | ||||
| @@ -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(); | ||||
							
								
								
									
										11
									
								
								MareSynchronos/FileCache/FileState.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								MareSynchronos/FileCache/FileState.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,11 @@ | ||||
| using MareSynchronos.Models; | ||||
|  | ||||
| namespace MareSynchronos.FileCache; | ||||
|  | ||||
|  | ||||
| public enum FileState | ||||
| { | ||||
|     Valid, | ||||
|     RequireUpdate, | ||||
|     RequireDeletion | ||||
| } | ||||
| @@ -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) | ||||
|   | ||||
| @@ -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)); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -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) | ||||
|         { | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Stanley Dimant
					Stanley Dimant