diff --git a/MareSynchronos/Factories/CharacterDataFactory.cs b/MareSynchronos/Factories/CharacterDataFactory.cs index b9aa74e..3471e8a 100644 --- a/MareSynchronos/Factories/CharacterDataFactory.cs +++ b/MareSynchronos/Factories/CharacterDataFactory.cs @@ -33,14 +33,26 @@ public class CharacterDataFactory this.transientResourceManager = transientResourceManager; } - public CharacterData BuildCharacterData(CharacterData previousData, ObjectKind objectKind, IntPtr playerPointer, CancellationToken token) + public unsafe CharacterData BuildCharacterData(CharacterData previousData, ObjectKind objectKind, IntPtr playerPointer, CancellationToken token) { if (!_ipcManager.Initialized) { throw new ArgumentException("Penumbra is not connected"); } - if (playerPointer == IntPtr.Zero) + bool pointerIsZero = true; + try + { + pointerIsZero = playerPointer == IntPtr.Zero || ((Character*)playerPointer)->GameObject.GetDrawObject() == null; + } + catch (Exception ex) + { + Logger.Warn("Could not create data for " + objectKind); + Logger.Warn(ex.Message); + Logger.Warn(ex.StackTrace ?? string.Empty); + } + + if (pointerIsZero) { Logger.Verbose("Pointer was zero for " + objectKind); previousData.FileReplacements.Remove(objectKind); @@ -191,7 +203,7 @@ public class CharacterDataFactory private void AddReplacementsFromTexture(string texPath, ObjectKind objectKind, CharacterData cache, int inheritanceLevel = 0, bool doNotReverseResolve = true) { - if (texPath.IsNullOrEmpty()) return; + if (string.IsNullOrEmpty(texPath)) return; //Logger.Verbose("Adding File Replacement for Texture " + texPath); @@ -220,6 +232,11 @@ public class CharacterDataFactory private unsafe CharacterData CreateCharacterData(CharacterData previousData, ObjectKind objectKind, IntPtr charaPointer, CancellationToken token) { + if (previousData.FileReplacements.ContainsKey(objectKind)) + { + previousData.FileReplacements[objectKind].Clear(); + } + Stopwatch st = Stopwatch.StartNew(); var chara = _dalamudUtil.CreateGameObject(charaPointer)!; while (!_dalamudUtil.IsObjectPresent(chara)) @@ -229,17 +246,9 @@ public class CharacterDataFactory } _dalamudUtil.WaitWhileCharacterIsDrawing(charaPointer); - if (previousData.FileReplacements.ContainsKey(objectKind)) - { - previousData.FileReplacements[objectKind].Clear(); - } - previousData.ManipulationString = _ipcManager.PenumbraGetMetaManipulations(); - if (objectKind is not ObjectKind.Mount) - { - previousData.GlamourerString[objectKind] = _ipcManager.GlamourerGetCharacterCustomization(chara); - } + previousData.GlamourerString[objectKind] = _ipcManager.GlamourerGetCharacterCustomization(chara); var human = (Human*)((Character*)charaPointer)->GameObject.GetDrawObject(); for (var mdlIdx = 0; mdlIdx < human->CharacterBase.SlotCount; ++mdlIdx) diff --git a/MareSynchronos/Managers/CachedPlayer.cs b/MareSynchronos/Managers/CachedPlayer.cs index 8ef1d8c..5070de0 100644 --- a/MareSynchronos/Managers/CachedPlayer.cs +++ b/MareSynchronos/Managers/CachedPlayer.cs @@ -9,9 +9,9 @@ using FFXIVClientStructs.FFXIV.Client.Game.Character; using MareSynchronos.API; using MareSynchronos.FileCacheDB; using MareSynchronos.Interop; +using MareSynchronos.Models; using MareSynchronos.Utils; using MareSynchronos.WebAPI; -using Penumbra.GameData.Structs; namespace MareSynchronos.Managers; @@ -59,7 +59,7 @@ public class CachedPlayer private CharacterCacheDto _cachedData = new(); - private CharacterEquipment? _currentCharacterEquipment; + private PlayerRelatedObject? _currentCharacterEquipment; public void ApplyCharacterData(CharacterCacheDto characterData) { @@ -235,15 +235,29 @@ public class CachedPlayer RequestedPenumbraRedraw = true; Logger.Debug( $"Request Redraw for {PlayerName}"); - _ipcManager.GlamourerApplyAll(glamourerData, PlayerCharacter.Address); - } - else if (objectKind == ObjectKind.Minion) - { - var minion = ((Character*)PlayerCharacter.Address)->CompanionObject; - if (minion != null) + if (_ipcManager.CheckGlamourerApi() && !string.IsNullOrEmpty(glamourerData)) { - Logger.Debug($"Request Redraw for Minion"); - _ipcManager.GlamourerApplyAll(glamourerData, obj: (IntPtr)minion); + _ipcManager.GlamourerApplyAll(glamourerData, PlayerCharacter.Address); + } + else + { + _ipcManager.PenumbraRedraw(PlayerCharacter.Address); + } + } + else if (objectKind == ObjectKind.MinionOrMount) + { + var minionOrMount = ((Character*)PlayerCharacter.Address)->CompanionObject; + if (minionOrMount != null) + { + Logger.Debug($"Request Redraw for Minion/Mount"); + if (_ipcManager.CheckGlamourerApi() && !string.IsNullOrEmpty(glamourerData)) + { + _ipcManager.GlamourerApplyAll(glamourerData, obj: (IntPtr)minionOrMount); + } + else + { + _ipcManager.PenumbraRedraw((IntPtr)minionOrMount); + } } } else if (objectKind == ObjectKind.Pet) @@ -252,7 +266,14 @@ public class CachedPlayer if (pet != IntPtr.Zero) { Logger.Debug("Request Redraw for Pet"); - _ipcManager.GlamourerApplyAll(glamourerData, pet); + if (_ipcManager.CheckGlamourerApi() && !string.IsNullOrEmpty(glamourerData)) + { + _ipcManager.GlamourerApplyAll(glamourerData, pet); + } + else + { + _ipcManager.PenumbraRedraw(pet); + } } } else if (objectKind == ObjectKind.Companion) @@ -261,16 +282,14 @@ public class CachedPlayer if (companion != IntPtr.Zero) { Logger.Debug("Request Redraw for Companion"); - _ipcManager.GlamourerApplyAll(glamourerData, companion); - } - } - else if (objectKind == ObjectKind.Mount) - { - var mount = ((CharaExt*)PlayerCharacter.Address)->Mount; - if (mount != null) - { - Logger.Debug($"Request Redraw for Mount"); - _ipcManager.PenumbraRedraw((IntPtr)mount); + if (_ipcManager.CheckGlamourerApi() && !string.IsNullOrEmpty(glamourerData)) + { + _ipcManager.GlamourerApplyAll(glamourerData, companion); + } + else + { + _ipcManager.PenumbraRedraw(companion); + } } } } @@ -281,15 +300,22 @@ public class CachedPlayer if (objectKind == ObjectKind.Player) { - _ipcManager.GlamourerApplyOnlyCustomization(_originalGlamourerData, PlayerCharacter); - _ipcManager.GlamourerApplyOnlyEquipment(_lastGlamourerData, PlayerCharacter); - } - else if (objectKind == ObjectKind.Minion) - { - var minion = ((Character*)PlayerCharacter.Address)->CompanionObject; - if (minion != null) + if (_ipcManager.CheckGlamourerApi()) { - _ipcManager.PenumbraRedraw((IntPtr)minion); + _ipcManager.GlamourerApplyOnlyCustomization(_originalGlamourerData, PlayerCharacter); + _ipcManager.GlamourerApplyOnlyEquipment(_lastGlamourerData, PlayerCharacter); + } + else + { + _ipcManager.PenumbraRedraw(PlayerCharacter.Address); + } + } + else if (objectKind == ObjectKind.MinionOrMount) + { + var minionOrMount = ((Character*)PlayerCharacter.Address)->CompanionObject; + if (minionOrMount != null) + { + _ipcManager.PenumbraRedraw((IntPtr)minionOrMount); } } else if (objectKind == ObjectKind.Pet) @@ -308,14 +334,6 @@ public class CachedPlayer _ipcManager.PenumbraRedraw(companion); } } - else if (objectKind == ObjectKind.Mount) - { - var mount = ((CharaExt*)PlayerCharacter.Address)->Mount; - if (mount != null) - { - _ipcManager.PenumbraRedraw((IntPtr)mount); - } - } } public void DisposePlayer() @@ -363,7 +381,8 @@ public class CachedPlayer _dalamudUtil.FrameworkUpdate += DalamudUtilOnFrameworkUpdate; _ipcManager.PenumbraRedrawEvent += IpcManagerOnPenumbraRedrawEvent; _originalGlamourerData = _ipcManager.GlamourerGetCharacterCustomization(PlayerCharacter); - _currentCharacterEquipment = new CharacterEquipment(PlayerCharacter); + _currentCharacterEquipment = new PlayerRelatedObject(ObjectKind.Player, IntPtr.Zero, IntPtr.Zero, + () => _dalamudUtil.GetPlayerCharacterFromObjectTableByName(PlayerName)?.Address ?? IntPtr.Zero); _isDisposed = false; if (cache != null) { @@ -382,7 +401,8 @@ public class CachedPlayer return; } - if (!_currentCharacterEquipment!.CompareAndUpdate(PlayerCharacter)) + _currentCharacterEquipment?.CheckAndUpdateObject(); + if (_currentCharacterEquipment?.HasUnprocessedUpdate ?? false) { OnPlayerChanged(); } @@ -406,7 +426,9 @@ public class CachedPlayer _penumbraRedrawEventTask = Task.Run(() => { PlayerCharacter = player; - _dalamudUtil.WaitWhileCharacterIsDrawing(PlayerCharacter.Address); + using var cts = new CancellationTokenSource(); + cts.CancelAfter(TimeSpan.FromSeconds(5)); + _dalamudUtil.WaitWhileCharacterIsDrawing(PlayerCharacter.Address, cts.Token); if (RequestedPenumbraRedraw == false) { @@ -425,6 +447,7 @@ public class CachedPlayer private void OnPlayerChanged() { Logger.Debug($"Player {PlayerName} changed, PenumbraRedraw is {RequestedPenumbraRedraw}"); + _currentCharacterEquipment!.HasUnprocessedUpdate = false; if (!RequestedPenumbraRedraw && PlayerCharacter is not null) { Logger.Debug($"Saving new Glamourer data"); diff --git a/MareSynchronos/Managers/IpcManager.cs b/MareSynchronos/Managers/IpcManager.cs index 9a40397..0466e99 100644 --- a/MareSynchronos/Managers/IpcManager.cs +++ b/MareSynchronos/Managers/IpcManager.cs @@ -158,12 +158,19 @@ namespace MareSynchronos.Managers public string GlamourerGetCharacterCustomization(GameObject character) { if (!CheckGlamourerApi()) return string.Empty; - var glamourerString = _glamourerGetAllCustomization!.InvokeFunc(character); - byte[] bytes = Convert.FromBase64String(glamourerString); - // ignore transparency - bytes[88] = 128; - bytes[89] = 63; - return Convert.ToBase64String(bytes); + try + { + var glamourerString = _glamourerGetAllCustomization!.InvokeFunc(character); + byte[] bytes = Convert.FromBase64String(glamourerString); + // ignore transparency + bytes[88] = 128; + bytes[89] = 63; + return Convert.ToBase64String(bytes); + } + catch + { + return string.Empty; + } } public void GlamourerRevertCharacterCustomization(GameObject character) diff --git a/MareSynchronos/Managers/PlayerManager.cs b/MareSynchronos/Managers/PlayerManager.cs index 5c6638a..baef948 100644 --- a/MareSynchronos/Managers/PlayerManager.cs +++ b/MareSynchronos/Managers/PlayerManager.cs @@ -5,12 +5,10 @@ using System; using System.Threading; using System.Threading.Tasks; using MareSynchronos.API; -using Penumbra.GameData.Structs; using FFXIVClientStructs.FFXIV.Client.Game.Character; using System.Collections.Generic; using System.Linq; using MareSynchronos.Models; -using MareSynchronos.Interop; namespace MareSynchronos.Managers { @@ -30,7 +28,6 @@ namespace MareSynchronos.Managers private CancellationTokenSource? _playerChangedCts = new(); private DateTime _lastPlayerObjectCheck; - private CharacterEquipment? _currentCharacterEquipment = new(); private List playerRelatedObjects = new List(); @@ -58,10 +55,9 @@ namespace MareSynchronos.Managers playerRelatedObjects = new List() { new PlayerRelatedObject(ObjectKind.Player, IntPtr.Zero, IntPtr.Zero, () => _dalamudUtil.PlayerPointer), - new PlayerRelatedObject(ObjectKind.Minion, IntPtr.Zero, IntPtr.Zero, () => (IntPtr)((Character*)_dalamudUtil.PlayerPointer)->CompanionObject), + new PlayerRelatedObject(ObjectKind.MinionOrMount, IntPtr.Zero, IntPtr.Zero, () => (IntPtr)((Character*)_dalamudUtil.PlayerPointer)->CompanionObject), new PlayerRelatedObject(ObjectKind.Pet, IntPtr.Zero, IntPtr.Zero, () => _dalamudUtil.GetPet()), new PlayerRelatedObject(ObjectKind.Companion, IntPtr.Zero, IntPtr.Zero, () => _dalamudUtil.GetCompanion()), - new PlayerRelatedObject(ObjectKind.Mount, IntPtr.Zero, IntPtr.Zero, () => (IntPtr)((CharaExt*)_dalamudUtil.PlayerPointer)->Mount), }; } diff --git a/MareSynchronos/MareSynchronos.csproj b/MareSynchronos/MareSynchronos.csproj index 847875a..093d1cf 100644 --- a/MareSynchronos/MareSynchronos.csproj +++ b/MareSynchronos/MareSynchronos.csproj @@ -3,7 +3,7 @@ - 0.3.4 + 0.3.10 https://github.com/Penumbra-Sync/client @@ -21,12 +21,12 @@ - $(appdata)\XIVLauncher\addon\Hooks\dev\ + $(appdata)\XIVLauncher\addon\Hooks\Dev\ - + @@ -84,7 +84,7 @@ - + diff --git a/MareSynchronos/Models/PlayerRelatedObject.cs b/MareSynchronos/Models/PlayerRelatedObject.cs index 1c8fde9..7d8e50e 100644 --- a/MareSynchronos/Models/PlayerRelatedObject.cs +++ b/MareSynchronos/Models/PlayerRelatedObject.cs @@ -47,7 +47,7 @@ namespace MareSynchronos.Models var chara = (Character*)curPtr; bool addr = Address == IntPtr.Zero || Address != curPtr; bool equip = CompareAndUpdateByteData(chara->EquipSlotData, chara->CustomizeData); - bool drawObj = (chara->GameObject.DrawObject != null && (IntPtr)chara->GameObject.DrawObject != DrawObjectAddress); + bool drawObj = (IntPtr)chara->GameObject.DrawObject != DrawObjectAddress; var name = new Utf8String(chara->GameObject.Name).ToString(); bool nameChange = (name != _name); if (addr || equip || drawObj || nameChange) @@ -60,17 +60,11 @@ namespace MareSynchronos.Models HasUnprocessedUpdate = true; } } - else + else if (Address != IntPtr.Zero || DrawObjectAddress != IntPtr.Zero) { - if (Address != IntPtr.Zero || DrawObjectAddress != IntPtr.Zero) - { - Address = IntPtr.Zero; - DrawObjectAddress = IntPtr.Zero; - HasUnprocessedUpdate = true; - } - Address = IntPtr.Zero; DrawObjectAddress = IntPtr.Zero; + Logger.Verbose(ObjectKind + " Changed: " + _name + ", now: " + Address + ", " + DrawObjectAddress); } } @@ -98,33 +92,30 @@ namespace MareSynchronos.Models } } - if (ObjectKind is not ObjectKind.Mount) + var newHatState = Marshal.ReadByte((IntPtr)customizeData + 30, 0); + var newWeaponOrVisorState = Marshal.ReadByte((IntPtr)customizeData + 31, 0); + if (newHatState != HatState) { - var newHatState = Marshal.ReadByte((IntPtr)customizeData + 30, 0); - var newWeaponOrVisorState = Marshal.ReadByte((IntPtr)customizeData + 31, 0); - if (newHatState != HatState) + if (HatState != null && !hasChanges && !HasUnprocessedUpdate) { - if (HatState != null && !hasChanges && !HasUnprocessedUpdate) - { - Logger.Debug("Not Sending Update, only Hat changed"); - DoNotSendUpdate = true; - } - HatState = newHatState; - hasChanges = true; + Logger.Debug("Not Sending Update, only Hat changed"); + DoNotSendUpdate = true; } + HatState = newHatState; + hasChanges = true; + } - newWeaponOrVisorState &= 0b1101; // ignore drawing weapon + newWeaponOrVisorState &= 0b1101; // ignore drawing weapon - if (newWeaponOrVisorState != VisorWeaponState) + if (newWeaponOrVisorState != VisorWeaponState) + { + if (VisorWeaponState != null && !hasChanges && !HasUnprocessedUpdate) { - if (VisorWeaponState != null && !hasChanges && !HasUnprocessedUpdate) - { - Logger.Debug("Not Sending Update, only Visor/Weapon changed"); - DoNotSendUpdate = true; - } - VisorWeaponState = newWeaponOrVisorState; - hasChanges = true; + Logger.Debug("Not Sending Update, only Visor/Weapon changed"); + DoNotSendUpdate = true; } + VisorWeaponState = newWeaponOrVisorState; + hasChanges = true; } return hasChanges; diff --git a/MareSynchronos/Plugin.cs b/MareSynchronos/Plugin.cs index d62b9e0..753a233 100644 --- a/MareSynchronos/Plugin.cs +++ b/MareSynchronos/Plugin.cs @@ -13,6 +13,7 @@ using MareSynchronos.WebAPI; using Dalamud.Interface.Windowing; using MareSynchronos.UI; using MareSynchronos.Utils; +using System.Runtime.InteropServices; namespace MareSynchronos { @@ -64,6 +65,10 @@ namespace MareSynchronos _apiController = new ApiController(_configuration, _dalamudUtil); _ipcManager = new IpcManager(PluginInterface, _dalamudUtil); + // Compatibility for FileSystemWatchers under OSX + if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) + Environment.SetEnvironmentVariable("MONO_MANAGED_WATCHER", "enabled"); + _fileCacheManager = new FileCacheManager(_ipcManager, _configuration); _fileDialogManager = new FileDialogManager(); diff --git a/MareSynchronos/UI/CompactUI.cs b/MareSynchronos/UI/CompactUI.cs index b48d416..f3f5252 100644 --- a/MareSynchronos/UI/CompactUI.cs +++ b/MareSynchronos/UI/CompactUI.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.IO; using System.Linq; using System.Numerics; using System.Reflection; @@ -33,7 +34,13 @@ namespace MareSynchronos.UI private float _windowContentWidth = 0; public CompactUi(WindowSystem windowSystem, - UiShared uiShared, Configuration configuration, ApiController apiController) : base("Mare Synchronos " + Assembly.GetExecutingAssembly().GetName().Version + "###MareSynchronosMainUI") + UiShared uiShared, Configuration configuration, ApiController apiController) +#if DEBUG + : base("Mare Synchronos " + new FileInfo(Assembly.GetExecutingAssembly().Location) .LastWriteTime.ToString("yyyyMMddHHmmss")+ "###MareSynchronosMainUI") +#else + : base("Mare Synchronos " + Assembly.GetExecutingAssembly().GetName().Version + "###MareSynchronosMainUI") +#endif + { Logger.Verbose("Creating " + nameof(CompactUi)); @@ -132,7 +139,8 @@ namespace MareSynchronos.UI var buttonSize = UiShared.GetIconButtonSize(pauseIcon); var trashButtonSize = UiShared.GetIconButtonSize(FontAwesomeIcon.Trash); - var textSize = ImGui.CalcTextSize(entry.OtherUID); + var entryUID = string.IsNullOrEmpty(entry.VanityUID) ? entry.OtherUID : entry.VanityUID; + var textSize = ImGui.CalcTextSize(entryUID); var originalY = ImGui.GetCursorPosY(); var buttonSizes = buttonSize.Y + trashButtonSize.Y; @@ -144,7 +152,7 @@ namespace MareSynchronos.UI UiShared.ColorText(FontAwesomeIcon.ArrowUp.ToIconString(), ImGuiColors.DalamudRed); ImGui.PopFont(); - UiShared.AttachToolTip(entry.OtherUID + " has not added you back"); + UiShared.AttachToolTip(entryUID + " has not added you back"); } else if (entry.IsPaused || entry.IsPausedFromOthers) { @@ -152,7 +160,7 @@ namespace MareSynchronos.UI UiShared.ColorText(FontAwesomeIcon.PauseCircle.ToIconString(), ImGuiColors.DalamudYellow); ImGui.PopFont(); - UiShared.AttachToolTip("Pairing status with " + entry.OtherUID + " is paused"); + UiShared.AttachToolTip("Pairing status with " + entryUID + " is paused"); } else { @@ -160,16 +168,16 @@ namespace MareSynchronos.UI UiShared.ColorText(FontAwesomeIcon.Check.ToIconString(), ImGuiColors.ParsedGreen); ImGui.PopFont(); - UiShared.AttachToolTip("You are paired with " + entry.OtherUID); + UiShared.AttachToolTip("You are paired with " + entryUID); } var textIsUid = true; _showUidForEntry.TryGetValue(entry.OtherUID, out var showUidInsteadOfName); if (!showUidInsteadOfName && _configuration.GetCurrentServerUidComments().TryGetValue(entry.OtherUID, out var playerText)) { - if (playerText.IsNullOrEmpty()) + if (string.IsNullOrEmpty(playerText)) { - playerText = entry.OtherUID; + playerText = entryUID; } else { @@ -178,7 +186,7 @@ namespace MareSynchronos.UI } else { - playerText = entry.OtherUID; + playerText = entryUID; } ImGui.SameLine(); @@ -189,7 +197,7 @@ namespace MareSynchronos.UI ImGui.TextUnformatted(playerText); if (textIsUid) ImGui.PopFont(); UiShared.AttachToolTip("Left click to switch between UID display and nick" + Environment.NewLine + - "Right click to change nick for " + entry.OtherUID); + "Right click to change nick for " + entryUID); if (ImGui.IsItemClicked(ImGuiMouseButton.Left)) { var prevState = textIsUid; @@ -240,7 +248,7 @@ namespace MareSynchronos.UI _apiController.PairedClients.Remove(entry); } } - UiShared.AttachToolTip("Hold CTRL and click to unpair permanently from " + entry.OtherUID); + UiShared.AttachToolTip("Hold CTRL and click to unpair permanently from " + entryUID); if (entry.IsSynced) { @@ -251,8 +259,8 @@ namespace MareSynchronos.UI _ = _apiController.SendPairedClientPauseChange(entry.OtherUID, !entry.IsPaused); } UiShared.AttachToolTip(!entry.IsPaused - ? "Pause pairing with " + entry.OtherUID - : "Resume pairing with " + entry.OtherUID); + ? "Pause pairing with " + entryUID + : "Resume pairing with " + entryUID); } } diff --git a/MareSynchronos/UI/UIShared.cs b/MareSynchronos/UI/UIShared.cs index 277084e..6c83c57 100644 --- a/MareSynchronos/UI/UIShared.cs +++ b/MareSynchronos/UI/UIShared.cs @@ -40,7 +40,6 @@ namespace MareSynchronos.UI public static bool CtrlPressed() => (GetKeyState(0xA2) & 0x8000) != 0 || (GetKeyState(0xA3) & 0x8000) != 0; - // todo remove after rework public ApiController ApiController => _apiController; public UiShared(IpcManager ipcManager, ApiController apiController, FileCacheManager fileCacheManager, FileDialogManager fileDialogManager, Configuration pluginConfiguration, DalamudUtil dalamudUtil, DalamudPluginInterface pluginInterface, Dalamud.Localization localization) diff --git a/MareSynchronos/WebAPI/ApIController.Functions.Files.cs b/MareSynchronos/WebAPI/ApIController.Functions.Files.cs index 100f54a..2c224be 100644 --- a/MareSynchronos/WebAPI/ApIController.Functions.Files.cs +++ b/MareSynchronos/WebAPI/ApIController.Functions.Files.cs @@ -74,7 +74,7 @@ namespace MareSynchronos.WebAPI Logger.Debug("Downloading files (Download ID " + currentDownloadId + ")"); List downloadFileInfoFromService = new List(); - downloadFileInfoFromService.AddRange(await _mareHub!.InvokeAsync>(Api.InvokeGetFilesSizes, fileReplacementDto.Select(m => m.Hash).ToList(), ct)); + downloadFileInfoFromService.AddRange(await _mareHub!.InvokeAsync>(Api.InvokeGetFilesSizes, fileReplacementDto.Select(f => f.Hash).ToList(), ct)); CurrentDownloads[currentDownloadId] = downloadFileInfoFromService.Distinct().Select(d => new DownloadFileTransfer(d)) .Where(d => d.CanBeTransferred).ToList(); diff --git a/MareSynchronos/WebAPI/ApiController.Connectivity.cs b/MareSynchronos/WebAPI/ApiController.Connectivity.cs index 802cff4..3f3b074 100644 --- a/MareSynchronos/WebAPI/ApiController.Connectivity.cs +++ b/MareSynchronos/WebAPI/ApiController.Connectivity.cs @@ -68,6 +68,7 @@ namespace MareSynchronos.WebAPI private void DalamudUtilOnLogOut() { Task.Run(async () => await StopConnection(_connectionCancellationTokenSource.Token)); + ServerState = ServerState.Offline; } private void DalamudUtilOnLogIn() @@ -124,21 +125,34 @@ namespace MareSynchronos.WebAPI private string ApiUri => _pluginConfiguration.ApiUri; public int OnlineUsers => SystemInfoDto.OnlineUsers; - public ServerState ServerState { get; private set; } + private ServerState _serverState; + public ServerState ServerState + { + get => _serverState; + private set + { + Logger.Debug($"New ServerState: {value}, prev ServerState: {_serverState}"); + _serverState = value; + } + } public async Task CreateConnections() { - Logger.Info("Recreating Connection"); - - await StopConnection(_connectionCancellationTokenSource.Token); + Logger.Debug("CreateConnections called"); if (_pluginConfiguration.FullPause) { + Logger.Info("Not recreating Connection, paused"); ServerState = ServerState.Disconnected; _connectionDto = null; + await StopConnection(_connectionCancellationTokenSource.Token); return; } + await StopConnection(_connectionCancellationTokenSource.Token); + + Logger.Info("Recreating Connection"); + _connectionCancellationTokenSource.Cancel(); _connectionCancellationTokenSource = new CancellationTokenSource(); var token = _connectionCancellationTokenSource.Token; @@ -188,7 +202,6 @@ namespace MareSynchronos.WebAPI await InitializeData(token); _mareHub.Closed += MareHubOnClosed; - _mareHub.Reconnected += MareHubOnReconnected; _mareHub.Reconnecting += MareHubOnReconnecting; } } @@ -287,7 +300,7 @@ namespace MareSynchronos.WebAPI .WithUrl(ApiUri + hubName, options => { options.Headers.Add("Authorization", SecretKey); - options.Transports = HttpTransportType.WebSockets; + options.Transports = HttpTransportType.WebSockets | HttpTransportType.ServerSentEvents | HttpTransportType.LongPolling; }) .WithAutomaticReconnect(new ForeverRetryPolicy()) .Build(); @@ -298,30 +311,21 @@ namespace MareSynchronos.WebAPI CurrentUploads.Clear(); CurrentDownloads.Clear(); _uploadCancellationTokenSource?.Cancel(); - Logger.Info("Connection closed"); Disconnected?.Invoke(); ServerState = ServerState.Offline; + Logger.Info("Connection closed"); return Task.CompletedTask; } - private async Task MareHubOnReconnected(string? arg) - { - Logger.Info("Connection restored"); - await Task.Delay(TimeSpan.FromSeconds(new Random().Next(5, 10))); - - _ = Task.Run(CreateConnections); - } - private Task MareHubOnReconnecting(Exception? arg) { - CurrentUploads.Clear(); - CurrentDownloads.Clear(); - _uploadCancellationTokenSource?.Cancel(); ServerState = ServerState.Disconnected; Logger.Warn("Connection closed... Reconnecting"); Logger.Warn(arg?.Message ?? string.Empty); Logger.Warn(arg?.StackTrace ?? string.Empty); Disconnected?.Invoke(); + ServerState = ServerState.Offline; + _ = Task.Run(CreateConnections); return Task.CompletedTask; } @@ -331,13 +335,24 @@ namespace MareSynchronos.WebAPI { _uploadCancellationTokenSource?.Cancel(); Logger.Info("Stopping existing connection"); - await _mareHub.StopAsync(token); _mareHub.Closed -= MareHubOnClosed; - _mareHub.Reconnected -= MareHubOnReconnected; _mareHub.Reconnecting += MareHubOnReconnecting; + await _mareHub.StopAsync(token); await _mareHub.DisposeAsync(); + CurrentUploads.Clear(); + CurrentDownloads.Clear(); + _uploadCancellationTokenSource?.Cancel(); + Disconnected?.Invoke(); _mareHub = null; } + + if (ServerState != ServerState.Disconnected) + { + while (ServerState != ServerState.Offline) + { + await Task.Delay(16); + } + } } } }