more refactoring, rework FileCacheManager
This commit is contained in:
@@ -14,35 +14,30 @@ namespace MareSynchronos.Factories
|
|||||||
{
|
{
|
||||||
public class CharacterDataFactory
|
public class CharacterDataFactory
|
||||||
{
|
{
|
||||||
private readonly ClientState _clientState;
|
private readonly DalamudUtil _dalamudUtil;
|
||||||
private readonly IpcManager _ipcManager;
|
private readonly IpcManager _ipcManager;
|
||||||
private readonly FileReplacementFactory _factory;
|
private readonly FileReplacementFactory _factory;
|
||||||
|
|
||||||
public CharacterDataFactory(ClientState clientState, IpcManager ipcManager, FileReplacementFactory factory)
|
public CharacterDataFactory(DalamudUtil dalamudUtil, IpcManager ipcManager, FileReplacementFactory factory)
|
||||||
{
|
{
|
||||||
Logger.Debug("Creating " + nameof(CharacterDataFactory));
|
Logger.Debug("Creating " + nameof(CharacterDataFactory));
|
||||||
|
|
||||||
_clientState = clientState;
|
_dalamudUtil = dalamudUtil;
|
||||||
_ipcManager = ipcManager;
|
_ipcManager = ipcManager;
|
||||||
_factory = factory;
|
_factory = factory;
|
||||||
}
|
}
|
||||||
|
|
||||||
private string GetPlayerName()
|
|
||||||
{
|
|
||||||
return _clientState.LocalPlayer!.Name.ToString();
|
|
||||||
}
|
|
||||||
|
|
||||||
public unsafe CharacterData BuildCharacterData()
|
public unsafe CharacterData BuildCharacterData()
|
||||||
{
|
{
|
||||||
Stopwatch st = Stopwatch.StartNew();
|
Stopwatch st = Stopwatch.StartNew();
|
||||||
var cache = new CharacterData();
|
var cache = new CharacterData();
|
||||||
|
|
||||||
while (_clientState.LocalPlayer == null)
|
while (!_dalamudUtil.IsPlayerPresent)
|
||||||
{
|
{
|
||||||
Logger.Debug("Character is null but it shouldn't be, waiting");
|
Logger.Debug("Character is null but it shouldn't be, waiting");
|
||||||
Thread.Sleep(50);
|
Thread.Sleep(50);
|
||||||
}
|
}
|
||||||
var model = (CharacterBase*)((Character*)_clientState.LocalPlayer!.Address)->GameObject.GetDrawObject();
|
var model = (CharacterBase*)((Character*)_dalamudUtil.PlayerPointer)->GameObject.GetDrawObject();
|
||||||
for (var idx = 0; idx < model->SlotCount; ++idx)
|
for (var idx = 0; idx < model->SlotCount; ++idx)
|
||||||
{
|
{
|
||||||
var mdl = (RenderModel*)model->ModelArray[idx];
|
var mdl = (RenderModel*)model->ModelArray[idx];
|
||||||
@@ -54,7 +49,7 @@ namespace MareSynchronos.Factories
|
|||||||
var mdlPath = new Utf8String(mdl->ResourceHandle->FileName()).ToString();
|
var mdlPath = new Utf8String(mdl->ResourceHandle->FileName()).ToString();
|
||||||
|
|
||||||
FileReplacement cachedMdlResource = _factory.Create();
|
FileReplacement cachedMdlResource = _factory.Create();
|
||||||
cachedMdlResource.GamePaths = _ipcManager.PenumbraReverseResolvePath(mdlPath, GetPlayerName());
|
cachedMdlResource.GamePaths = _ipcManager.PenumbraReverseResolvePath(mdlPath, _dalamudUtil.PlayerName);
|
||||||
cachedMdlResource.SetResolvedPath(mdlPath);
|
cachedMdlResource.SetResolvedPath(mdlPath);
|
||||||
//PluginLog.Verbose("Resolving for model " + mdlPath);
|
//PluginLog.Verbose("Resolving for model " + mdlPath);
|
||||||
|
|
||||||
@@ -69,7 +64,7 @@ namespace MareSynchronos.Factories
|
|||||||
var mtrlPath = new Utf8String(mtrl->ResourceHandle->FileName()).ToString().Split("|")[2];
|
var mtrlPath = new Utf8String(mtrl->ResourceHandle->FileName()).ToString().Split("|")[2];
|
||||||
//PluginLog.Verbose("Resolving for material " + mtrlPath);
|
//PluginLog.Verbose("Resolving for material " + mtrlPath);
|
||||||
var cachedMtrlResource = _factory.Create();
|
var cachedMtrlResource = _factory.Create();
|
||||||
cachedMtrlResource.GamePaths = _ipcManager.PenumbraReverseResolvePath(mtrlPath, GetPlayerName());
|
cachedMtrlResource.GamePaths = _ipcManager.PenumbraReverseResolvePath(mtrlPath, _dalamudUtil.PlayerName);
|
||||||
cachedMtrlResource.SetResolvedPath(mtrlPath);
|
cachedMtrlResource.SetResolvedPath(mtrlPath);
|
||||||
cache.AddAssociatedResource(cachedMtrlResource, cachedMdlResource, null!);
|
cache.AddAssociatedResource(cachedMtrlResource, cachedMdlResource, null!);
|
||||||
|
|
||||||
@@ -82,12 +77,12 @@ namespace MareSynchronos.Factories
|
|||||||
|
|
||||||
var cachedTexResource = _factory.Create();
|
var cachedTexResource = _factory.Create();
|
||||||
cachedTexResource.GamePaths = new[] { texPath };
|
cachedTexResource.GamePaths = new[] { texPath };
|
||||||
cachedTexResource.SetResolvedPath(_ipcManager.PenumbraResolvePath(texPath, GetPlayerName())!);
|
cachedTexResource.SetResolvedPath(_ipcManager.PenumbraResolvePath(texPath, _dalamudUtil.PlayerName)!);
|
||||||
if (!cachedTexResource.HasFileReplacement)
|
if (!cachedTexResource.HasFileReplacement)
|
||||||
{
|
{
|
||||||
// try resolving tex with -- in name instead
|
// try resolving tex with -- in name instead
|
||||||
texPath = texPath.Insert(texPath.LastIndexOf('/') + 1, "--");
|
texPath = texPath.Insert(texPath.LastIndexOf('/') + 1, "--");
|
||||||
var reResolvedPath = _ipcManager.PenumbraResolvePath(texPath, GetPlayerName())!;
|
var reResolvedPath = _ipcManager.PenumbraResolvePath(texPath, _dalamudUtil.PlayerName)!;
|
||||||
if (reResolvedPath != texPath)
|
if (reResolvedPath != texPath)
|
||||||
{
|
{
|
||||||
cachedTexResource.GamePaths = new[] { texPath };
|
cachedTexResource.GamePaths = new[] { texPath };
|
||||||
@@ -100,8 +95,8 @@ namespace MareSynchronos.Factories
|
|||||||
}
|
}
|
||||||
|
|
||||||
cache.GlamourerString = _ipcManager.GlamourerGetCharacterCustomization()!;
|
cache.GlamourerString = _ipcManager.GlamourerGetCharacterCustomization()!;
|
||||||
cache.ManipulationString = _ipcManager.PenumbraGetMetaManipulations(_clientState.LocalPlayer!.Name.ToString());
|
cache.ManipulationString = _ipcManager.PenumbraGetMetaManipulations(_dalamudUtil.PlayerName);
|
||||||
cache.JobId = _clientState.LocalPlayer!.ClassJob.Id;
|
cache.JobId = _dalamudUtil.PlayerJobId;
|
||||||
|
|
||||||
st.Stop();
|
st.Stop();
|
||||||
Logger.Debug("Building Character Data took " + st.Elapsed);
|
Logger.Debug("Building Character Data took " + st.Elapsed);
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Threading;
|
||||||
using MareSynchronos.FileCacheDB;
|
using MareSynchronos.FileCacheDB;
|
||||||
using MareSynchronos.Utils;
|
using MareSynchronos.Utils;
|
||||||
|
|
||||||
@@ -9,6 +10,11 @@ namespace MareSynchronos.Factories
|
|||||||
public FileCache Create(string file)
|
public FileCache Create(string file)
|
||||||
{
|
{
|
||||||
FileInfo fileInfo = new(file);
|
FileInfo fileInfo = new(file);
|
||||||
|
while (IsFileLocked(fileInfo))
|
||||||
|
{
|
||||||
|
Thread.Sleep(100);
|
||||||
|
Logger.Debug("File is locked, waiting for release: " + fileInfo.FullName);
|
||||||
|
}
|
||||||
var sha1Hash = Crypto.GetFileHash(fileInfo.FullName);
|
var sha1Hash = Crypto.GetFileHash(fileInfo.FullName);
|
||||||
return new FileCache()
|
return new FileCache()
|
||||||
{
|
{
|
||||||
@@ -24,5 +30,19 @@ namespace MareSynchronos.Factories
|
|||||||
cache.Hash = Crypto.GetFileHash(cache.Filepath);
|
cache.Hash = Crypto.GetFileHash(cache.Filepath);
|
||||||
cache.LastModifiedDate = fileInfo.LastWriteTimeUtc.Ticks.ToString();
|
cache.LastModifiedDate = fileInfo.LastWriteTimeUtc.Ticks.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private bool IsFileLocked(FileInfo file)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using var fs = file.Open(FileMode.Open, FileAccess.ReadWrite, FileShare.None);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -75,7 +75,7 @@ namespace MareSynchronos.Managers
|
|||||||
Task.WaitAll(apiTask);
|
Task.WaitAll(apiTask);
|
||||||
|
|
||||||
_characterCacheManager.AddInitialPairs(apiTask.Result);
|
_characterCacheManager.AddInitialPairs(apiTask.Result);
|
||||||
|
|
||||||
_ipcManager.PenumbraRedrawEvent += IpcManager_PenumbraRedrawEvent;
|
_ipcManager.PenumbraRedrawEvent += IpcManager_PenumbraRedrawEvent;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -142,7 +142,7 @@ namespace MareSynchronos.Managers
|
|||||||
Logger.Debug("Not sending data, already sent");
|
Logger.Debug("Not sending data, already sent");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
await _apiController.SendCharacterData(cacheDto, _dalamudUtil.GetLocalPlayers().Select(d => d.Key).ToList());
|
_ = _apiController.SendCharacterData(cacheDto, _dalamudUtil.GetLocalPlayers().Select(d => d.Key).ToList());
|
||||||
_lastSentHash = cacheDto.Hash;
|
_lastSentHash = cacheDto.Hash;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
@@ -15,14 +14,14 @@ namespace MareSynchronos.Managers
|
|||||||
{
|
{
|
||||||
internal class FileCacheManager : IDisposable
|
internal class FileCacheManager : IDisposable
|
||||||
{
|
{
|
||||||
private const int MinutesForScan = 10;
|
|
||||||
private readonly FileCacheFactory _fileCacheFactory;
|
private readonly FileCacheFactory _fileCacheFactory;
|
||||||
private readonly IpcManager _ipcManager;
|
private readonly IpcManager _ipcManager;
|
||||||
private readonly Configuration _pluginConfiguration;
|
private readonly Configuration _pluginConfiguration;
|
||||||
private CancellationTokenSource? _scanCancellationTokenSource;
|
private CancellationTokenSource? _scanCancellationTokenSource;
|
||||||
private System.Timers.Timer? _scanScheduler;
|
|
||||||
private Task? _scanTask;
|
private Task? _scanTask;
|
||||||
private Stopwatch? _timerStopWatch;
|
private FileSystemWatcher? _penumbraDirWatcher;
|
||||||
|
private FileSystemWatcher? _cacheDirWatcher;
|
||||||
|
|
||||||
public FileCacheManager(FileCacheFactory fileCacheFactory, IpcManager ipcManager, Configuration pluginConfiguration)
|
public FileCacheManager(FileCacheFactory fileCacheFactory, IpcManager ipcManager, Configuration pluginConfiguration)
|
||||||
{
|
{
|
||||||
Logger.Debug("Creating " + nameof(FileCacheManager));
|
Logger.Debug("Creating " + nameof(FileCacheManager));
|
||||||
@@ -41,17 +40,82 @@ namespace MareSynchronos.Managers
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void OnCreated(object sender, FileSystemEventArgs e)
|
||||||
|
{
|
||||||
|
var fi = new FileInfo(e.FullPath);
|
||||||
|
using var db = new FileCacheContext();
|
||||||
|
if (fi.Extension.ToLower() is not ".mdl" or ".tex" or ".mtrl")
|
||||||
|
{
|
||||||
|
// this is most likely a folder
|
||||||
|
Logger.Debug("Folder added: " + e.FullPath);
|
||||||
|
var newFiles = Directory.EnumerateFiles(e.FullPath, "*.*", SearchOption.AllDirectories)
|
||||||
|
.Where(f => f.EndsWith(".tex", StringComparison.OrdinalIgnoreCase) ||
|
||||||
|
f.EndsWith(".mdl", StringComparison.OrdinalIgnoreCase) ||
|
||||||
|
f.EndsWith(".mtrl", StringComparison.OrdinalIgnoreCase)).ToList();
|
||||||
|
foreach (var file in newFiles)
|
||||||
|
{
|
||||||
|
Logger.Debug("Adding " + file);
|
||||||
|
db.Add(_fileCacheFactory.Create(file));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Logger.Debug("File created: " + e.FullPath);
|
||||||
|
var createdFileCache = _fileCacheFactory.Create(fi.FullName);
|
||||||
|
db.Add(createdFileCache);
|
||||||
|
}
|
||||||
|
|
||||||
|
db.SaveChanges();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnDeleted(object sender, FileSystemEventArgs e)
|
||||||
|
{
|
||||||
|
var fi = new FileInfo(e.FullPath);
|
||||||
|
using var db = new FileCacheContext();
|
||||||
|
if (fi.Extension.ToLower() is not ".mdl" or ".tex" or ".mtrl")
|
||||||
|
{
|
||||||
|
// this is most likely a folder
|
||||||
|
var filesToRemove = db.FileCaches.Where(f => f.Filepath.StartsWith(e.FullPath.ToLower())).ToList();
|
||||||
|
Logger.Debug($"Folder deleted: {e.FullPath}, removing {filesToRemove.Count} files");
|
||||||
|
db.RemoveRange(filesToRemove);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Logger.Debug("File deleted: " + e.FullPath);
|
||||||
|
var fileInDb = db.FileCaches.SingleOrDefault(f => f.Filepath == fi.FullName.ToLower());
|
||||||
|
if (fileInDb == null) return;
|
||||||
|
db.Remove(fileInDb);
|
||||||
|
}
|
||||||
|
db.SaveChanges();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnModified(object sender, FileSystemEventArgs e)
|
||||||
|
{
|
||||||
|
Logger.Debug("OnModified: " + e.FullPath);
|
||||||
|
var fi = new FileInfo(e.FullPath);
|
||||||
|
if (fi.Extension.ToLower() is not ".mdl" or ".tex" or ".mtrl") return;
|
||||||
|
Logger.Debug("File changed: " + e.FullPath);
|
||||||
|
using var db = new FileCacheContext();
|
||||||
|
var modifiedFile = _fileCacheFactory.Create(fi.FullName);
|
||||||
|
var fileInDb = db.FileCaches.SingleOrDefault(f => f.Filepath == fi.FullName.ToLower() || modifiedFile.Hash == f.Hash);
|
||||||
|
if (fileInDb == null) return;
|
||||||
|
db.Remove(fileInDb);
|
||||||
|
db.Add(modifiedFile);
|
||||||
|
db.SaveChanges();
|
||||||
|
}
|
||||||
|
|
||||||
public long CurrentFileProgress { get; private set; }
|
public long CurrentFileProgress { get; private set; }
|
||||||
public bool IsScanRunning => !_scanTask?.IsCompleted ?? false;
|
public bool IsScanRunning => !_scanTask?.IsCompleted ?? false;
|
||||||
|
|
||||||
public TimeSpan TimeToNextScan => TimeSpan.FromMinutes(MinutesForScan).Subtract(_timerStopWatch?.Elapsed ?? TimeSpan.FromMinutes(MinutesForScan));
|
|
||||||
public long TotalFiles { get; private set; }
|
public long TotalFiles { get; private set; }
|
||||||
|
public string WatchedPenumbraDirectory => (!_penumbraDirWatcher?.EnableRaisingEvents ?? false) ? "Not watched" : _penumbraDirWatcher!.Path;
|
||||||
|
public string WatchedCacheDirectory => (!_cacheDirWatcher?.EnableRaisingEvents ?? false) ? "Not watched" : _cacheDirWatcher!.Path;
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
Logger.Debug("Disposing " + nameof(FileCacheManager));
|
Logger.Debug("Disposing " + nameof(FileCacheManager));
|
||||||
|
|
||||||
_scanScheduler?.Stop();
|
_cacheDirWatcher?.Dispose();
|
||||||
|
_penumbraDirWatcher?.Dispose();
|
||||||
_scanCancellationTokenSource?.Cancel();
|
_scanCancellationTokenSource?.Cancel();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -65,21 +129,20 @@ namespace MareSynchronos.Managers
|
|||||||
{
|
{
|
||||||
_scanCancellationTokenSource = new CancellationTokenSource();
|
_scanCancellationTokenSource = new CancellationTokenSource();
|
||||||
var penumbraDir = _ipcManager.PenumbraModDirectory()!;
|
var penumbraDir = _ipcManager.PenumbraModDirectory()!;
|
||||||
Logger.Debug("Getting files from " + penumbraDir);
|
Logger.Debug("Getting files from " + penumbraDir + " and " + _pluginConfiguration.CacheFolder);
|
||||||
var scannedFiles = new ConcurrentDictionary<string, bool>(
|
var scannedFiles = new ConcurrentDictionary<string, bool>(
|
||||||
Directory.EnumerateFiles(penumbraDir, "*.*", SearchOption.AllDirectories)
|
Directory.EnumerateFiles(penumbraDir, "*.*", SearchOption.AllDirectories)
|
||||||
.Select(s => s.ToLowerInvariant())
|
.Select(s => s.ToLowerInvariant())
|
||||||
.Where(f => f.Contains(@"\chara\") && (f.EndsWith(".tex") || f.EndsWith(".mdl") || f.EndsWith(".mtrl")))
|
.Where(f => f.Contains(@"\chara\"))
|
||||||
|
.Concat(Directory.EnumerateFiles(_pluginConfiguration.CacheFolder, "*.*", SearchOption.AllDirectories)
|
||||||
|
.Select(s => s.ToLowerInvariant()))
|
||||||
|
.Where(f => (f.EndsWith(".tex", StringComparison.OrdinalIgnoreCase) || f.EndsWith(".mdl", StringComparison.OrdinalIgnoreCase) || f.EndsWith(".mtrl", StringComparison.OrdinalIgnoreCase)))
|
||||||
.Select(p => new KeyValuePair<string, bool>(p, false)));
|
.Select(p => new KeyValuePair<string, bool>(p, false)));
|
||||||
List<FileCache> fileCaches;
|
await using FileCacheContext db = new();
|
||||||
await using (FileCacheContext db = new())
|
List<FileCache> fileCaches = db.FileCaches.ToList();
|
||||||
{
|
|
||||||
fileCaches = db.FileCaches.ToList();
|
|
||||||
}
|
|
||||||
|
|
||||||
TotalFiles = scannedFiles.Count;
|
TotalFiles = scannedFiles.Count;
|
||||||
|
|
||||||
var fileCachesToUpdate = new ConcurrentBag<FileCache>();
|
|
||||||
var fileCachesToDelete = new ConcurrentBag<FileCache>();
|
var fileCachesToDelete = new ConcurrentBag<FileCache>();
|
||||||
var fileCachesToAdd = new ConcurrentBag<FileCache>();
|
var fileCachesToAdd = new ConcurrentBag<FileCache>();
|
||||||
|
|
||||||
@@ -105,8 +168,8 @@ namespace MareSynchronos.Managers
|
|||||||
}
|
}
|
||||||
FileInfo fileInfo = new(cache.Filepath);
|
FileInfo fileInfo = new(cache.Filepath);
|
||||||
if (fileInfo.LastWriteTimeUtc.Ticks == long.Parse(cache.LastModifiedDate)) return;
|
if (fileInfo.LastWriteTimeUtc.Ticks == long.Parse(cache.LastModifiedDate)) return;
|
||||||
_fileCacheFactory.UpdateFileCache(cache);
|
fileCachesToAdd.Add(_fileCacheFactory.Create(cache.Filepath));
|
||||||
fileCachesToUpdate.Add(cache);
|
fileCachesToDelete.Add(cache);
|
||||||
}
|
}
|
||||||
|
|
||||||
var files = CurrentFileProgress;
|
var files = CurrentFileProgress;
|
||||||
@@ -131,15 +194,18 @@ namespace MareSynchronos.Managers
|
|||||||
CurrentFileProgress = files;
|
CurrentFileProgress = files;
|
||||||
});
|
});
|
||||||
|
|
||||||
await using (FileCacheContext db = new())
|
if (fileCachesToAdd.Any() || fileCachesToDelete.Any())
|
||||||
{
|
{
|
||||||
if (fileCachesToAdd.Any() || fileCachesToUpdate.Any() || fileCachesToDelete.Any())
|
Logger.Debug("Found " + fileCachesToAdd.Count + " additions and " + fileCachesToDelete.Count + " deletions");
|
||||||
|
try
|
||||||
{
|
{
|
||||||
db.FileCaches.AddRange(fileCachesToAdd);
|
|
||||||
db.FileCaches.UpdateRange(fileCachesToUpdate);
|
|
||||||
db.FileCaches.RemoveRange(fileCachesToDelete);
|
db.FileCaches.RemoveRange(fileCachesToDelete);
|
||||||
|
db.FileCaches.AddRange(fileCachesToAdd);
|
||||||
await db.SaveChangesAsync(ct);
|
db.SaveChanges();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
PluginLog.Error(ex, ex.Message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -151,40 +217,41 @@ namespace MareSynchronos.Managers
|
|||||||
{
|
{
|
||||||
_pluginConfiguration.InitialScanComplete = true;
|
_pluginConfiguration.InitialScanComplete = true;
|
||||||
_pluginConfiguration.Save();
|
_pluginConfiguration.Save();
|
||||||
_timerStopWatch = Stopwatch.StartNew();
|
|
||||||
StartScheduler();
|
|
||||||
}
|
|
||||||
else if (_timerStopWatch == null)
|
|
||||||
{
|
|
||||||
StartScheduler();
|
|
||||||
_timerStopWatch = Stopwatch.StartNew();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
StartWatchers();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void StartScheduler()
|
public void StartWatchers()
|
||||||
{
|
{
|
||||||
Logger.Debug("Scheduling next scan for in " + MinutesForScan + " minutes");
|
Logger.Debug("Starting File System Watchers");
|
||||||
_scanScheduler = new System.Timers.Timer(TimeSpan.FromMinutes(MinutesForScan).TotalMilliseconds)
|
_penumbraDirWatcher?.Dispose();
|
||||||
{
|
_cacheDirWatcher?.Dispose();
|
||||||
AutoReset = false,
|
|
||||||
Enabled = false,
|
|
||||||
};
|
|
||||||
_scanScheduler.AutoReset = true;
|
|
||||||
_scanScheduler.Elapsed += (_, _) =>
|
|
||||||
{
|
|
||||||
_timerStopWatch?.Stop();
|
|
||||||
if (_scanTask?.IsCompleted ?? false)
|
|
||||||
{
|
|
||||||
PluginLog.Warning("Scanning task is still running, not re-initiating.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Logger.Debug("Initiating periodic scan for mod changes");
|
_penumbraDirWatcher = new FileSystemWatcher(_ipcManager.PenumbraModDirectory()!)
|
||||||
Task.Run(() => _scanTask = StartFileScan(_scanCancellationTokenSource!.Token));
|
{
|
||||||
_timerStopWatch = Stopwatch.StartNew();
|
EnableRaisingEvents = true,
|
||||||
|
Filter = "*.*",
|
||||||
|
IncludeSubdirectories = true,
|
||||||
};
|
};
|
||||||
|
_penumbraDirWatcher.NotifyFilter = NotifyFilters.FileName | NotifyFilters.DirectoryName | NotifyFilters.Size;
|
||||||
|
_penumbraDirWatcher.Created += OnCreated;
|
||||||
|
_penumbraDirWatcher.Deleted += OnDeleted;
|
||||||
|
_penumbraDirWatcher.Changed += OnModified;
|
||||||
|
_penumbraDirWatcher.Error += (sender, args) => PluginLog.Error(args.GetException(), "Error in Penumbra Dir Watcher");
|
||||||
|
|
||||||
_scanScheduler.Start();
|
_cacheDirWatcher = new FileSystemWatcher(_pluginConfiguration.CacheFolder)
|
||||||
|
{
|
||||||
|
EnableRaisingEvents = true,
|
||||||
|
Filter = "*.*",
|
||||||
|
IncludeSubdirectories = true,
|
||||||
|
};
|
||||||
|
_cacheDirWatcher.NotifyFilter = NotifyFilters.FileName | NotifyFilters.DirectoryName | NotifyFilters.Size;
|
||||||
|
_cacheDirWatcher.Created += OnCreated;
|
||||||
|
_cacheDirWatcher.Deleted += OnDeleted;
|
||||||
|
_cacheDirWatcher.Changed += OnModified;
|
||||||
|
_cacheDirWatcher.Error +=
|
||||||
|
(sender, args) => PluginLog.Error(args.GetException(), "Error in Cache Dir Watcher");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ namespace MareSynchronos.Models
|
|||||||
public bool IsReady => FileReplacements.All(f => f.Computed);
|
public bool IsReady => FileReplacements.All(f => f.Computed);
|
||||||
|
|
||||||
[JsonProperty]
|
[JsonProperty]
|
||||||
public uint JobId { get; set; } = 0;
|
public int JobId { get; set; } = 0;
|
||||||
|
|
||||||
public string ManipulationString { get; set; } = string.Empty;
|
public string ManipulationString { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
|||||||
@@ -15,18 +15,18 @@ namespace MareSynchronos.Models
|
|||||||
[JsonObject(MemberSerialization.OptIn)]
|
[JsonObject(MemberSerialization.OptIn)]
|
||||||
public class FileReplacement
|
public class FileReplacement
|
||||||
{
|
{
|
||||||
private readonly string penumbraDirectory;
|
private readonly string _penumbraDirectory;
|
||||||
|
|
||||||
private Task? computationTask = null;
|
private Task? _computationTask = null;
|
||||||
|
|
||||||
public FileReplacement(string penumbraDirectory)
|
public FileReplacement(string penumbraDirectory)
|
||||||
{
|
{
|
||||||
this.penumbraDirectory = penumbraDirectory;
|
this._penumbraDirectory = penumbraDirectory;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<FileReplacement> Associated { get; set; } = new List<FileReplacement>();
|
public List<FileReplacement> Associated { get; set; } = new List<FileReplacement>();
|
||||||
|
|
||||||
public bool Computed => (computationTask == null || (computationTask?.IsCompleted ?? true)) && Associated.All(f => f.Computed);
|
public bool Computed => (_computationTask == null || (_computationTask?.IsCompleted ?? true)) && Associated.All(f => f.Computed);
|
||||||
|
|
||||||
[JsonProperty]
|
[JsonProperty]
|
||||||
public string[] GamePaths { get; set; } = Array.Empty<string>();
|
public string[] GamePaths { get; set; } = Array.Empty<string>();
|
||||||
@@ -74,10 +74,10 @@ namespace MareSynchronos.Models
|
|||||||
|
|
||||||
public void SetResolvedPath(string path)
|
public void SetResolvedPath(string path)
|
||||||
{
|
{
|
||||||
ResolvedPath = path.ToLower().Replace('/', '\\').Replace(penumbraDirectory, "").Replace('\\', '/');
|
ResolvedPath = path.ToLower().Replace('/', '\\').Replace(_penumbraDirectory, "").Replace('\\', '/');
|
||||||
if (!HasFileReplacement) return;
|
if (!HasFileReplacement) return;
|
||||||
|
|
||||||
computationTask = Task.Run(() =>
|
_computationTask = Task.Run(() =>
|
||||||
{
|
{
|
||||||
FileCache? fileCache;
|
FileCache? fileCache;
|
||||||
using (FileCacheContext db = new())
|
using (FileCacheContext db = new())
|
||||||
|
|||||||
@@ -145,7 +145,7 @@ namespace MareSynchronos
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
var characterCacheFactory =
|
var characterCacheFactory =
|
||||||
new CharacterDataFactory(_clientState, _ipcManager, new FileReplacementFactory(_ipcManager));
|
new CharacterDataFactory(_dalamudUtil, _ipcManager, new FileReplacementFactory(_ipcManager));
|
||||||
_characterManager = new CharacterManager(_apiController, _objectTable, _ipcManager,
|
_characterManager = new CharacterManager(_apiController, _objectTable, _ipcManager,
|
||||||
characterCacheFactory, _characterCacheManager, _dalamudUtil, _playerWatcher);
|
characterCacheFactory, _characterCacheManager, _dalamudUtil, _playerWatcher);
|
||||||
_characterManager.StartWatchingPlayer();
|
_characterManager.StartWatchingPlayer();
|
||||||
|
|||||||
@@ -242,8 +242,9 @@ namespace MareSynchronos.UI
|
|||||||
{
|
{
|
||||||
if (_apiController.PairedClients.All(w => w.OtherUID != tempNameUID))
|
if (_apiController.PairedClients.All(w => w.OtherUID != tempNameUID))
|
||||||
{
|
{
|
||||||
|
var nameToSend = tempNameUID;
|
||||||
tempNameUID = string.Empty;
|
tempNameUID = string.Empty;
|
||||||
_ = _apiController.SendPairedClientAddition(tempNameUID);
|
_ = _apiController.SendPairedClientAddition(nameToSend);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ImGui.PopFont();
|
ImGui.PopFont();
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using System.IO;
|
using System;
|
||||||
|
using System.IO;
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Dalamud.Interface.Colors;
|
using Dalamud.Interface.Colors;
|
||||||
@@ -59,13 +60,10 @@ namespace MareSynchronos.UI
|
|||||||
? "Collecting files"
|
? "Collecting files"
|
||||||
: $"Processing {_fileCacheManager.CurrentFileProgress} / {_fileCacheManager.TotalFiles} files");
|
: $"Processing {_fileCacheManager.CurrentFileProgress} / {_fileCacheManager.TotalFiles} files");
|
||||||
}
|
}
|
||||||
else if (_fileCacheManager.TimeToNextScan.TotalSeconds == 0)
|
|
||||||
{
|
|
||||||
ImGui.Text("Scan not started");
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ImGui.Text("Next scan in " + _fileCacheManager.TimeToNextScan.ToString(@"mm\:ss") + " minutes");
|
ImGui.Text("Watching Penumbra Directory: " + _fileCacheManager.WatchedPenumbraDirectory);
|
||||||
|
ImGui.Text("Watching Cache Directory: " + _fileCacheManager.WatchedCacheDirectory);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -156,6 +154,7 @@ namespace MareSynchronos.UI
|
|||||||
if (!string.IsNullOrEmpty(_pluginConfiguration.CacheFolder) && Directory.Exists(_pluginConfiguration.CacheFolder))
|
if (!string.IsNullOrEmpty(_pluginConfiguration.CacheFolder) && Directory.Exists(_pluginConfiguration.CacheFolder))
|
||||||
{
|
{
|
||||||
_pluginConfiguration.Save();
|
_pluginConfiguration.Save();
|
||||||
|
_fileCacheManager.StartWatchers();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -23,6 +23,10 @@ namespace MareSynchronos.Utils
|
|||||||
|
|
||||||
public string PlayerName => _clientState.LocalPlayer!.Name.ToString();
|
public string PlayerName => _clientState.LocalPlayer!.Name.ToString();
|
||||||
|
|
||||||
|
public int PlayerJobId => (int)_clientState.LocalPlayer!.ClassJob.Id;
|
||||||
|
|
||||||
|
public IntPtr PlayerPointer => _clientState.LocalPlayer!.Address;
|
||||||
|
|
||||||
public string PlayerNameHashed => Crypto.GetHash256(PlayerName + _clientState.LocalPlayer!.HomeWorld.Id);
|
public string PlayerNameHashed => Crypto.GetHash256(PlayerName + _clientState.LocalPlayer!.HomeWorld.Id);
|
||||||
|
|
||||||
public Dictionary<string, PlayerCharacter> GetLocalPlayers()
|
public Dictionary<string, PlayerCharacter> GetLocalPlayers()
|
||||||
@@ -44,6 +48,7 @@ namespace MareSynchronos.Utils
|
|||||||
{
|
{
|
||||||
var obj = (GameObject*)characterAddress;
|
var obj = (GameObject*)characterAddress;
|
||||||
|
|
||||||
|
// ReSharper disable once LoopVariableIsNeverChangedInsideLoop
|
||||||
while ((obj->RenderFlags & 0b100000000000) == 0b100000000000) // 0b100000000000 is "still rendering" or something
|
while ((obj->RenderFlags & 0b100000000000) == 0b100000000000) // 0b100000000000 is "still rendering" or something
|
||||||
{
|
{
|
||||||
Logger.Debug("Waiting for character to finish drawing");
|
Logger.Debug("Waiting for character to finish drawing");
|
||||||
|
|||||||
@@ -87,7 +87,7 @@ namespace MareSynchronos.WebAPI
|
|||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
Logger.Debug("Disposing " + nameof(ApiController));
|
Logger.Debug("Disposing " + nameof(ApiController));
|
||||||
|
|
||||||
_cts?.Cancel();
|
_cts?.Cancel();
|
||||||
_ = DisposeHubConnections();
|
_ = DisposeHubConnections();
|
||||||
}
|
}
|
||||||
@@ -124,19 +124,9 @@ namespace MareSynchronos.WebAPI
|
|||||||
var hash = file.Hash;
|
var hash = file.Hash;
|
||||||
var data = await DownloadFile(hash);
|
var data = await DownloadFile(hash);
|
||||||
var extractedFile = LZ4Codec.Unwrap(data);
|
var extractedFile = LZ4Codec.Unwrap(data);
|
||||||
var ext = file.GamePaths.First().Split(".", StringSplitOptions.None).Last();
|
var ext = file.GamePaths.First().Split(".").Last();
|
||||||
var filePath = Path.Combine(_pluginConfiguration.CacheFolder, file.Hash + "." + ext);
|
var filePath = Path.Combine(_pluginConfiguration.CacheFolder, file.Hash + "." + ext);
|
||||||
await File.WriteAllBytesAsync(filePath, extractedFile);
|
await File.WriteAllBytesAsync(filePath, extractedFile);
|
||||||
await using (var db = new FileCacheContext())
|
|
||||||
{
|
|
||||||
db.Add(new FileCache
|
|
||||||
{
|
|
||||||
Filepath = filePath.ToLower(),
|
|
||||||
Hash = file.Hash,
|
|
||||||
LastModifiedDate = DateTime.Now.Ticks.ToString(),
|
|
||||||
});
|
|
||||||
await db.SaveChangesAsync();
|
|
||||||
}
|
|
||||||
Logger.Debug("File downloaded to " + filePath);
|
Logger.Debug("File downloaded to " + filePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user