refactor + add resiliency against penumbra/api shutdowns
This commit is contained in:
@@ -37,6 +37,46 @@ public class CharacterCacheManager : IDisposable
|
||||
_apiController = apiController;
|
||||
_dalamudUtil = dalamudUtil;
|
||||
_ipcManager = ipcManager;
|
||||
|
||||
_clientState.Login += ClientStateOnLogin;
|
||||
_clientState.Logout += ClientStateOnLogout;
|
||||
|
||||
_apiController.CharacterReceived += ApiControllerOnCharacterReceived;
|
||||
_apiController.PairedClientOnline += ApiControllerOnPairedClientOnline;
|
||||
_apiController.PairedClientOffline += ApiControllerOnPairedClientOffline;
|
||||
_apiController.PairedWithOther += ApiControllerOnPairedWithOther;
|
||||
_apiController.UnpairedFromOther += ApiControllerOnUnpairedFromOther;
|
||||
_apiController.Disconnected += ApiControllerOnDisconnected;
|
||||
_ipcManager.PenumbraDisposed += IpcManagerOnPenumbraDisposed;
|
||||
|
||||
if (clientState.IsLoggedIn)
|
||||
{
|
||||
ClientStateOnLogin(null, EventArgs.Empty);
|
||||
}
|
||||
}
|
||||
|
||||
private void IpcManagerOnPenumbraDisposed(object? sender, EventArgs e)
|
||||
{
|
||||
foreach (var character in _onlineCachedPlayers.ToList())
|
||||
{
|
||||
RestoreCharacter(character);
|
||||
character.IsVisible = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void ApiControllerOnDisconnected(object? sender, EventArgs e)
|
||||
{
|
||||
RestoreAllCharacters();
|
||||
}
|
||||
|
||||
private void ClientStateOnLogin(object? sender, EventArgs e)
|
||||
{
|
||||
_framework.Update += FrameworkOnUpdate;
|
||||
}
|
||||
|
||||
private void ClientStateOnLogout(object? sender, EventArgs e)
|
||||
{
|
||||
_framework.Update -= FrameworkOnUpdate;
|
||||
}
|
||||
|
||||
public void AddInitialPairs(List<string> apiTaskResult)
|
||||
@@ -55,8 +95,15 @@ public class CharacterCacheManager : IDisposable
|
||||
_apiController.PairedClientOffline -= ApiControllerOnPairedClientOffline;
|
||||
_apiController.PairedWithOther -= ApiControllerOnPairedWithOther;
|
||||
_apiController.UnpairedFromOther -= ApiControllerOnUnpairedFromOther;
|
||||
_ipcManager.PenumbraDisposed -= ApiControllerOnDisconnected;
|
||||
_framework.Update -= FrameworkOnUpdate;
|
||||
_clientState.Login -= ClientStateOnLogin;
|
||||
_clientState.Logout -= ClientStateOnLogout;
|
||||
RestoreAllCharacters();
|
||||
}
|
||||
|
||||
private void RestoreAllCharacters()
|
||||
{
|
||||
foreach (var character in _onlineCachedPlayers.ToList())
|
||||
{
|
||||
RestoreCharacter(character);
|
||||
@@ -65,18 +112,6 @@ public class CharacterCacheManager : IDisposable
|
||||
_onlineCachedPlayers.Clear();
|
||||
}
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
_onlineCachedPlayers.Clear();
|
||||
|
||||
_apiController.CharacterReceived += ApiControllerOnCharacterReceived;
|
||||
_apiController.PairedClientOnline += ApiControllerOnPairedClientOnline;
|
||||
_apiController.PairedClientOffline += ApiControllerOnPairedClientOffline;
|
||||
_apiController.PairedWithOther += ApiControllerOnPairedWithOther;
|
||||
_apiController.UnpairedFromOther += ApiControllerOnUnpairedFromOther;
|
||||
_framework.Update += FrameworkOnUpdate;
|
||||
}
|
||||
|
||||
public async Task UpdatePlayersFromService(Dictionary<string, int> playerJobIds)
|
||||
{
|
||||
await _apiController.GetCharacterData(playerJobIds);
|
||||
@@ -190,6 +225,7 @@ public class CharacterCacheManager : IDisposable
|
||||
if (DateTime.Now < _lastPlayerObjectCheck.AddSeconds(2)) return;
|
||||
|
||||
_localVisiblePlayers.Clear();
|
||||
if (!_ipcManager.Initialized) return;
|
||||
foreach (var obj in _objectTable)
|
||||
{
|
||||
if (obj.ObjectKind != Dalamud.Game.ClientState.Objects.Enums.ObjectKind.Player) continue;
|
||||
|
||||
@@ -70,7 +70,6 @@ namespace MareSynchronos.Managers
|
||||
{
|
||||
var apiTask = _apiController.SendCharacterName(_dalamudUtil.PlayerNameHashed);
|
||||
_lastSentHash = string.Empty;
|
||||
_characterCacheManager.Initialize();
|
||||
|
||||
Task.WaitAll(apiTask);
|
||||
|
||||
@@ -81,8 +80,6 @@ namespace MareSynchronos.Managers
|
||||
|
||||
private void ApiController_Disconnected(object? sender, EventArgs args)
|
||||
{
|
||||
_characterCacheManager.Dispose();
|
||||
|
||||
Logger.Debug(nameof(ApiController_Disconnected));
|
||||
|
||||
_ipcManager.PenumbraRedrawEvent -= IpcManager_PenumbraRedrawEvent;
|
||||
@@ -126,6 +123,12 @@ namespace MareSynchronos.Managers
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_ipcManager.Initialized)
|
||||
{
|
||||
PluginLog.Warning("Penumbra not active, doing nothing.");
|
||||
return;
|
||||
}
|
||||
|
||||
_playerChangedTask = Task.Run(async () =>
|
||||
{
|
||||
Stopwatch st = Stopwatch.StartNew();
|
||||
@@ -152,28 +155,21 @@ namespace MareSynchronos.Managers
|
||||
Logger.Debug("Watcher Player Changed");
|
||||
Task.Run(() =>
|
||||
{
|
||||
try
|
||||
// fix for redraw from anamnesis
|
||||
while (!_dalamudUtil.IsPlayerPresent)
|
||||
{
|
||||
// fix for redraw from anamnesis
|
||||
while (!_dalamudUtil.IsPlayerPresent)
|
||||
{
|
||||
Logger.Debug("Waiting Until Player is Present");
|
||||
Thread.Sleep(100);
|
||||
}
|
||||
|
||||
if (actor.Name.ToString() == _dalamudUtil.PlayerName)
|
||||
{
|
||||
Logger.Debug("Watcher: PlayerChanged");
|
||||
PlayerChanged(actor.Name.ToString());
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.Debug("PlayerChanged: " + actor.Name.ToString());
|
||||
}
|
||||
Logger.Debug("Waiting Until Player is Present");
|
||||
Thread.Sleep(100);
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
||||
if (actor.Name.ToString() == _dalamudUtil.PlayerName)
|
||||
{
|
||||
PluginLog.Error(ex, "Actor was null or broken " + actor);
|
||||
Logger.Debug("Watcher: PlayerChanged");
|
||||
PlayerChanged(actor.Name.ToString());
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.Debug("PlayerChanged: " + actor.Name.ToString());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -26,17 +26,32 @@ namespace MareSynchronos.Managers
|
||||
_ipcManager = ipcManager;
|
||||
_pluginConfiguration = pluginConfiguration;
|
||||
|
||||
if (_ipcManager.CheckPenumbraApi()
|
||||
&& _pluginConfiguration.AcceptedAgreement
|
||||
&& !string.IsNullOrEmpty(_pluginConfiguration.CacheFolder)
|
||||
&& _pluginConfiguration.ClientSecret.ContainsKey(_pluginConfiguration.ApiUri)
|
||||
&& !string.IsNullOrEmpty(_ipcManager.PenumbraModDirectory()))
|
||||
StartWatchersAndScan();
|
||||
|
||||
_ipcManager.PenumbraInitialized += IpcManagerOnPenumbraInitialized;
|
||||
_ipcManager.PenumbraDisposed += IpcManagerOnPenumbraDisposed;
|
||||
}
|
||||
|
||||
private void StartWatchersAndScan()
|
||||
{
|
||||
if (_ipcManager.Initialized && _pluginConfiguration.HasValidSetup)
|
||||
{
|
||||
Logger.Debug("Penumbra is active, configuration is valid, starting watchers and scan");
|
||||
StartWatchers();
|
||||
StartInitialScan();
|
||||
}
|
||||
}
|
||||
|
||||
private void IpcManagerOnPenumbraInitialized(object? sender, EventArgs e)
|
||||
{
|
||||
StartWatchersAndScan();
|
||||
}
|
||||
|
||||
private void IpcManagerOnPenumbraDisposed(object? sender, EventArgs e)
|
||||
{
|
||||
StopWatchersAndScan();
|
||||
}
|
||||
|
||||
public long CurrentFileProgress { get; private set; }
|
||||
public long FileCacheSize { get; set; }
|
||||
public bool IsScanRunning => !_scanTask?.IsCompleted ?? false;
|
||||
@@ -68,6 +83,14 @@ namespace MareSynchronos.Managers
|
||||
{
|
||||
Logger.Debug("Disposing " + nameof(FileCacheManager));
|
||||
|
||||
_ipcManager.PenumbraInitialized -= IpcManagerOnPenumbraInitialized;
|
||||
_ipcManager.PenumbraDisposed -= IpcManagerOnPenumbraDisposed;
|
||||
|
||||
StopWatchersAndScan();
|
||||
}
|
||||
|
||||
private void StopWatchersAndScan()
|
||||
{
|
||||
_cacheDirWatcher?.Dispose();
|
||||
_penumbraDirWatcher?.Dispose();
|
||||
_scanCancellationTokenSource?.Cancel();
|
||||
@@ -81,6 +104,7 @@ namespace MareSynchronos.Managers
|
||||
|
||||
public void StartWatchers()
|
||||
{
|
||||
if (!_ipcManager.Initialized || !_pluginConfiguration.HasValidSetup) return;
|
||||
Logger.Debug("Starting File System Watchers");
|
||||
_penumbraDirWatcher?.Dispose();
|
||||
_cacheDirWatcher?.Dispose();
|
||||
@@ -91,7 +115,6 @@ namespace MareSynchronos.Managers
|
||||
InternalBufferSize = 65536
|
||||
};
|
||||
_penumbraDirWatcher.NotifyFilter = NotifyFilters.FileName | NotifyFilters.Size;
|
||||
//_penumbraDirWatcher.Created += OnCreated;
|
||||
_penumbraDirWatcher.Deleted += OnDeleted;
|
||||
_penumbraDirWatcher.Changed += OnModified;
|
||||
_penumbraDirWatcher.Filters.Add("*.mtrl");
|
||||
@@ -107,7 +130,6 @@ namespace MareSynchronos.Managers
|
||||
InternalBufferSize = 65536
|
||||
};
|
||||
_cacheDirWatcher.NotifyFilter = NotifyFilters.FileName | NotifyFilters.Size;
|
||||
//_cacheDirWatcher.Created += OnCreated;
|
||||
_cacheDirWatcher.Deleted += OnDeleted;
|
||||
_cacheDirWatcher.Changed += OnModified;
|
||||
_cacheDirWatcher.Filters.Add("*.mtrl");
|
||||
@@ -134,49 +156,6 @@ namespace MareSynchronos.Managers
|
||||
return false;
|
||||
}
|
||||
|
||||
private void OnCreated(object sender, FileSystemEventArgs e)
|
||||
{
|
||||
var fi = new FileInfo(e.FullPath);
|
||||
using var db = new FileCacheContext();
|
||||
var ext = fi.Extension.ToLower();
|
||||
if (ext is ".mdl" or ".tex" or ".mtrl")
|
||||
{
|
||||
Logger.Debug("File created: " + e.FullPath);
|
||||
try
|
||||
{
|
||||
var createdFileCache = Create(fi.FullName.ToLower());
|
||||
db.Add(createdFileCache);
|
||||
}
|
||||
catch (FileLoadException)
|
||||
{
|
||||
Logger.Debug("File was still being written to.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Directory.Exists(e.FullPath))
|
||||
{
|
||||
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(Create(file));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
db.SaveChanges();
|
||||
|
||||
if (e.FullPath.Contains(_pluginConfiguration.CacheFolder, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
Task.Run(RecalculateFileCacheSize);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnDeleted(object sender, FileSystemEventArgs e)
|
||||
{
|
||||
var fi = new FileInfo(e.FullPath);
|
||||
|
||||
@@ -17,6 +17,7 @@ namespace MareSynchronos.Managers
|
||||
private readonly ICallGateSubscriber<string, string, bool, (int, string)> _penumbraCreateTemporaryCollection;
|
||||
private readonly ICallGateSubscriber<string, string> _penumbraGetMetaManipulations;
|
||||
private readonly ICallGateSubscriber<object> _penumbraInit;
|
||||
private readonly ICallGateSubscriber<object> _penumbraDispose;
|
||||
private readonly ICallGateSubscriber<IntPtr, int, object?> _penumbraObjectIsRedrawn;
|
||||
private readonly ICallGateSubscriber<string, int, object>? _penumbraRedraw;
|
||||
private readonly ICallGateSubscriber<string, int> _penumbraRemoveTemporaryCollection;
|
||||
@@ -30,6 +31,7 @@ namespace MareSynchronos.Managers
|
||||
Logger.Debug("Creating " + nameof(IpcManager));
|
||||
|
||||
_penumbraInit = pi.GetIpcSubscriber<object>("Penumbra.Initialized");
|
||||
_penumbraDispose = pi.GetIpcSubscriber<object>("Penumbra.Disposed");
|
||||
_penumbraResolvePath = pi.GetIpcSubscriber<string, string, string>("Penumbra.ResolveCharacterPath");
|
||||
_penumbraResolveModDir = pi.GetIpcSubscriber<string>("Penumbra.GetModDirectory");
|
||||
_penumbraRedraw = pi.GetIpcSubscriber<string, int, object>("Penumbra.RedrawObjectByName");
|
||||
@@ -44,7 +46,8 @@ namespace MareSynchronos.Managers
|
||||
pi.GetIpcSubscriber<string, string>("Penumbra.GetMetaManipulations");
|
||||
|
||||
_penumbraObjectIsRedrawn.Subscribe(RedrawEvent);
|
||||
_penumbraInit.Subscribe(RedrawSelf);
|
||||
_penumbraInit.Subscribe(PenumbraInit);
|
||||
_penumbraDispose.Subscribe(PenumbraDispose);
|
||||
|
||||
_penumbraSetTemporaryMod =
|
||||
pi
|
||||
@@ -56,12 +59,17 @@ namespace MareSynchronos.Managers
|
||||
_penumbraRemoveTemporaryCollection =
|
||||
pi.GetIpcSubscriber<string, int>("Penumbra.RemoveTemporaryCollection");
|
||||
|
||||
Initialized = true;
|
||||
if (Initialized)
|
||||
{
|
||||
PenumbraInitialized?.Invoke(null, EventArgs.Empty);
|
||||
}
|
||||
}
|
||||
|
||||
public event EventHandler? PenumbraInitialized;
|
||||
public event EventHandler? PenumbraDisposed;
|
||||
public event EventHandler? PenumbraRedrawEvent;
|
||||
|
||||
public bool Initialized { get; private set; } = false;
|
||||
public bool Initialized => CheckPenumbraApi();
|
||||
public bool CheckGlamourerApi()
|
||||
{
|
||||
try
|
||||
@@ -78,18 +86,22 @@ namespace MareSynchronos.Managers
|
||||
{
|
||||
try
|
||||
{
|
||||
return _penumbraApiVersion.InvokeFunc() >= 4;
|
||||
return _penumbraApiVersion.InvokeFunc() >= 5;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Logger.Debug("Disposing " + nameof(IpcManager));
|
||||
|
||||
Uninitialize();
|
||||
_penumbraDispose.Unsubscribe(PenumbraDispose);
|
||||
_penumbraInit.Unsubscribe(PenumbraInit);
|
||||
_penumbraObjectIsRedrawn.Unsubscribe(RedrawEvent);
|
||||
Logger.Debug("IPC Manager disposed");
|
||||
}
|
||||
|
||||
public void GlamourerApplyCharacterCustomization(string customization, string characterName)
|
||||
@@ -174,17 +186,15 @@ namespace MareSynchronos.Managers
|
||||
PenumbraRedrawEvent?.Invoke(objectTableIndex, EventArgs.Empty);
|
||||
}
|
||||
|
||||
private void RedrawSelf()
|
||||
private void PenumbraInit()
|
||||
{
|
||||
PenumbraInitialized?.Invoke(null, EventArgs.Empty);
|
||||
_penumbraRedraw!.InvokeAction("self", 0);
|
||||
}
|
||||
|
||||
private void Uninitialize()
|
||||
private void PenumbraDispose()
|
||||
{
|
||||
_penumbraInit.Unsubscribe(RedrawSelf);
|
||||
_penumbraObjectIsRedrawn.Unsubscribe(RedrawEvent);
|
||||
Initialized = false;
|
||||
Logger.Debug("IPC Manager disposed");
|
||||
PenumbraDisposed?.Invoke(null, EventArgs.Empty);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user