diff --git a/MareSynchronos/MareSynchronos.csproj b/MareSynchronos/MareSynchronos.csproj index 92e01ae..8b2c0bb 100644 --- a/MareSynchronos/MareSynchronos.csproj +++ b/MareSynchronos/MareSynchronos.csproj @@ -3,7 +3,7 @@ - 0.8.0 + 0.8.1 https://github.com/Penumbra-Sync/client diff --git a/MareSynchronos/PlayerData/Pairs/CachedPlayer.cs b/MareSynchronos/PlayerData/Pairs/CachedPlayer.cs index 3a5ff99..5e8e1e5 100644 --- a/MareSynchronos/PlayerData/Pairs/CachedPlayer.cs +++ b/MareSynchronos/PlayerData/Pairs/CachedPlayer.cs @@ -23,6 +23,7 @@ public sealed class CachedPlayer : DisposableMediatorSubscriberBase private readonly Func, bool, GameObjectHandler> _gameObjectHandlerFactory; private readonly IpcManager _ipcManager; private readonly IHostApplicationLifetime _lifetime; + private CancellationTokenSource _applicationCancellationTokenSource = new(); private Guid _applicationId; private Task? _applicationTask; private CharacterData _cachedData = new(); @@ -149,6 +150,8 @@ public sealed class CachedPlayer : DisposableMediatorSubscriberBase try { Guid applicationId = Guid.NewGuid(); + _applicationCancellationTokenSource.Cancel(); + _applicationCancellationTokenSource.Dispose(); _downloadCancellationTokenSource?.Cancel(); _downloadCancellationTokenSource?.Dispose(); _downloadCancellationTokenSource = null; @@ -178,13 +181,15 @@ public sealed class CachedPlayer : DisposableMediatorSubscriberBase } } - private async Task ApplyBaseData(Guid applicationId, Dictionary moddedPaths, string manipulationData) + private async Task ApplyBaseData(Guid applicationId, Dictionary moddedPaths, string manipulationData, CancellationToken token) { await _dalamudUtil.RunOnFrameworkThread(() => _ipcManager.PenumbraRemoveTemporaryCollection(Logger, applicationId, PlayerName!)).ConfigureAwait(false); + token.ThrowIfCancellationRequested(); await _dalamudUtil.RunOnFrameworkThread(() => _ipcManager.PenumbraSetTemporaryMods(Logger, applicationId, PlayerName!, moddedPaths, manipulationData)).ConfigureAwait(false); + token.ThrowIfCancellationRequested(); } - private async Task ApplyCustomizationData(Guid applicationId, KeyValuePair> changes, API.Data.CharacterData charaData) + private async Task ApplyCustomizationData(Guid applicationId, KeyValuePair> changes, CharacterData charaData, CancellationToken token) { if (PlayerCharacter == IntPtr.Zero) return; var ptr = PlayerCharacter; @@ -197,9 +202,6 @@ public sealed class CachedPlayer : DisposableMediatorSubscriberBase _ => throw new NotSupportedException("ObjectKind not supported: " + changes.Key) }; - CancellationTokenSource applicationTokenSource = new(); - applicationTokenSource.CancelAfter(TimeSpan.FromSeconds(30)); - if (handler.Address == IntPtr.Zero) { if (handler != _charaHandler) handler.Dispose(); @@ -228,11 +230,11 @@ public sealed class CachedPlayer : DisposableMediatorSubscriberBase case PlayerChanges.Mods: if (charaData.GlamourerData.TryGetValue(changes.Key, out var glamourerData)) { - await _ipcManager.GlamourerApplyAll(Logger, handler, glamourerData, applicationId, applicationTokenSource.Token).ConfigureAwait(false); + await _ipcManager.GlamourerApplyAll(Logger, handler, glamourerData, applicationId, token).ConfigureAwait(false); } else { - await _ipcManager.PenumbraRedraw(Logger, handler, applicationId, applicationTokenSource.Token).ConfigureAwait(false); + await _ipcManager.PenumbraRedraw(Logger, handler, applicationId, token).ConfigureAwait(false); } break; } @@ -389,6 +391,9 @@ public sealed class CachedPlayer : DisposableMediatorSubscriberBase if (downloadToken.IsCancellationRequested) return; + _applicationCancellationTokenSource?.Dispose(); + _applicationCancellationTokenSource = new(); + var token = _applicationCancellationTokenSource.Token; _applicationTask = Task.Run(async () => { _applicationId = Guid.NewGuid(); @@ -396,16 +401,18 @@ public sealed class CachedPlayer : DisposableMediatorSubscriberBase if (updateModdedPaths && (moddedPaths.Any() || !string.IsNullOrEmpty(charaData.ManipulationData))) { - await ApplyBaseData(_applicationId, moddedPaths, charaData.ManipulationData).ConfigureAwait(false); + await ApplyBaseData(_applicationId, moddedPaths, charaData.ManipulationData, token).ConfigureAwait(false); } + token.ThrowIfCancellationRequested(); + foreach (var kind in updatedData) { - await ApplyCustomizationData(_applicationId, kind, charaData).ConfigureAwait(false); + await ApplyCustomizationData(_applicationId, kind, charaData, token).ConfigureAwait(false); } Logger.LogDebug("[{applicationId}] Application finished", _applicationId); - }); + }, token); }, downloadToken); } @@ -426,7 +433,7 @@ public sealed class CachedPlayer : DisposableMediatorSubscriberBase Logger.LogDebug("Unauthorized character change detected"); await ApplyCustomizationData(applicationId, new(ObjectKind.Player, new HashSet(new[] { PlayerChanges.Palette, PlayerChanges.Customize, PlayerChanges.Heels, PlayerChanges.Mods })), - _cachedData).ConfigureAwait(false); + _cachedData, _applicationCancellationTokenSource.Token).ConfigureAwait(false); }, token); } diff --git a/MareSynchronos/Services/DalamudUtilService.cs b/MareSynchronos/Services/DalamudUtilService.cs index a1b7d84..36ff33a 100644 --- a/MareSynchronos/Services/DalamudUtilService.cs +++ b/MareSynchronos/Services/DalamudUtilService.cs @@ -186,12 +186,6 @@ public class DalamudUtilService : IHostedService return Task.CompletedTask; } - public Vector2 WorldToScreen(Dalamud.Game.ClientState.Objects.Types.GameObject? obj) - { - if (obj == null) return Vector2.Zero; - return _gameGui.WorldToScreen(obj.Position, out var screenPos) ? screenPos : Vector2.Zero; - } - public async Task WaitWhileCharacterIsDrawing(ILogger logger, GameObjectHandler handler, Guid redrawId, int timeOut = 5000, CancellationToken? ct = null) { if (!_clientState.IsLoggedIn || handler.Address == IntPtr.Zero) return; @@ -202,7 +196,6 @@ public class DalamudUtilService : IHostedService int curWaitTime = 0; try { - // ReSharper disable once LoopVariableIsNeverChangedInsideLoop while ((!ct?.IsCancellationRequested ?? true) && curWaitTime < timeOut && await handler.IsBeingDrawnRunOnFramework().ConfigureAwait(true)) // 0b100000000000 is "still rendering" or something @@ -242,6 +235,12 @@ public class DalamudUtilService : IHostedService Thread.Sleep(tick * 2); } + public Vector2 WorldToScreen(Dalamud.Game.ClientState.Objects.Types.GameObject? obj) + { + if (obj == null) return Vector2.Zero; + return _gameGui.WorldToScreen(obj.Position, out var screenPos) ? screenPos : Vector2.Zero; + } + private void FrameworkOnUpdate(Framework framework) { _performanceCollector.LogPerformance(this, "FrameworkOnUpdate", FrameworkOnUpdateInternal); diff --git a/MareSynchronos/UI/CompactUI.cs b/MareSynchronos/UI/CompactUI.cs index 9503a4b..da16d43 100644 --- a/MareSynchronos/UI/CompactUI.cs +++ b/MareSynchronos/UI/CompactUI.cs @@ -679,7 +679,7 @@ public class CompactUi : WindowMediatorSubscriberBase var color = UiSharedService.GetBoolColor(!_serverManager.CurrentServer!.FullPause); var connectedIcon = !_serverManager.CurrentServer.FullPause ? FontAwesomeIcon.Link : FontAwesomeIcon.Unlink; - if (_apiController.ServerState != ServerState.Reconnecting) + if (_apiController.ServerState is not (ServerState.Reconnecting or ServerState.Disconnecting)) { ImGui.PushStyleColor(ImGuiCol.Text, color); if (ImGuiComponents.IconButton(connectedIcon)) @@ -819,6 +819,7 @@ public class CompactUi : WindowMediatorSubscriberBase ServerState.Connecting => "Attempting to connect to the server.", ServerState.Reconnecting => "Connection to server interrupted, attempting to reconnect to the server.", ServerState.Disconnected => "You are currently disconnected from the Mare Synchronos server.", + ServerState.Disconnecting => "Disconnecting from the server", ServerState.Unauthorized => "Server Response: " + _apiController.AuthFailureMessage, ServerState.Offline => "Your selected Mare Synchronos server is currently offline.", ServerState.VersionMisMatch => @@ -838,6 +839,7 @@ public class CompactUi : WindowMediatorSubscriberBase ServerState.Reconnecting => ImGuiColors.DalamudRed, ServerState.Connected => ImGuiColors.ParsedGreen, ServerState.Disconnected => ImGuiColors.DalamudYellow, + ServerState.Disconnecting => ImGuiColors.DalamudYellow, ServerState.Unauthorized => ImGuiColors.DalamudRed, ServerState.VersionMisMatch => ImGuiColors.DalamudRed, ServerState.Offline => ImGuiColors.DalamudRed, @@ -854,6 +856,7 @@ public class CompactUi : WindowMediatorSubscriberBase ServerState.Reconnecting => "Reconnecting", ServerState.Connecting => "Connecting", ServerState.Disconnected => "Disconnected", + ServerState.Disconnecting => "Disconnecting", ServerState.Unauthorized => "Unauthorized", ServerState.VersionMisMatch => "Version mismatch", ServerState.Offline => "Unavailable", diff --git a/MareSynchronos/UI/SettingsUi.cs b/MareSynchronos/UI/SettingsUi.cs index 8f7deb6..5ea7b46 100644 --- a/MareSynchronos/UI/SettingsUi.cs +++ b/MareSynchronos/UI/SettingsUi.cs @@ -147,7 +147,11 @@ public class SettingsUi : WindowMediatorSubscriberBase _configService.Current.ShowTransferWindow = showTransferWindow; _configService.Save(); } - + UiSharedService.DrawHelpText($"The download window will show the current progress of outstanding downloads.{Environment.NewLine}{Environment.NewLine}" + + $"What do W/Q/P/D stand for?{Environment.NewLine}W = Waiting for Slot (see Maximum Parallel Downloads){Environment.NewLine}" + + $"Q = Queued on Server, waiting for queue ready signal{Environment.NewLine}" + + $"P = Processing download (aka downloading){Environment.NewLine}" + + $"D = Decompressing download"); if (!_configService.Current.ShowTransferWindow) ImGui.BeginDisabled(); ImGui.Indent(); bool editTransferWindowPosition = _uiShared.EditTrackerPosition; diff --git a/MareSynchronos/WebAPI/SignalR/ApiController.cs b/MareSynchronos/WebAPI/SignalR/ApiController.cs index 80d7408..cc61bd7 100644 --- a/MareSynchronos/WebAPI/SignalR/ApiController.cs +++ b/MareSynchronos/WebAPI/SignalR/ApiController.cs @@ -334,7 +334,7 @@ public sealed partial class ApiController : DisposableMediatorSubscriberBase, IM private async Task StopConnection(ServerState state) { - ServerState = state; + ServerState = ServerState.Disconnecting; if (_mareHub is not null) { @@ -346,5 +346,7 @@ public sealed partial class ApiController : DisposableMediatorSubscriberBase, IM _mareHub = null; _connectionDto = null; } + + ServerState = state; } } \ No newline at end of file diff --git a/MareSynchronos/WebAPI/SignalR/Utils/ServerState.cs b/MareSynchronos/WebAPI/SignalR/Utils/ServerState.cs index f37f992..2988d44 100644 --- a/MareSynchronos/WebAPI/SignalR/Utils/ServerState.cs +++ b/MareSynchronos/WebAPI/SignalR/Utils/ServerState.cs @@ -5,10 +5,11 @@ public enum ServerState Offline, Connecting, Reconnecting, + Disconnecting, Disconnected, Connected, Unauthorized, VersionMisMatch, RateLimited, NoSecretKey, -} +} \ No newline at end of file