refactor + add resiliency against penumbra/api shutdowns

This commit is contained in:
Stanley Dimant
2022-06-25 21:39:20 +02:00
parent 8c9f816e6d
commit 3bba240cd5
9 changed files with 169 additions and 150 deletions

View File

@@ -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;

View File

@@ -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());
}
});
}

View File

@@ -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);

View File

@@ -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);
}
}
}